From cd38ee93a924b7e179bfddbca11e3dc8f8fef836 Mon Sep 17 00:00:00 2001 From: Patrick O'Brien Date: Mon, 22 Aug 2022 17:34:34 -0400 Subject: [PATCH 01/46] Change PySide2 imports to PySide6 imports --- .pylintrc | 2 +- .../tut/quick-topics/Managing-variables.ipynb | 13 ++- environment.yml | 2 +- qiskit_metal/__init__.py | 6 +- qiskit_metal/_gui/__compile_ui_to_py.bat | 10 +-- qiskit_metal/_gui/__compile_ui_to_py.shell | 6 +- qiskit_metal/_gui/component_widget_ui.py | 4 +- qiskit_metal/_gui/elements_ui.py | 8 +- qiskit_metal/_gui/elements_window.py | 8 +- qiskit_metal/_gui/endcap_hfss_gui.py | 2 +- qiskit_metal/_gui/endcap_hfss_ui.py | 4 +- qiskit_metal/_gui/endcap_q3d_gui.py | 2 +- qiskit_metal/_gui/endcap_q3d_ui.py | 4 +- qiskit_metal/_gui/list_model_base.py | 6 +- qiskit_metal/_gui/main_window.py | 15 +++- qiskit_metal/_gui/main_window_base.py | 8 +- qiskit_metal/_gui/main_window_rc_rc.py | 4 +- qiskit_metal/_gui/main_window_ui.py | 88 +++++++++---------- qiskit_metal/_gui/net_list_ui.py | 4 +- qiskit_metal/_gui/net_list_window.py | 8 +- qiskit_metal/_gui/plot_window_ui.py | 18 ++-- qiskit_metal/_gui/renderer_gds_gui.py | 2 +- qiskit_metal/_gui/renderer_gds_model.py | 6 +- qiskit_metal/_gui/renderer_gds_ui.py | 4 +- qiskit_metal/_gui/renderer_hfss_gui.py | 2 +- qiskit_metal/_gui/renderer_hfss_model.py | 6 +- qiskit_metal/_gui/renderer_hfss_ui.py | 4 +- qiskit_metal/_gui/renderer_q3d_gui.py | 2 +- qiskit_metal/_gui/renderer_q3d_model.py | 6 +- qiskit_metal/_gui/renderer_q3d_ui.py | 4 +- qiskit_metal/_gui/tree_view_base.py | 6 +- .../_gui/utility/_handle_qt_messages.py | 6 +- qiskit_metal/_gui/utility/_toolbox_qt.py | 12 +-- .../table_model_all_components.py | 8 +- .../table_view_all_components.py | 8 +- .../widgets/bases/QWidget_PlaceholderText.py | 8 +- .../_gui/widgets/bases/dict_tree_base.py | 10 +-- .../_gui/widgets/bases/expanding_toolbar.py | 6 +- .../build_history_scroll_area.py | 2 +- .../build_history_scroll_area_ui.py | 4 +- .../model_view/tree_delegate_param_entry.py | 4 +- .../model_view/tree_model_param_entry.py | 8 +- .../model_view/tree_view_param_entry.py | 6 +- .../parameter_entry_window.py | 8 +- .../parameter_entry_window_ui.py | 4 +- .../edit_component/component_widget.py | 10 +-- .../edit_component/table_model_options.py | 6 +- .../edit_component/table_view_options.py | 6 +- .../edit_component/tree_model_options.py | 6 +- .../edit_component/tree_view_options.py | 6 +- .../_gui/widgets/log_widget/log_metal.py | 7 +- .../_gui/widgets/plot_widget/plot_window.py | 4 +- .../qlibrary_display/delegate_qlibrary.py | 6 +- .../qlibrary_display/file_model_qlibrary.py | 6 +- .../qlibrary_display/proxy_model_qlibrary.py | 6 +- .../qlibrary_display/tree_view_qlibrary.py | 6 +- .../variable_table/add_delete_table_ui.py | 4 +- .../widgets/variable_table/dialog_popup_ui.py | 4 +- .../variable_table/prop_val_table_gui.py | 4 +- .../variable_table/prop_val_table_model.py | 6 +- .../variable_table/right_click_table_view.py | 10 +-- .../renderer_mpl/extensions/animated_text.py | 2 +- .../renderers/renderer_mpl/mpl_canvas.py | 4 +- .../renderers/renderer_mpl/mpl_interaction.py | 6 +- qiskit_metal/toolbox_metal/about.py | 4 +- qiskit_metal/toolbox_python/display.py | 2 +- .../Managing variables.ipynb | 2 +- 67 files changed, 244 insertions(+), 231 deletions(-) diff --git a/.pylintrc b/.pylintrc index 395adc8bf..b5c307a08 100644 --- a/.pylintrc +++ b/.pylintrc @@ -6,7 +6,7 @@ # A comma-separated list of package or module names from where C extensions may # be loaded. Extensions are loading into the active Python interpreter and may # run arbitrary code. -extension-pkg-whitelist=PySide2 +extension-pkg-whitelist=PySide6 # Add files or directories to the blacklist. They should be base names, not # paths. diff --git a/docs/tut/quick-topics/Managing-variables.ipynb b/docs/tut/quick-topics/Managing-variables.ipynb index b30188c64..4737a8127 100644 --- a/docs/tut/quick-topics/Managing-variables.ipynb +++ b/docs/tut/quick-topics/Managing-variables.ipynb @@ -136,7 +136,7 @@ "metadata": {}, "outputs": [], "source": [ - "from PySide2.QtWidgets import QAbstractItemView\n", + "from PySide6.QtWidgets import QAbstractItemView\n", "table.setVerticalScrollMode(QAbstractItemView.ScrollPerPixel)\n", "table.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel)" ] @@ -170,7 +170,7 @@ "outputs": [ { "data": { - "image/png": "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8jVdbX53/4m+2mVLUucO7D8dX7J29eIGdt87+zfedvcae2/4F2+uvOxyECM7dx2aatEZvP2m1UoyPNyr5fvUeDQkil7wNt5x262jve/uOileuXGJJ5MYTXOL2wKDJw8cG5GXLOqq9XGJ4VP7ToY7Vi5JnDqS4hrvec97lYPpswASlqOjYd4ZXHt5c8AfGD154MCFyJWbbm518nt272UaV6xeHDi7f9fRoYSjtuWKNr8nEDh5rn/18p6zB7ceGZaWr97QU6vu3n7A3r7sys66wRP7jozg7o7W1o6G4SO7Dg4IK9es7+LsbicDFNN9xdoVrY53t+5O1S5a2uSK9h9L+ZZf3uY9tuftsxHyZY4w30AImR+LDQCSJEUSwrI1G0rbuVQXRZFVFSMENM1UauZKWhTOv7une5FZ8ggh5PP5iJQhVJsC+9GpGNtpRFNIVlSMcd94ZlFNgdDo2rsf/8JNzDe/+3vccPn/+OMPPPfjH6954IstdU9vvOWWn7/w1uf//JMv/vs/Lt646Xtf2W8818Zx7YMfW52OPfON71z1wKNLR949wAc+/NANx3BPZM8LY/Y1DyzpfTs6Hs2EXJfd/v61/gGe/VCDbYsE7544t/byRb3BzszQIaxQV97y3ls7JJ5b51fDfxjFHnfje99/14tvpD58b8N334g/ct/GX/Y23xiIvDHsDNptHRvvvm21exTVPeKAkSW31p585ZhYdPKD69z06LXNv9ox+tDD9z3f/5tbb2vZ09uyhD3/6pFkE9BLr7phkX3g+bOZx+9ZumNnLB6lY/zFL160reNzT979kxfeffyPNrz06y33ve9+6o2+m9c19/KeD98HB2PjEWoslcqAg1265laWn4gfIfaOhx+rG/59uPWGDyw++ooEANw1t9109IX9S3pa33717Pq77uHj+z7+oRu+/89Pp8Dpcrsfft+DP3p574cevOaZH71x4z23DiTffvCGVd86fkRO87HxpDAakjsBnME77lj2o2f7P/eRDT/41bGH7rspcwjdswLCsKInSKdbr+3b9esoLwGAp2v14/c0vbR9/C+eXPnt348+fM9m8YDz4atrB2X/B93Sf78re9wN73nf3ZkXT3ziYzc8/dOD9z14U+bN1IPr2F/u56/1OmqWXHv3jT2nxu0fuZ9+C666Du94Ga27d33XwAh+9P23PXuIPn/meLH/BATCbIZhmNra2kSiwK6ktI3x1dTO8r3UBT5VcANOVVXHxsbIcZKEamMoltOKur0vQSE4MJyKi0qQs50IiwyF6EJnSy698orokXfeOXwszEMqFj6wb/fhvkQThPaF1Ftvvu747t3X3Xa3M3budMRkJkb67V88/aOdkeWd3gCStu7fcXDH6zi41GGHiURvemRobLC/j/K1sEpibLB399E+AOg99i50X/uJzZ7f7uxXARpb2qn0+IUTh46NczddvxrxIburkXOKB7buOPT67lSgYWld7bZ3Xtu9Zf8An2lobnWq/OjZo3vOhtJCZO/2naFU0VKmtq3tzM7X9+7ce2zwYnLm1IEdcVfX7Vd1A7DX3bb64I6dY+NpACU0Mjoy1D8Sn9yGB585tHf7npPRoZNv7N0VSbsCLU0cLadGTry9/+zgcGiwry+49Lrl9TgtqMFaPwAgira53Zf5I8++enTfvr2RafvzqacP7N1/4J1DA3RbI9d77N2jvemN16918IKN8zodtr6ju/eePnDogrpuxWVDpw7zYFOE8ZFQ5Py5vuxA2cmDO7duPRRiPMvaW2gxPdR3au/R82+8tXXR2utWddTabDYEcGLv1neOHD9//PSh/cdTjKOpqY1T+bHzJ3YPyjfeuI7iwwzb4GaVM/t27Ni5YxRquxY1HHpny6Ede06FeEdDs5/OJAfObDnWB1Jm764tCVTjYdB4Ymjbrv62xQ0kvUSYZ8iyHItVM3M7+5Blmez2S6g2hlLm5kX+OxfXLKnj3ntZ3Z1LalY2uB5cEbil22+nC4QKd2zb0nzNI597/LHlQfA3Lfrwxz5x5yL80rbdew+PrFruffbHv6tdtOjUtncKHQ6bPvbq7zvu+yCjoI8+9uTHn/zU+OE3TvdG7rn/0U/fuwEABDGx+Kob2LH9uH5lc7AGtI3A+aHdJwRH4uyICABw6sg+b9Py+qAXpanupnou2OBipg2Op86cvuuDn3vyiXvbPY6zJw6x/s76YJ2aKTB9w4TQiYOLb//4p/7oA2s7a7U7XG2Qo9VgXQtA6uff//W1Dz++aUkDAhDTqfqlG9d06a8UA4D+k2eoGn99sI6SxURKXL751lWXBZt8wfoal/YaGldc/eRti18ZdP7tZx577ME76tjs2lTXumv+6PEnN9ePHDo7DgDAODqaGvzBeo9j6p9v14lzGzYuPrz35MaHPnpnjzuapm6//Qa9daLyid0H3IsW1wc9WIT6+kYA1NC6+BOf+2hDXtHzJw7Q/kWNwTqbIvc0NbDBBpdt2htm6Mzxq+762BMff99lje7E2aNJrrEpWMcoohaeGjp7LO0K1gcDjBo/uOWUpU4nEOYO2kb+l9qLGYVhKpbSIhCMQE3dl2tXgRsej2x9mvEG1z3yPxtq9YdY2un21QQGB/q2/ORf+dO7tJvKugepw6/U+Vx8MimkUkAxfp/XzlC29jVf/8yd3/ja/zk8KIRiKcbh8ruZWJT31rrF2Dgv50Zl7E4nQigtCIzDaVMlQVJdXo8ipDmvm0FqLBKVKbvf5wVVzghJXkY+r0dIRG2uWtYGYjIhAoMyggw2G6OKMuW241Ra9flr7DROxuKIdbscKCNIfEZikMKnsdttE3jJ66+hVTmtpPlk2uWvcTKIH4/JjEPhU1IxXyS8NTXj0SgA8vhrWJq780P37fvBd85JtAQOH2ebcC9NsS5aloDBPC95fTWB+uaOZh8FysDxU33j40lBcTuZJC+6XC5BEFxeH2ujhWQ8JSG/zy3yvMvlVpWMwPPAOCRJtlNqSqbra9w1Hcvv6sHffHE/ygiU0ymLEudz2yk6nYqNC+B20clUhvN43U5aEtNJUbIzkBIy3uU3fXq9/P//cAvDcigjKDZXDUclBVnJSDYnwwuK2wkJQXZxDiGV9tTWOGgsJJLgdLMMjscTjMOeTisOWuEz4HLSSUFxc0yKT3t8NU4bOO04cgAAIABJREFUJSTiio1zO6mMKKXEtJ1BKUHiXGxGEDlfjRMpgiTxKZ71+Dk7nU6NC9iGpFRaRi6vz+VgMnwimQa6oYuvafec3+6rrQWA8WhUVdWf//d3l3R3FftGt4iqql/5yleeeOKJ1tbWKjVBWMik0+ktW7awLGsyuguCsH3/u+uuu3X2J5gObX31mg1X2Yzn9GCMW1tbOzo6iJohVI9//fZ/5eYvpejgrh88hRj9PyHPypsfeuxT2371A/7sXkOrqhyLRgDAV5vs7esfHAmFYgAAcjoVSgMAREJRc7fktKgdi5AaHwcAMTyRhVEzkXBoslg0EgEAMRaeSDtrX+wz2vkBSQEAIBaZKC/FJuNAWrlkUgGAaGTK4Hg0PK5dpUs+SQonYpEEiKGxsKjIyZQMkB5NZTWbHJ8sGouGadYbSDIIFFESk6k0ACR5GQBSqRQAJGLRyYx6JBwBAF6Y+D6XlgFAAgCQRsdE2RUJ1zsyQgoAIMUDQDwy1cnJlAwAfCLOT5iTJICGFZ+9vfs3v/yJCpAReAAAJTk2YT6TkgAgwQMApFICAMQj4YvPxIhmJi3JACBLMOm21tB4LHLxRYrTWwTgUzxk9zNAMh6dCIJp/yw4NX7xX4pmbGQFE2GeYbPZ6urqtD/whQDGOBwOt7a2krkyhKqS9/bCWEkZSg1VGGdtlCqMg1p4z5H4ie1f+PL2Mv2bm/C/efonForh8ODZ8GAF2oucP/Kj80XWGTn6N/9ytAJtEwgEy6iqKgjCpfZi5iAnYxNmBrJGjkAgEGYIRVEKLl8iEAjFkiVlMAAqpGwKFiAQCAQCAQAAKIpqaGgwP6eJQCifqQSTOHwyeOunvF4fY7zcOtDQ6jBewURRFFXGW5aiKIRQORYuIXPX81kLVc0dpQmESwJN036/X5KMdgedb5AEE2FmmJIyqRPbcEa8+hN/7fN4TCoc7RtRhHHdRzYLB4sUhOW48o1UH6RNSJ0UfYosc7kH3uYpQn2JiPQeIt3LvKq5z/TKGho2r6rnlsVJuGj6/6y1iHLvqKqaBgJhXoEQomm6oJRRFYVPpWxSxc4uqAaiIEAhjYIxjsfjqqqSwAyhqkyb9suf2/er//2eAjUwYEX/7zAtCMJCmZmfK2Ug+zc07c50MaA7uCO9J6jAc6N7E74Zm9IpkW/NQI/ovpp8a/n9k985U79M/MizU7ETfAmEWYEsy5FIhDP9wma32912+viut2b5+j0MEKghhxIQZgWMg2UzUwFAjOVZ/T1gdlBtHZMvACzpGF23LOkYfRllRccYvKLCOibvSrdzyF4UhHmHbrZFUZShoaFMJsMwjNPp9Pu8DGP1ACaKQvXBIMuyhYta8G1wcChjLf+lKIoo8MPDwwzDCIIQCATcbnfO/jEIIb/fT+QOodowXr8/lUiIPF9CMpOmaSfLxivv1WzGio7JC1aYjPol6BijYIxOI2h6CYvBmCl7OnamKukFY6b9L9dkzp2sG4adQyDMJyiKygnJYIxVVY1Go6fPnceAEEKiIAyHwitWX2UxKRMaGMQYeroXle+eKIoHj59s7Oi20nSKzxzdd2BJTzdF07IkRWOxRV1dXq83W81ox2eS/fEI1YZhbDZfba23pqa0d5uqKAtJylRYxxRKKlmKoBi4dcmSSjptQ253TP9hGNohn3+EeQbDMD6fb3x8arphJpPp6+vrHRh0uLwZUcBYVTHm3J6lK1dZ3O33FGNTFb5wOQuoqury+JZevtpkA99JxuOxE4f2qRgjjB2cO5bkT58+c9llK5zOqcSwqqqjo6OdnZ0kMEOoKgwASJl0MhYBjBm7w+WrMX/PqYqSjEcUSQIKeWvq0AJanl2Sjsn/zfCmTjymKO9mEDPnLeaVjO+Ake4iEOY6mUxmZGRkMhkkSdL58+cHhkfsnDvDjzc3NPh8PoTQvqMnM5m0ilUrNmVZruDfi6qqUjqtWtgEFatqU0P94q4ORFHDQ8MqRSfT0smTpzo62nNiMwRCtWEAQEglLhw76PbX1ja2AhRONElpMTI8kByPLl2zycm5q+/kbMBYx5jlTfJqZBebTXklS6ZM8kolxGP0fDD1mECYD6iqCgAYY1mWR0ZGhkZDNtYl8amOttaWlha73S5JEoOVQ9vftKgG0qIQXNJdEd9omlZE/uD2N6w0rapqoMbX0tJCUVRdIHDk6LFUWookUumTJ7u7u7UpMgghp9NJZA2h2jAAABi7awJYVRwsVzDKgijK5nACQm5f7Uw4OBvQz6lUT8fo1bS6WAlyNESl8koTlYiOIRDKgqZpjHEmk7lw4cLAyKjd6VIywrIlPXV1dVpax263X3/NJk3xWAEhZCUfZAWHw3HTdZutN80wjHa4EsuyXZ0dp8+cEWScyihnzp69bMUK7dTMYDBIVmITqg0DADRj8wcb3b7avpOHG9q7vbV1JhVioeHI0ED70svjoWGKXgAnhOnoGCvjNOiP+rrRkOk29MSJRR0zm+bH6FkznR9jEBUiEOYRDoejqalpZGTkzNmzQ6NjTs4ji6klPd1NTU3ZxeyX7kzs0ppGCAUCAZqmz50/P86n+Yxy7Pjxrs5Or9fb39/f1NRUKbFFIOhCAQDn8dY2NDs5V0v3stBgbyIWNiodD4/GRoebu5c6WK6upcPBzont7MqhgjrGzH7xblmZaqNb08psFYN4ibEXpm1b0TEEwpwHT6BOkH8tiuLAwMDAwMBoOOpg3UqaX9TZEQwGL7XvFUBbd335ypU+zolVNZWWjx0/EQ6Hs/vBpH8utfuEuQ0DAAhR2gDHeXxNnT2SlBkd6FXU3EkzDEU5WGdT1xIn54KJfeXn9X7U+YGPMvImJvEYmBrgS80rlRKPmSpW2bxS0fEYMOxqonkIc4cLFy7E43G73R4Kh7Gqsizr8/tDY2OyLNM03dDYGAmHU6nUiZMnx1M8Y3dQqrRs2VK/3z9vIhZaqquzs+PM2bNJIY1p5szZcwihAwcOiKIIAIFAAADC4TAAuN1ur9c7ODgIABzHrV69muShCCWTmyFi3V5+eCBRu8q19IacR/F3X67LnNd0zPxHZwCvro6ZhXkl0O2G6S0Y/cz+pUBeScdjImEIc493du48ePSUk2VVrIK2RQxCKsaAsfZ9EWMMgJ0MRdscalpYsnRJXV3d/JsS6/f7e7q7L1y4EBlPqg728MmzB46f0TYG1JbHajEYRCEESIvNuBzMZZddVpFd/ggLE53JLrKisF3rvVfem3t/fEQ+dmpGvLrkGH+4FMgrGVQyy/iYV80pWzivZDEeU5aOMapg5BiY5pXMrMy3T3nCPMbG2ACwosgA2p5RSLsGAJqiJ69lWbVjdXFP9/zIK+WDEPL5fJdddtnJkycHR8comgFAWv5NUVRNzWCsYmVC7akqz/OyLF9qxwlzmAUwb7doSssrgdGoX8o+ePrVTMXHJc8rgXH/mOaV8p6R1BJhTnLbrbcsXbI4EokAgMvl8nq9w8PDGGOGYZqamwcHBxVZVhQlkUjYbDa32z2Pd43TTs1sb2/nOI5hmMsvvzyVSvE8r80OVhQlGo0CgMfjYVl2LBRy2O0kJEMoByJlsjFNdpjIFpJX0ovUWNExhbqaQJgzeL3elStXZt9ZvHixdoEQ6ursBIB0Ov3WW2+5XK75l1fKASHkdrtZlmUYZvHixdqabV2WTZSfMd8I8w8iZSYpdTPfEnTMhJlZqGMM1l3rVrWiYww7p5COIZ9rhLmHyXisPVpoAzZFUdq+MgvthRNmmHkb4awkJn+Dxo8K6Ri9qib7+Rq1OhM6xvCeEYXVSKHOKb5NAmEOQNO03++/1F7MHBjjdDqtexg4gVBBjKSM3jsP43k6tKDJwAfKuQk6eSWTRNNkRQs6Jq/irDgnEum/Ih2lMWFtSrbkR64M80o6pqbdmqdvNMKCByFkkmqZf2CM4/E42TaGUG1y/6gwxjabLX7oN8r4SM4j/vQ2r8OJMZ5focIKH3YNszGvpBvz0NUx+l5Mr2Alr6RrzUpeybAygTAPkGU5FAq5XAtjSwsCYabIlTKJaIiiUCMVlc+9nPPI57QrspQaj7l9NTPlXrWp4CGREw9MIyiV0THFhHbK0DG6oRwrOsZiMCbfWn5XE0lDIMxhtIXZ83itFmGWwACAqiiqqjI2W2xsODo62NS1xOi8az45Pnz+lKq0e2uDspSh5vrmjDqDq6UqRg8MR97KxmMmyxQyZZCxsRiPsdI1JopPp1iheAyBMM+hKGpBrTpGCDkcjvkVyCfMRigA4JPx8FDveGQsMjLQ2NFjpGMAgHN769sWhQZ7E9HwaN+5tMDPoKuVBRns56sTkpk+DQTpjb2zIK+k33z+yyk5r5RlTTdQBcZ5JWQ1rzTtB/n4I8w7GIZZUNN+VVUdGxtTFOVSO0KY51AAoCpKLDQy3HumedEyp8tjXsHl9Td29AydPzUeDeG5OpnLYrJj+shcRF5Jx5oVHYMA5ekYNM1UETpGX5blVdKVZbrzYwytZQk8Ax1juatNJVFZJBKJZ5555ktf+tLQ0NDkTYzxnj17nnrqqWeffZZ82hJmgEwmMzo6eqm9mFHI8iXCDEABAEKIH49jRY2ODhacaq4qcmxsGCuykIjPze/NpouV8kIDU0UMdAxC+fNjStQx05uEXB+zi1k0VYKOye8M0wjKhBmDYJUlHZNvu/LvK4xxW1tbX1+fts2oxoULF77xjW88/PDDhw8ffvHFFyveKIGQz4ISzQghlmVJgolQbSgAcHlrlq+/rmP5FYHG1oLzsyiaDjS3daxYtXz99SapqNlLCX9TpvGYQg2VrGPy7aEi5scYSaKpShY7wlDHFK5oWcfot1hRvF7vtddeW1tbm33z0KFDq1evXrly5Qc+8IGtW7eqqjo4OHjmzJndu3cLglANNwgLHO3s6EvtxcyhTfslR14Tqg0FABRNOzmXk3PbnYXlM0KUw8k5ObeTc821eelG82Om/bSc7MjPK+UGMnLjNRcfWdQxaHoJPR+M5seUqGOKX3eNNHPFxGPyQl+QfSP3FVX3y5wgCNqyWI/Hw/O8oiiyLMuynMlkSFScUA0YhgkEApfai5kDYxwOhxdUIIpwSZhbWqQcLA6u08f54vJKOVYtig/dvBLKvrS4CZ7e9FrLeSXIz0pZ0DGmkki/q6ebsiAZq0gwGBweHgaA3t7ehoYGhmHa29uXLl26efNmjuNm2BnCQkCW5Vgsdqm9mDkwxpIkkS8GhGqzQPadNE125BYtWEZXCuRclqxjrFFS7tmsUq4jhXRMTvHsipZ1zPTn1dUxqVTqueee279///e+972HHnroyJEjXV1dV1999UsvvfTUU0+dP3/+L//yLxFC5DOXUFUwxqIoOp1OhBBFURhj7S2HEEIIaVMVtevJR9nFTKpQFDUZ/LBYxUqLRlUstqIdDE7myhCqzUUp42A5f32DzWa3WE3KpCMjw1JarJpjFaTa+/nq6BjdYIgVt3KsVT+vhKb/b3pdvSCKkQ+THhdvytCxCn4A2u32zZs3r127FgCampq6u7sdDofL5fpf/+t/DQ4Oer3etra2ijVGIBhA07TX61VVFSFUV1cnSZIWpPH5fA6HIxQKqarKsqzP5wuHw5IkMQxTX18fjUa1yVv19fWZTGayitPpHBkZAQCn01lfX9/X14cxpmm6sbExHA6LoogQCgaD6XQ6Ho9PtjI2NoYxzmklGAzGYjGtlYaGBlEUtSp+v99ut2urrliWDQQCAwMDGGOKopqbm8fGxtLpNEKovr5eEITx8fH8Kh0dHWSuDKHaMADA2O2tPUtdPl9RNTm3t/fkUXW2J0ErrGNMdqEzzCuVcLgSFJFXyrana8r4kEjjzWMgtzum/5gJHVNZbDbbsmXL8u/X1tbmzAUmEKoHwzDr16/XIhY0TWOMtWuKohBCnZ2dAIAQomm6o6NDOyWGpum2tjYt4JFfpaOjQ6vCMExjY+Nk9dbWVqMqRq0oiqJVYRhGVVWjKs3NzZPXLS0t5q1QFKX9OqO9TFh4MADgYDnOU2A7mXxcfr/N7pDS6Sp4VSH0x3D9ZEdJQYLcoXoWHxJp6IVO22DcP6bWTPVininQ75yKx2MIhFkFTdPZUYrs6+yFFNmnTuacQGlUJXttlMUqRq3kOFlmKwRCtWEALqY2oZjvwhh0Jr7OMiqsYyzcLFnHWEPHWsn9X5KOMWxRX3cVMGXs+6x+WxEIBAJhlnFRUzMMc+91G3ramy1WO3qm9+Vtu6vmVdlUOh4DueNrzuCuV9PqoQSQoyEqFY+ZqFShvFKeD9nWio/HGDhm0s8EAoFAIOhxUcoghJqCtYvbW7KfZa/myEl2hmOJGXCuRHR0TAUH13zDVT5cKc+a5bxS7s1JL4zazrdmmleyMg8pzxTodw7JKxEIBAKhNAwXYysYvxrlD6fSALDO47zGx9JzYpyxvAme0Y+cipU6XEmvBQs6xtIhkXm/6CuPaS0Y6xjdbipNx+gatahj5sKbjUAgEAizAB0pI6n4hJDZEuP/5kI4JKsA0Gin/7qj7iqvcxlnn92Cpngdk3OZY8pEfBi6YLF/rMVjjCqWMupbjMdML2OoiowbztdjBSoAkHgMgUAgEEpFR8o8Ozr+VxfCYUmRMW5zMBhgKC1/4cxorY3+5+76++pm67lLJcRjwGgInat5JdDthuktGP3M/qVAPEbH4+p0NdE3BAKBQCiEznq5P0T5/rQsqPjJltr9G7r3re9+pMGXUnFfWn4jxs+8i5Yo4XAlsD64omnWLOuYiwdAzpSOmVhSVikdgwxNFdAxKM8U0TEEAoFAqBY6Ukab61tvo59oqQnYmKCd+WRrTQ1DAYA6s85Zpoh4TH4RHXOFBtEyBtlSdEx26UJeWNExZo7lxVIsU0QHTz0vOBWpeD8IBAKBsLAw3MUoqaj9oqQdq9ErSoI6O8+mQXoJHIvxGF25YLyf71Q8Jn/Q1tliB00EMHRMTVwWc05kpfJKU22bBVGMdFLua0KQ61t+PMbAMQs6hggZAoFAIBREZ66MNn7wKv6LMyN9oiRj/C99EVHFYDC+XTpKOpQAykl2zKH5MbpVzYJVpvpB12NDyaj7W05FomMIBAKBUBF0pMxqt+MnYwkAOJhMf/LEUM6jGfKrMNXWMfkCYA6tu678Jnh5zZgGY4DoGAKBQCDMEDpS5tMt/hv9XELJnRjjZaiVrkkpc6nzTYV1jGEt3buGg6eJ1Wquuy5Dx1gkX0tZL22l0arrGFmWZVlmGCbnIBgCgUAgLCgYAFAVJZPJHD/f73Vx2nDiA9A9Jrs3DgCAVXzywoAsSVi9JPOAK3zYNczNvFIx++BZySuZWbOSV7JkqkI6huf5UCgkiiJFUaqqOhyOuro6l8tloSqBQCAQ5hsMAIh8KhYafXXHvtd27LNYDQNER4czabGavukyO5IdxeoYlFWmkCmDFUfW8kqQ1xmWdIxh5xTSMUV0daF9egz9yEeSpLq6OpZlEUIYY0EQMpmMtaoEAoFAmG9cjMr0nToRGRlmsk5vN0fKZPjxeDUd0yVfxxSKEIDR4Ko7eFoYXIs47HrGdYxOVcPQjpVgTN6z0iVjqTpGX9v4fD4ASKVSsVhMURQAaG62ehIqgUAgEOYZE5MMME7FY5fUk4IYCAb9ovlXesWMnhYZJNBryFijGDdvEjeZXqkIv8y9MixmpGNKsW+oI7MurYa+sunt7W1oaKBpGgAoynBbAQKBQCDMb+bKfMkKz4/Rj61MN2NlcC2w40u58RjrOqb4+TF5vZVjqlJdDbmvtcTQVz4cx5E5vwQCgUCYE8OA3iyUmU92zICOMU4qTVQyiHDk1raiY4rMK0FuH1erqy3HwkRRHBwctNvtANDe3k4CMwQCgbAwmf1SpojNfLOKWIwQQP7gakV5gP6Yb8GUvgdl6Jj8zjC2lvXDUMcUJxlNQjsmXZ1lrWQdAwAMw3R2dmoJJgKBQCAsWGa5lLGyA4tOpVKKGo7KutV0Yhf6ZXLvGgzvpegY3QoGYZsCd8DAX30dU6L9vDvl6BgASKfTJ06c0BJMXV1dNsuT1gkEAoEwn5jNUmamkh0mmSAoMa9U5UMJjGpXIa9kFI8xtKabN8rxUa9mEQuYLtLd3S3LMsYYAEhshkAgEBYss1bKFL8zG1Rax1Qzr1SujjHKK4FBr0BROqbkrraSVypmnx5TBgcHJUnS/mk7OzvJXBkCgUBYmMxOKWN5Z39rOqaUO0XsH6NXxoK1PFMV1DG6RqutY3SxWMzALVMURVm0aBGJxxAIBMICZxZKmZleDFxGPCbXmuV4TH6zldUx+d1kqGOKD32Z6cWK5JUs7iDEMMypU6cmVzCRuTIEAoGwMJllUgblDZyTv1Ul2VGOjrEgifKsoen/0zFl1AfTW5iFOqbQ0rAi80oWojmCILS1tWlRGbK7DIFAICxYZtMAoBOIsDJO51WauHOJD4nUb96KjjFUHvptg04/zBYdU0xXW9kkMBuMcTgcdjgcAGC320mmiUAgEBYms0fKGA9aJoOrfkWzDIhZGas6JteM5SXjBXSMWUUjHaP7OgrYL3lKtX5TZvGYErBcu6GhQVVV3Z2bCQQCgbBwmB1SRienYnFwLTIeY/Tc6F5p8Zg8a9XKK+lZM43H6Hpc3bySjh/l5ZUAIB6PMwzj9Xq1k7EzmUwikfD7/ZYqEwgEAmF+MQukTAl5JShpcC0h2VGCjpmxvFIJOkbnNeV2jo5/Ve5qKCgZ87DZbOFwWBRFRVEoimJZtra21qQ8gUAgEOYxl1bKWBlcIXdkNhn1Z62OMRYxE5Us6hhDkTd1dWl0TG7n6PWF9WCMjnzLhuM4juP0nxEIBAJhgXFJdxWzrGN0qundLDRpw2qQQK8RCzpG34a1lIlu7cI6JqctYx2jU8/QmlnfT7Zh9LJKfrlVN0YgEAiE+cmlisqUFI+BkoIEus+Nrc3W+TG6ymN6faPOKSEeU17oS6dyiV1tJmYwxoqiaAcXMAxD5v8SCATCwuSSSJlq55UsJDv07lVqE7yJOgXmfxTMK+W/DP0UkIEPBqamvDM2ZexYhboazHWMNU0yODiYTCa160WLFpEt8ggEAmFhMvNSxmKyI384tR4kMLY69cjiN3gdOWGtjmGWp3DtwrkbXfFh7o+Vhs1LW+lqSzoP9F+kgbI0JpVK9fT0kKOXCAQCYYEzw1KmpEMJwDjkYCHZUYEgwcRllfNK02oZ/bQcRNH1uIKhr3xr5ezna62rp6Oqan9/v7ZFXjAYJFvkEQgEwsJkJqVMtXVMicmO0tcr6XtgRcfoKQ+dGJKhjsm6YdA5JXR19XWMxfVKFrccDAaD2lwZEpghEAiEhcyMSZkiJm0UGlx1B08LOqaah0QamNJ1YSZ0jJVgTN4NfWuFNsEz8KPKOgYAKIoKh8MA4Pf7iZohEAiEBcvMDACmQYLcotlXhqNawUkbVsdDnUZ05ETRNnTLmL6iQnbzKhZpqVArhvEY01pQnI4xtY8A5WkwMwdGR0c7OjoWLVqUSCQymYyZqwQCgUCYv8xAVKaC8ZiJB5VIdoB+wMVCkMDSOYh5v5hEmHL7xzCIAqYvcdKQlZBMSV1dnXgMGIe+TEEICYLAMIyiKGQlNoFAICxYqi1lilhXXK28kt49KzNPp4pZMQU6r2h6pQrllUyUR0Ul40zmlSym8HJoaWkJhUKqqtbX15OV2AQCgbBgqWqCqTQdg0rVMUhvIEX6g2tuI7k+6iQ78pqH7FdYQR2jZ82KjkG5pkrTMchMx0y1YbmrdRopV8dEo1EAiEQiAEBRVDweVxTFpDyBQCAQ5jHVi8pYOepYd3A1KGpiSEcTFHJLt36BmiZhCsN7xcyPKeSYoRnLhyjk3ijdMd3Xqe+WabeVFo/RDmByuVxaMEaWZZJgIhAIhAVLlaIypsmO/EDD1JXFZEdWyakgik49C27lBjKKicfkREIsx2N0ojmG8SqY6hiDeJVRV0/9nPpRMLqTF1vJjRlVTMdYWBpmJE/sdrssy7FYjGVZlmVTqZQsywZlCQQCgTDPqXhURjdnoD9O542Y+mGJgpM2rCgP0B9cLZjS98DU1FQlQ+Wh23a+tYLKw0wy6poytGba1VmVS9UxJXa1Lqqqnj59Oh6PawuXKIoi++MRCATCgqWyUkb3i7jFesUnO/LGaNNqhX0r5nyl0nSMbgV9VVHoDhSlY6Y/t2w/704Z8RgL6FjTt4IQWrp0aSKRcLlc2h2yrwyBQCAsWColZablSywmO7LuGyY7dFqZ1uCMxmPQ9P/pmJqqZFF86Merpq5mKh4Duq/V3I8S8krFdbWhHhobG2toaBgeHp6c7dvT00MWMREIBMLCpJJRGaQz9JQ2uIKZjpn6Oet0jMHhSka19UXe9BvlSiIrOqaQZKz+4UpGXW1AQ0MDACxatIiiKJ7nKYpimEtyxjuBQCAQLj0VCsvrjmt6Omaa3DFcdz13dYzBK8rvjMnfS9IxKN+UkY2pVorUMcjguX4dVGJX608zLihmAADOnTvH83x/f39vb68kSQVKEwgEAmGeUhkpYzjo5A2uheoYDN4F75Q6aaOIZEeuqUIjbV4LOuJDp7R5mZLOVzISWObxGEMXjcsYPTGRjMWaykJRlEgkUldX53Q6VVUtwjiBQCAQ5hFVCsvrxGPybhQfJLj407KOKZA3qWw8JvdmjrPFBVEqqGOsniue76OeHzMwP2ZaWTNF09jYKIqi1+tFCJGJMgQCgbBgqc5ibDAfp0FviLKiYypxuBIYD676zVvRMYbKQ79t0OmHS6pj8h0s8pBIU2tlSEYzEELxeDwajdbV1ZEVTAQCgbBgqU5Uxij8YjJOLxwdoxdyyDJjGNopTscU0dVV1DHFrG9HhnYMGBoaWrRoEcMwZ86c8Xq9DoejYBUCgUAgzD8quhg799Li92vDETf71+rqGP3mC+gYs9qFdYyxf3oPi47HFCHpKlANAAAgAElEQVQZTZu6eM/4hRewVpjiQjFZUBSVTCYZhsEYk4MLCAQCYcFS6ahMBZIdkDdUV+IEZpgcMysYj9Fpz7KOsRJEKeJQgulXlyT0lWutglv16NLS0hKJRBRFaWhoKDhXJpPJPP/887t27Vq0aNHjjz/udrsBIBQKfelLX9LCOV/+8pfr6uqstEsgEAiEWUXVzmDK+THndAzKEQn5Oib3ZrYjMO1l5PiGdPrnEugYlG/NYlcbhL4K6Rir664LvZQJVFUVRVEURSvHYh86dGj79u1/+qd/OjY29vrrr2s30+l0JpN56qmn/vZv/7a2tja7PMa4oE0CgUAgzAYqK2XQ5JCGCozTAPonF+YOh6XqmOk6o4hDIiFvFM4rY/yK9HRMjo3pVxdFXjE6Jk8IQfYN/b3/dXVMbmWd11mSZCy6q40lozl9fX2tra09PT2jo6PaYUwmHD9+fO3atS0tLbfddtu+ffu0mzabjeO4p5566otf/GIoFAKAY8eO7dy58/nnn08kEtY9IRAIBMIlpCpRGf1AQuGbFsoYfU83sWd5cNQdpS22nz3KG+uYfKfMOse0G/V0jLHzpcyPMbRl/PsMdfVFaJoWBIHneYSQdmFSWJZl7chJmqYnoziBQOAf/uEfvva1r23YsOGFF14AgJaWlp6envXr17Msa/XFEAgEAuGSUvlpv9O//FtPduRcztr5MWbxGJ1R3Sgeo+eDgal8x6zrmPyuzvetElOqUVaZQqbK6+op7HZ7NBpFCNE0HYvFtBCLUeHW1tZt27YJgnD8+PHOzs5EIsEwDE3TCCHtYG1NCXm93kAg0NbWRjaqIRAIhLlChaf95qVP9IuUkuzQMWQp2aHngm7zpeWVdMdlQx2TdaNcSVSoq3W7sjpdfSl0DAB0dXUVLDPJhg0bXn/99c9+9rMA8NWvfvUHP/hBT09Pc3Pzf/3XfymKIoriX/3VX1m3RiAQCITZQ/UO4bMeJMipUcyy2kokO6yUNvOp0ACvY1zfWp5GsdKmaelKdrWxCxO/l6ZjLErGcvF4PF/96lcVRdFiMH/8x3+srd/+2te+hjHWbla8UQKBQCDMAJWRMla+2ZcYjzG6Z5LsgMnh0mJIprQgQXHxGDB9iQaBjxxrFuMxADrncepYs9LVVY7HlKVjxsbGOI5jWdbiVr80TU/qlckLsk0wgUAgzHUqGpVBsyDZAfoyR998QVMmOiZftJSXV9IP3ZiZ0nUM9HRMiZKx8jrGWC+CflebyRqE0OjoqCRJfr/f7/fbbDayUd4sAWMsiqIkSQ6HIx6PAwDDMC6XK5lMaoExt9udTqfT6TRCyOVyqaqqzVVyOp12uz2RSGCMGYZxu92JREKbpu33+7PFaAnIshyLxRBCPp8vHo8rioIQ8nq9oiim02kAcLlcAJBKpQDA4XA4HI5JT1wuVyqVkmUZIeTxeDTnAcDj8ZQzQxxjPD4+rpny+XxGnrAsG4vFAICmaY/Ho/VJdjdmV9FeoN1uL8erRCIhiqJmFiGUTCYBwG63cxwXj8e1QKbf7zfqxskqDofD6XQmEgmWZTmOK/kvVJZl7d2SSqUwxna7nWXZRCKhqipFUV6vN5lMyrKsdWM6ndZ13uVyRaPRyW4URdHtdpMvM/ODCkmZqXG2NB2jNyzPgp3ZLpGOKcOUkYqYbqYCktFyVxuULSseoxEIBJxO5+jo6MDAQDQadblcra2tRVkgVI+hoaFz584xDKONwUZSBgDcbrcVKeN2u5uamlasWFGySzzP7927V5Ikn88Xi8VUVS1BymjOi6KYyWQQQkuWLFm2bFk5HTUwMHD+/HnNq4pIGZqmN2/eXI6UGR8f37Nnj6YArEgZyNNh+VKmq6trxYoVJUsZnuf37dunqmoymdSkjNPpTCaT5lKG4zhtT/BJ57O7UVGUa665ppyOIsweqjdXZhqFJm0UOYgVa0J/t5VCdk0jTIV80BcnJbihU7SkSmbxGJ1qpi/TpExldYypr2fPnqVpur6+vqOjAwCGh4fNShNmnDNnz57tH2bsDih7v0GEkMAnb9y8sRwp43Q6Y/H4/iMnHCynyHKZLgFCUlqMj493dXWVc/4XTdP7D70rqhTGKpS9LyOiKJDT1113XTlGRkdHt72zQ2GcqqpiVS3fpXRqvKurq5ygqRa+emv7Ts7rw2r53YQAcMDl3LRpU7mmCLODSsXWzKRK1TaZzTdlMdmhqzymmzaJx6CcCmZBlKyQk6E105BMlo2p+/o6Q3833WmNF5lXMrZmMfSl9woth74KSbb29vaOjg63263lHZqbm83LE2YSn89H04ynNijwKRtDuV2sjaZohBkK3C7ObqNphGmEXayTddq1a6fd5nax2rWNprweN00BhTBW5HRa9AYaytyCGSGkYtzc1cP5arAqMxRyc6zDxtAI0wg41sE6HROeMG6OpSmgEbYxlMfNMTTSHnncLoeNAayIAu8NBDMZqRyXMMZjY2OyorJuL8Kq1gTndHATnjime+J2sTaGohGmKXC7WIeduViFdbAOuypLQNGYsmlJvZJRVVVW1OVrNgCA02Gb9MTj5ib/dTwuzkaji/+g3KQnMOE8aFVsDI0BOd0+7aiQktEm5js9fkmSGRp5XJzWJwyFvB637eK/Drhd3FSfOB0cm9WNrovdSFOgypLbH6AYhqSk5w3VXcFUKNmhN4hVc5IvZI/TuqamKhkoD4O2861l/TCIcJSSVzK0VmjzGNDrC4Ou1mlkmrUZS+GZf8zkbP1CPpVmIbIs1XldH//YR1mWFQRBy+lwHJdOp7V0AMuy2sQaALDb7TabTcuq0DTNcZyWQRgeHv7dK69msFpTU1ugPVMEQUgkEsjmSfP8++6/p6mpieO4TCYjSVK+JwzDCIKAMaZpmmVZnudVVQUALbvU29v70m9/p8hy+e86jDHGIAqp+26/tb29DQCcTicAaJ7YbDa73c7zvOaJ0+nM7sZs5wVB2LJly6ETZ1QVWznKwwS73U5RNELI5WA+9IH3MQyjeeJwOLRkDUVRHMdpfYIQYllWkiTNkxzn9+3b9+b2XTKiwuFwe3t7yd3ldDpra2sxVmlQPvCeB9va2jRPEEJutzuVSmn/Oi6Xa7JPjLpREITt7+w4PRiqD3jJusV5Q5WkjCUdYyVCAJXTMRUZXAEMf2b/YqpjdD22omMMJJFJV5v4camnIlk5/4Ewd4nH4+l0GgH4fL5AIKBN7Jh8mvMd3efz6T7iOE5RlEgkQtGUirH5hs7WoWmqobGxvr4+/1G2Jx6PZ/Jam4kyeW2z2ViW5VUUrK8vc7IFy7IIIVXFPJ+qr6+fHOyN+sQovEFRlN1uRwghhMucylpTU2N3aC8KeTwer9c7+SinH4wsTDp/MVaMy1VXgiBoR4vQFO31el0uV3brJntj5nfj6dOnVUUBwKFwSJZlTagR5jrVmrxdcCMWi6OV3rBWYjymLB1jVMHIMTCJoFh58brxGIuYiJHJ343jMaZVi9lysEBXG6IrEQlzFaQN1SXXV1X1YrqkbCnDMIzD7gAAWZaT5Z2xJYqiqqgAeDwel8uYdqOtNqKoCrzZOY7TjnZ3OBzZ43cJhEKhtCgCAEVRZYadKO21IVSmYsATYsjldptIKCsoiqKSw2LnHRWXMsgg2VH0N/upYkYjYgVNTVUyiMfk1jYLokyYMQs56IRkULaNfNu6Aquk+TFW80oox1ox8Riz+TETPut2dc5rJ3pmrsKyLMMwGHA4HK7UMeNlDqtOp5NzcXAxp1OWS5PrZURRVMuYGIsxDoVCmgW6vMFekiRBEABAykhakq5kFEXR+ofjuDJP8GhoaKAoiqaompqacv75tANGAEAUBC1nVDIT+gzRFMkuzR8qH5UxS3ZcTIbkvaHzBmSYHDrL1jHIcJzOr2SgY/RexnTlka9BDHUMyn0ZOb7lmTIOFFnIK5WjY6ZdWvlXQ9P/p2Nqqp+tdDVhDuN2u7XMSzkjPQBoS20BACGqzGBDKpWKx+KQNS7OBmRZxhgohILBYDl2JOmiglFUteBB8RYRRbGcmBMAaKvZVVUdHx8vx47T6QwEAgAgy3KZLgUCAW3FWU1tDckuzRsq+PecHyEAHcWgV0/nnsHgXaiMbpAgv7ZFHWNcoUBRs3iMqXWDipbcQfm/lqpjcq0WN3vFtKsL1srVUIS5ydjYmJYPsttLX6gMAAghp9NZkflTGGMVqwBgs9my53+UgNfrtdkYAFRTU+5wSNM0QqBiHA6Hy7FTQRobG7V9/2RZLlOJJpNJFWOMcTqdLicSJkmSNs+3fBKJhCxLABCLxsqcwUOYPVTsZOxYOFRoE4KSh8OSHKqUIWPTpT2urguFNFk1KbVdA/HCOFinO1COQ4RLDgLkr/GXk1lQFGVsbAwDxlgtc40xRVEMzaQBJEkaTyTKiYLYbDaEKMBYUZVyRmiEUH19vRYiksoLpTgcDk2f2e32MoVaNBrV4joVWxSIyk0OyrKspc84jjOZ5GsFURRlWQHAsiJXKvVJuORU6AwmBIqsgPEGT4zN5vJ4Zk9Qd96DAdTZ/YVDUZS0IMiS4bYcFEN24ZzD0DSNKAoDjkaiGOMyt0fLuSgNlmU9Hk8qJWOMy/zrCIfDmUwGbOx4fFxRlJIDMxjjaDSqqhgoQOV9PE5mzTBWy0zBpNNpLVzBca4y58rU1dVRFEJA1dbWljlXRquuqGqZgSKYCMOT7RvmEzORKaRouqYu0FRX6/O4yJtnBsAY4onU6XMX+GRZs/+qCk3TnMedGk+U/8FEmG0ghILBIMeykExLUlnBBoTQxb10ESr/63gymQTkLMdIxRFFEWNMIRSoLSsGKYqitiu/JMmVWrVefoJJA2Nc5vQdu92uzZRKi2KZ0379fr82i8vn85N9ZeYNMyFlOJc74PMs72px2MmBfzMBxhjjoMPG7H/3mEnY49KiKAqfTLGcK5U0WRZL3i1zEm1hjpYRKDMWS9N0IBBAgFDZUkZRFEmWwOa02cpNwTidTpqmZACXy1WRYDMGLIpC+XYqQm1trSYfJ8MzJRMKhVQVqxhr839L/vzX5g6X40m2KS28l06LJME0b5iJjA+ikIvjiI6ZMRBCFIVqfLM9o4cxrlw2njC70L7QI0B1wWCZc2VGR0cxYKxi7VjjkkEIIUQBgKoqYjpdjimv18swDABiWbacb/aTc2UwhjKntTIMo+1vyzBMOYd1A4AkSbMtVprJZLQ1UHaHo5wTrwAgHo9nMhIA1vZNrpCDhEvMjCxFw1hWZBVjmoxbM4gky+Uf41d9Zr+HlrDy9Q4hNAPfAmemFa2hAk8RAsDJsr+OT8z8KHfHWJZlvR6PKKiKomTKkzLhcDiTkYChw+GwJEklD67a0p6Jv4KyPh4np/3SNFXmBsSJRGJi739HmSkYt9tNIQQU8nq9Ffkqa2NsC2cF9UILGpXzDqnYCiaTZ5IkDY+FAz53c10tTc/qOMH8AGPMpzN9Q2Nlzv6rNjTDmHiou/nM7ARjPDo6qm2s7vf7GYbRrlmWrampGRoa0g7QaWpqGh0dzWQy2lQSnue1L+J+v5+maW0tLsdxHo8nFAopimK322tqamKxWDqdpiiqrq4up0okEsEYcxzn9XpHR0dVVdVaGRkZ0YaixsbGZDKpVampqaEoarIVr9c7NjaW04qWzZlsRdvWLBqNaq14PJ6xsTFVVRmGaWlp4TjOJOwXCARYpxOnMuXP25hoBdnsZU1BlWU5k8lU5ENvchO58gebeDyuqhgxyOcrK+eVSqXGxsYAIJ3OxOPxmpqaMh0DAIqmy4zsagoGQbm7/dpsNm2T31QqmUql/H5/yaZcLpcWUXO73bM5bq2qan9/fyKRAIBgMJjJZLQVfF6v1+FwaP/W2tFUIyMj2tzzQCAQj8dFUaQoqra2djKU5fV67XZ7JBJRVdXpdPr9/lAoJMsyTdMNDQ3hcDidTgNAfX29KIpaFZ/PZ7fbs1sZHh7W/vaDwWAkEtE+lAKBgCiKmpM+n89ms2mtsCzr9XrD4bB2NMRkFa0V7TS0ySqTn5aNjY0lJ5FnQt6KPG+32w8eP3vaPUpyTDODIsuRcMReXiS2qiCKomg6Zb5x1px6s2h/9tFoFCGkKQmKokZGRtITAQBtjas2+EWjUVVVtTBDThWGYSaWwqKxsTFJkiarKIpiXiWnlXg8nl0FADTtaNJKOBzOdsyoyuDg4KpVq0zGy1QqJVVCSTMM09zcfDFn6i9reM5kMoIogM3DMEyZ024YhkEUAgDt2KNyTGkgAJou99O4Ul/i3W43Y7MBgMDzkiSVk67Sxj8FgyaIS+4r7SjNkt3Ixul0MgwNANqRmRWxWQ20P3DtUyUWi02GJyORCEVRk3/7o6Oj2icMQkiTDlrWTJMU2h9yThXtq87kp8rkx0UsFjOqktPKZPXsVvI/lLI/VSavcz6UJqsghHp7ezdt2lRaTLESUkZVoJC2HY/HbTZbIl7Who+E+YRqYddOjCiEZ/WScg2MsfaXPxmNn1zCqqpq9nX2d1OKorK/FE4WwxhnX09WwRhbqZLdisUq2a1YdGzypGgjBEGQJQkB1NSUtQpX/X/svWl4Xcd55/lWnf3uG/adAMFNIinRlqnNlmTLW7zFjhN3bLczHfdMJstknvF0OpmZJ+lMMvNM2pl00o/Gk07iSSdx7MROIluyZcuyZFELRYk7xQ0gFmLf7r6c/VTNhwKurkgQvEJdgCBxfh8kELinTuHgnKr3vMv/JYS1PiDcuTJvg28Pi8fjsiQ5BEWjUR5/Q7UHk0tpNpflmRLbPAAAY8RZQa2qKruT+U0jQggbg9PMsiyL/fUFQeCMeeVyOcuyAWixWPA8j/NabRye5+VyOWHFMYbQ2/6sq64wzPtbvT5rPMjVm7bORemas9S5XNQuRDddlAghrJqvzutzDQ0wZVBuhjT1YT2/StpDzXLheeRt311zJam7s9Jqh9bxoRuI7N9sdVtTgA6t+q/VlHzRtd+48TA3/PmqK/ENjl3jst1QRXXVY+rRXF1rXtdcagVWvz4MQZRcJYwyMzc95S2HUmoYxnYLbNcJ5UuHIoSwSigA6vCV4ymKEgwELQdc19X5uhQVi0XHdQELuXzOdV2e3BRFUZafZr77h0UBAECWldqe3uug2k5SFHn9FqIoopWKek5tIWY6X9MTex0QQm6LR5VSyrO1347c4lwZPH6C3PsJGm1Fq69Z9eyV9dko73wfvbY7YT2Hr7EXv4MLvbra8Fr/qvlmHeepy2Jb65Kt0S1h9W9cP1Qdv03ND1ZtmrDGwQ6lVjmPps9DKHSjoX1uFalUau39kkX0qe7k+SILtfB3aRYEAZwG7A2WZRGPAAbX4VKMZVlWxCNIAM6yI9M0md/CssxcLsdZbc7QNN52kp2dnVjAAJgnuwUABEFg9mKpVCqVSjy2mizLgoABkKqoWznAtN1ACLW1ta37raBBuTJTl9z9nwLuWC8nwom/lwWKUQMyuVzXAQriO3mMCSWObSvKhghwUaA2nzDU7YfrgHl7RCQxxs3NzZztiG8vSqWSaZprrDuN2iQEQWhubkaAMMacDReXkw2lEF7ZF9cNWumK2yiNNYRQiM9kJ4QwrxWlvNEcWZaxIABApVK2bZsnSWV6epp4xAO6tLTU1dW17ruiKpHH39U8Go1KkgwAWkDbymm/giA0NTWxXJltQj6fd113fdZzY4wPjED0dLjVWQ2kuBhNRhuS61rMlQghsfA70N+0LTtbWkpGO/nPfj3E8xYWFzdiZB9++MVMbzssy1o73FMoFCzLQgCc4YDqtSWUliu8DQVZtEsUBJXPBZJIJGRJdimKx+P8iSkIIUJpNsurmrOSVMErSxiLxWSJdTXn9WC5rssKvTgVXCzLYlrGCPM2HMjn8+yOKhSKWzlXhlLKUmW3ieuIhenXfZ80xpRJktyAe7YhQ/FwErZ07bHPnQqllCX/b+WXvFsECoZCnGm/+XyeAgVK9QpXXbcoioqsWBQcxy4WCi3NzeseyrZtQgkArVQqnuet++/OyvIxRgDgeVzLFyuyBQBFVjijS9ls1rJZuQrPMDVwt5Os+pz4c2VWBAApIbf65XtNlu/87ZQrw8OduvJKu/bsisgAALv37Bnc/8ivfOqe9Q6F2nfc9ZHHH/3AAwfi0aYDO1vrcSj3De5MaQAA/YN74to1R4TuvqtXWbnwoZ4DX/ncI+zrX/jSv93burUaxPj4rEo0Gl07t0NVVVEUKdDFxcUtshwrisJqsPmnUyqVXMcFAE7FWErp1NQUK4l4R+Hs63Fdl5XLOo7DqeXjui4lBADC4QintG5nZ6eAsSiIbW1tnO0kmb1omhZnDyaMMUIIAAmCuE0cHrcFCKFkMrnuesDGmzLRprbBHd2tEQ0ABFnt7ukd3NEbUxt6x2ClORVd8zfWHnrkwaYAAAAWBISwGm2+e89AVBabOrp39femErG9u3ft6mtVkNbT37d7sL8jEQAQO9qbxWsvibDr3ffHK7Ni18EPH+gRMEo2dewcHNjT3QQgdff37xvsCV5n3bQM3Ht4sAXkzg8/ti8ajO3ds2tXd3MwGOnu7R3sSIqioAbiu/fs2tvbImCkBeO79gymQqIgCAgLzR09d+/ZEZPlZFvX3Xt2pQL+w7bVQQhFIpFt5ZK5aRlIMLjSVJnPcMAYRyIRBAgh3tRRXdcLxSIAIIQa1kewQU8nRijBJ2rnOA7L1vII4Qx3CoLAOjzous45VD6fJ5R6xGMyaOtGVdVkMgkAruNwKn8mk0lVVQAgGols5XaSy3f+djK2eN4KGpyoG2rb+dH7eiZmc+9+977nv/Oj3vc+1knyk4bWHSwdGdYVEQzdECRVlDC4DhVlcEzTQ5osCRh03SBYCmmybeoOiKokCZhUKiaIclCVHMt0QZAlUaBeRWr/2IcHnv2nI0sUKxIyddO5cUz3wYcefvPcWHNrZ/c9nYfiErrvYzDyynOnnZ7u/nsP9f/k71/6zK889tzzQ3sOtP2/z2U+/VjT17+1eN2DQsvFfEG325IDj/dqV+V3t+jjyYGWf/rbk5/6+J43xpZgbuLC21sijg2N3rWrqwXFShdPZrzAnp7u+9/14SMvXH7/w51PPnnxkcfavz17rGtH/8PvHnj6O68HmtoGepXHd2klgGC8+733HzKFwOG+IW3XXZOXF+LO6EsjfuBsS8M6HW6rRYel/a7h6s/lcuZyQS+XswFjzClnV4VSSogHAoiiFAxy5diGw2FREl1A8VicU8cWY4wQUEqZlisP1TuQ81aMx+OyIgNzz/BZouVymeXpMh22dU/McZzlHlXcD1m1LUOpXGYiubwjbgwIIU3TimuLiN5BUEpzuRzTIF7H4Y39K+K7Dr4rc+kHR4dL2cDPHri7v63F/cE/HF3yQIo0f/pnPwYUlc8fofs+2iUWIyFlZLKUCKSfvwj/6pGu+YowfOxFu+/ddyvIo5PHF+IfvTuhi6HXn/4uuvs9uwRRltKXna77Ep4S1b7/k8vNzd2H7z2g9Q84dm7khddOLt1kFZi5cvoHp4P/63vaZsr5k6+/LvV87J4BWcSBUEhMTw4ffe4F+pnPfv5TfWOvfEdfJX4qHXzgfefHh586L3z5cQX0/KvHT+xt/YhQmr840dEiwaXrnq7M/AR66KGHg9KxnxztGnxk346UqMhBSZy5cvr4cOa9tL1r796DXe1iUAtjnJ+6/OzzM//TfzdgWRDpGBxsCZ+6Mj+VzXgXxntTgSlbBeDNdvTZUAgh8/PzW3lZ3HyY2wYBamnhaifpuu78/DwFSilhiZ/rBiEkYAEAXM+pVMoA68+VkWUZIwQUPD6REoRQe3s7xpgCWHxtoWRZZiXKsixxFkNVKhWXT8Kn4biuy+SFNC3AX7Xuuh6TKdoioc9V8TxvYWGBdSO51XO5DWiwSxxjYC4iQijWVA0te5djLV3C/PmnnjnTvKdPdIovvvbGgl4+8uzruhYJit7UpXM/PDnRsaN3b9z856efMoI7oxqMnTv14uV8srvtgYEOJSg6FsFgnX7tjTcWXbm8NDMz8vLJi5mCmZ+aW3JWWQLkUOK+w/c/dngvq7lMdu3+3Af2jl+ZZR+NNYWKcwXLrd7H5ptnp+/vps+OrhqFtV/78ff/5bmTb/e8QLQ1KVfsZHff9bEur5I7WwwdjltzZV2Lxo3MjEvfdqlDWrxUXrA9hABCLb2PffJBa3TUdqEyN5NznZk5I9ISbVIoTbR3BrZogr3PdkbTtLXrmSVJwgKmQOfnF7bIhhEKhaKxGABQwtuZMpPJ2I5TVYxd9ziUUtbWCoA3ybaqoEop729nGAYb4a0o4XpJpVIYI0EQUqlUQ9yWDRW420Zu1K0P0yNYt93W2JdIMnR56GP7D+4lM/f0SUe/M+w2D9xzYHC4pAy0i2K8bWAXcZbmSLTdo5QSbyUohAKR+C65pZA9r4ea9/TvDqCc6biEUEoptfS5TGHm/AkDqWp3E6IUUQDPBSnY3pRIT4919u/ZkZ6ezC+bICvPcOV73/7nuCqCp19+8smibmaWmmRsjw9PB6Zyeo7YR35gdCbsE5cy6dyl74wZHiRlePmV48y2YcqSlL1WIu/kT55GZRMAnPTFb/wQmXTILOcn/+F7Rlaftcp46MRIduXUlHqeJwgCgHvmJ8/Mq3bZgXOvPFPpSjmvnc/mbUW0Adxv/cNPCwUy1pkir55YXChf1ZcUAd6YGBGjuUo+M5JZbA4rQ0NLWItHhi+OD+cBwPOb0W9hmJjpsgN8e6Bp2tqbXDQaVWQFwOIszGHXFlaieDxD6bpeKhYBqQjxFvQCrHSz5t5VLcuiFDBCqVSKZxzTNFmIynFczrTfla7mUG3ow8lKA/D1oygKy5SyTJMz7TcejyuKDIDisdhWdniwO5/zl729CAaD6844bIwpQyhllaiZ0VM/Jnsevv8B89JLk5Yz/ZPn7zJUtSkAACAASURBVNo92J10zx5741LH7r4E/v6rQ8E2s5TLHT12Tofi68fOO2J3MJYgb55/6cIoGancN9j24o9fSkMsgypF8XTBmCnM0Ht3tAq5+bEL5yCfRyffsLOLpVNTTVGh5InpK6dOTeSB9aoF0EtlURRFUZwZH61VvC8VlvubVObnAADs3KXLyyoO+QoAgF2cfv7qGCWEAtiWZZkmpdTQdVXTCkvz7JPUKk4vAEABAMr6HACUhpcDW67r6qUypbRSLAUjYYyQVViaKAAA2OXMpUuZ2ss1M2MAwNDl5SkVrqxEx4w5ANCnr64IyCx/wPNIedtETLca5XK5VCqpqqppWqFQYP5e1kqapR+yVtKCIDiOs1IcccdSFSibn58PhULRaDQcDhNCmBmnaZqiKMVikTVOYqsw5wVZlshDCAEKh7niJp7nOa4DkiqKImeujKIoWMAAEAiu1R68fphKPf8g/DMBpisjywBgWRangyedThNCCaWlUolTIqVRvx0hhI1kWRbPmIQQ1hkxHA6XSiXXdRFCsVjMMAz2p2TxPtYCmi0gTI4ZYyzLsmEYgUBAURT2TUmSWMNq1qIoHo+XSiXWwJWz58PWh60qhJDJyUl270WjUdu2mUXOOpkXi0VKqSzLsVhs1WW2MaZMuVQq5PPRWAxjPDd+6emlwqOP7d/fmTs9WTx96uTyh8YuzY4BAOSnJgCgWK4AwNjoTDCFf/rKlTPjaQCA3OzLr88CAMBCGQCgnAcAmHx5abLmZFcBIHvxzVEAgKvse57nLczNE8/zXDc9P7+OX2F+evr6bxYymXeaiVcpFSsl3+y4c3jt2LFXXj0qSrIsSYZpUkoxRpqmGYbJXlgDAc1xHKA0Eg7t27u3Uf17tyau605PT88vLDqOc+LUaQqgKAql1LJsAJAkURRF0zQpBcuy0uml9h27m9tbeBZiz/NmZmbYSrew0BiVSEKI43AV5jBlPNtDmhbgebNHCDU3N2OMXYByqXTzA26MKIrs3hNFkTObxPM8yi2O11gsy2I+J1lROJWaC4WCbdsAVDdu0hJ1bTzPO3fu3BvHT4iSbFmm5xGEQNMCjmM7jgsArE7KNC0AkCRRkmVd14ECQpDJZBRFCQZDoijqhgEAgoA1TatUKpQCQiigaZZtYQTxaHTv3r1bVsePH6YEePXqRDqTcV33xKkzgEBVVc/zbNsBlpeGkWVaFEAQcGdH+xd+8RevvwcaY8o4tj06NFT7SB994bt1H/3GK9wToMDbDMXHZ1V0w0SBqBwIAoAWiLJvUgBVfUuFTNIAeXZRr4yMjnZ1dt6pJZSu605OTk7NzElaEAArgSha6VUSqPFxaAEAAMl1xqdnbNsulYo8r+OUWyi2SjAYjEVjC7rneR5nvGNxcdG2LBC1XDbjOM66xVdWIi8NWLgkSWIFZRhjzp2vWCwyU09VFc4QTCgUQghhhMLhcEMeCuZ05x+HH+ZcyZvurl0HKKX1iA4kAACAEHLlhR+3RBJiJAkAgZVVhQBoynJvKQogqxS5Vq5UGR0d6+hoD/FJTW5ZXNcdHx+fmV9UgiFAghpKsF9TfLt1ogUBAAghl0fGHcfZEFNGCwQ0PvlFH58bUbnVCSj9O/oWFxYIIZqmKapayOcppZIkhcLhUrHoui7GOBKNLC4ueoKYzhV1/cpA/454PH4nrTsskzSTyUzNzomqZumlSCioqkIs9pYfOBQKYUEorfiBQ+E4quzMlYuiwCUGU6MBgzj3MMdxLNtqyKJXDVLwS/sXCgVCKBJRJBrlGcc0TVbh5Th2qVRiXbI5EQSRM3wWjUYxQgQQp9SeJEksU8rQdcMw4hwaPIFAQBRFABQKhnh+O6b7oigqJXT43ElVkbVAwLZtz3UBQFFUCtS2LAAQJUmSJEPXAQALWFHUkCQ0h9SgRK+JnoTC4Xw+RzyCMY7FE1NTU64gzi1ldEPf0dcXjUbvsFXFdd2lpaWZ+QVZC9l6ORwMqjIkk4lKpcKCdJFIhFK6HKTTtICmec2xVS31BjzVgigqfP5MH58bYRrGrZ3A4M6dPd3dACCx9cgwKKWCILCMPEIIy867cOHCj5/7CcVYt93h4SsHDx64kyJNjuNMTU1NTM/IgZBrGf29PfF4fP/+/S0tLZ7nMRU1FtFf0ZIRFUVh6xFnpF8QhJaWlpV2klyJsbZtG4YBUlgUxQZo1SAAAFFqjGIsApD4DLVq4RJ/O8lgMMikhyuViuM4POGq2dlZQohHIZ1O9/b2rvtaiaLIfE787SSZ9QDLSoBcoU8mE2Do5T393R/8wAcCgYBt2+6yKaPASoG9JEmiKLJicoyxqqqVSkXTNISQLMuCIJimSSllT42u68yLqarq0aNHj73+uidKhbIxNja2986KX1uWNTExMTO/oAQjnqnv3NEXjUbvu+++WCxm2zbT/mG/L1tVJEmSZdk0zY0yZXx87mBkWa51ZtYqdlQF4gghiqLs3jU4fvVq2XQsii5eutTb08My1DZ7xo3Gtu2x8fGZuXk1FLXLhf4dfV1dXYZhsNYEbP2tfrh2lQmHwyzzkQdCSC6Xo0AJIUt8irFvg8/+aG9vVxW17KFkMskTzUEIRaNRjJFLaSaT5ZkSxpjt0PwBJlVVhQbdt7x2xwqGYbAe0QJ3gGlpack0TQBaKBZ42klWQ58YC61Nbc03a+lV+yxcI/xT+8/q167rapq2a3BwdGzMpGLRtIeGhnt7e+6M+LVlWVeuXFnM5tVA2CoX9u7e1dzczFQ3mbVXa7TV/o1u9BLSAFNGL5dNvto/H58b4RGiNUjsdeNgPV0jkchd+/YND1/JFMslE4aGr+zo621qarp9rRnmAV5YWJhfTMuBkF0p9vZ0t7a2soY4m/N7EUKMZc8cZW2P1o2iKMFA0HLA9Vy9UuEZKpPJ2I4NWMmk06tG7t/RrFYETrg2/Wo7SUni9TnlcjnLtgFAFLn8FgAgyzJaqStuyAasqipnrKpRMJ8KABDiFfjEG1eF5VHFYrH9d9994eLFsknyFePy0NBAf388Hr+tVxXbtufm5pZyBVkNuGZlYEcfUyLg8ZM1wJSRVXXrbzY+tyn6rc6VqRMmVaIoSnd3lz06WjJsWxBGx8Y1TWMJj57n5XJ5QuvNYMUIx+ON0b3wPC+Xy5G6X48xwolEnEWLJiYm5pYyoqJSx9o9uDOVSrE3pJu2k2wg1dWNc/nGGAuCAA5tiBgM8QhgcF2Px+9AKV1cXCSEIAFUlet6WpbFRO5ZMyaebBJCCEti1bQAp4Nn2ZRHmGc+UONzMgzdMAyeblyiKGKMAJAs84Y+k8kkAkQBvI1pss1WFVVVe3t6RsfGDMczXDQ2Nr53r1q1Vkvlcv1l/KIoxmOxhtiUlmUVS6X6b35JlGKxKABUKpWJiYmFTFZWA5i6O3cOpFIpttDxtJNsgCkjiqLqmzI+G4N1OyhEYYxTqVS5XGbxgsGdO0dGRgq66UnypaGh/r4+VVWLxeKx0282tXfWpzFKl2ZnHnng3ZwtBhnZXO6V46dTrR31fJhSujAz8f6H7hcwnpmZmV1Mq4GQa1Z29u9oa2urfswwDNu2NyFyX90wEMaJJFcqq2EYxVIRpDAWMGdBb8NBCLGFft1Uk5YIoZwNF2VZZlZjpVLm/Cun02lCiAdkcXGxs7Nz3ZuopmlNTU0AQDzCWdHW1NSkqhpALhwO87wqeJ6XzWYbYBffAHbnp9Np1jIaYzw+frVoWrpLLg8N9/Z0Mx2EN06cEkNxoQ4LgBCSX5z90KPvbchje3VicmRmIRKr65H0PLeYXnjsoftd152YmEjni4oW9MzK4O5d1cAcpbRSqXiet743Fj9XxseHFxaIYV8jhMLh8P79+4evXJlfyoCqnTt/QRRwpaJrkdjBww/jOlZzQumpo0cape1BCW1q6zh4+OF6thHHdX745PTJk6ckWfIoUgNBz9J39PW2tLTUfsw0TWdT2vRUry2llFPEtoqABc4gRSqVkmXZpailpYXTKlJVFSFEKF1YWBwcHOQZihkKLPzHM04sFpNlBRpRn2VZFgUAytX0GAB0XV9cXAQAhHmVmhcWFljIMpvNuK67bjdAVcJYwDge5zJDbzR+7aoSj8fD4fCFixdzpUrFRmffPC8KmFJaqugPP/KRelykjuOcfPknDVMapLS7f3DH4J56Plwul3/83X88fuIkQohiUVY1Yum7BneybucMZsqs+z7ZJFOmubkln1m0PV/3xecOhPV0ZYLXAIAQEkWxq7PTse10vqgEQgCIGLZlGJ7r0jq2GUJJYzXKCCGe69azB7iOa9s2DQckNSgQDxN31+5dsVjsVol5EELy+TwFCpTqFS5TRhRFWZYtCq7rVvhyZSzLIpQA0GKx6LruuqMwTB8WYwQAtO7g46pomsYKsKt9JddNNpu1bAuWu3bzdoZi5hVnqLRanxUMBDkzgVa6OPFmJFdlAkjjjOxa2J1fbSfJVpW+3l5vZLSoG7IWAoQMvVKuVIjn1SPK7Hlug1eV+s4LAMuygaIiybLruQqG/r17Yg1tHLEhy1O068C//tghcL2FkRPf/ekFG+BTn/m5U8dfk0pL0a4dR468bDgb11FIOfTog/k3XhjlWql8fHgJhUL9/f3ixIRp2bIseaaUnVs88fLzqI4AEwVazKbFwZ6GzEQUxczc9PGXflLPqT3PcyrFaFcLQh4WUVdX76qNACORyKblylTh3FY1TQuHwqWSzS+7VyqVXMcFSTIMg2coSikLwQAGxOdK8TyP5Uy4rsOpvOK6Ll1WsubNlWFaxoBQMpnk+fNV22ZZlsXiaHxDsf9zXfDlHpmAKKWWtRlxcIRQJBLp798xPT1tO44kSSJ1iop05rWX6rEJCCFmudgo60GWxJErl9JzMzf/KIBtWwJxw5pEPE9VxN6enlp/DIPF0W5lrsz1aLEUnTj1xDNnAEBL9H32sf07E8Jx28Ra24c+9IE4Nn5w5I2iBWqq52cePGAvXHp+Av3sg3suvfH8Zaf9sf3dmlectMI9Wv6pIxMPvm9vQgpcPnPszbTwkccPi+nhp48tve8jh1oV8fIbr5/Nyp/6yGGSm3j5dObdh3clFXri5MiD731/oNn9q+8dTZtcAWMfnzphS8w1L/oIoWAwuHv3btZUxXXdQ7Zdv+cfY9yoSo14PPaR9z9S545LKX3o0N2KorD3LVFcXTeFX96jTpgQGQAghCPRyE0/vwalUimbzYIUQgjhLdNH0HVdSgFj1NbayjOObdvsDvQ8wr/Zs2J10zQ5024qlQqllBDK2g6sG1VVWZGL4zickc2mpiaWLJJKrX/jBABCSKVS2bhnAGMcDoeLb+++x7LxWME2W1UOHngHyUOCIDQqS6yvt7e9ra3ORYBSKhw+JElSdVVZ9WM8bwUb5DSWdj/w/t/oODB04qhy10MLr/zLZNsXkj27e62Z+dnZV05fLtsASPjQz3ykcOLpk4veL33xUz/95pHHP/1xYUg/3Jw/pb33rqFn0+0Pv3vQfPTe3qd/eOmDj74rUu4Ozx6xBx95NHfqgw/1P/3M6Ifff19Y7+wTZ7X73q/D5cd2Sz+8FHxkf24+PZ85dipv+XaMzybBqgyu3/LR2/3qU9Mz9ZcR3UIwQgP9O9Ze8kqlEhOB2OjJLF9bQGxinKOxJE1RlMIhrnaS4XBYlEQXIBbnDb2JoogQUELT6fTAwADPUI2iubmZbfb8nbFLpRKhlPXk4ulf4ThOozrPl0olZgzlcnnP89b951vpokoxwqFQ4wtfEEKappWu68zFIk3sa1EUZ2Zni6XboMxTVeS+3t41VhVKKevRuz6/0QaZMs7lo88/8cwZUJp/+WF6eaq0jwIAUM+xLbtQ1gkFJOC2EP7RXKbkhGLEHF2cv59oilicm1vIJBYrk3mvg0oCFHKL8wt5+b7OsIAX30ibLVZzQMlnFucXF9z+Ha0tocUz85cvTObElvR8biETH0iC7dilYtm9DbYMnzsEQkg6nV57WSyXK2Ozi72De7a4vBUhZHToYnt7W3RrdLDzPG9paYkCpZTkclzqHQghAQsA4HlOuVK5iaLZmiiKgjEGApzJBwihVCqFMaYAnK6UaoqMLEucuTKFQsGxbeDVEawB8QYHXddlubqBQIAzV8YwDNf1AKjrOjyexWrMCxrXtbsWz/NY8HGNrd3zvOHR8WT3wFaryLsG13WHRy53tLevXTzFcxk3yJQRd93/2G90HFgYefPCGP1vfv0LWhAPU+p53pIX+dxHHvrOMy/mTPfVkeyXv/iFy5fPvDDp/favfDG/8NpsoWl/kFJC6IoDu7X/3i/93OD40LNnpju//Lmfx3b56y9ndz3SAkCJYx47OvLrH31P67xxbHSWML1uaqVz3id+7qNT33huztiMCgsfH6jDNUqBhqKxnoFdW1zbyvO8pbmZm/bG0zRt01bPRu0TwWAwGo3qZYcQ6vHFTdLptG3ZIGmFQmHd75EAQCllPZgAQ31V+jekqrzCnwlkmiYLBPDryiSTSYwRApxIJBpixBPCW4zdKDBmYjmIUFKpbIhf5OarCqVYELv6Bra4tJttWenpibUfZIRQKBRa96O0IabM/JvP/sabz67869Sx2p+9eHblK/rms/+w8qkT1c98DQBgCABg/M8htu9do6f+8r/8KA8AMPSHl55nn/nqfxoGgP905QIA/PaZ5QNfBQCAywAAF/lbbfv41A8LgjTKAX5boKoq5yZXJ+zasq/4X8dLpRKgrdXFhnX1wgixXJB1Y5pmLpcDAMdxK5UKU2HhhBCP025ACAEgJvDKM46iKEwWzzTN+hXhViUWiymyDIBisThnDixvXfjNBmeN3jbsDFuOQCCw7je9Lf2CCMUrf/mtl4o3/5yPz62EqT5scXdLY8nn8xtRgHo9giDE43EECHGbMp7nOa4DAJIksVTidbMcYAIIBNe/+NZCAcxNqYKph3g8LisKAJimVWe17Y3IZDKUEEJI6Z0ow65Ko5xz1Xx127Z4xiSEMIk8jJCiNN4+Xr7zt3Y8uoGwar5153Rv7cWX2PmiviWciT4+N+atktptw6ZVMLGMAQqUEsq8DjywjYEQwsTN1k0sFpNkCQCCgSDPmz1CiEn7U0rL1yV4viMEQWDuK1EUOOvkPY+rG0MtjbpLLMtiNVDXtHddB4VCwbZtAKrrOmchPfvlEEIBrfHxHc/zMpnM5jxlW4RbXMFkmSatb4kRJUkLBrePmenDg+s4pqHbliVvje5xa0ApdRyuFMLbDlEUGyhvtQbs2rIvOT0EgUAgEo6YBvE8j9OUWc6VEdWlpSXHcdZdNr8SeWnAnaOqKnM18RfcFotFlvarKArnXzkYDCKEMEKsExnPUAxJkjcnsnlTMMbBYBAAeYTk8rxG9vVst1UFISRJ0q1sJ2nLMSvUkqA5ia7uGqKUlopFSqmkKJVSaVv54X3WB6vbFASBc/faNDZnX986xGIxznBPndTI8CPOPcx1XdtxABrTobNRewxL+0Ui4ox5VSqVpaUlALAsu1gscrZvZIiiyLlcR6NRjBABxGldSZLE7rdKpVypVHjaSQYCAVEUAVAwGOL57Zjuy8rGuyEGhyAI28eUAYCmpqZ1P+MNMGVIqp/0PdDmXojQ1dMeme90cXHRMkxDr/CKWrpuPa2zNuhwn82BLRBqIKBsfMNCfjDGzc3N1ytA3MHkcrlKpbIJRUyCILS0tCBAGCOeDQwAbNs2DB2ksCiKGl9EQBAEhBEA8LxH1oIAJO6LWd32OPe/YDDIiqF0veI4Dk+4amFhgRDiAWSz2b6+vvW/c4tio0znFVMGRFHg+dtVZQIQgCg0fk8RRbGpqWl+fr7hI29ZmI9zfavKZmzqCKFQOFyuVMrFoqppYb71qJDNRjiSoQrZbDTB1V/XZ3NYnJkRRdHdlJ6FnKyU1K6lAHGH4Xm8tS11Uu3BxK8YWwtrDbRuksmkLEkOQfFEnNNXFIlEMEYupZl0mmecqvsKY8Sp2qdpmrBc180zDABzXwEA5bWuTNPMZrMAgAWB8ynLZDKWZQHQQqHged66/3zVtlAY43CES8hnVTzPKxQKPLqCtxecAbUNifWoweYDg60t3XsfO7wvLAJwN0/x2YbcRn5V1rR5W7mCNw1CCNNGA2hAQW8wEARoQDvJYrHouC4AzWazPDr6y6XmjVgeA4EAK8BWZIUzVpVOpy3ThEYEmCRJQit1xTy7QFUsJxQMcmpMNypjneV2AAAh5Jr2Ag2BUsoK9Rs+8h3JhnhlgvH2gVZ7sHVPOle6d8fSkeHFaz7Q0vPQH/z+v3rt6//xb86j3/2NL7zxvb985uzCOzrF537zt3uv/uj/+t6ZD3z+K+9TT/7h119kWXwf+tL/eKhw5P/87uk1jxYf/tQvf+E9kck8wjNv/NE3XnwHC2Rk5x//u4//3V/+1dnJG967/+a3/9D76V/8zeuT9Y/qs9FUKpUnnnhidHQ0HA7/zu/8TrWfyxNPPHHx4kVFUX73d3+3uZlHAPYmYITz6aXL5041zKynYNoWs/hUReHTV6sZldJiLoPQjrU/lkwmQ3za/+uAc1vFGAuCAE4D9gbTNIlHAIPruDybDaV0aWmJEIIwqCpX2VFVV8a0zHw+z2nNMFRV5XTwtLa2snaS0WiUZ5xqLnOpVCqVSjxyxpIkYYwBkCxzWVeCIDQ3NyOEKIDn3Zo+OQgh4jpXLpzlj04yKKGWbQMAxkiW5EatKp7nGXp57auNEGpra1t3zHpDTJl8ZtK8931w9VTaayWVVSoFMJbCQflDP/PJ52d/EggEZBElWzvjmuDqhas5p681gTECcB1XEsGYmV+yxVB/W8Kz9Zn5JTbCpYtzH3zkYOx7Fw/s75p65tm2vh4RyOLMjKQGAoYUa26XzUyOBDpDdHy+3NrZGhJRenE+ry+/P4mKujTy+t+/jP7Dbz3U//R5OxEkrjU3Mx9t6woIyKpkXSUeUSC7MF/Goe6miG0U59LlVEtrMNGRjARFjAAgEEkmAmRhsZhqb/cqeigWQsSZnZ5VA0FXlptb2+3CgqMmY7gyk3G6+9pkz5lbWKhYt0ce6x3GyZMnC4XCV7/61b/927999tlnP//5zwPAuXPnJicn/+iP/uj73//+t7/97V/7tV9jb2yEkHfk18UYNzU1rf2iHw6HDu7Z6RGvUf4mz/VsqxyJxkuFXETDgtiw2FZq98BN8xIqlYplWY1qeLkGgiA0NTUhQAjjRJIrNLwskSeFMMacUSGElruMY4HXsU0pBco6knIFKTzPY14rSrmKWuGtzR50XXccZ22x+bVZWFgglHgEZbPZ7u7udZsOsiwzY4jfpxKLxdh+GQpyFdIv58pQigAwX5PtVWGdt9Nrhh1FUdx/195SuQzQmGivaVrEs4OhSLmQjWrRhtXoSKhj7+6bminFYtF13fU9mxtiynhG9kfPPI0RAEzdSCDcyQ+/ejX82Uf3sbUw1d57aG//I/uSf/CN43/2P3z4B69dfODhw6d+9NrdH9zzzf/76+p7Pn2AXEkdvPe/fu2JpaUsAEwMnc5+6DP9u+8+oM7+51l7YPeeBx56dOG5P58FACx+6Au/2Xnpr76t3/fHj7i/9WTplz7SMuu0dSz+9Pf+/rXqBHruevCLSW/oxVf1WPNdd+/94MP7vvcXf3rfr/5B09gPf3BF/6UP3fvd514cAnzo45+Nzkzueaj7qe9d/MxH7/rRuXxSWb7QqZ2H//0ne/7L13/63/9vn//mH38zNDj42Hvve/lv/hgAIJD44q/8yvRTfzi1+1//fPDMXw8lP/MubIb25I9942s/Ht6Ia+6zNlevXt29e3c0Gj106NCPfvQj9s2xsbFdu3YlEokHH3zwT/7kTzzPO3ny5HPPPed53le+8pXEO8mpumkDYVEUe7q71v8LXIfjOFq2kGppTS/MtSRim1yhapomZ4Pi+lm+tpQausE51Eo7Sd4c0ng8LkuyS1EinuC88izyQijNZLI840BNHJ/T85dMJpmRymx6nqFs26YUgFLODtu2befzeQDO7g4AAPl8ntl8+ULBdd11u52qEsYY43BkQ/qq3rR+EyHUlEo18elE11LR9ZLpxBLJzLzW2pTczOQ/SmmlUlm3Fb4hpkyoZeCLH70vk8mBp596/cRIepW3VUrcZ578/q//u/+2I2IDxPYc2nt3MqREO3tSx63i4rGTZ3YfevjNN34QfvhAT0v73Yf3FE/PDZ29mNWXb+T87OSlWftTn3188fIZQ2v5+ME9IhJ6+7uuXwzufuThztDs1JXx4cW3+Ycmzr/61a+/ZCJ8z4OffuBAjxwI9bc3AdjHj7xwbC7xngcf/NlHDj1pKg/f03UlP3Pm9JX2u99ljx7556cXPnDPZ9gIk+dPzX38rsMf/5B57PlifOCD+3dIstrf3XbtAq8F3/vo4ah5bvrqpXTZD3zeGhBC7CGpdbdc0w0OIXTo0KHHHnvsy1/+8juqZSWE5HI5QsgaLzGUUtYceP2/w9txXdcyTUPXLdMyTZNzq6iFP7OhgXiel8vlWH81zgQXURRlWbYo2LZdKBR44omO4xBCANGKXvE8b90vryvtJBFwByk0TWPGt6oqnKVeS0tLpmVBA3McEW9w0PM8ZjqHQmHOyOby3w4oIY1xkFNKN6K9ALvzb1pM4DhOA5990zBNyzF03bJMwzAaaMpgjDfUibshpowgSjOXjz/12pW1P6YvXP7nly/87mcOQjDxM4f6X37xRKKj8/qPmXrp0th8s740M22KdCWtxc0fvTj7C7/88N/9x/+vbf8XEvbi5UKyg/2IkvmZmft2HTystwNMTgwNlZPq5Oiop1eu30cQFh54/MHi5SNC7C3D1nVLrz33TPhnPtGVOjUyZeiFiZm8kAlfevy9977/obmktvISZs0fG3V/8/GBv/nTbx58/Cve3PFMcGVxtPSpxdye/fcleI1Z4AAAIABJREFU2pKQO3/h8mh/tzU+M6nPcq3FPuumv7//ySefTKfTR48e3bdv3+TkZCAQGBwcPHLkyMLCwvPPP3/w4EEmuiqKYqMqbGspFosvHn09FIk1LKmF0LKuCyPjxHODgQDiK8mpGRfKhdz73/vg2htGJBLhlJTdfBRFCWiBkt6ADaxUKrmuC5Jk6AanYuz8/DwhBDCIIq9qDttQHcepVCo8uSme51GWYxsKcdbbd3R0CBgjhFlaybrHqdZnmabJKW+IMWadoQRB5JmSKIptbW3ozEVCqXWLmk64rvvaG8ctgvkDnQzP9QzLwlig1AtMzzcsr49Qz9IfffjBNW4nhFAikVi3k2xDTBni0YH73v8/H3zIKi0+++yR4aVr9WYy82e/+mdjRaCnn/vHfz/8ytLM2NmFUlwhZ8+dmZhb+sO5ibHZ7J//P3+2tFC5+rW/qkxN5q88cXdvMzhGLv9W25eR1575X+aPjV1aMq98M9OTot7JSm6+iKZOO5lpc6TQ00a98/+7mTt7tfjEVG9YRtnZuZUlxzt75MkpoWQDUM/5x7/4zz2JgHv+cnp6Vp7/U2MmT4VEuZj7l7/52sWRCenF0Z3tMc8sjZw8+R/G+sPY+z+eOD4+zywS+toPvrl0OjpxZRHNfK2vJeQdv5CfmyRDf04zE4Xz/3WsM+Ec/9sX8vNDi69m9vVK4M5lGy8K6VMP995775kzZ37v936vubn58ccff+qpp3p6eh566KEDBw78/u//fiQS+a3f+i2E0Pq8JgihcDi8ts/A9bxIquXg4YcaGFZf3kRRI0P1hHinjr50U8/2phVWrAiRIYQwZ+qoruulUgmEQI3sHi/8a73neZQCRiie4BK1YxYMAHge4Sz1WtnswTAMzjf+YrFIKSXEy+VyXV3rD7Cqqsocpa7jcEY2E4mEosiwXAa//tuAEFIul+lyyKvxLkx2569dG0UI8QjsP/yw2qDOCaxDCECDVxXbts8dfXFD9U43xJRxy5VCKTsxsrCjJ7rqgmcb2fMXswAAeunCpcsAAMU3x1d+ms/lAWDo8iUAyF5mrp2FE2euLXFyCivftOZP56s6Qjn2uTPn3sqWGrp48e2H0uz8ZDUUlZ4ZT89Uj7547ekWp04sTq2M8+Y1c6hk585m5wAAFiZy1QmmhwAAYObEW+PC2TPXHuuzmaiq+qu/+qvVf37pS19iX3z5y1/mH5y1p7/pGx7GWJLkLa52XWe4pFQqGYaxCYK/K/LwAACVSmV6ehpjnEwmVzrpQDKZNE2T7eLhcFiSJCZAwnopLywsAIAgCMlkMpfLOY4DAkiSFOYr8AmHw6IouoBC4Ug+n2ebazwedxyHNUgPhUKSJLGSIlmWY7FYtUtXa2trNptlk692IaWUNqqgl1Lqum4+n2czCQaDsizn83lKqaIo4XA4l8uxv3IymSwWi8zJkUgkbNtmh4iiyGIBrutyZhCXSiVCKaWQzWZzuZymaZlMBlbSeLPZrOd5giDEYrFKpcK8SvF43HVdJjgZDAYVRcnlcrZtN6p9qa7rzD4rFPLT09OapqVSqYWFBRZ6TqVSpVKJzSQWi3med81MKKWyLEcikWw2m81mAShCOBRq/IPA7vybC28iJEpyoyqYNoh6qigopdls1nXd9UW1NsSUUaNRUikRYmYLkeZ44EqNV6ZcLJa5n1i9vLqs8OYc7uNzDYSQubk5z/M4K1d9rsd13fn5eQoUYXz02OvnL1xACCmKatsW22UVRfU8z11peY0xZnszFgRFlpkmDUJIUVXbsgrFUutA3HGccqnU3NS07lnJssxcFxcvXZ6cnGSvm4qieB5hMxElSajOBGNZVizLZK4sTQtYlrkyecXzSFnXtYhi8eVbyLLM+hwRSp/83tOCgJmBxbplrcxEkGWJ5WyxjCjbdljKiKIohBB2CBaEXKHQELUbAEAAFODosddPnTknCAKLxWCMZVmuzkRWFNdx2GWUZYVScv3kKQVASAsEOCObuq67rocQmp6Z+8fv/BPGgqqqhmEAUACkqorz1kxkSsFx7JqZ2AB0ZfK267pUkBGCjZDBYnf+thLe5GFDVt7C/NDTZ9R/84F9p158/uQYl4Slj4/PFkRV1U3oWlAFAYiSCLGURQEATJsCyEzg03IAQAAsAIDlAXgAWAUAoGBYdPlrANOiALIcTbqOUyrkOJ0N2WzWcWysqjQY1SkAltaaCYBhU0DL2j+WRa6ZfKy5rZTP8avmMHXsaLLJsG3wYHkmBIDUzgSqMzFtAJCunzxQiDa3L85OqYrCWZ+VTCYp8SKJZse2K3XOxH1rJtdMPhxQvHKeZz4MhMA2jWRHt00oAJgWAbyckWpdO5Pls6/MRKmZvAySHAyFluZn48IGSlJtExBCQY7y+A3oHCHJAsbO3NBf/N0QwHLczcfnDgYhJMvyFin52RxY2GITTsTykA7dc3DoyggRRYxQU3NzVWM3mUyYplmp6AAQCYcFQcjl8wCgKkooFMrlch4hkihGo9FiqWTbNkYoFhDiO/s4q2AEQejv6wOM34pzJRKWZZVZnCsUEleiS4oix6KxxcVFyuJciUQ+n7cdByMUjcVs265UKgigZ6B3YOdOninZtm1Z1o6udi0QqIlzBSVpJboky5FoNJvJeIQghJqbm1ngBlh0qWbykiRlczmo5Pr7ezkdjZFIZEd3h2FawWhUluVCPk9YnCsUYrXQgiDE4/FSqbQc54rH7ZognSzLLFwoy3I8Hl9cWAi1t3KaoalUaufAQKlcphRYqCify7kszhWNVnTdNE2EUDQa9Ty3XCpTgFAwKK1MXpakWCyWyWY9z0MINacihQJtrM4Cg6kJc6Y93V6Ew+EtZMpEUy0xVRvob5cAgBhvnn5zIteYGKePz9YEY9za2trADkFbn0wmUy6XN0cib/fu3fv27bv//vtZMELTNNNcDtCoqlot02XWJNsRBUGQpOVICgsHsKgBMzr5Q4EdHR2f+MTHFUWxbZsFI2pnUhvnYjK1pmmymSiKYlkWIYTNhMV0EEKsbo5nSpqmPfTQQ+w6EEJc16WUspnYtk0prZ0Ja5hQnXxtdOmayXNeqK6urs/9wi9Uh63OhG3S7DooylsxnTVmoigKCxdy3nXJZDIej+/fvx9W7hM2k+vvkzUuY/WPyC7jRiTAiaLY2to6PT3d8JG3Jqyab3BwcH1/38abMpm5Keg9SDMj3z893b3r3o6mkG/K+NzZeJ43MzPDI7flcyPYNg8AtRkStfqz10j31mYi1x5Suz7yJx8IK00Na4etcya1k2dbKedkGMzIW3XY2rOvcU1uNHkeJEm60Uxqr0OdM2lU/T/GuHbYOmdSz+QbiOM4MzMza6tV+VRp/MqbbNv1wQd2J0W3eYctIve1ly43/BQ+PluNDa0z3IKwLMhbPQsfnzsZfrXl2wgWUFt3mL7x5l5mbuhb33ryxaEFADRx+fSVJd8l43Pns60SZQAgFottQiW2j892ZrutKk1NTet2Um6I5yrRvveRHu8b//yc2HvoPQPrr3j08bktwBi3t7dvKy9FPp/nbCPg4+OzBkxNeFtFl5aWltatf7ghoX3HK1RI26EDfTIR2np6ujKVqazvm/G5Y6GU3rRbCka4kEkPnz+7xd+0KKXFXBahHWt/jF88zcfHZw2Wu4+tKS6HECKeO3rp/BaXyPM81zQqay99lFLHcdYdUNsYU6ZSGVnIxkLa9OgFy3Mt11/yfO5kKKW6rl//ELLeuazSIRDQdvV2Aqm3t3MDxfXhnQTdKdCBzlZRFF3XdV2X1W5cvwat+k0fH59GQSk1DGONVQVjjDHevbO/XK5Afb1IG7uqeMSrUxqQUhrp7kQIsQIxSZJWfesTBGHdq0rjTRkpkvrQI4/EpCUDJzpjiz944aV0vau3j8+dA3vJGB4eLpcrbOOfW1iM1t2yGCG479C9DSnZqFQqJ06fqfNtx/O8udmZYqmoKqrruq2tLe3t7dcbLtFo1M+V8fHZTJhZY5rm8PAVXdcFURAEoVAo4robkaqK/O5D9zYkFL64uHhp6EqdLhTbtnOZTKFQEASBUtra2tLW1oYQql1VWNeILdROsnfH4NLFn35vZBEAdr7rfft7Wl+4PH/To3x8bl8wxk1NTbW5I5TSUqk0NTWVzpdkLeB6XiGft0V17/2PoTreiiglbx5/TdeNBpkyOpFDdx16Tz1S9I5jTz71L0XDdpFECB0eGfU8r7Oz85olxjAM27ZrS1J9fHwaiCAIqVQqnX6bXH6hUBi/erVQMSVFcT1ilCvzC4uPfeLnFfXmC4Xr2G++/opt2w1ZVTK5fKilq3tgVz0fLpWKL/zgu0XTkWXkuW5pdIytKte8IJXL5Tp7wF1P400ZwzBTrR2JuZwhRLqaw0b61nQ/9/HZTGqLsVnqzOjYWMV0sCh6ZllVlEhAwUQMhEL1PKiEEElqZPBbkuVAHQ0vAcB1nWgkIgERqWPajhKMTEzPBAKBRCJRa82YpsnZoNjHx2dtalcVQkgulxu+csWmCACIpauKooa1UimoBYJaHS5Sx7aFhgpfKaoWrE81G2McCgRk8ATiuMQTFW18YjISidTK+1JKK5XKujPwGm/KzI5fTmrv+vRnPyl4dOjMmbPTDWiZ4eOzlSGEZLNZFr1mkeyR0VHdcrEgCNTbOTgYDofLlcrJi1eW5ufqsScopYZegUbloiAw9PLS/CzUMSKlRJXlvXsHQsFgNpsdm5gUFe3ylZGO1pbu7m5RFP0UGR+fTYCl/bJiApaNNzI6ahNECQnI4o4dA6FQiFJaKBuZxXlZubl/1HNdx7YaNT0EUCrmF+dm6/mw6zrRSOiuu/aJori0tDQ5Oy8o2vmLl7o7O9ra2qoF2DxrS+NNGWLrZ8+8dPbM27/pFzv4bAMopYVCYXJqqmJ7GGMZ0/4dA6lUikWFk0FlaeTNOodKBKRgg5JRQsFgTBEWr9R76qaIlojHZVkOBAKO40xMzciB0NXJaQDo7u5m6044HG6U9KqPj88aMC/v+NUJywNCSFiTd/T1xeNxhBAhpLujLT85XOdQbYloo1qnpVLJ4vjE4pVzdX6+ozkViUQEQdA0zXHdqdk5NRgeu3rV87zu7m6W8BuLxbZQrsz1EEKy6QxrpeHjc+fBWh6WSqWlpaXRsTGLAACNBQO7d++qLhyKorzr3ntuyfQ0TVvfqRFC3d3dlNKpmTk1FL46NRMIBJqamnzfjI/PRoMxDofD+Xx+YWHhysgoFWTPdVuSsZ07d1YfQIzxzoH+dzRso57cZCKRTCTWcWpBEHp7ehDA1Oy8EghdnZoOhULxeJynfAkaYsrg2bM4PTJGTQFWd71QSm3Ljjel+M/l47MFYe3pDcMYGx+3CQCFkCL19HTXtsu+hXv/uk/NpMS7uroCweDo2LgSCA2PjhWLxZ6eHkKIYRh+EZOPzwaBMdY0bWZmZmR0jIqy5zqRoNrV1XXNi8StWlh4VhVZlnt6ejRNG5+cltTAxcvDnR1tHe3thmGwZunrGLYBpgyy9WhIReiGbiuWPcB/Ih+fzYe1wBUEgXXlZQ7ScrkMAAihQCBgmqZt25cuXbo8PGwTBABBRdg5MBCNRu8M14WiKK0tLa7rjoyNy1pwZn6RENLe3m4YBmsGrigKQsg0TQAQRVGWZaaHIQhCIBDYVnKlPj43hVLKYhSrPjUYY1VVLcsyTfPSpUtj41eJIBHXiYcCfX19ofqS97c4rB16R0eHZdmTMzNyIDwxNU08r7m5Wdd1dk1UVa1eKEmSRFFkTd1FUQwEAtdfhMYEmFRNw2taUtut2Z7PHcOJEyfOnb+gqko2mwUASZLi8Xh6KU0owQgnkolSqWRZlm3ZICmu6zbFI7t37brDQjAY4/a2NuJ54xOTkhqcXVgqVyojo2OO6wBAOBzGGDOzRlXUYCjI0hVbmps/9clPhuqrcfDx2SZQSl9+5ZXx8auCIOQLeQBQFCUcCmdzWUKIKIrRSLRUKtmObZqWoGiOZXW1tfT19TaqifoWAWPc3d2FEFydnFJD0anZuWw+Pzo+bts2QigSjhBKSqUSAAQCAUVWCoUCoaSjvf0zn/709ZdiM3JlAGBbtafxuZO4Ojk1nSkGQmEQAgBgEihlyoCX6wX0nA4ggKAhRXRNPREJ9awkxt5hCILQ2dkZCAZHRsdkLWBSTKhIBQkATN0D8Javjwv5vAFIBQFGp+YqlYpvyvj41EIIGR2/OpevyIpafWoKeZ09NUChXDAARMACVgTHMpoT0c7OjnXnw25lJEnq7u4OhUJDV0ZkLWQDMjwRBBEAjIoDAMvXxwKwLMAqIWRo9CpTIb9mqDvw6vj4NJA9uwaLxaKu6wAgSZKmaaVSaSV6EtQN3XNdhJAkS0owzh7LWz3lDQEhJIpiUyrlOs7U1LTnurGI6jgOix0HAgEKYOg6AMiyoihyqVQKNa5cwsfnjgFjfPe+vd7Zc6ZpAICiKJIkVSo6pUQURVXTDF33PA8hJMmiFkl2d3drmnYneXmrsGy85uZmwzDmFxYIoYlwwDAM13EAIBgKea7L4k2KqkqiWC4bkebkqjFr35Tx8VmLe+65Z8+ePczPyeqTC4UCM2XC4XC5XHZdFwCmpqZKpdIdFle6HoRQS0tLNBo1TfM973kPC+oDAJO4YHrHiqJompbP50VRjEQit3rKPj5bC4zx/YcPHzxwgD0vqqrKssxekCRJCgQClUqFtWsdHR11HOeO9PLWghDq7OxMpVK2bT/22GO2bTP5zUgk4jgOS1LUNE2SpGKxKEnSqi9Ivinj47MWCCFN02o1VJqamqpfJxIJAPA8b3p6+pqWIncqgiAEg0FJkhRFiUajtT8KBoPVr5ubmzd9aj4+twcY42AwWPu81PYAURQFABzHGRkZ2SZZ86IoBoNBVVUlSbrmsoTD4dp/3nCEjZhWtLVnb2civzg5PJnx0319tgOcogi3HdFo1JfI8/HZUJjO762exeaRSCTW7YJqvMWnNfX+4s99JCW6D3z8c48OvDMJHR+f2xHWTnKbvD8xCoUCc/z6+PhsBKIoMqHwWz2RzSObza67s9tGeGWkytjxp4+92aJHHowEAbIbcAofny0E64PN5Gdu9Vw2Cdd1fYUFH5+NgxDCEmi2iTXD9OfW7YVqvCkjgEmSD/zGv70LAQAMfBy/8PSJqYafxcdn68AyXreVKxhuqX6xj88dDyFE1/VttapsmXaSCPUO7IkpcP70cfaNxemR2byv8+vjc6eRSCRqs/N8fHx8eGDVkeuWb2isVwapWjAaCTz84Y8ekGe+P4rtU9lvHZ9v6Cl8fLYcGONUKsVKK7cJhmFYlsVKLXx8fBqOIAjJZDKTydzqiWwepVJpVfm7emioKUPJ5XPHMzvvPTj86lPF8rOj5IOxG5ZO+fjcSRCyei/VOxXDMNadoOfj41MP22pVYWH6df/Kja+5SM/PpHHnxz/7xd//uf6zF5YaPr6Pz1aDEJLNZrfVuuPj47OheJ7Hepnd6oncHjQ+7ZeWFv7hG3/96ks/MtIzC0Wr4eP7+PjccsLh8BpyVT4+Pj7vCIRQPB5fd6upBpsyid59n3n0XUFFBOJ6FE7/9MlXRoqNPYWPz1YDIRQKhcrl8q2eyOaxTaSNfXxuFRjjUCjEWqZsE3ikuRpsymSvXvjLv76w532filz57uuzjR3bx2eLwkyZbSWRVywWDcMIBAK3eiI+PncmCKFgMLh9XpAopZlMxnXd9alzbaPF18dngyCELCws+JJxPj4+jcLzvMXFxW2lK8PDhgSYkqkm8a4v3Wf7ASafbYTjOEzwV5ZlJurPWlEahsHWI1VVXddlnbSZfIJt2wAgiqIoiqyXPcZYlmXbtlm6340OWeMsmqbZts3sKs6z1B5yzVlYR8nNvLw+PtsNJoCLMZYkCWPMutBf8+wrilJ9kBVF8TyPPcjXH2KaJtMO1jTNNM3rn/01zqKqqmVZqy4XCKHqIZIkWZbFzlLnIYqi6LrOzhIOh9ft296QAFNjx/Tx2eJgjDs7O5lknKZpkUhkYWEBAARBaG5uXlpacl0XIZRMJnVdZ89tNBpFCOXzeXZIMBhkNVCSJMVisUKhwJawRCKx6iGBQCAYDKbTaUrpNWdhCjfskFgsBgC1h2QyGUKILMvRaDSfzzuOc81ZYrEYpbRQKLBDAoFAJpOhlIqi2NTUtLi4yIyktra2UCh0ay63j882QBTFvr4+plYViUREUcxmswCgqmokEkmn04QQURTj8XixWLQsC2Mcj8cty2IxqUgkIghCPp+nlLL+0tls1vM8QRCampoymQwTU0ilUoZhVM8iCEIul2NniUajzC0kimIikcjn82xRisfjpmmyQ6LRKMaYnYWtY7lczvM8URSTyWS1p1JTU5Ou67WHsLPUrpaiKLa2tq77BWlDOmP7+GwrEEJNTU1NTU3V70Sj0erXtU3qE4m3NVhtbm5e9UfxeLyeQ2o/VnuW2u+vccgaZ2lpaVn1R7Vn8fHx2TgQQh0dHbXfSaVS1a/ZWwrjmue9ltpFqfZjkUiknkNq17HaM65xSO1yUXv4NZO80VnWjZ8r4+Pj4+Pj43Mb45syPj4+Pj4+Prcxvinj4+Pj4+PjcxuzUbkyMk4oEBEIQp6XEyY36Cw+Pj4+Pj4+tRBCXNclhCCERFGsKrWwJFxRFK/Xt2TVUqyIqfb7pmnKsrxGYREhxLZtVktVHcqyLITQ9aO9I9ivUGev7A3xyiAQNKlDQIoISog03fwAHx8fHx8fH25c1y2VSrquO45jmiarb2IaCo7j3KgLLOvmeL04FivbZj9lugzXQAipVCrlcrl6rOd5pVKpUqmsIYpTLZta+xdhZZX10DCvDBUkkugRcVhyKKpkFamFevkgDZaEqUadwsfHx8fHx+dGUErL5TLGmGm0UEoNwyiXy/F4nGm9VD9W/e+qHhqmDVPVeqGUMlUYphNzja+FjWDbNhvfsqxrWimxAWvPRQjxPK86WvUDsN6mKI0xZSgWrK7dIpWRkMIVXQnEHKuigKxDmoAvgerj4+Pj47PhuK7reV61j0pVqs6yLE3TmJMjGAx6nlcul6uWRDgcrrUeLMvSdT0UCsmynMvlYrGY67rMo2NZliRJ14gyIIRkWbas/7+9+46vokobB36mz+01vRdIIBBCCyUEIfSugICoWFfUdde2++qWd1/fd/W3zS26i6u4umJZVwUVFVR6lY50SAghkJ7cXubeqef3x2g2IghoIAk+3w9/cOfOPXPm5pbnnjnneUSe5zHGsizrGTjbuxSNRtvz4+lH15PvBQIBkiTtdnssFtOHfPT8NAaD4XKjmc4JZWSbU6NIsqUWJblloZ7CNk1qZYh0lrAwKuMnz3TKUQAAAABwIYqikCTZcdSEIAiKohRF6Xi5Jx6PUxSlZ5fBGOvjIvpdelRhsVg6jqzoOYUpirpQkKHn+dXHWjDGDMPooQzGOBwOcxynRz/hcDgej+vBih5y6a2xLKuP6GiaFg6HGYa53Fx5nTNXBpMUpmhCjCKCQlgjEBZVD9YURJAU+jaloQAAAABwub4eahAEcc60FZIk9UoCehzT/pCOccx52+m48zl36dGMJEkdJ+qqqqon/9U0TU9P3D5a07E1giAkSRIEIRaL6XOWL/esO2dUhhIiWNVUdzatShTnQjJhNwxiFIOmRCTiIlN7AAAAAPDdnTPvRKfXhuu4RR8CEQRBL5aiF13RFzGxLEtR1LeYrcJxnD6T12w2t3egfcpw+27nTKNBX47coC/LM8my/C2KaHZOKEPHIqSnATuyEcWRrINU4iTBIE1hEB8jWjvlEAAAAAD4BgzDaJomy3J77KJPczEajR2jE5Ik9QpriqKEQiE9giEIwmw262uLTCbT5UYzDMPoJeFomm5fJ6VHRXp1p4476wNF+uRiff6vXmdKn6f8LU6801YwUcFWFA1qiBQxkjBhYXuH1NNm5OYw1JwDAAAArjg9RhEEQS8DqWmaIAgcx50zFhKPx/XrO+esSNKnAOtLqY1GY8c5N/o1Kb0A7TlxiY4gCL1O0zkxE8uy0WiU53mCINoreOuH1ivg6keRJEkfFtL3uVydFsoQCCFFRAhh/Z8m2qneBmxkNASzZQAAAICrgOd5kiTj8Xg8HldVVV80pIcXHUOTeDyuX8cxGAztAyr6HGGz2RyNRvVFT3rUoq+E0vPH6A22t9Nxykt7++0BSvtIj754iiRJ/dqWvsQpEonos4+NRmM8Htdz9LVn5NM7c4lnfaWy/Yak4yH9fwxCCKmq+i1LdwMAAADg0uiJd/Xcu7FYLBaLqaqqJ2sxGo36PjzPt+eYaX9Ue4Vqmqbb/99e0brjxo4oivr6doZh2jeSJNkx9Gnf2LE699f7gxBqP4tLcaVCmY6wpsUFgTcYrsKxAAAAAIAQ4nn+69Nsr0mdc5KelpZvmCKEMVYvf20VAAAAAL41fY10V/fiauicUMZstRIXrhqFMY4Eg51yIAC+nd27d3/wwQdWq3Xx4sXtI59HjhxZunQpSZIOh+PnP//59+Q9DwAA15jOCWV4g4H8xuk5MCoDulA0Gv3zn//805/+9Pjx40uWLHnsscf02WRtbW1ut/uRRx4hSfJ7MgwLAADXnitSGfvrLn0eMgCdrrKyMiMjY+DAgTfccMORI0fa8xaYTKazZ88+/vjjzz77rJ5fEmPcnnu7S7sMAADgUsEvUXCtaWtre+6551paWvSbBoNhwoQJegIofY1fe5hSXFz8xz/+UVGUJ5544vDhw4MGDdq7d++6des0TXv00UedTmeXncOlwRgHg0GbzfYtUnN2LVVVo9HoOUXsegRBECiKuvSFFd1Ez32p9NCe99Buox7bcwhlwLXG5XI98sgj7XmWCILw+/0rVqyIRCKtra0Wi0Uv4sowDE3Ten5Ju90eCoUQQoMHDx43btzs2bMVRWkaS+eaAAAgAElEQVRra+vS87g4RVGef/75e++9t8ddHfN4PKtWrVq0aFHP+rhECK1bt87tdpeUlHR1Ry6PpmnPPffcPffc07E+To8gy/ILL7xw33339ayhff29uXjx4h43A0+SpKVLl95///3khee/div6ou4e9gkIwEXpCSs7brFarXl5eY8//ng4HH7ggQc4jnv44Yd/+MMfVldXb9y4US8RUlpaqj+2tLT07bff7hFfsaqqbt68OR6P95QPnXaRSOTQoUMej6dHPM8dHT9+3Gw2b9iwoas7cnkwxhs3bhQEocdFvT30Ra5p2qZNm2KxWM+KwBBCiqJs2bJFFMWe8t689dZbEULEoLHTvksrmqq2NDQkpaV1mPZLpef3TqPDVX6Cj7U0hSSEkBCJMCwbCYXigvBdO3510ebE3m58orbt2+RS7n7SexUIdTW+uNzVHbkkzoSEeCyGELI5nQihkN+vadry117snZdzuU2JohgMBimKcjqdBEEEAgGTyaTXH0EIWa1WPa/21yuxdWeapu3atWvYsGE961MeISQIwokTJwYNGtTVHbls1dXVJpMpJSWlqztyeTDGO3fuLC0t7XHfrPqLfPjw4T3lm1XXc9+bqqru3r27Bz3hBEE8u/SVzo/QbWm95k4cQYYaGo5pY4zU69tqO/0QVww7YcFtw3PtLQdWL119VN9kTCu5+Trtf5euk766a175nKLQ+g8OBs7XDp3Xb/TcWcWMv/m1d1Y2xGxz51+f7+JDDUf++ea6cOfFRMOmzCcrP9pRE0UIDZo4z1L78eaq8Dc/ZPQNc0KbNstsgMwbcPrNt05Iaqf1pnvjOC4xMbH9pl4rhGEYw1czN+o5Ma925y5fNBp96aWX9u7d+8QTT3T8nf3JJ5+89dZbVqu1sLDwvvvu68IeXkhNTc1rr73W0NCwdOnSjtsPHz7873//W5blH/zgB/n5+d3trxCLxd56661Dhw4VFxfPnz+//fvp9ddf37Rpk8lkGj58+E033dS1nexIkqR33nln3759vXr1uv322w0GQ1lZmaqqK1as2LlzZ2pq6g9/+MOv51ftDgKBwAsvvNDa2lpRUTFlyhSapsvKynbv3v23v/3N4XBkZ2ffd9993bPn69atW7VqVUFBwb333kuSZFlZGUKopqZm2bJloijOmTNnyJAh3e2FjRCKxWIrVqxYv379vffeq8deZWVl4XD4qaeeEgSBIIjFixf37du3q7t5EZ0fyoiY4Iy2zIzURZmRQ8s/7/T2r6S8KaXkb/7n7zanEaGkOx+ZZ/HXfrxfQgg5Mgrm3DCFbtj17IqDM2+7pdDOGBN697Fkef70j8/OhJA5+0f3zOQiLe+89daZIDIkFtx+Y/+X//CXaN/ZD8ws/bCxV46w58mX9mX3LrBmlSy+cUzlxhU7Gh2TJg3OMQs7T5H9U8Xl/95Ycv0NRQnswXUffHwofMuP7jK3fr78w/2jpszOybVXrXtzzXF08z0L7f6qlZtPDBxd1jfVvObDNePGVeSNTfT9+q+VWsKYsWOLmRTvX5YXT56eEq3845ub9FPKHjrhlrH9Dqx/a8MpeuFts0cXud/ZhHhT4qgJU3mL+tRrK5uD8a58ysG3wjDM6NGjjx49Go1GO25vaWkpLy+fN29et72OYLVaKyoqnn322Y4bMcZLliyZN2+ew+H47W9/+9e//rU9w3o3sXv37oMHDz7++OO/+93vsrOzx4wZo29vaWmZPn36hAkTutsTvm/fvj179vzkJz/561//um3btgkTJiCEKisr165d+/Of//yNN9748MMP586d292+WTHGK1asYFn2gQceeOqppwoLC/Py8hBCXq+3b9++DzzwAE3T3XbOdU5OztixY7ds2dJx47PPPjt58uSkpKQ//vGPL730UjfsPEVRAwcOrKqq8nq97RsVRamvr3/mmWfOW1KgG+r8sa944/FnXnhzy7Gz21a89lGVp9Pbv5KObzrEL757QYaNG3Xz7f3ItuSi8vLiDITQjIV3WIl40cy586fcUKwe/MszS97bf3rze69/diaEEEKR5sMn61x9h4/vn48QcqUlm0NNpyOotbqGSC4Y0y/9yLFTCKHamsDs26Zve/nFkll3DOk3YJDLvzNYMIjdd1BIG1lSOLk09Y1P9oyaOO66hffbj75ZbRw4b0z/itH5763aP2bipPFzFg00+BJLK6YOGDKpD/Pq9rYZw9MOHj+18o3XKsMIRdsOnTi16s1XXaPmm6o37GOG3Dk6FSHEujN/tGB8rUebeeMNC+bNadu87JOjHos7q182d/zU0df+8S7EMT0Uy7IlJSVm87ll5x0Ox44dOx566KF//vOf367A7JXmdrsLCgrOmXzq9XolSRo2bNjAgQNlWQ4EzjvY2ZUOHDhQUVGRlJRUUVFx8ODB9u0ul+vjjz9+4IEHVq5c2a0uTR45cmTEiBHp6emTJ0/evXu3vvHAgQPDhw/Pzs6eM2fO1q1bu+ErRFXVffv2zZw5Mycnp1+/fsePH9e32+32ysrKBx988LnnnovHu+mnVl5eXnZ29jkbm5ubBw8e3KdPH5Ikz/nh0U2wLFtUVHTOgk2KotLS0p544okHH3zwxIkTXdW3S9f5vyTMqb3nDLAte+3V/KHTZw/b9+6upk4/xJXC2net/Pv+rJE/Hnfdljhz+uixNe/vRYkDcvshm5Gs2rrlvY1bsnJGR8OBc67K9Bo7t9xV//npNn2uacDjkyyFGSZayMokfGcqw5bszFR0MJCQkWFhRCEqxUSNJLXWFo8gCq0tLSgHIYT8Pq+syCTDmRkmGo0IQpymKMHT1hSLywpyWI01R/d9unI7z+Wl5EaFOKFp2tcDUZrDsbAUEeL6tHmOYUgt/Pm6Ffs+s46YfH08HnMyjHjln0jQuaqrq5csWdKeDic7O/vHP/7xecctJk6cOGHChEgk8otf/KK2tjY3N/fq9vRc69atW758efvNMWPGzJs37+u7qapKkmR7OdwujwmOHDnyt7/9rf1mcXFx+7RTkiRV9T8fAPPnz58/f34gEPjFL35RXl7efebQKIqiT4uhKKq9w6qq6htpmu6GcQz6MrGTPsTV8akePHjw3/72N1VVf/WrXx07dmzw4MFd2s3Lo1+27viH6P7MZvOvfvUriqLWrl37zjvvFBUVdXWPLqLzQxlJUW25Q//n8XJEqAdX7+309q8gwrbox4stmnxoy5odp06XPzTz1n6BjUebA5HY5m0751RcP8AQXPmnNfyDCx9Lr/206vSgKQtHnn75szOh5rp6x8RhxQo6IioIoUjdseWbey3+2WMJjLr0heePhk4tvnPWL/tMFJqr122qu/nxh701O043MVlGURRDEVGLR8OCpDhyhzx6h61m/adbj6iP/uiRrHDTB/+qnZiTjxUpEPbv2VB959033lrSsmNTbSAcUyUiEBVrop77b7y5smZJZRjVNLT8ZM4tb67YlzP1xgFK6C9/b0QIRb2N6yojixbMbfNXb998ZNbtD1tYZU0sGgyGa4XQ3Dtnn30DLjD1ADk5Ob/+9a/bb5IkyfO8LMuqqiqKon8/+Xw+m82mfw3oSXSUbpBie/To0cOHD2+/qUfYiqJomiZJEk3TqqoKguB0OlVVbWhocLvdsix3+dWlwsLCp59+uv0mRVGrV6+uqqoaP358VVVVVlYWxtjv99vtdk3TWJZlWVbPrNiFfT5HRkbG0aNH4/H4iRMncnJywuEwwzCZmZnr16+PxWIHDx7Mz8/vhjNSaZrWe56QkFBfXz9ixAi/32+1WlVVpWlaTw0ly9101YKqqrIsa5omyzLGOBaL2Ww2o9HY1tamKIooil8vEN0dYIxVVdU/TBRF0U+B4zg9/OI4TpKki7fS1a7ECibEGV3XjR3uObptf+0XpZd67gqmb41iUv77dw+37lj95vub/Bd769FsxhO/mP7H3/zdD3FFB524gukaE41Gn3766ZUrV+bn5y9atGj69Om33XbbH/7wh5UrVx4+fFgUxYKCggcffLAbLlc5efLkn//8540bN5aXlz/22GOxWOzVV1/9/e9/v2LFio8++khRlAULFkydOrW7zeFoa2t78sknZVlmGOaXv/yl2Wy+5557lixZsnTp0rq6umg0Wl5efuutt3af4CAYDD755JOhUEjTtN/85jfLli0rKSkZNWrUE0884fF4RFF8+umnO06E7z5OnTr1v//7vyzL5uTkPPTQQw8++OBvfvObjRs3bt26VVXV9PT0H//4x1+/tNodrFq16pVXXqmpqZkxY8aUKVNWrFjx+9//ft26dW+88QZFUaNGjVq0aFH3eYW0i8fjL7744ttvv221WufMmWO3230+38SJE5csWSKKYiQSue+++7r5MNgzL/yz80MZc0L+1MG29z/Z1zGQ+x6GMgghmmFJpMmycgnD5QRNk4rSjX7VdQcQylwIxlgURf1CDE3TDMOIosiyrP67Si+H2w3jGISQqqrtP/LaR4/0UQ19u/5zsEv7eB4YY/251dMqIoQkSWJZVh8bI0mSYZju9i2l/8LWO6woCkmSFEXpGymKYhimGz7PCCGMsf6ssixLkqT+POsDHt35hY0QkmVZHwrV+6mfAsZYkiSMsX46Xd3H89B7qF9wpCiq/UKqPjzTnV8q7Z554Z9XYta94u414v6MfipCn298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\n", + "image/png": "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8jVdbX53/4m+2mVLUucO7D8dX7J29eIGdt87+zfedvcae2/4F2+uvOxyECM7dx2aatEZvP2m1UoyPNyr5fvUeDQkil7wNt5x262jve/uOileuXGJJ5MYTXOL2wKDJw8cG5GXLOqq9XGJ4VP7ToY7Vi5JnDqS4hrvec97lYPpswASlqOjYd4ZXHt5c8AfGD154MCFyJWbbm518nt272UaV6xeHDi7f9fRoYSjtuWKNr8nEDh5rn/18p6zB7ceGZaWr97QU6vu3n7A3r7sys66wRP7jozg7o7W1o6G4SO7Dg4IK9es7+LsbicDFNN9xdoVrY53t+5O1S5a2uSK9h9L+ZZf3uY9tuftsxHyZY4w30AImR+LDQCSJEUSwrI1G0rbuVQXRZFVFSMENM1UauZKWhTOv7une5FZ8ggh5PP5iJQhVJsC+9GpGNtpRFNIVlSMcd94ZlFNgdDo2rsf/8JNzDe/+3vccPn/+OMPPPfjH6954IstdU9vvOWWn7/w1uf//JMv/vs/Lt646Xtf2W8818Zx7YMfW52OPfON71z1wKNLR949wAc+/NANx3BPZM8LY/Y1DyzpfTs6Hs2EXJfd/v61/gGe/VCDbYsE7544t/byRb3BzszQIaxQV97y3ls7JJ5b51fDfxjFHnfje99/14tvpD58b8N334g/ct/GX/Y23xiIvDHsDNptHRvvvm21exTVPeKAkSW31p585ZhYdPKD69z06LXNv9ox+tDD9z3f/5tbb2vZ09uyhD3/6pFkE9BLr7phkX3g+bOZx+9ZumNnLB6lY/zFL160reNzT979kxfeffyPNrz06y33ve9+6o2+m9c19/KeD98HB2PjEWoslcqAg1265laWn4gfIfaOhx+rG/59uPWGDyw++ooEANw1t9109IX9S3pa33717Pq77uHj+z7+oRu+/89Pp8Dpcrsfft+DP3p574cevOaZH71x4z23DiTffvCGVd86fkRO87HxpDAakjsBnME77lj2o2f7P/eRDT/41bGH7rspcwjdswLCsKInSKdbr+3b9esoLwGAp2v14/c0vbR9/C+eXPnt348+fM9m8YDz4atrB2X/B93Sf78re9wN73nf3ZkXT3ziYzc8/dOD9z14U+bN1IPr2F/u56/1OmqWXHv3jT2nxu0fuZ9+C666Du94Ga27d33XwAh+9P23PXuIPn/meLH/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6C9/b0QIRb2N6yojixbMbfNXb998ZNbtD1tYZU0sGgyGa4XQ3Dtnn30DLjD1ADk5Ob/+9a/bb5IkyfO8LMuqqiqKon8/+Xw+m82mfw3oSXSUbpBie/To0cOHD2+/qUfYiqJomiZJEk3TqqoKguB0OlVVbWhocLvdsix3+dWlwsLCp59+uv0mRVGrV6+uqqoaP358VVVVVlYWxtjv99vtdk3TWJZlWVbPrNiFfT5HRkbG0aNH4/H4iRMncnJywuEwwzCZmZnr16+PxWIHDx7Mz8/vhjNSaZrWe56QkFBfXz9ixAi/32+1WlVVpWlaTw0ly9101YKqqrIsa5omyzLGOBaL2Ww2o9HY1tamKIooil8vEN0dYIxVVdU/TBRF0U+B4zg9/OI4TpKki7fS1a7ECibEGV3XjR3uObptf+0XpZd67gqmb41iUv77dw+37lj95vub/Bd769FsxhO/mP7H3/zdD3FFB524gukaE41Gn3766ZUrV+bn5y9atGj69Om33XbbH/7wh5UrVx4+fFgUxYKCggcffLAbLlc5efLkn//8540bN5aXlz/22GOxWOzVV1/9/e9/v2LFio8++khRlAULFkydOrW7zeFoa2t78sknZVlmGOaXv/yl2Wy+5557lixZsnTp0rq6umg0Wl5efuutt3af4CAYDD755JOhUEjTtN/85jfLli0rKSkZNWrUE0884fF4RFF8+umnO06E7z5OnTr1v//7vyzL5uTkPPTQQw8++OBvfvObjRs3bt26VVXV9PT0H//4x1+/tNodrFq16pVXXqmpqZkxY8aUKVNWrFjx+9//ft26dW+88QZFUaNGjVq0aFH3eYW0i8fjL7744ttvv221WufMmWO3230+38SJE5csWSKKYiQSue+++7r5MNgzL/yz80MZc0L+1MG29z/Z1zGQ+x6GMgghmmFJpMmycgnD5QRNk4rSjX7VdQcQylwIxlgURf1CDE3TDMOIosiyrP67Si+H2w3jGISQqqrtP/LaR4/0UQ19u/5zsEv7eB4YY/251dMqIoQkSWJZVh8bI0mSYZju9i2l/8LWO6woCkmSFEXpGymKYhimGz7PCCGMsf6ssixLkqT+POsDHt35hY0QkmVZHwrV+6mfAsZYkiSMsX46Xd3H89B7qF9wpCiq/UKqPjzTnV8q7Z554Z9XYta94u414v6MfipCn298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", "text/plain": [ "" ] @@ -555,7 +555,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3.10.5 ('pob_pyside6')", "language": "python", "name": "python3" }, @@ -569,7 +569,12 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.8" + "version": "3.10.5" + }, + "vscode": { + "interpreter": { + "hash": "dfaca1dc5e36f3627306c0cd7529793f0c893d996af719425010aac17208ef7e" + } } }, "nbformat": 4, diff --git a/environment.yml b/environment.yml index 7bf016421..5299598a1 100644 --- a/environment.yml +++ b/environment.yml @@ -14,7 +14,6 @@ dependencies: - pint - pyepr-quantum>=0.8.5.7 - pygments - - pyside2 - qutip - scipy - shapely @@ -24,3 +23,4 @@ dependencies: - pip: - pyaedt - gmsh + - pyside6 diff --git a/qiskit_metal/__init__.py b/qiskit_metal/__init__.py index 3c65065f7..9fae06beb 100644 --- a/qiskit_metal/__init__.py +++ b/qiskit_metal/__init__.py @@ -55,10 +55,10 @@ def __setup_Qt_backend(): # pylint: disable=invalid-name # When in vscode and in debug-mode, may want to comment # next line out, "os.environ["QT_API"] = "pyside2"" - os.environ["QT_API"] = "pyside2" + os.environ["QT_API"] = "pyside6" - from PySide2 import QtCore #, QtWidgets - from PySide2.QtCore import Qt + from PySide6 import QtCore #, QtWidgets + from PySide6.QtCore import Qt def set_attribute(name: str, value=True): """Describes attributes that change the behavior of application-wide diff --git a/qiskit_metal/_gui/__compile_ui_to_py.bat b/qiskit_metal/_gui/__compile_ui_to_py.bat index bcf941648..4b427864e 100644 --- a/qiskit_metal/_gui/__compile_ui_to_py.bat +++ b/qiskit_metal/_gui/__compile_ui_to_py.bat @@ -6,12 +6,12 @@ cd /d "%~dp0" echo "The current directory is %CD%" -call pyside2-uic -o main_window_ui.py --from-imports main_window_ui.ui -call pyside2-uic -o component_widget_ui.py --from-imports component_widget_ui.ui -call pyside2-uic -o plot_window_ui.py --from-imports plot_window_ui.ui -call pyside2-uic -o elements_ui.py --from-imports elements_ui.ui +call pyside6-uic -o main_window_ui.py --from-imports main_window_ui.ui +call pyside6-uic -o component_widget_ui.py --from-imports component_widget_ui.ui +call pyside6-uic -o plot_window_ui.py --from-imports plot_window_ui.ui +call pyside6-uic -o elements_ui.py --from-imports elements_ui.ui -call pyside2-rcc -o main_window_rc_rc.py main_window_rc.qrc +call pyside6-rcc -o main_window_rc_rc.py main_window_rc.qrc rem ############################################################################ rem # Zlatko: diff --git a/qiskit_metal/_gui/__compile_ui_to_py.shell b/qiskit_metal/_gui/__compile_ui_to_py.shell index 91a25f0c1..cf0e7e8fa 100755 --- a/qiskit_metal/_gui/__compile_ui_to_py.shell +++ b/qiskit_metal/_gui/__compile_ui_to_py.shell @@ -7,9 +7,9 @@ cd "$(dirname "$0")" echo -e "Present working directory: ${RED}${PWD}${NC}" # Define conversion -ui_to_py=pyside2-uic -rc_to_py=pyside2-rcc -# pyside2-uic +ui_to_py=pyside6-uic +rc_to_py=pyside6-rcc +# pyside6-uic # -o : The Python code generated is written to the file . # -i : Resource modules are imported using # from import ... rather than a simple import .... diff --git a/qiskit_metal/_gui/component_widget_ui.py b/qiskit_metal/_gui/component_widget_ui.py index 5674e67a5..3ac8b4dd6 100644 --- a/qiskit_metal/_gui/component_widget_ui.py +++ b/qiskit_metal/_gui/component_widget_ui.py @@ -4,11 +4,11 @@ # licensing of './component_widget_ui.ui' applies. # # Created: Sat Jun 19 22:02:29 2021 -# by: pyside2-uic running on PySide2 5.13.2 +# by: pyside6-uic running on PySide2 5.13.2 # # WARNING! All changes made in this file will be lost! -from PySide2 import QtCore, QtGui, QtWidgets +from PySide6 import QtCore, QtGui, QtWidgets class Ui_ComponentWidget(object): diff --git a/qiskit_metal/_gui/elements_ui.py b/qiskit_metal/_gui/elements_ui.py index 4b03c135f..44324288d 100644 --- a/qiskit_metal/_gui/elements_ui.py +++ b/qiskit_metal/_gui/elements_ui.py @@ -4,11 +4,11 @@ # licensing of './elements_ui.ui' applies. # # Created: Thu Jun 30 16:30:20 2022 -# by: pyside2-uic running on PySide2 5.13.2 +# by: pyside6-uic running on PySide2 5.13.2 # # WARNING! All changes made in this file will be lost! -from PySide2 import QtCore, QtGui, QtWidgets +from PySide6 import QtCore, QtGui, QtWidgets class Ui_ElementsWindow(object): @@ -50,7 +50,7 @@ def setupUi(self, ElementsWindow): self.label.sizePolicy().hasHeightForWidth()) self.label.setSizePolicy(sizePolicy) font = QtGui.QFont() - font.setWeight(75) + font.setLegacyWeight(75) font.setBold(True) self.label.setFont(font) self.label.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | @@ -77,7 +77,7 @@ def setupUi(self, ElementsWindow): self.horizontalLayout.addWidget(self.line) self.label_3 = QtWidgets.QLabel(self.centralwidget) font = QtGui.QFont() - font.setWeight(75) + font.setLegacyWeight(75) font.setBold(True) self.label_3.setFont(font) self.label_3.setObjectName("label_3") diff --git a/qiskit_metal/_gui/elements_window.py b/qiskit_metal/_gui/elements_window.py index 738429e85..4c93bf21e 100644 --- a/qiskit_metal/_gui/elements_window.py +++ b/qiskit_metal/_gui/elements_window.py @@ -16,9 +16,9 @@ from typing import TYPE_CHECKING import numpy as np -from PySide2 import QtCore, QtWidgets -from PySide2.QtCore import QAbstractTableModel, QModelIndex -from PySide2.QtWidgets import QMainWindow +from PySide6 import QtCore, QtWidgets +from PySide6.QtCore import QAbstractTableModel, QModelIndex +from PySide6.QtWidgets import QMainWindow from .elements_ui import Ui_ElementsWindow @@ -33,7 +33,7 @@ class ElementsWindow(QMainWindow): Extends the `QMainWindow` class. - PySide2 Signal / Slots Extensions: + PySide6 Signal / Slots Extensions: The UI can call up to this class to execeute button clicks for instance Extensiosn in qt designer on signals/slots are linked to this class """ diff --git a/qiskit_metal/_gui/endcap_hfss_gui.py b/qiskit_metal/_gui/endcap_hfss_gui.py index 2f8a9fdb5..151620aa6 100644 --- a/qiskit_metal/_gui/endcap_hfss_gui.py +++ b/qiskit_metal/_gui/endcap_hfss_gui.py @@ -14,7 +14,7 @@ from typing import Tuple -from PySide2.QtWidgets import (QComboBox, QTableWidgetItem, QAbstractItemView, +from PySide6.QtWidgets import (QComboBox, QTableWidgetItem, QAbstractItemView, QMainWindow, QLineEdit) from .endcap_hfss_ui import Ui_mainWindow diff --git a/qiskit_metal/_gui/endcap_hfss_ui.py b/qiskit_metal/_gui/endcap_hfss_ui.py index 24fa2a023..7b6139210 100644 --- a/qiskit_metal/_gui/endcap_hfss_ui.py +++ b/qiskit_metal/_gui/endcap_hfss_ui.py @@ -4,11 +4,11 @@ # licensing of './endcap_hfss_ui.ui' applies. # # Created: Sat Jun 19 22:02:30 2021 -# by: pyside2-uic running on PySide2 5.13.2 +# by: pyside6-uic running on PySide2 5.13.2 # # WARNING! All changes made in this file will be lost! -from PySide2 import QtCore, QtGui, QtWidgets +from PySide6 import QtCore, QtGui, QtWidgets class Ui_mainWindow(object): diff --git a/qiskit_metal/_gui/endcap_q3d_gui.py b/qiskit_metal/_gui/endcap_q3d_gui.py index 25bcaa49c..1ac997501 100644 --- a/qiskit_metal/_gui/endcap_q3d_gui.py +++ b/qiskit_metal/_gui/endcap_q3d_gui.py @@ -14,7 +14,7 @@ from typing import Tuple -from PySide2.QtWidgets import (QComboBox, QTableWidgetItem, QAbstractItemView, +from PySide6.QtWidgets import (QComboBox, QTableWidgetItem, QAbstractItemView, QMainWindow) from .endcap_q3d_ui import Ui_mainWindow diff --git a/qiskit_metal/_gui/endcap_q3d_ui.py b/qiskit_metal/_gui/endcap_q3d_ui.py index c5cc0127a..ce796040a 100644 --- a/qiskit_metal/_gui/endcap_q3d_ui.py +++ b/qiskit_metal/_gui/endcap_q3d_ui.py @@ -4,11 +4,11 @@ # licensing of './endcap_q3d_ui.ui' applies. # # Created: Sat Jun 19 22:02:29 2021 -# by: pyside2-uic running on PySide2 5.13.2 +# by: pyside6-uic running on PySide2 5.13.2 # # WARNING! All changes made in this file will be lost! -from PySide2 import QtCore, QtGui, QtWidgets +from PySide6 import QtCore, QtGui, QtWidgets class Ui_mainWindow(object): diff --git a/qiskit_metal/_gui/list_model_base.py b/qiskit_metal/_gui/list_model_base.py index 0ac492d94..1efed9b67 100644 --- a/qiskit_metal/_gui/list_model_base.py +++ b/qiskit_metal/_gui/list_model_base.py @@ -12,9 +12,9 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. -from PySide2 import QtCore -from PySide2.QtCore import Qt -from PySide2.QtGui import QStandardItem, QStandardItemModel +from PySide6 import QtCore +from PySide6.QtCore import Qt +from PySide6.QtGui import QStandardItem, QStandardItemModel class DynamicList(QStandardItemModel): diff --git a/qiskit_metal/_gui/main_window.py b/qiskit_metal/_gui/main_window.py index f68c9a225..ca184297b 100644 --- a/qiskit_metal/_gui/main_window.py +++ b/qiskit_metal/_gui/main_window.py @@ -16,15 +16,16 @@ import logging import os +from time import sleep import webbrowser from pathlib import Path from typing import TYPE_CHECKING, List -from PySide2.QtCore import Qt, QTimer -from PySide2.QtGui import QIcon, QPixmap -from PySide2.QtWidgets import (QAction, QDialog, QDockWidget, QFileDialog, +from PySide6.QtCore import Qt, QTimer +from PySide6.QtGui import QIcon, QPixmap, QAction +from PySide6.QtWidgets import (QDialog, QDockWidget, QFileDialog, QLabel, QMainWindow, QMessageBox, QVBoxLayout) -from PySide2.QtCore import QSortFilterProxyModel +from PySide6.QtCore import QSortFilterProxyModel from qiskit_metal._gui.widgets.qlibrary_display.delegate_qlibrary import \ LibraryDelegate from qiskit_metal._gui.widgets.qlibrary_display.file_model_qlibrary import \ @@ -323,13 +324,19 @@ def __init__(self, design: QDesign = None): self._setup_plot_widget() self._setup_design_components_widget() self._setup_elements_widget() + self.main_window.show() self._setup_variables_widget() self._ui_adjustments_final() + print('Sleeping') + sleep(10) self._setup_library_widget() self._setup_net_list_widget() + sleep(10) + # Show and raise self.main_window.show() + # self.qApp.processEvents(QEventLoop.AllEvents, 1) # - don't think I need this here, it doesn't help to show and raise # - need to call from different thread. diff --git a/qiskit_metal/_gui/main_window_base.py b/qiskit_metal/_gui/main_window_base.py index 349185e3d..d0c4a13c7 100644 --- a/qiskit_metal/_gui/main_window_base.py +++ b/qiskit_metal/_gui/main_window_base.py @@ -20,10 +20,10 @@ from copy import deepcopy from pathlib import Path -from PySide2 import QtCore, QtGui, QtWidgets -from PySide2.QtCore import QTimer -from PySide2.QtGui import QIcon -from PySide2.QtWidgets import QApplication, QFileDialog, QMainWindow, QMessageBox, QDockWidget +from PySide6 import QtCore, QtGui, QtWidgets +from PySide6.QtCore import QTimer +from PySide6.QtGui import QIcon +from PySide6.QtWidgets import QApplication, QFileDialog, QMainWindow, QMessageBox, QDockWidget from .. import Dict, config from ..toolbox_python._logging import setup_logger diff --git a/qiskit_metal/_gui/main_window_rc_rc.py b/qiskit_metal/_gui/main_window_rc_rc.py index 85c5181ba..3aafecb35 100644 --- a/qiskit_metal/_gui/main_window_rc_rc.py +++ b/qiskit_metal/_gui/main_window_rc_rc.py @@ -3,11 +3,11 @@ # Resource object code # # Created: Thu Jun 30 16:30:21 2022 -# by: The Resource Compiler for PySide2 (Qt v5.12.9) +# by: The Resource Compiler for PySide6 (Qt v5.12.9) # # WARNING! All changes made in this file will be lost! -from PySide2 import QtCore +from PySide6 import QtCore qt_resource_data = b"\ \x00\x00e\xee\ diff --git a/qiskit_metal/_gui/main_window_ui.py b/qiskit_metal/_gui/main_window_ui.py index 39e659553..903c037df 100644 --- a/qiskit_metal/_gui/main_window_ui.py +++ b/qiskit_metal/_gui/main_window_ui.py @@ -4,11 +4,11 @@ # licensing of './main_window_ui.ui' applies. # # Created: Thu Jun 30 16:30:19 2022 -# by: pyside2-uic running on PySide2 5.13.2 +# by: pyside6-uic running on PySide6 5.13.2 # # WARNING! All changes made in this file will be lost! -from PySide2 import QtCore, QtGui, QtWidgets +from PySide6 import QtCore, QtGui, QtWidgets class Ui_MainWindow(object): @@ -109,7 +109,7 @@ def setupUi(self, MainWindow): MainWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.toolBarDesign) self.toolBarView = QtWidgets.QToolBar(MainWindow) font = QtGui.QFont() - font.setWeight(75) + font.setLegacyWeight(75) font.setBold(True) self.toolBarView.setFont(font) self.toolBarView.setToolButtonStyle(QtCore.Qt.ToolButtonIconOnly) @@ -121,7 +121,7 @@ def setupUi(self, MainWindow): QtGui.QIcon.On) self.dockDesign.setWindowIcon(icon5) self.dockDesign.setFloating(False) - self.dockDesign.setFeatures(QtWidgets.QDockWidget.AllDockWidgetFeatures) + # self.dockDesign.setFeatures(QtWidgets.QDockWidget.DockWidgetFeatures) self.dockDesign.setObjectName("dockDesign") self.dockWidgetContents = QtWidgets.QWidget() self.dockWidgetContents.setObjectName("dockWidgetContents") @@ -185,8 +185,8 @@ def setupUi(self, MainWindow): icon8.addPixmap(QtGui.QPixmap(":/component"), QtGui.QIcon.Normal, QtGui.QIcon.On) self.dockLibrary.setWindowIcon(icon8) - self.dockLibrary.setFeatures( - QtWidgets.QDockWidget.AllDockWidgetFeatures) + # self.dockLibrary.setFeatures( + # QtWidgets.QDockWidget.AllDockWidgetFeatures) self.dockLibrary.setObjectName("dockLibrary") self.dockLibraryContents = QtWidgets.QWidget() self.dockLibraryContents.setObjectName("dockLibraryContents") @@ -204,8 +204,8 @@ def setupUi(self, MainWindow): MainWindow.addDockWidget(QtCore.Qt.DockWidgetArea(1), self.dockLibrary) self.dockComponent = QtWidgets.QDockWidget(MainWindow) self.dockComponent.setMinimumSize(QtCore.QSize(62, 38)) - self.dockComponent.setFeatures( - QtWidgets.QDockWidget.AllDockWidgetFeatures) + # self.dockComponent.setFeatures( + # QtWidgets.QDockWidget.AllDockWidgetFeatures) self.dockComponent.setObjectName("dockComponent") self.dockComponentCental = QtWidgets.QWidget() self.dockComponentCental.setObjectName("dockComponentCental") @@ -222,7 +222,7 @@ def setupUi(self, MainWindow): icon9.addPixmap(QtGui.QPixmap(":/log"), QtGui.QIcon.Normal, QtGui.QIcon.On) self.dockLog.setWindowIcon(icon9) - self.dockLog.setFeatures(QtWidgets.QDockWidget.AllDockWidgetFeatures) + # self.dockLog.setFeatures(QtWidgets.QDockWidget.AllDockWidgetFeatures) self.dockLog.setObjectName("dockLog") self.dockWidgetContents_4 = QtWidgets.QWidget() sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, @@ -300,20 +300,20 @@ def setupUi(self, MainWindow): self.toolbar_renderers.setIconSize(QtCore.QSize(32, 32)) self.toolbar_renderers.setObjectName("toolbar_renderers") MainWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.toolbar_renderers) - self.actionSave = QtWidgets.QAction(MainWindow) + self.actionSave = QtGui.QAction(MainWindow) icon11 = QtGui.QIcon() icon11.addPixmap(QtGui.QPixmap(":/save"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.actionSave.setIcon(icon11) self.actionSave.setObjectName("actionSave") - self.actionLoad = QtWidgets.QAction(MainWindow) + self.actionLoad = QtGui.QAction(MainWindow) icon12 = QtGui.QIcon() icon12.addPixmap(QtGui.QPixmap(":/load"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.actionLoad.setIcon(icon12) self.actionLoad.setAutoRepeat(False) self.actionLoad.setObjectName("actionLoad") - self.actionDesign = QtWidgets.QAction(MainWindow) + self.actionDesign = QtGui.QAction(MainWindow) self.actionDesign.setCheckable(True) self.actionDesign.setChecked(True) icon13 = QtGui.QIcon() @@ -321,12 +321,12 @@ def setupUi(self, MainWindow): QtGui.QIcon.Off) self.actionDesign.setIcon(icon13) self.actionDesign.setObjectName("actionDesign") - self.actionElements = QtWidgets.QAction(MainWindow) + self.actionElements = QtGui.QAction(MainWindow) self.actionElements.setCheckable(True) self.actionElements.setChecked(False) self.actionElements.setIcon(icon2) self.actionElements.setObjectName("actionElements") - self.actionLog = QtWidgets.QAction(MainWindow) + self.actionLog = QtGui.QAction(MainWindow) self.actionLog.setCheckable(True) self.actionLog.setChecked(True) icon14 = QtGui.QIcon() @@ -334,7 +334,7 @@ def setupUi(self, MainWindow): QtGui.QIcon.Off) self.actionLog.setIcon(icon14) self.actionLog.setObjectName("actionLog") - self.actionNewComponent = QtWidgets.QAction(MainWindow) + self.actionNewComponent = QtGui.QAction(MainWindow) self.actionNewComponent.setCheckable(True) self.actionNewComponent.setChecked(False) icon15 = QtGui.QIcon() @@ -342,26 +342,26 @@ def setupUi(self, MainWindow): QtGui.QIcon.Normal, QtGui.QIcon.Off) self.actionNewComponent.setIcon(icon15) self.actionNewComponent.setObjectName("actionNewComponent") - self.actionDelete_All = QtWidgets.QAction(MainWindow) + self.actionDelete_All = QtGui.QAction(MainWindow) icon16 = QtGui.QIcon() icon16.addPixmap(QtGui.QPixmap(":/delete_all"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.actionDelete_All.setIcon(icon16) - self.actionDelete_All.setPriority(QtWidgets.QAction.LowPriority) + self.actionDelete_All.setPriority(QtGui.QAction.LowPriority) self.actionDelete_All.setObjectName("actionDelete_All") - self.actionZoom = QtWidgets.QAction(MainWindow) + self.actionZoom = QtGui.QAction(MainWindow) icon17 = QtGui.QIcon() icon17.addPixmap(QtGui.QPixmap(":/plot/zoom"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.actionZoom.setIcon(icon17) self.actionZoom.setObjectName("actionZoom") - self.actionPan = QtWidgets.QAction(MainWindow) + self.actionPan = QtGui.QAction(MainWindow) icon18 = QtGui.QIcon() icon18.addPixmap(QtGui.QPixmap(":/plot/pan"), QtGui.QIcon.Normal, QtGui.QIcon.On) self.actionPan.setIcon(icon18) self.actionPan.setObjectName("actionPan") - self.actionConnectors = QtWidgets.QAction(MainWindow) + self.actionConnectors = QtGui.QAction(MainWindow) self.actionConnectors.setCheckable(True) self.actionConnectors.setChecked(False) icon19 = QtGui.QIcon() @@ -369,19 +369,19 @@ def setupUi(self, MainWindow): QtGui.QIcon.Off) self.actionConnectors.setIcon(icon19) self.actionConnectors.setObjectName("actionConnectors") - self.actionStyleOpen = QtWidgets.QAction(MainWindow) + self.actionStyleOpen = QtGui.QAction(MainWindow) self.actionStyleOpen.setObjectName("actionStyleOpen") - self.actionStyleDefault = QtWidgets.QAction(MainWindow) + self.actionStyleDefault = QtGui.QAction(MainWindow) self.actionStyleDefault.setObjectName("actionStyleDefault") - self.actionStyleDark = QtWidgets.QAction(MainWindow) + self.actionStyleDark = QtGui.QAction(MainWindow) self.actionStyleDark.setObjectName("actionStyleDark") - self.actionScreenshot = QtWidgets.QAction(MainWindow) + self.actionScreenshot = QtGui.QAction(MainWindow) icon20 = QtGui.QIcon() icon20.addPixmap(QtGui.QPixmap(":/screenshot"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.actionScreenshot.setIcon(icon20) self.actionScreenshot.setObjectName("actionScreenshot") - self.action_full_refresh = QtWidgets.QAction(MainWindow) + self.action_full_refresh = QtGui.QAction(MainWindow) icon21 = QtGui.QIcon() icon21.addPixmap(QtGui.QPixmap(":/force_refresh"), QtGui.QIcon.Normal, QtGui.QIcon.Off) @@ -389,42 +389,42 @@ def setupUi(self, MainWindow): self.action_full_refresh.setShortcutContext( QtCore.Qt.WidgetWithChildrenShortcut) self.action_full_refresh.setAutoRepeat(False) - self.action_full_refresh.setPriority(QtWidgets.QAction.HighPriority) + self.action_full_refresh.setPriority(QtGui.QAction.HighPriority) self.action_full_refresh.setObjectName("action_full_refresh") - self.actionRebuild = QtWidgets.QAction(MainWindow) + self.actionRebuild = QtGui.QAction(MainWindow) icon22 = QtGui.QIcon() icon22.addPixmap(QtGui.QPixmap(":/rebuild"), QtGui.QIcon.Normal, QtGui.QIcon.Off) icon22.addPixmap(QtGui.QPixmap(":/rebuild"), QtGui.QIcon.Active, QtGui.QIcon.On) self.actionRebuild.setIcon(icon22) - self.actionRebuild.setPriority(QtWidgets.QAction.HighPriority) + self.actionRebuild.setPriority(QtGui.QAction.HighPriority) self.actionRebuild.setObjectName("actionRebuild") - self.actionFull_Screen = QtWidgets.QAction(MainWindow) + self.actionFull_Screen = QtGui.QAction(MainWindow) icon23 = QtGui.QIcon() icon23.addPixmap(QtGui.QPixmap(":/plot/----autozoom"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.actionFull_Screen.setIcon(icon23) self.actionFull_Screen.setObjectName("actionFull_Screen") - self.actionMetal_Dark = QtWidgets.QAction(MainWindow) + self.actionMetal_Dark = QtGui.QAction(MainWindow) self.actionMetal_Dark.setObjectName("actionMetal_Dark") - self.actionSaveAs = QtWidgets.QAction(MainWindow) + self.actionSaveAs = QtGui.QAction(MainWindow) self.actionSaveAs.setIcon(icon11) self.actionSaveAs.setObjectName("actionSaveAs") - self.actionSave_window_state = QtWidgets.QAction(MainWindow) + self.actionSave_window_state = QtGui.QAction(MainWindow) self.actionSave_window_state.setIcon(icon11) self.actionSave_window_state.setObjectName("actionSave_window_state") - self.actionLabelDesign = QtWidgets.QAction(MainWindow) + self.actionLabelDesign = QtGui.QAction(MainWindow) self.actionLabelDesign.setEnabled(False) self.actionLabelDesign.setObjectName("actionLabelDesign") - self.actionClose_window = QtWidgets.QAction(MainWindow) + self.actionClose_window = QtGui.QAction(MainWindow) self.actionClose_window.setObjectName("actionClose_window") - self.actionMetal_Window = QtWidgets.QAction(MainWindow) + self.actionMetal_Window = QtGui.QAction(MainWindow) self.actionMetal_Window.setEnabled(False) self.actionMetal_Window.setObjectName("actionMetal_Window") - self.actionViewDummyLabel = QtWidgets.QAction(MainWindow) + self.actionViewDummyLabel = QtGui.QAction(MainWindow) self.actionViewDummyLabel.setObjectName("actionViewDummyLabel") - self.actionVariables = QtWidgets.QAction(MainWindow) + self.actionVariables = QtGui.QAction(MainWindow) self.actionVariables.setCheckable(True) self.actionVariables.setChecked(False) icon24 = QtGui.QIcon() @@ -432,34 +432,34 @@ def setupUi(self, MainWindow): QtGui.QIcon.Off) self.actionVariables.setIcon(icon24) self.actionVariables.setObjectName("actionVariables") - self.actionToggleDocks = QtWidgets.QAction(MainWindow) + self.actionToggleDocks = QtGui.QAction(MainWindow) self.actionToggleDocks.setIcon(icon6) self.actionToggleDocks.setObjectName("actionToggleDocks") - self.actionGDS = QtWidgets.QAction(MainWindow) + self.actionGDS = QtGui.QAction(MainWindow) icon25 = QtGui.QIcon() icon25.addPixmap(QtGui.QPixmap(":/renderer/_imgs/renderers/GDS.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.actionGDS.setIcon(icon25) self.actionGDS.setObjectName("actionGDS") - self.actionHFSS = QtWidgets.QAction(MainWindow) + self.actionHFSS = QtGui.QAction(MainWindow) icon26 = QtGui.QIcon() icon26.addPixmap(QtGui.QPixmap(":/renderer/_imgs/renderers/HFSS.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.actionHFSS.setIcon(icon26) self.actionHFSS.setObjectName("actionHFSS") - self.actionQ3D = QtWidgets.QAction(MainWindow) + self.actionQ3D = QtGui.QAction(MainWindow) icon27 = QtGui.QIcon() icon27.addPixmap(QtGui.QPixmap(":/renderer/_imgs/renderers/Q3D.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.actionQ3D.setIcon(icon27) self.actionQ3D.setObjectName("actionQ3D") - self.actionBuildHistory = QtWidgets.QAction(MainWindow) + self.actionBuildHistory = QtGui.QAction(MainWindow) icon28 = QtGui.QIcon() icon28.addPixmap(QtGui.QPixmap(":/build_history"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.actionBuildHistory.setIcon(icon28) self.actionBuildHistory.setObjectName("actionBuildHistory") - self.actionDeveloperMode = QtWidgets.QAction(MainWindow) + self.actionDeveloperMode = QtGui.QAction(MainWindow) self.actionDeveloperMode.setCheckable(True) icon29 = QtGui.QIcon() icon29.addPixmap(QtGui.QPixmap(":/_imgs/lightbulb.png"), @@ -468,7 +468,7 @@ def setupUi(self, MainWindow): QtGui.QIcon.Normal, QtGui.QIcon.On) self.actionDeveloperMode.setIcon(icon29) self.actionDeveloperMode.setObjectName("actionDeveloperMode") - self.actionWebHelp = QtWidgets.QAction(MainWindow) + self.actionWebHelp = QtGui.QAction(MainWindow) icon30 = QtGui.QIcon() icon30.addPixmap(QtGui.QPixmap(":/browser"), QtGui.QIcon.Normal, QtGui.QIcon.Off) diff --git a/qiskit_metal/_gui/net_list_ui.py b/qiskit_metal/_gui/net_list_ui.py index 6d4d7b5a4..3cbf8757b 100644 --- a/qiskit_metal/_gui/net_list_ui.py +++ b/qiskit_metal/_gui/net_list_ui.py @@ -4,11 +4,11 @@ # licensing of './net_list_ui.ui' applies. # # Created: Wed May 25 09:29:27 2022 -# by: pyside2-uic running on PySide2 5.13.2 +# by: pyside6-uic running on PySide2 5.13.2 # # WARNING! All changes made in this file will be lost! -from PySide2 import QtCore, QtGui, QtWidgets +from PySide6 import QtCore, QtGui, QtWidgets class Ui_NetListWindow(object): diff --git a/qiskit_metal/_gui/net_list_window.py b/qiskit_metal/_gui/net_list_window.py index 9e1be7335..641347816 100644 --- a/qiskit_metal/_gui/net_list_window.py +++ b/qiskit_metal/_gui/net_list_window.py @@ -16,9 +16,9 @@ from typing import TYPE_CHECKING import numpy as np -from PySide2 import QtCore, QtWidgets -from PySide2.QtCore import QAbstractTableModel, QModelIndex -from PySide2.QtWidgets import QMainWindow +from PySide6 import QtCore, QtWidgets +from PySide6.QtCore import QAbstractTableModel, QModelIndex +from PySide6.QtWidgets import QMainWindow from .net_list_ui import Ui_NetListWindow @@ -33,7 +33,7 @@ class NetListWindow(QMainWindow): Extends the `QMainWindow` class. - PySide2 Signal / Slots Extensions: + PySide6 Signal / Slots Extensions: The UI can call up to this class to execute button clicks for instance Extensions in qt designer on signals/slots are linked to this class """ diff --git a/qiskit_metal/_gui/plot_window_ui.py b/qiskit_metal/_gui/plot_window_ui.py index 94d8d662d..4f815953a 100644 --- a/qiskit_metal/_gui/plot_window_ui.py +++ b/qiskit_metal/_gui/plot_window_ui.py @@ -4,11 +4,11 @@ # licensing of './plot_window_ui.ui' applies. # # Created: Sat Jun 19 22:02:29 2021 -# by: pyside2-uic running on PySide2 5.13.2 +# by: pyside6-uic running on PySide2 5.13.2 # # WARNING! All changes made in this file will be lost! -from PySide2 import QtCore, QtGui, QtWidgets +from PySide6 import QtCore, QtGui, QtWidgets class Ui_MainWindowPlot(object): @@ -37,19 +37,19 @@ def setupUi(self, MainWindowPlot): self.toolBar.setToolButtonStyle(QtCore.Qt.ToolButtonTextUnderIcon) self.toolBar.setObjectName("toolBar") MainWindowPlot.addToolBar(QtCore.Qt.TopToolBarArea, self.toolBar) - self.actionPan = QtWidgets.QAction(MainWindowPlot) + self.actionPan = QtGui.QAction(MainWindowPlot) icon = QtGui.QIcon() icon.addPixmap(QtGui.QPixmap(":/plot/pan"), QtGui.QIcon.Normal, QtGui.QIcon.On) self.actionPan.setIcon(icon) self.actionPan.setObjectName("actionPan") - self.actionZoom = QtWidgets.QAction(MainWindowPlot) + self.actionZoom = QtGui.QAction(MainWindowPlot) icon1 = QtGui.QIcon() icon1.addPixmap(QtGui.QPixmap(":/plot/zoom"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.actionZoom.setIcon(icon1) self.actionZoom.setObjectName("actionZoom") - self.actionConnectors = QtWidgets.QAction(MainWindowPlot) + self.actionConnectors = QtGui.QAction(MainWindowPlot) self.actionConnectors.setCheckable(True) self.actionConnectors.setChecked(False) icon2 = QtGui.QIcon() @@ -57,7 +57,7 @@ def setupUi(self, MainWindowPlot): QtGui.QIcon.Off) self.actionConnectors.setIcon(icon2) self.actionConnectors.setObjectName("actionConnectors") - self.actionCoords = QtWidgets.QAction(MainWindowPlot) + self.actionCoords = QtGui.QAction(MainWindowPlot) self.actionCoords.setCheckable(True) self.actionCoords.setChecked(True) icon3 = QtGui.QIcon() @@ -65,19 +65,19 @@ def setupUi(self, MainWindowPlot): QtGui.QIcon.Off) self.actionCoords.setIcon(icon3) self.actionCoords.setObjectName("actionCoords") - self.actionAuto = QtWidgets.QAction(MainWindowPlot) + self.actionAuto = QtGui.QAction(MainWindowPlot) icon4 = QtGui.QIcon() icon4.addPixmap(QtGui.QPixmap(":/plot/autozoom"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.actionAuto.setIcon(icon4) self.actionAuto.setObjectName("actionAuto") - self.actionReplot = QtWidgets.QAction(MainWindowPlot) + self.actionReplot = QtGui.QAction(MainWindowPlot) icon5 = QtGui.QIcon() icon5.addPixmap(QtGui.QPixmap(":/plot/refresh_plot"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.actionReplot.setIcon(icon5) self.actionReplot.setObjectName("actionReplot") - self.actionRuler = QtWidgets.QAction(MainWindowPlot) + self.actionRuler = QtGui.QAction(MainWindowPlot) icon6 = QtGui.QIcon() icon6.addPixmap(QtGui.QPixmap(":/plot/ruler"), QtGui.QIcon.Normal, QtGui.QIcon.Off) diff --git a/qiskit_metal/_gui/renderer_gds_gui.py b/qiskit_metal/_gui/renderer_gds_gui.py index 29cca8818..cc128eccf 100644 --- a/qiskit_metal/_gui/renderer_gds_gui.py +++ b/qiskit_metal/_gui/renderer_gds_gui.py @@ -12,7 +12,7 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. -from PySide2.QtWidgets import (QAbstractItemView, QFileDialog, QMainWindow, +from PySide6.QtWidgets import (QAbstractItemView, QFileDialog, QMainWindow, QMessageBox) from .list_model_base import DynamicList diff --git a/qiskit_metal/_gui/renderer_gds_model.py b/qiskit_metal/_gui/renderer_gds_model.py index 16580a3d4..aa7ce75ef 100644 --- a/qiskit_metal/_gui/renderer_gds_model.py +++ b/qiskit_metal/_gui/renderer_gds_model.py @@ -13,9 +13,9 @@ # that they have been altered from the originals. # Tree model for GDS renderer -import PySide2 -from PySide2 import QtWidgets -from PySide2.QtWidgets import QTreeView, QWidget +import PySide6 +from PySide6 import QtWidgets +from PySide6.QtWidgets import QTreeView, QWidget from .widgets.bases.dict_tree_base import QTreeModel_Base diff --git a/qiskit_metal/_gui/renderer_gds_ui.py b/qiskit_metal/_gui/renderer_gds_ui.py index b59c122e3..68b82905d 100644 --- a/qiskit_metal/_gui/renderer_gds_ui.py +++ b/qiskit_metal/_gui/renderer_gds_ui.py @@ -4,11 +4,11 @@ # licensing of './renderer_gds_ui.ui' applies. # # Created: Sat Jun 19 22:02:30 2021 -# by: pyside2-uic running on PySide2 5.13.2 +# by: pyside6-uic running on PySide2 5.13.2 # # WARNING! All changes made in this file will be lost! -from PySide2 import QtCore, QtGui, QtWidgets +from PySide6 import QtCore, QtGui, QtWidgets class Ui_MainWindow(object): diff --git a/qiskit_metal/_gui/renderer_hfss_gui.py b/qiskit_metal/_gui/renderer_hfss_gui.py index d7422c243..b747bf000 100644 --- a/qiskit_metal/_gui/renderer_hfss_gui.py +++ b/qiskit_metal/_gui/renderer_hfss_gui.py @@ -12,7 +12,7 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. -from PySide2.QtWidgets import (QAbstractItemView, QMainWindow, QMessageBox) +from PySide6.QtWidgets import (QAbstractItemView, QMainWindow, QMessageBox) from .list_model_base import DynamicList from .renderer_hfss_model import RendererHFSS_Model diff --git a/qiskit_metal/_gui/renderer_hfss_model.py b/qiskit_metal/_gui/renderer_hfss_model.py index 6da82d8c8..8c6dff38c 100644 --- a/qiskit_metal/_gui/renderer_hfss_model.py +++ b/qiskit_metal/_gui/renderer_hfss_model.py @@ -13,9 +13,9 @@ # that they have been altered from the originals. # Tree model for Ansys HFSS renderer -import PySide2 -from PySide2 import QtWidgets -from PySide2.QtWidgets import QTreeView, QWidget +import PySide6 +from PySide6 import QtWidgets +from PySide6.QtWidgets import QTreeView, QWidget from .widgets.bases.dict_tree_base import QTreeModel_Base diff --git a/qiskit_metal/_gui/renderer_hfss_ui.py b/qiskit_metal/_gui/renderer_hfss_ui.py index 127be16bb..4afce7c90 100644 --- a/qiskit_metal/_gui/renderer_hfss_ui.py +++ b/qiskit_metal/_gui/renderer_hfss_ui.py @@ -4,11 +4,11 @@ # licensing of './renderer_hfss_ui.ui' applies. # # Created: Sat Jun 19 22:02:29 2021 -# by: pyside2-uic running on PySide2 5.13.2 +# by: pyside6-uic running on PySide2 5.13.2 # # WARNING! All changes made in this file will be lost! -from PySide2 import QtCore, QtGui, QtWidgets +from PySide6 import QtCore, QtGui, QtWidgets class Ui_MainWindow(object): diff --git a/qiskit_metal/_gui/renderer_q3d_gui.py b/qiskit_metal/_gui/renderer_q3d_gui.py index 24f80c130..c4a6224c2 100644 --- a/qiskit_metal/_gui/renderer_q3d_gui.py +++ b/qiskit_metal/_gui/renderer_q3d_gui.py @@ -12,7 +12,7 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. -from PySide2.QtWidgets import (QAbstractItemView, QMainWindow, QMessageBox) +from PySide6.QtWidgets import (QAbstractItemView, QMainWindow, QMessageBox) from .list_model_base import DynamicList from .renderer_q3d_model import RendererQ3D_Model diff --git a/qiskit_metal/_gui/renderer_q3d_model.py b/qiskit_metal/_gui/renderer_q3d_model.py index a5295479f..cf99cbec6 100644 --- a/qiskit_metal/_gui/renderer_q3d_model.py +++ b/qiskit_metal/_gui/renderer_q3d_model.py @@ -13,9 +13,9 @@ # that they have been altered from the originals. # Tree model for Ansys Q3D renderer -import PySide2 -from PySide2 import QtWidgets -from PySide2.QtWidgets import QTreeView, QWidget +import PySide6 +from PySide6 import QtWidgets +from PySide6.QtWidgets import QTreeView, QWidget from .widgets.bases.dict_tree_base import QTreeModel_Base diff --git a/qiskit_metal/_gui/renderer_q3d_ui.py b/qiskit_metal/_gui/renderer_q3d_ui.py index 45a4bfe67..9259ccf2c 100644 --- a/qiskit_metal/_gui/renderer_q3d_ui.py +++ b/qiskit_metal/_gui/renderer_q3d_ui.py @@ -4,11 +4,11 @@ # licensing of './renderer_q3d_ui.ui' applies. # # Created: Sat Jun 19 22:02:29 2021 -# by: pyside2-uic running on PySide2 5.13.2 +# by: pyside6-uic running on PySide2 5.13.2 # # WARNING! All changes made in this file will be lost! -from PySide2 import QtCore, QtGui, QtWidgets +from PySide6 import QtCore, QtGui, QtWidgets class Ui_MainWindow(object): diff --git a/qiskit_metal/_gui/tree_view_base.py b/qiskit_metal/_gui/tree_view_base.py index 162e6f6c0..63fc469a2 100644 --- a/qiskit_metal/_gui/tree_view_base.py +++ b/qiskit_metal/_gui/tree_view_base.py @@ -13,9 +13,9 @@ # that they have been altered from the originals. """Handles editing a QComponent.""" -from PySide2 import QtCore, QtWidgets -from PySide2.QtCore import Qt, QTimer -from PySide2.QtWidgets import QTreeView, QAbstractItemView +from PySide6 import QtCore, QtWidgets +from PySide6.QtCore import Qt, QTimer +from PySide6.QtWidgets import QTreeView, QAbstractItemView class QTreeView_Base(QTreeView): diff --git a/qiskit_metal/_gui/utility/_handle_qt_messages.py b/qiskit_metal/_gui/utility/_handle_qt_messages.py index 9b084a631..3dabc342c 100644 --- a/qiskit_metal/_gui/utility/_handle_qt_messages.py +++ b/qiskit_metal/_gui/utility/_handle_qt_messages.py @@ -20,8 +20,8 @@ import types from functools import wraps -from PySide2 import QtCore -from PySide2.QtCore import Slot +from PySide6 import QtCore +from PySide6.QtCore import Slot from ... import logger @@ -77,7 +77,7 @@ def _qt_message_handler(mode, context, message): def do_debug(msg, name='info'): - """Utility function used to print debug statements from PySide2 Socket + """Utility function used to print debug statements from PySide6 Socket calls A bit of a cludge. Args: diff --git a/qiskit_metal/_gui/utility/_toolbox_qt.py b/qiskit_metal/_gui/utility/_toolbox_qt.py index e6e613d94..9d681a669 100644 --- a/qiskit_metal/_gui/utility/_toolbox_qt.py +++ b/qiskit_metal/_gui/utility/_toolbox_qt.py @@ -13,10 +13,10 @@ # that they have been altered from the originals. """This is a utility module used for qt.""" -from PySide2 import QtCore, QtWidgets -from PySide2.QtCore import QTimer -from PySide2.QtGui import QColor -from PySide2.QtWidgets import QDockWidget +from PySide6 import QtCore, QtWidgets +from PySide6.QtCore import QTimer +from PySide6.QtGui import QColor +from PySide6.QtWidgets import QDockWidget __all__ = ['blend_colors'] @@ -73,8 +73,8 @@ def doResetStyle(self: 'QDockWidget'): ### Alternative to doShowHighlighWidget: -# from PySide2.QtWidgets import QFrame, QWidget -# from PySide2 import QtCore +# from PySide6.QtWidgets import QFrame, QWidget +# from PySide6 import QtCore # obj = gui.canvas # frame = QFrame(obj.parent()) # frame.setGeometry(obj.frameGeometry()) diff --git a/qiskit_metal/_gui/widgets/all_components/table_model_all_components.py b/qiskit_metal/_gui/widgets/all_components/table_model_all_components.py index b9a75a3fe..bd4271bd4 100644 --- a/qiskit_metal/_gui/widgets/all_components/table_model_all_components.py +++ b/qiskit_metal/_gui/widgets/all_components/table_model_all_components.py @@ -13,10 +13,10 @@ # that they have been altered from the originals. import numpy as np -from PySide2 import QtCore, QtWidgets -from PySide2.QtCore import QAbstractTableModel, QModelIndex, Qt -from PySide2.QtGui import QBrush, QColor, QFont, QIcon, QPixmap -from PySide2.QtWidgets import QTableView +from PySide6 import QtCore, QtWidgets +from PySide6.QtCore import QAbstractTableModel, QModelIndex, Qt +from PySide6.QtGui import QBrush, QColor, QFont, QIcon, QPixmap +from PySide6.QtWidgets import QTableView from ...utility._handle_qt_messages import slot_catch_error from ...utility._toolbox_qt import blend_colors diff --git a/qiskit_metal/_gui/widgets/all_components/table_view_all_components.py b/qiskit_metal/_gui/widgets/all_components/table_view_all_components.py index 7a717b9db..3f659c150 100644 --- a/qiskit_metal/_gui/widgets/all_components/table_view_all_components.py +++ b/qiskit_metal/_gui/widgets/all_components/table_view_all_components.py @@ -15,10 +15,10 @@ from typing import TYPE_CHECKING from typing import List -from PySide2 import QtCore, QtWidgets -from PySide2.QtCore import QModelIndex, Qt, QTimer -from PySide2.QtGui import QContextMenuEvent -from PySide2.QtWidgets import (QInputDialog, QLabel, QLineEdit, QMenu, +from PySide6 import QtCore, QtWidgets +from PySide6.QtCore import QModelIndex, Qt, QTimer +from PySide6.QtGui import QContextMenuEvent +from PySide6.QtWidgets import (QInputDialog, QLabel, QLineEdit, QMenu, QMessageBox, QTableView, QVBoxLayout, QAbstractItemView) diff --git a/qiskit_metal/_gui/widgets/bases/QWidget_PlaceholderText.py b/qiskit_metal/_gui/widgets/bases/QWidget_PlaceholderText.py index 90251bbb0..099beea8b 100644 --- a/qiskit_metal/_gui/widgets/bases/QWidget_PlaceholderText.py +++ b/qiskit_metal/_gui/widgets/bases/QWidget_PlaceholderText.py @@ -14,10 +14,10 @@ from typing import TYPE_CHECKING -from PySide2 import QtCore, QtWidgets -from PySide2.QtCore import QModelIndex, Qt -from PySide2.QtGui import QContextMenuEvent -from PySide2.QtWidgets import (QInputDialog, QLineEdit, QMenu, QMessageBox, +from PySide6 import QtCore, QtWidgets +from PySide6.QtCore import QModelIndex, Qt +from PySide6.QtGui import QContextMenuEvent +from PySide6.QtWidgets import (QInputDialog, QLineEdit, QMenu, QMessageBox, QTableView, QLabel, QVBoxLayout, QWidget) diff --git a/qiskit_metal/_gui/widgets/bases/dict_tree_base.py b/qiskit_metal/_gui/widgets/bases/dict_tree_base.py index 56931f66d..e7448adea 100644 --- a/qiskit_metal/_gui/widgets/bases/dict_tree_base.py +++ b/qiskit_metal/_gui/widgets/bases/dict_tree_base.py @@ -18,11 +18,11 @@ from typing import Union, TYPE_CHECKING import numpy as np -import PySide2 -from PySide2 import QtCore, QtGui, QtWidgets -from PySide2.QtCore import QAbstractItemModel, QModelIndex, QTimer, Qt -from PySide2.QtGui import QFont -from PySide2.QtWidgets import (QAbstractItemView, QApplication, QFileDialog, +import PySide6 +from PySide6 import QtCore, QtGui, QtWidgets +from PySide6.QtCore import QAbstractItemModel, QModelIndex, QTimer, Qt +from PySide6.QtGui import QFont +from PySide6.QtWidgets import (QAbstractItemView, QApplication, QFileDialog, QWidget, QTreeView, QLabel, QMainWindow, QMessageBox, QTabWidget) from .... import logger diff --git a/qiskit_metal/_gui/widgets/bases/expanding_toolbar.py b/qiskit_metal/_gui/widgets/bases/expanding_toolbar.py index a0be69c48..025c710be 100644 --- a/qiskit_metal/_gui/widgets/bases/expanding_toolbar.py +++ b/qiskit_metal/_gui/widgets/bases/expanding_toolbar.py @@ -12,9 +12,9 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. -from PySide2 import QtCore, QtGui -from PySide2.QtCore import Qt -from PySide2.QtWidgets import QToolBar +from PySide6 import QtCore, QtGui +from PySide6.QtCore import Qt +from PySide6.QtWidgets import QToolBar import time diff --git a/qiskit_metal/_gui/widgets/build_history/build_history_scroll_area.py b/qiskit_metal/_gui/widgets/build_history/build_history_scroll_area.py index 293219002..c05ce65d6 100644 --- a/qiskit_metal/_gui/widgets/build_history/build_history_scroll_area.py +++ b/qiskit_metal/_gui/widgets/build_history/build_history_scroll_area.py @@ -1,4 +1,4 @@ -from PySide2.QtWidgets import (QLabel, QScrollArea, QVBoxLayout, QLabel, +from PySide6.QtWidgets import (QLabel, QScrollArea, QVBoxLayout, QLabel, QGroupBox) from typing import List from .build_history_scroll_area_ui import Ui_BuildHistory diff --git a/qiskit_metal/_gui/widgets/build_history/build_history_scroll_area_ui.py b/qiskit_metal/_gui/widgets/build_history/build_history_scroll_area_ui.py index 72d69b961..c95d5f723 100644 --- a/qiskit_metal/_gui/widgets/build_history/build_history_scroll_area_ui.py +++ b/qiskit_metal/_gui/widgets/build_history/build_history_scroll_area_ui.py @@ -4,11 +4,11 @@ # licensing of './widgets/build_history/build_history_scroll_area_ui.ui' applies. # # Created: Sat Jun 19 22:02:31 2021 -# by: pyside2-uic running on PySide2 5.13.2 +# by: pyside6-uic running on PySide2 5.13.2 # # WARNING! All changes made in this file will be lost! -from PySide2 import QtCore, QtGui, QtWidgets +from PySide6 import QtCore, QtGui, QtWidgets class Ui_BuildHistory(object): diff --git a/qiskit_metal/_gui/widgets/create_component_window/model_view/tree_delegate_param_entry.py b/qiskit_metal/_gui/widgets/create_component_window/model_view/tree_delegate_param_entry.py index be2cd6d7d..d946c2dcd 100644 --- a/qiskit_metal/_gui/widgets/create_component_window/model_view/tree_delegate_param_entry.py +++ b/qiskit_metal/_gui/widgets/create_component_window/model_view/tree_delegate_param_entry.py @@ -15,8 +15,8 @@ Delegate for Param Entry Window's MVD """ -from PySide2.QtCore import QAbstractItemModel, QModelIndex, Qt -from PySide2.QtWidgets import QItemDelegate, QStyleOptionViewItem, QWidget +from PySide6.QtCore import QAbstractItemModel, QModelIndex, Qt +from PySide6.QtWidgets import QItemDelegate, QStyleOptionViewItem, QWidget from qiskit_metal._gui.widgets.create_component_window.model_view.tree_model_param_entry import TreeModelParamEntry # pylint: disable=line-too-long diff --git a/qiskit_metal/_gui/widgets/create_component_window/model_view/tree_model_param_entry.py b/qiskit_metal/_gui/widgets/create_component_window/model_view/tree_model_param_entry.py index b1f1ca593..294790b9e 100644 --- a/qiskit_metal/_gui/widgets/create_component_window/model_view/tree_model_param_entry.py +++ b/qiskit_metal/_gui/widgets/create_component_window/model_view/tree_model_param_entry.py @@ -22,10 +22,10 @@ from typing import Union, TYPE_CHECKING, Any import numpy as np -from PySide2 import QtCore -from PySide2.QtCore import QAbstractItemModel, QModelIndex, QTimer, Qt -from PySide2.QtGui import QFont -from PySide2.QtWidgets import (QComboBox, QTreeView, QWidget) +from PySide6 import QtCore +from PySide6.QtCore import QAbstractItemModel, QModelIndex, QTimer, Qt +from PySide6.QtGui import QFont +from PySide6.QtWidgets import (QComboBox, QTreeView, QWidget) from addict import Dict if TYPE_CHECKING: diff --git a/qiskit_metal/_gui/widgets/create_component_window/model_view/tree_view_param_entry.py b/qiskit_metal/_gui/widgets/create_component_window/model_view/tree_view_param_entry.py index f893da68a..8c602d032 100644 --- a/qiskit_metal/_gui/widgets/create_component_window/model_view/tree_view_param_entry.py +++ b/qiskit_metal/_gui/widgets/create_component_window/model_view/tree_view_param_entry.py @@ -15,9 +15,9 @@ Tree view for Param Entry Window """ -from PySide2 import QtGui, QtWidgets -from PySide2.QtCore import QModelIndex -from PySide2.QtWidgets import QTreeView +from PySide6 import QtGui, QtWidgets +from PySide6.QtCore import QModelIndex +from PySide6.QtWidgets import QTreeView class TreeViewParamEntry(QTreeView): diff --git a/qiskit_metal/_gui/widgets/create_component_window/parameter_entry_window.py b/qiskit_metal/_gui/widgets/create_component_window/parameter_entry_window.py index 1e5628387..bef043d18 100644 --- a/qiskit_metal/_gui/widgets/create_component_window/parameter_entry_window.py +++ b/qiskit_metal/_gui/widgets/create_component_window/parameter_entry_window.py @@ -41,10 +41,10 @@ from typing import TYPE_CHECKING, Union, Type import numpy as np -from PySide2 import QtGui, QtWidgets -from PySide2.QtCore import Qt -from PySide2.QtWidgets import QDockWidget, QWidget -from PySide2.QtWidgets import (QMainWindow, QMessageBox) +from PySide6 import QtGui, QtWidgets +from PySide6.QtCore import Qt +from PySide6.QtWidgets import QDockWidget, QWidget +from PySide6.QtWidgets import (QMainWindow, QMessageBox) from qiskit_metal import designs from qiskit_metal.qlibrary.core import QComponent diff --git a/qiskit_metal/_gui/widgets/create_component_window/parameter_entry_window_ui.py b/qiskit_metal/_gui/widgets/create_component_window/parameter_entry_window_ui.py index 84c5a6432..8b4de5e45 100644 --- a/qiskit_metal/_gui/widgets/create_component_window/parameter_entry_window_ui.py +++ b/qiskit_metal/_gui/widgets/create_component_window/parameter_entry_window_ui.py @@ -4,11 +4,11 @@ # licensing of './widgets/create_component_window/parameter_entry_window_ui.ui' applies. # # Created: Sat Jun 19 22:02:30 2021 -# by: pyside2-uic running on PySide2 5.13.2 +# by: pyside6-uic running on PySide2 5.13.2 # # WARNING! All changes made in this file will be lost! -from PySide2 import QtCore, QtGui, QtWidgets +from PySide6 import QtCore, QtGui, QtWidgets class Ui_MainWindow(object): diff --git a/qiskit_metal/_gui/widgets/edit_component/component_widget.py b/qiskit_metal/_gui/widgets/edit_component/component_widget.py index cb4f9c360..403e7e3c3 100644 --- a/qiskit_metal/_gui/widgets/edit_component/component_widget.py +++ b/qiskit_metal/_gui/widgets/edit_component/component_widget.py @@ -19,11 +19,11 @@ from typing import TYPE_CHECKING, Union import numpy as np -import PySide2 -from PySide2 import QtCore, QtGui, QtWidgets -from PySide2.QtCore import QAbstractTableModel, QModelIndex, Qt -from PySide2.QtGui import QFont, QColor -from PySide2.QtWidgets import (QAbstractItemView, QApplication, QFileDialog, +import PySide6 +from PySide6 import QtCore, QtGui, QtWidgets +from PySide6.QtCore import QAbstractTableModel, QModelIndex, Qt +from PySide6.QtGui import QFont, QColor +from PySide6.QtWidgets import (QAbstractItemView, QApplication, QFileDialog, QLabel, QMainWindow, QMessageBox, QTabWidget) from .... import logger diff --git a/qiskit_metal/_gui/widgets/edit_component/table_model_options.py b/qiskit_metal/_gui/widgets/edit_component/table_model_options.py index 1ab0d6c14..209931b3e 100644 --- a/qiskit_metal/_gui/widgets/edit_component/table_model_options.py +++ b/qiskit_metal/_gui/widgets/edit_component/table_model_options.py @@ -18,9 +18,9 @@ from inspect import getfile, signature from pathlib import Path from typing import TYPE_CHECKING, Union -from PySide2 import QtCore, QtGui, QtWidgets -from PySide2.QtCore import QAbstractTableModel, QModelIndex, Qt -from PySide2.QtGui import QFont +from PySide6 import QtCore, QtGui, QtWidgets +from PySide6.QtCore import QAbstractTableModel, QModelIndex, Qt +from PySide6.QtGui import QFont __all__ = ['parse_param_from_str'] diff --git a/qiskit_metal/_gui/widgets/edit_component/table_view_options.py b/qiskit_metal/_gui/widgets/edit_component/table_view_options.py index 212fe4749..4533fc52a 100644 --- a/qiskit_metal/_gui/widgets/edit_component/table_view_options.py +++ b/qiskit_metal/_gui/widgets/edit_component/table_view_options.py @@ -15,9 +15,9 @@ from typing import TYPE_CHECKING -from PySide2 import QtCore, QtWidgets -from PySide2.QtCore import Qt, QTimer -from PySide2.QtWidgets import QTableView, QAbstractItemView +from PySide6 import QtCore, QtWidgets +from PySide6.QtCore import Qt, QTimer +from PySide6.QtWidgets import QTableView, QAbstractItemView from ..bases.QWidget_PlaceholderText import QWidget_PlaceholderText diff --git a/qiskit_metal/_gui/widgets/edit_component/tree_model_options.py b/qiskit_metal/_gui/widgets/edit_component/tree_model_options.py index e3ff37e77..6beb653a7 100644 --- a/qiskit_metal/_gui/widgets/edit_component/tree_model_options.py +++ b/qiskit_metal/_gui/widgets/edit_component/tree_model_options.py @@ -14,9 +14,9 @@ """Tree model for component options menu.""" from typing import TYPE_CHECKING -from PySide2.QtCore import QModelIndex, Qt -from PySide2.QtGui import QFont -from PySide2.QtWidgets import QTreeView, QWidget +from PySide6.QtCore import QModelIndex, Qt +from PySide6.QtGui import QFont +from PySide6.QtWidgets import QTreeView, QWidget from ..bases.dict_tree_base import LeafNode, BranchNode, QTreeModel_Base, parse_param_from_str if TYPE_CHECKING: diff --git a/qiskit_metal/_gui/widgets/edit_component/tree_view_options.py b/qiskit_metal/_gui/widgets/edit_component/tree_view_options.py index 63abf492f..7fff3f696 100644 --- a/qiskit_metal/_gui/widgets/edit_component/tree_view_options.py +++ b/qiskit_metal/_gui/widgets/edit_component/tree_view_options.py @@ -15,9 +15,9 @@ from typing import TYPE_CHECKING -from PySide2 import QtCore, QtWidgets -from PySide2.QtCore import Qt, QTimer -from PySide2.QtWidgets import QTreeView, QAbstractItemView +from PySide6 import QtCore, QtWidgets +from PySide6.QtCore import Qt, QTimer +from PySide6.QtWidgets import QTreeView, QAbstractItemView from ..bases.QWidget_PlaceholderText import QWidget_PlaceholderText diff --git a/qiskit_metal/_gui/widgets/log_widget/log_metal.py b/qiskit_metal/_gui/widgets/log_widget/log_metal.py index afe8d8680..0a0997832 100644 --- a/qiskit_metal/_gui/widgets/log_widget/log_metal.py +++ b/qiskit_metal/_gui/widgets/log_widget/log_metal.py @@ -23,9 +23,10 @@ import random from pathlib import Path -from PySide2 import QtGui -from PySide2.QtCore import Qt -from PySide2.QtWidgets import QAction, QDockWidget, QTextEdit +from PySide6 import QtGui +from PySide6.QtCore import Qt +from PySide6.QtGui import QAction +from PySide6.QtWidgets import QDockWidget, QTextEdit from .... import Dict, __version__, config from ...utility._handle_qt_messages import slot_catch_error diff --git a/qiskit_metal/_gui/widgets/plot_widget/plot_window.py b/qiskit_metal/_gui/widgets/plot_widget/plot_window.py index 74869059a..7b2d920f0 100644 --- a/qiskit_metal/_gui/widgets/plot_widget/plot_window.py +++ b/qiskit_metal/_gui/widgets/plot_widget/plot_window.py @@ -21,8 +21,8 @@ from typing import TYPE_CHECKING -from PySide2 import QtWidgets -from PySide2.QtWidgets import (QApplication, QFileDialog, QLabel, QMainWindow, +from PySide6 import QtWidgets +from PySide6.QtWidgets import (QApplication, QFileDialog, QLabel, QMainWindow, QMessageBox) from ... import config diff --git a/qiskit_metal/_gui/widgets/qlibrary_display/delegate_qlibrary.py b/qiskit_metal/_gui/widgets/qlibrary_display/delegate_qlibrary.py index be6650511..2f87ed13d 100644 --- a/qiskit_metal/_gui/widgets/qlibrary_display/delegate_qlibrary.py +++ b/qiskit_metal/_gui/widgets/qlibrary_display/delegate_qlibrary.py @@ -19,9 +19,9 @@ import inspect import os -from PySide2.QtCore import QAbstractItemModel, QAbstractProxyModel, QModelIndex, Signal -from PySide2.QtGui import QPainter -from PySide2.QtWidgets import QItemDelegate, QStyle, QStyleOptionViewItem, QWidget +from PySide6.QtCore import QAbstractItemModel, QAbstractProxyModel, QModelIndex, Signal +from PySide6.QtGui import QPainter +from PySide6.QtWidgets import QItemDelegate, QStyle, QStyleOptionViewItem, QWidget from qiskit_metal._gui.widgets.qlibrary_display.file_model_qlibrary import QFileSystemLibraryModel from qiskit_metal.toolbox_metal.exceptions import QLibraryGUIException diff --git a/qiskit_metal/_gui/widgets/qlibrary_display/file_model_qlibrary.py b/qiskit_metal/_gui/widgets/qlibrary_display/file_model_qlibrary.py index ea6d9423e..5ee1dd51e 100644 --- a/qiskit_metal/_gui/widgets/qlibrary_display/file_model_qlibrary.py +++ b/qiskit_metal/_gui/widgets/qlibrary_display/file_model_qlibrary.py @@ -18,9 +18,9 @@ import os import typing from pathlib import Path -from PySide2.QtCore import QModelIndex, QTimeZone, Qt, QSize -from PySide2.QtGui import QIcon, QPixmap -from PySide2.QtWidgets import QFileSystemModel +from PySide6.QtCore import QModelIndex, QTimeZone, Qt, QSize +from PySide6.QtGui import QIcon, QPixmap +from PySide6.QtWidgets import QFileSystemModel from qiskit_metal._gui.utility.utils import findProperty diff --git a/qiskit_metal/_gui/widgets/qlibrary_display/proxy_model_qlibrary.py b/qiskit_metal/_gui/widgets/qlibrary_display/proxy_model_qlibrary.py index 8ea45bfec..f06ac6cff 100644 --- a/qiskit_metal/_gui/widgets/qlibrary_display/proxy_model_qlibrary.py +++ b/qiskit_metal/_gui/widgets/qlibrary_display/proxy_model_qlibrary.py @@ -17,8 +17,8 @@ import typing -from PySide2.QtCore import QModelIndex, QSortFilterProxyModel, Qt, QSize -from PySide2.QtWidgets import QWidget +from PySide6.QtCore import QModelIndex, QSortFilterProxyModel, Qt, QSize +from PySide6.QtWidgets import QWidget class LibraryFileProxyModel(QSortFilterProxyModel): @@ -38,7 +38,7 @@ def __init__(self, parent: QWidget = None): # (Aren't hidden (begin w/ .), don't begin with __init__, don't begin with _template, etc. AND end in .py) OR (don't begin with __pycache__ and don't have a '.' in the name # pylint: disable=line-too-long # (QComponent files) OR (Directories) self.accepted_files__regex = r"(^((?!\.))(?!base)(?!__init__)(?!_template)(?!_parsed)(?!__pycache__).*\.py)|(?!__pycache__)(^([^.]+)$)" # pylint: disable=line-too-long - self.setFilterRegExp(self.accepted_files__regex) + self.setFilterRegularExpression(self.accepted_files__regex) def filterAcceptsColumn( self, source_column: int, source_parent: QModelIndex) -> bool: #pylint: disable=unused-argument diff --git a/qiskit_metal/_gui/widgets/qlibrary_display/tree_view_qlibrary.py b/qiskit_metal/_gui/widgets/qlibrary_display/tree_view_qlibrary.py index 80ab0d4ca..be79b98e1 100644 --- a/qiskit_metal/_gui/widgets/qlibrary_display/tree_view_qlibrary.py +++ b/qiskit_metal/_gui/widgets/qlibrary_display/tree_view_qlibrary.py @@ -15,9 +15,9 @@ Tree view for Param Entry Window """ -from PySide2 import QtCore, QtGui, QtWidgets -from PySide2.QtCore import QModelIndex, Signal -from PySide2.QtWidgets import QTreeView, QWidget +from PySide6 import QtCore, QtGui, QtWidgets +from PySide6.QtCore import QModelIndex, Signal +from PySide6.QtWidgets import QTreeView, QWidget from qiskit_metal._gui.widgets.qlibrary_display.proxy_model_qlibrary import LibraryFileProxyModel from qiskit_metal.toolbox_metal.exceptions import QLibraryGUIException diff --git a/qiskit_metal/_gui/widgets/variable_table/add_delete_table_ui.py b/qiskit_metal/_gui/widgets/variable_table/add_delete_table_ui.py index 266f73fb4..e945b09a6 100644 --- a/qiskit_metal/_gui/widgets/variable_table/add_delete_table_ui.py +++ b/qiskit_metal/_gui/widgets/variable_table/add_delete_table_ui.py @@ -4,11 +4,11 @@ # licensing of './widgets/variable_table/add_delete_table_ui.ui' applies. # # Created: Sat Jun 19 22:02:31 2021 -# by: pyside2-uic running on PySide2 5.13.2 +# by: pyside6-uic running on PySide2 5.13.2 # # WARNING! All changes made in this file will be lost! -from PySide2 import QtCore, QtGui, QtWidgets +from PySide6 import QtCore, QtGui, QtWidgets class Ui_MainWindow(object): diff --git a/qiskit_metal/_gui/widgets/variable_table/dialog_popup_ui.py b/qiskit_metal/_gui/widgets/variable_table/dialog_popup_ui.py index e71d4f4a7..348d79790 100644 --- a/qiskit_metal/_gui/widgets/variable_table/dialog_popup_ui.py +++ b/qiskit_metal/_gui/widgets/variable_table/dialog_popup_ui.py @@ -4,11 +4,11 @@ # licensing of './widgets/variable_table/dialog_popup_ui.ui' applies. # # Created: Sat Jun 19 22:02:31 2021 -# by: pyside2-uic running on PySide2 5.13.2 +# by: pyside6-uic running on PySide2 5.13.2 # # WARNING! All changes made in this file will be lost! -from PySide2 import QtCore, QtGui, QtWidgets +from PySide6 import QtCore, QtGui, QtWidgets class Ui_Dialog(object): diff --git a/qiskit_metal/_gui/widgets/variable_table/prop_val_table_gui.py b/qiskit_metal/_gui/widgets/variable_table/prop_val_table_gui.py index 256d9476e..d145a1b69 100644 --- a/qiskit_metal/_gui/widgets/variable_table/prop_val_table_gui.py +++ b/qiskit_metal/_gui/widgets/variable_table/prop_val_table_gui.py @@ -12,8 +12,8 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. -from PySide2.QtCore import QModelIndex -from PySide2.QtWidgets import QDialog, QMainWindow +from PySide6.QtCore import QModelIndex +from PySide6.QtWidgets import QDialog, QMainWindow from .add_delete_table_ui import Ui_MainWindow from .dialog_popup_ui import Ui_Dialog diff --git a/qiskit_metal/_gui/widgets/variable_table/prop_val_table_model.py b/qiskit_metal/_gui/widgets/variable_table/prop_val_table_model.py index 9b8c5eb91..5cc8aa693 100644 --- a/qiskit_metal/_gui/widgets/variable_table/prop_val_table_model.py +++ b/qiskit_metal/_gui/widgets/variable_table/prop_val_table_model.py @@ -12,9 +12,9 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. -from PySide2 import QtCore -from PySide2.QtCore import QAbstractTableModel, QModelIndex, Qt -from PySide2.QtGui import QFont +from PySide6 import QtCore +from PySide6.QtCore import QAbstractTableModel, QModelIndex, Qt +from PySide6.QtGui import QFont from .... import config diff --git a/qiskit_metal/_gui/widgets/variable_table/right_click_table_view.py b/qiskit_metal/_gui/widgets/variable_table/right_click_table_view.py index 6c1a0b212..6b46ab09a 100644 --- a/qiskit_metal/_gui/widgets/variable_table/right_click_table_view.py +++ b/qiskit_metal/_gui/widgets/variable_table/right_click_table_view.py @@ -12,11 +12,11 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. -from PySide2 import QtWidgets, QtCore, QtGui -from PySide2.QtGui import QContextMenuEvent -from PySide2.QtCore import QPoint, QModelIndex, QTimer -from PySide2.QtWidgets import QInputDialog, QLineEdit, QTableView, QMenu, QMessageBox -from PySide2.QtWidgets import QAbstractItemView +from PySide6 import QtWidgets, QtCore, QtGui +from PySide6.QtGui import QContextMenuEvent +from PySide6.QtCore import QPoint, QModelIndex, QTimer +from PySide6.QtWidgets import QInputDialog, QLineEdit, QTableView, QMenu, QMessageBox +from PySide6.QtWidgets import QAbstractItemView class RightClickView(QTableView): diff --git a/qiskit_metal/renderers/renderer_mpl/extensions/animated_text.py b/qiskit_metal/renderers/renderer_mpl/extensions/animated_text.py index 3efede528..bd3031342 100644 --- a/qiskit_metal/renderers/renderer_mpl/extensions/animated_text.py +++ b/qiskit_metal/renderers/renderer_mpl/extensions/animated_text.py @@ -14,7 +14,7 @@ """""" import matplotlib.pyplot as plt -from PySide2.QtCore import QTimer +from PySide6.QtCore import QTimer from ...._gui.utility._handle_qt_messages import slot_catch_error diff --git a/qiskit_metal/renderers/renderer_mpl/mpl_canvas.py b/qiskit_metal/renderers/renderer_mpl/mpl_canvas.py index 37296df94..fff1887fe 100644 --- a/qiskit_metal/renderers/renderer_mpl/mpl_canvas.py +++ b/qiskit_metal/renderers/renderer_mpl/mpl_canvas.py @@ -26,8 +26,8 @@ FigureCanvasQTAgg as FigureCanvas from matplotlib.figure import Figure from matplotlib.transforms import Bbox -from PySide2.QtCore import QTimer -from PySide2.QtWidgets import QSizePolicy +from PySide6.QtCore import QTimer +from PySide6.QtWidgets import QSizePolicy from ... import Dict from ...designs import QDesign from .mpl_interaction import PanAndZoom diff --git a/qiskit_metal/renderers/renderer_mpl/mpl_interaction.py b/qiskit_metal/renderers/renderer_mpl/mpl_interaction.py index 140638ebc..379227a14 100644 --- a/qiskit_metal/renderers/renderer_mpl/mpl_interaction.py +++ b/qiskit_metal/renderers/renderer_mpl/mpl_interaction.py @@ -84,9 +84,9 @@ import matplotlib.pyplot as _plt import numpy -from PySide2.QtCore import Qt -from PySide2.QtGui import QIcon -from PySide2.QtWidgets import QAction, QLabel +from PySide6.QtCore import Qt +from PySide6.QtGui import QIcon, QAction +from PySide6.QtWidgets import QLabel from ... import Dict diff --git a/qiskit_metal/toolbox_metal/about.py b/qiskit_metal/toolbox_metal/about.py index de5ce0e89..351da8d88 100644 --- a/qiskit_metal/toolbox_metal/about.py +++ b/qiskit_metal/toolbox_metal/about.py @@ -49,8 +49,8 @@ def about(): str: About message """ import qiskit_metal - from PySide2.QtCore import __version__ as QT_VERSION_STR - from PySide2 import __version__ as PYSIDE_VERSION_STR + from PySide6.QtCore import __version__ as QT_VERSION_STR + from PySide6 import __version__ as PYSIDE_VERSION_STR try: import matplotlib diff --git a/qiskit_metal/toolbox_python/display.py b/qiskit_metal/toolbox_python/display.py index 8f4aa7431..e8de81895 100644 --- a/qiskit_metal/toolbox_python/display.py +++ b/qiskit_metal/toolbox_python/display.py @@ -112,7 +112,7 @@ def get_screenshot(self: 'QMainWindow', do_display (bool): True to display the file. Defaults to True. disp_ops (dict): Disctionary of options. Defaults to None. """ - from PySide2.QtWidgets import QApplication, QMainWindow + from PySide6.QtWidgets import QApplication, QMainWindow path = Path(name).resolve() diff --git a/tutorials/Appendix B Quick topics/Managing variables.ipynb b/tutorials/Appendix B Quick topics/Managing variables.ipynb index 6762e2067..422c773ee 100644 --- a/tutorials/Appendix B Quick topics/Managing variables.ipynb +++ b/tutorials/Appendix B Quick topics/Managing variables.ipynb @@ -114,7 +114,7 @@ "metadata": {}, "outputs": [], "source": [ - "from PySide2.QtWidgets import QAbstractItemView\n", + "from PySide6.QtWidgets import QAbstractItemView\n", "table.setVerticalScrollMode(QAbstractItemView.ScrollPerPixel)\n", "table.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel)" ] From 2d85448c9331b41970cf8bdb6d2c8b89caa0e694 Mon Sep 17 00:00:00 2001 From: Patrick O'Brien Date: Sun, 25 Sep 2022 13:53:59 -0400 Subject: [PATCH 02/46] Update QT_API to PySide6 and update mpl backend --- qiskit_metal/__init__.py | 2 +- qiskit_metal/_gui/main_window_base.py | 2 +- qiskit_metal/renderers/renderer_mpl/mpl_canvas.py | 2 +- qiskit_metal/toolbox_metal/about.py | 2 +- requirements.txt | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/qiskit_metal/__init__.py b/qiskit_metal/__init__.py index 9fae06beb..48689c225 100644 --- a/qiskit_metal/__init__.py +++ b/qiskit_metal/__init__.py @@ -107,7 +107,7 @@ def set_attribute(name: str, value=True): if not os.getenv('QISKIT_METAL_HEADLESS', None): # pylint: disable=import-outside-toplevel import matplotlib as mpl - mpl.use("Qt5Agg") + mpl.use("QtAgg") # pylint: disable=redefined-outer-name import matplotlib.pyplot as plt plt.ion() # interactive diff --git a/qiskit_metal/_gui/main_window_base.py b/qiskit_metal/_gui/main_window_base.py index d0c4a13c7..3a6ae411c 100644 --- a/qiskit_metal/_gui/main_window_base.py +++ b/qiskit_metal/_gui/main_window_base.py @@ -497,7 +497,7 @@ def load_stylesheet(self, path=None): 'Please do so from the terminal using\n' ' >>> pip install qdarkstyle') - os.environ['QT_API'] = 'pyside2' + os.environ['QT_API'] = 'pyside6' self.main_window.setStyleSheet(qdarkstyle.load_stylesheet()) elif path == 'metal_dark': diff --git a/qiskit_metal/renderers/renderer_mpl/mpl_canvas.py b/qiskit_metal/renderers/renderer_mpl/mpl_canvas.py index fff1887fe..d229ca6c6 100644 --- a/qiskit_metal/renderers/renderer_mpl/mpl_canvas.py +++ b/qiskit_metal/renderers/renderer_mpl/mpl_canvas.py @@ -44,7 +44,7 @@ from ..._gui.widgets.plot_widget.plot_window import QMainWindowPlot # @mfacchin - moved to the root __init__ to prevent windows from hanging -# mpl.use("Qt5Agg") +mpl.use("QtAgg") BACKGROUND_COLOR = '#F4F4F4' MPL_CONTEXT_DEFAULT = { diff --git a/qiskit_metal/toolbox_metal/about.py b/qiskit_metal/toolbox_metal/about.py index 351da8d88..063f6536d 100644 --- a/qiskit_metal/toolbox_metal/about.py +++ b/qiskit_metal/toolbox_metal/about.py @@ -86,7 +86,7 @@ def about(): GUI ____________________________________ - PySide2 version {PYSIDE_VERSION_STR} + PySide6 version {PYSIDE_VERSION_STR} Qt version {QT_VERSION_STR} SIP version {SIP_VERSION_STR} diff --git a/requirements.txt b/requirements.txt index d0197b423..1c07d1001 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,7 +9,7 @@ pandas pint pyEPR-quantum>=0.8.5.7 pygments -pyside2 +pyside6 qutip scipy shapely #using conda on Windows OS: pip install of shapely will fail on import for missing geos_c.dll, if <= v1.7.x. For as long as a 1.8.0 version is not released (already patched in github), you will need to run `conda install shapely` (before installing qiskit_metal). From a00ea96e4aeee06862e503d57a96602b7e8c2e90 Mon Sep 17 00:00:00 2001 From: "Patrick J. O'Brien" Date: Thu, 26 Jan 2023 15:02:25 -0500 Subject: [PATCH 03/46] Install libegl in ubuntu environment For ubuntu unit tests --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 47f83c6ba..1fd6486c5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -37,7 +37,7 @@ jobs: - name: Install Deps run: | python -m pip install -U tox setuptools virtualenv wheel - sudo apt install libglu1-mesa libglu1-mesa-dev + sudo apt install libglu1-mesa libglu1-mesa-dev libegl1-mesa libegl1 - name: Install and Run Tests run: tox -e py macos-tests: From e9defda1fe481a9244d2c569a898da3f7c880e34 Mon Sep 17 00:00:00 2001 From: "Patrick J. O'Brien" Date: Thu, 26 Jan 2023 15:38:50 -0500 Subject: [PATCH 04/46] Comment out mpl.use Hoping this will resolve an issue with running tests and doc building --- qiskit_metal/renderers/renderer_mpl/mpl_canvas.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit_metal/renderers/renderer_mpl/mpl_canvas.py b/qiskit_metal/renderers/renderer_mpl/mpl_canvas.py index d229ca6c6..e717d1292 100644 --- a/qiskit_metal/renderers/renderer_mpl/mpl_canvas.py +++ b/qiskit_metal/renderers/renderer_mpl/mpl_canvas.py @@ -44,7 +44,7 @@ from ..._gui.widgets.plot_widget.plot_window import QMainWindowPlot # @mfacchin - moved to the root __init__ to prevent windows from hanging -mpl.use("QtAgg") +# mpl.use("QtAgg") BACKGROUND_COLOR = '#F4F4F4' MPL_CONTEXT_DEFAULT = { From d0bcb56c5c60d2431f467fa6198f0ee38111aeae Mon Sep 17 00:00:00 2001 From: Patrick O'Brien Date: Tue, 31 Jan 2023 17:22:37 -0500 Subject: [PATCH 05/46] Yapf format main_window.py --- qiskit_metal/_gui/main_window.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/qiskit_metal/_gui/main_window.py b/qiskit_metal/_gui/main_window.py index ca184297b..6602e41ab 100644 --- a/qiskit_metal/_gui/main_window.py +++ b/qiskit_metal/_gui/main_window.py @@ -23,8 +23,8 @@ from PySide6.QtCore import Qt, QTimer from PySide6.QtGui import QIcon, QPixmap, QAction -from PySide6.QtWidgets import (QDialog, QDockWidget, QFileDialog, - QLabel, QMainWindow, QMessageBox, QVBoxLayout) +from PySide6.QtWidgets import (QDialog, QDockWidget, QFileDialog, QLabel, + QMainWindow, QMessageBox, QVBoxLayout) from PySide6.QtCore import QSortFilterProxyModel from qiskit_metal._gui.widgets.qlibrary_display.delegate_qlibrary import \ LibraryDelegate @@ -336,7 +336,7 @@ def __init__(self, design: QDesign = None): # Show and raise self.main_window.show() - + # self.qApp.processEvents(QEventLoop.AllEvents, 1) # - don't think I need this here, it doesn't help to show and raise # - need to call from different thread. From 61a00c2637e8a79ac6c30d48f51451a21e5c80d2 Mon Sep 17 00:00:00 2001 From: Patrick O'Brien Date: Wed, 1 Feb 2023 11:39:55 -0500 Subject: [PATCH 06/46] Remove sleeps from GUI --- qiskit_metal/_gui/main_window.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/qiskit_metal/_gui/main_window.py b/qiskit_metal/_gui/main_window.py index 6602e41ab..262ab32e3 100644 --- a/qiskit_metal/_gui/main_window.py +++ b/qiskit_metal/_gui/main_window.py @@ -16,7 +16,6 @@ import logging import os -from time import sleep import webbrowser from pathlib import Path from typing import TYPE_CHECKING, List @@ -327,13 +326,9 @@ def __init__(self, design: QDesign = None): self.main_window.show() self._setup_variables_widget() self._ui_adjustments_final() - print('Sleeping') - sleep(10) self._setup_library_widget() self._setup_net_list_widget() - sleep(10) - # Show and raise self.main_window.show() From fb66b0a438e7068a4f65d35136e096c92ac1fbb4 Mon Sep 17 00:00:00 2001 From: Patrick O'Brien Date: Wed, 1 Feb 2023 11:45:34 -0500 Subject: [PATCH 07/46] Add qdarkstyle to dependencies --- environment.yml | 1 + requirements.txt | 1 + 2 files changed, 2 insertions(+) diff --git a/environment.yml b/environment.yml index 5299598a1..51a30ea01 100644 --- a/environment.yml +++ b/environment.yml @@ -14,6 +14,7 @@ dependencies: - pint - pyepr-quantum>=0.8.5.7 - pygments + - qdarkstyle - qutip - scipy - shapely diff --git a/requirements.txt b/requirements.txt index f006c97c2..79f9fe83b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,6 +10,7 @@ pint pyEPR-quantum>=0.8.5.7 pygments pyside6 +qdarkstyle qutip scipy shapely From cedd497d9fd7eac14312907a48cb8931ebe66f7d Mon Sep 17 00:00:00 2001 From: Patrick O'Brien Date: Mon, 6 Feb 2023 12:51:54 -0500 Subject: [PATCH 08/46] Fix version of libegl1 to 22.0.1 --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1fd6486c5..510d2c995 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -37,7 +37,7 @@ jobs: - name: Install Deps run: | python -m pip install -U tox setuptools virtualenv wheel - sudo apt install libglu1-mesa libglu1-mesa-dev libegl1-mesa libegl1 + sudo apt install libglu1-mesa libglu1-mesa-dev libegl1-mesa==22.0.1 libegl1==22.0.1 - name: Install and Run Tests run: tox -e py macos-tests: From c4dd5bd7af13618bed12fbeb9cf3bab6cbc9e7c8 Mon Sep 17 00:00:00 2001 From: Patrick O'Brien Date: Mon, 6 Feb 2023 12:57:46 -0500 Subject: [PATCH 09/46] Fix version number for libegl1 --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 510d2c995..3f1c52f37 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -37,7 +37,7 @@ jobs: - name: Install Deps run: | python -m pip install -U tox setuptools virtualenv wheel - sudo apt install libglu1-mesa libglu1-mesa-dev libegl1-mesa==22.0.1 libegl1==22.0.1 + sudo apt install libglu1-mesa libglu1-mesa-dev libegl1-mesa=22.0.1 libegl1=22.0.1 - name: Install and Run Tests run: tox -e py macos-tests: From 08bf56d98fb0e1c384b93f199f02cd983f208fce Mon Sep 17 00:00:00 2001 From: Patrick O'Brien Date: Mon, 6 Feb 2023 13:14:10 -0500 Subject: [PATCH 10/46] Try installing libegl1 version 22.0.1-1ubuntu2 --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3f1c52f37..10da35fcb 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -37,7 +37,7 @@ jobs: - name: Install Deps run: | python -m pip install -U tox setuptools virtualenv wheel - sudo apt install libglu1-mesa libglu1-mesa-dev libegl1-mesa=22.0.1 libegl1=22.0.1 + sudo apt install libglu1-mesa libglu1-mesa-dev libegl1-mesa=22.0.1-1ubuntu2 libegl1=22.0.1-1ubuntu2 - name: Install and Run Tests run: tox -e py macos-tests: From eb5b94aea8476fbb18e8fdea54b1e3a7fc0bbcfb Mon Sep 17 00:00:00 2001 From: Patrick O'Brien Date: Mon, 6 Feb 2023 13:43:17 -0500 Subject: [PATCH 11/46] Fix libegl1 version to 1.4.0-1 --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 10da35fcb..074dd3d59 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -37,7 +37,7 @@ jobs: - name: Install Deps run: | python -m pip install -U tox setuptools virtualenv wheel - sudo apt install libglu1-mesa libglu1-mesa-dev libegl1-mesa=22.0.1-1ubuntu2 libegl1=22.0.1-1ubuntu2 + sudo apt install libglu1-mesa libglu1-mesa-dev libegl1-mesa=22.0.1-1ubuntu2 libegl1=1.4.0-1 - name: Install and Run Tests run: tox -e py macos-tests: From 94f791cda5a3dae54a67ba5a3884902f5a21b114 Mon Sep 17 00:00:00 2001 From: Patrick O'Brien Date: Mon, 6 Feb 2023 13:55:25 -0500 Subject: [PATCH 12/46] Install libegl-mesa0 version 22.0.1-1ubuntu2 --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 074dd3d59..5329fb677 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -37,7 +37,7 @@ jobs: - name: Install Deps run: | python -m pip install -U tox setuptools virtualenv wheel - sudo apt install libglu1-mesa libglu1-mesa-dev libegl1-mesa=22.0.1-1ubuntu2 libegl1=1.4.0-1 + sudo apt install libglu1-mesa libglu1-mesa-dev libegl-mesa0=22.0.1-1ubuntu2 libegl1-mesa=22.0.1-1ubuntu2 libegl1=1.4.0-1 - name: Install and Run Tests run: tox -e py macos-tests: From 35f31eab85c56792cd05cca027a3a171cff55915 Mon Sep 17 00:00:00 2001 From: Patrick O'Brien Date: Mon, 6 Feb 2023 15:10:53 -0500 Subject: [PATCH 13/46] Run sudo apt update and remove libegl1 dep --- .github/workflows/main.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5329fb677..e2766d4b8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -37,7 +37,8 @@ jobs: - name: Install Deps run: | python -m pip install -U tox setuptools virtualenv wheel - sudo apt install libglu1-mesa libglu1-mesa-dev libegl-mesa0=22.0.1-1ubuntu2 libegl1-mesa=22.0.1-1ubuntu2 libegl1=1.4.0-1 + sudo apt update + sudo apt install libglu1-mesa libglu1-mesa-dev libegl1-mesa - name: Install and Run Tests run: tox -e py macos-tests: From 0cfd93a9d656e396cfb6895d61f8ea620430ee71 Mon Sep 17 00:00:00 2001 From: Patrick O'Brien Date: Tue, 7 Feb 2023 17:17:46 -0500 Subject: [PATCH 14/46] Change some Qt6 class paths --- qiskit_metal/_gui/main_window_base.py | 2 +- qiskit_metal/_gui/utility/_handle_qt_messages.py | 8 ++++---- .../_gui/widgets/bases/QWidget_PlaceholderText.py | 8 ++++---- .../_gui/widgets/edit_component/component_widget.py | 1 - 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/qiskit_metal/_gui/main_window_base.py b/qiskit_metal/_gui/main_window_base.py index 3a6ae411c..ef275ba2a 100644 --- a/qiskit_metal/_gui/main_window_base.py +++ b/qiskit_metal/_gui/main_window_base.py @@ -618,7 +618,7 @@ def kick_start_qApp(): try: from IPython import get_ipython ipython = get_ipython() - ipython.magic('gui qt5') + ipython.magic('gui qt6') except Exception as e: print("exception") diff --git a/qiskit_metal/_gui/utility/_handle_qt_messages.py b/qiskit_metal/_gui/utility/_handle_qt_messages.py index 3dabc342c..f873ce182 100644 --- a/qiskit_metal/_gui/utility/_handle_qt_messages.py +++ b/qiskit_metal/_gui/utility/_handle_qt_messages.py @@ -56,13 +56,13 @@ def _qt_message_handler(mode, context, message): 'QSocketNotifier: Multiple socket notifiers for same socket'): pass # Caused by running %gui qt multiple times else: - if mode == QtCore.QtInfoMsg: + if mode == QtCore.QtMsgType.QtInfoMsg: mode = 'INFO' - elif mode == QtCore.QtWarningMsg: + elif mode == QtCore.QtMsgType.QtWarningMsg: mode = 'WARNING' - elif mode == QtCore.QtCriticalMsg: + elif mode == QtCore.QtMsgType.QtCriticalMsg: mode = 'CRITICAL' - elif mode == QtCore.QtFatalMsg: + elif mode == QtCore.QtMsgType.QtFatalMsg: mode = 'FATAL' else: mode = 'DEBUG' diff --git a/qiskit_metal/_gui/widgets/bases/QWidget_PlaceholderText.py b/qiskit_metal/_gui/widgets/bases/QWidget_PlaceholderText.py index 099beea8b..be2db1bd5 100644 --- a/qiskit_metal/_gui/widgets/bases/QWidget_PlaceholderText.py +++ b/qiskit_metal/_gui/widgets/bases/QWidget_PlaceholderText.py @@ -72,12 +72,12 @@ def update_placeholder_text(self, text=None): palette = self.palette() # This enum value has been introduced in Qt 5.12 if hasattr(palette, 'PlaceholderText'): - placeholder_color = palette.PlaceholderText + placeholder_color = palette.ColorRole.PlaceholderText else: - placeholder_color = palette.WindowText + placeholder_color = palette.ColorRole.WindowText color = palette.color(placeholder_color) - palette.setColor(palette.Text, color) - palette.setColor(palette.Text, color) + palette.setColor(palette.ColorRole.Text, color) + palette.setColor(palette.ColorRole.Text, color) label.setPalette(palette) def show_placeholder_text(self): diff --git a/qiskit_metal/_gui/widgets/edit_component/component_widget.py b/qiskit_metal/_gui/widgets/edit_component/component_widget.py index 403e7e3c3..e7f82e710 100644 --- a/qiskit_metal/_gui/widgets/edit_component/component_widget.py +++ b/qiskit_metal/_gui/widgets/edit_component/component_widget.py @@ -137,7 +137,6 @@ def create_QTextDocument(doc: QtWidgets.QTextEdit) -> QtGui.QTextDocument: font.setStyleHint(QFont.Arial) else: font.setStyleHint(QFont.Courier) - font.setFamily("Courier") document.setDefaultFont(font) return document From 65d34d718681cbdaabd7e3238ab13d1f9474eee1 Mon Sep 17 00:00:00 2001 From: shanto268 Date: Sun, 17 Nov 2024 16:13:13 -0800 Subject: [PATCH 15/46] fix: changed env and qwidget for working gui --- qiskit_metal/tests/test_designs.py | 4 +- qiskit_metal/tests/test_qlibrary_2_options.py | 6 +- qiskit_metal/tests/test_renderers.py | 92 +++++++++++++++++++ 3 files changed, 100 insertions(+), 2 deletions(-) diff --git a/qiskit_metal/tests/test_designs.py b/qiskit_metal/tests/test_designs.py index a021b5936..3cdc312b0 100644 --- a/qiskit_metal/tests/test_designs.py +++ b/qiskit_metal/tests/test_designs.py @@ -503,7 +503,7 @@ def test_design_get_list_of_tables_in_metadata(self): result = q1._get_table_values_from_renderers(design) - self.assertEqual(len(result), 11) + self.assertEqual(len(result), 17) self.assertEqual(result['hfss_inductance'], '10nH') self.assertEqual(result['hfss_capacitance'], 0) self.assertEqual(result['hfss_resistance'], 0) @@ -515,6 +515,8 @@ def test_design_get_list_of_tables_in_metadata(self): self.assertEqual(result['gds_cell_name'], 'my_other_junction') self.assertEqual(result['hfss_wire_bonds'], False) self.assertEqual(result['q3d_wire_bonds'], False) + self.assertEqual(result['aedt_hfss_inductance'], 10e-9) + self.assertEqual(result['aedt_hfss_capacitance'], 0) if __name__ == '__main__': diff --git a/qiskit_metal/tests/test_qlibrary_2_options.py b/qiskit_metal/tests/test_qlibrary_2_options.py index ac5294d44..e99a51987 100644 --- a/qiskit_metal/tests/test_qlibrary_2_options.py +++ b/qiskit_metal/tests/test_qlibrary_2_options.py @@ -487,7 +487,7 @@ def test_qlibrary_transmon_cross_options(self): self.assertEqual(_options['cross_length'], '200um') self.assertEqual(_options['cross_gap'], '20um') - self.assertEqual(len(_options['_default_connection_pads']), 6) + self.assertEqual(len(_options['_default_connection_pads']), 8) self.assertEqual(_options['_default_connection_pads']['connector_type'], '0') self.assertEqual(_options['_default_connection_pads']['claw_length'], @@ -498,6 +498,10 @@ def test_qlibrary_transmon_cross_options(self): '10um') self.assertEqual(_options['_default_connection_pads']['claw_gap'], '6um') + self.assertEqual( + _options['_default_connection_pads']['claw_cpw_length'], '40um') + self.assertEqual(_options['_default_connection_pads']['claw_cpw_width'], + '10um') self.assertEqual( _options['_default_connection_pads']['connector_location'], '0') diff --git a/qiskit_metal/tests/test_renderers.py b/qiskit_metal/tests/test_renderers.py index 8bfd5f47b..b5d6a5d17 100644 --- a/qiskit_metal/tests/test_renderers.py +++ b/qiskit_metal/tests/test_renderers.py @@ -33,6 +33,10 @@ from qiskit_metal.renderers.renderer_gds.gds_renderer import QGDSRenderer from qiskit_metal.renderers.renderer_mpl.mpl_interaction import MplInteraction from qiskit_metal.renderers.renderer_gmsh.gmsh_renderer import QGmshRenderer +from qiskit_metal.renderers.renderer_elmer.elmer_renderer import QElmerRenderer +from qiskit_metal.renderers.renderer_ansys_pyaedt.hfss_renderer_eigenmode_aedt import QHFSSEigenmodePyaedt +from qiskit_metal.renderers.renderer_ansys_pyaedt.hfss_renderer_drivenmodal_aedt import QHFSSDrivenmodalPyaedt +from qiskit_metal.renderers.renderer_ansys_pyaedt.q3d_renderer_aedt import QQ3DPyaedt from qiskit_metal.renderers.renderer_ansys import ansys_renderer @@ -131,6 +135,27 @@ def test_renderer_instantiate_qgmsh_renderer(self): "QGmshRenderer(design, initiate=False, options={}) failed in DesignPLanar" ) + def test_renderer_instantiate_qelmer_renderer(self): + """Test instantiation of QElmerRenderer in elmer_renderer.py.""" + design = designs.MultiPlanar() + try: + QElmerRenderer(design) + except Exception: + self.fail("QElmerRenderer(design) failed") + + try: + QElmerRenderer(design, initiate=False) + except Exception: + self.fail( + "QElmerRenderer(design, initiate=False) failed in MultiPlanar") + + try: + QElmerRenderer(design, initiate=False, options={}) + except Exception: + self.fail( + "QElmerRenderer(design, initiate=False, options={}) failed in MultiPlanar" + ) + def test_renderer_qansys_renderer_options(self): """Test that defaults in QAnsysRenderer were not accidentally changed.""" design = designs.DesignPlanar() @@ -223,6 +248,52 @@ def test_renderer_qansysrenderer_default_setup(self): self.assertEqual(default_setup['q3d']['solution_order'], 'High') self.assertEqual(default_setup['q3d']['solver_type'], 'Iterative') + def test_renderer_qelmer_renderer_default_setup(self): + """Test that default_setup in QElmerRenderer have not been accidentally changed.""" + default_setup = QElmerRenderer.default_setup + + self.assertEqual(len(default_setup), 4) + self.assertEqual(len(default_setup['capacitance']), 12) + self.assertEqual(len(default_setup['eigenmode']), 0) + self.assertEqual(len(default_setup['materials']), 2) + self.assertEqual(len(default_setup['constants']), 2) + + self.assertEqual( + default_setup['capacitance']['Calculate_Electric_Field'], True) + self.assertEqual( + default_setup['capacitance']['Calculate_Electric_Energy'], True) + self.assertEqual( + default_setup['capacitance']['Calculate_Capacitance_Matrix'], True) + self.assertEqual( + default_setup['capacitance']['Capacitance_Matrix_Filename'], + 'cap_matrix.txt') + self.assertEqual(default_setup['capacitance']['Linear_System_Solver'], + 'Iterative') + self.assertEqual( + default_setup['capacitance']['Steady_State_Convergence_Tolerance'], + 1e-05) + self.assertEqual( + default_setup['capacitance'] + ['Nonlinear_System_Convergence_Tolerance'], 1e-07) + self.assertEqual( + default_setup['capacitance']['Nonlinear_System_Max_Iterations'], 20) + self.assertEqual( + default_setup['capacitance']['Linear_System_Convergence_Tolerance'], + 1e-10) + self.assertEqual( + default_setup['capacitance']['Linear_System_Max_Iterations'], 500) + self.assertEqual( + default_setup['capacitance']['Linear_System_Iterative_Method'], + 'BiCGStab') + self.assertEqual( + default_setup['capacitance']['BiCGstabl_polynomial_degree'], 2) + + self.assertEqual(default_setup['materials'], ['vacuum', 'silicon']) + + self.assertEqual(default_setup['constants']['Permittivity_of_Vacuum'], + 8.8542e-12) + self.assertEqual(default_setup['constants']['Unit_Charge'], 1.602e-19) + def test_renderer_qq3d_render_options(self): """Test that defaults in QQ3DRenderer were not accidentally changed.""" design = designs.DesignPlanar() @@ -331,6 +402,21 @@ def test_renderer_qgmsh_renderer_options(self): self.assertEqual(options["colors"]["jj"], (84, 140, 168, 150)) self.assertEqual(options["colors"]["dielectric"], (180, 180, 180, 255)) + def test_renderer_qelmer_renderer_options(self): + """Test that default_options in QElmerRenderer were not accidentally + changed.""" + design = designs.MultiPlanar() + renderer = QElmerRenderer(design) + options = renderer.default_options + + self.assertEqual(len(options), 6) + self.assertEqual(options["simulation_type"], "steady_3D") + self.assertEqual(options["simulation_dir"], "./simdata") + self.assertEqual(options["mesh_file"], "out.msh") + self.assertEqual(options["simulation_input_file"], "case.sif") + self.assertEqual(options["postprocessing_file"], "case.msh") + self.assertEqual(options["output_file"], "case.result") + def test_renderer_ansys_renderer_get_clean_name(self): """Test get_clean_name in ansys_renderer.py""" self.assertEqual(ansys_renderer.get_clean_name('name12'), 'name12') @@ -365,6 +451,12 @@ def test_renderer_qgmsh_renderer_name(self): renderer = QGmshRenderer(design, initiate=False) self.assertEqual(renderer.name, 'gmsh') + def test_renderer_qelmer_renderer_name(self): + """Test name in QElmerRenderer.""" + design = designs.MultiPlanar() + renderer = QElmerRenderer(design, initiate=False) + self.assertEqual(renderer.name, 'elmer') + def test_renderer_gdsrenderer_inclusive_bound(self): """Test functionality of inclusive_bound in gds_renderer.py.""" design = designs.DesignPlanar() From a72617f5214cba15b504167b82476b0b630fba59 Mon Sep 17 00:00:00 2001 From: shanto268 Date: Sun, 17 Nov 2024 16:13:15 -0800 Subject: [PATCH 16/46] fix: changed QWidget_PlaceholderText and environment files --- environment.yml | 2 +- .../table_view_all_components.py | 18 +- .../widgets/bases/QWidget_PlaceholderText.py | 60 +- qiskit_metal/tests/mes.md | 22 + qiskit_metal/tests/run_all_tests.py | 60 +- qiskit_metal/tests/test_results.txt | 1057 +++++++++++++++++ qiskit_metal/tests/test_toolbox_metal.py | 34 +- 7 files changed, 1174 insertions(+), 79 deletions(-) create mode 100644 qiskit_metal/tests/mes.md create mode 100644 qiskit_metal/tests/test_results.txt diff --git a/environment.yml b/environment.yml index 51a30ea01..3097f8864 100644 --- a/environment.yml +++ b/environment.yml @@ -2,7 +2,7 @@ name: qiskit-metal channels: - conda-forge dependencies: - - python>=3.9 + - python=3.10.* - addict - descartes - gdspy>=1.5.2 diff --git a/qiskit_metal/_gui/widgets/all_components/table_view_all_components.py b/qiskit_metal/_gui/widgets/all_components/table_view_all_components.py index 3f659c150..0de6b3e60 100644 --- a/qiskit_metal/_gui/widgets/all_components/table_view_all_components.py +++ b/qiskit_metal/_gui/widgets/all_components/table_view_all_components.py @@ -12,15 +12,14 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. -from typing import TYPE_CHECKING -from typing import List +from typing import TYPE_CHECKING, List from PySide6 import QtCore, QtWidgets from PySide6.QtCore import QModelIndex, Qt, QTimer from PySide6.QtGui import QContextMenuEvent -from PySide6.QtWidgets import (QInputDialog, QLabel, QLineEdit, QMenu, - QMessageBox, QTableView, QVBoxLayout, - QAbstractItemView) +from PySide6.QtWidgets import (QAbstractItemView, QInputDialog, QLabel, + QLineEdit, QMenu, QMessageBox, QTableView, + QVBoxLayout) from ...utility._handle_qt_messages import slot_catch_error from ..bases.QWidget_PlaceholderText import QWidget_PlaceholderText @@ -48,16 +47,17 @@ def __init__(self, parent: QtWidgets.QWidget): parent (QWidget): Parent widget """ QTableView.__init__(self, parent) - QWidget_PlaceholderText.__init__( - self, - "No QComponents to show.\n\nCreate components from the QLibrary.") + QWidget_PlaceholderText.__init__(self, "No QComponents to show.\n\nCreate components from the QLibrary.", self) + + # Connect signals self.clicked.connect(self.viewClicked) self.doubleClicked.connect(self.doDoubleClicked) - # Handling selection dynamically + # Configure selection behavior self.setSelectionMode(QAbstractItemView.ExtendedSelection) self.setSelectionBehavior(QTableView.SelectRows) + # Apply styling QTimer.singleShot(100, self.style2) def style2(self): diff --git a/qiskit_metal/_gui/widgets/bases/QWidget_PlaceholderText.py b/qiskit_metal/_gui/widgets/bases/QWidget_PlaceholderText.py index be2db1bd5..2a4446d72 100644 --- a/qiskit_metal/_gui/widgets/bases/QWidget_PlaceholderText.py +++ b/qiskit_metal/_gui/widgets/bases/QWidget_PlaceholderText.py @@ -12,47 +12,45 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. -from typing import TYPE_CHECKING +from PySide6.QtCore import Qt +from PySide6.QtWidgets import QLabel, QVBoxLayout, QWidget -from PySide6 import QtCore, QtWidgets -from PySide6.QtCore import QModelIndex, Qt -from PySide6.QtGui import QContextMenuEvent -from PySide6.QtWidgets import (QInputDialog, QLineEdit, QMenu, QMessageBox, - QTableView, QLabel, QVBoxLayout, QWidget) +class QWidget_PlaceholderText: + """QTableView or Tree with placeholder text if empty. -class QWidget_PlaceholderText(QWidget): - """QTableView or Tree with palceholder text if empty. - - This class extends the `QWidget` class. + This class acts as a mixin for placeholder text functionality. """ __placeholder_text = "The table is empty." - def __init__(self, placeholder_text: str = None): + def __init__(self, placeholder_text: str = None, parent=None): """ Args: - placeholder_text (str): Placeholder text.. Defaults to None. + placeholder_text (str): Placeholder text. Defaults to None. + parent: Parent widget. """ self._placeholder_text = placeholder_text if placeholder_text else self.__placeholder_text + self._placeholder_label = QLabel(self._placeholder_text, parent) + self.setup_placeholder_label(parent) - self._placeholder_label = QLabel(self._placeholder_text, self) - self.setup_placeholder_label() - - def setup_placeholder_label(self): - """QComponents will be displayed here when you create them.""" + def setup_placeholder_label(self, parent): + """Set up the placeholder label.""" + # Update placeholder text self.update_placeholder_text() - if not self.layout(): - layout = QVBoxLayout() - self.setLayout(layout) + # Ensure layout is present + if parent and not parent.layout(): + layout = QVBoxLayout(parent) + parent.setLayout(layout) - self.layout().addWidget(self._placeholder_label) + if parent: + parent.layout().addWidget(self._placeholder_label) def update_placeholder_text(self, text=None): """Update the placeholder text to the given string. Args: - text (str): New placeholder text.. Defaults to None. + text (str): New placeholder text. Defaults to None. """ if text: self._placeholder_text = text @@ -60,23 +58,15 @@ def update_placeholder_text(self, text=None): label = self._placeholder_label label.setText(self._placeholder_text) - # Text + # Styling label.setWordWrap(True) label.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter) - - # transperant label.setAutoFillBackground(False) label.setAttribute(Qt.WA_TranslucentBackground) - # color PlaceholderText - palette = self.palette() - # This enum value has been introduced in Qt 5.12 - if hasattr(palette, 'PlaceholderText'): - placeholder_color = palette.ColorRole.PlaceholderText - else: - placeholder_color = palette.ColorRole.WindowText - color = palette.color(placeholder_color) - palette.setColor(palette.ColorRole.Text, color) + # Placeholder text color + palette = self._placeholder_label.palette() + color = palette.color(palette.ColorRole.WindowText) # Correct usage palette.setColor(palette.ColorRole.Text, color) label.setPalette(palette) @@ -86,4 +76,4 @@ def show_placeholder_text(self): def hide_placeholder_text(self): """Hide the placeholder text.""" - self._placeholder_label.hide() + self._placeholder_label.hide() \ No newline at end of file diff --git a/qiskit_metal/tests/mes.md b/qiskit_metal/tests/mes.md new file mode 100644 index 000000000..2ec6a0672 --- /dev/null +++ b/qiskit_metal/tests/mes.md @@ -0,0 +1,22 @@ +Hi @zlatko-minev, + +Upon running some initial tests, it does not seem like the `pyside6-port` branch is ready to be merged... Below is a brief report summarizing the issues observed during the testing process: + +## Environment + +- **System:** macOS 15.1 +- **Python Version:** 3.10.6 (via Conda environment with Anaconda3 as the manager) +- **Setup:** Tested in a fresh Conda environment using the `environment.yml` file in the PR branch. +- **Tests:** + - Executed using `run_all_tests.py` + - Design workflow files used in our lab that work with the current `main` branch + +--- + + +## Issues + +**tldr;** + +[Explain the issues and link to the txt file for the entire error log] + diff --git a/qiskit_metal/tests/run_all_tests.py b/qiskit_metal/tests/run_all_tests.py index ca142ac20..29db43701 100644 --- a/qiskit_metal/tests/run_all_tests.py +++ b/qiskit_metal/tests/run_all_tests.py @@ -12,7 +12,6 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. """Qiskit Metal main unit test functionality.""" - import os import fnmatch import sys @@ -23,20 +22,47 @@ PATTERN = "test*.py" print("====> Running the entire test suite now...") ERRORS_EXIST = 0 - for entry in LIST_OF_FILES: - if fnmatch.fnmatch(entry, PATTERN): - if entry != sys.argv[0]: - print("Running ", entry, " tests...") - cmd = 'python ' + entry - ERROR_BACK = subprocess.call(cmd, shell=True) - if ERROR_BACK != 3221225477: # access violation - ERRORS_EXIST += ERROR_BACK - print("") - print("All tests complete") - if ERRORS_EXIST == 0: - print("Congratulations, all the tests PASSED!") - print("Have a nice day...") - else: - print("One or more tests have FAILED!") - print("Scroll up to review the results") + # Open log files + with open("test_results.log", "w") as results_log, open("test_errors.log", "w") as errors_log: + for entry in LIST_OF_FILES: + if fnmatch.fnmatch(entry, PATTERN): + if entry != sys.argv[0]: + print(f"Running {entry} tests...") + results_log.write(f"Running {entry} tests...\n") + + # Run the test and capture output + result = subprocess.run( + f"python {entry}", + shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True + ) + + # Write the stdout and stderr to test_results.log + results_log.write(result.stdout) + results_log.write(result.stderr) + results_log.write("\n") + + # If there's an error, write it to test_errors.log + if result.returncode != 0: + ERRORS_EXIST += 1 + errors_log.write(f"Error in {entry}:\n") + errors_log.write(result.stderr) + errors_log.write("\n") + + print("") + + print("All tests complete") + results_log.write("All tests complete\n") + if ERRORS_EXIST == 0: + print("Congratulations, all the tests PASSED!") + print("Have a nice day...") + results_log.write("Congratulations, all the tests PASSED!\n") + results_log.write("Have a nice day...\n") + else: + print("One or more tests have FAILED!") + print("Scroll up to review the results") + results_log.write("One or more tests have FAILED!\n") + results_log.write("Scroll up to review the results\n") diff --git a/qiskit_metal/tests/test_results.txt b/qiskit_metal/tests/test_results.txt new file mode 100644 index 000000000..586b4fb36 --- /dev/null +++ b/qiskit_metal/tests/test_results.txt @@ -0,0 +1,1057 @@ +test_qlibrary_short_to_ground_component_metadata (__main__.TestComponentFunctionality.test_qlibrary_short_to_ground_component_metadata) +Test component_metadata in component/short_to_ground.py. ... ok +test_qlibrary_squid_loop_component_metadata (__main__.TestComponentFunctionality.test_qlibrary_squid_loop_component_metadata) +Test component_metadata in qubits.squid_loop.py. ... ok +test_qlibrary_star_qubit_component_metadata (__main__.TestComponentFunctionality.test_qlibrary_star_qubit_component_metadata) +Test component_metadata in qubits.transmon_cross.py. ... ok +test_qlibrary_straight_path_component_metadata (__main__.TestComponentFunctionality.test_qlibrary_straight_path_component_metadata) +Test component_metadata in tlines/straight_path.py. ... ok +test_qlibrary_template_component_metadata (__main__.TestComponentFunctionality.test_qlibrary_template_component_metadata) +Test component_metadata in _template.py. ... ok +test_qlibrary_transmon_coupler_01_component_metadata (__main__.TestComponentFunctionality.test_qlibrary_transmon_coupler_01_component_metadata) +Test component_metadata in qubits.tunable_coupler_01.py. ... ok +test_qlibrary_transmon_cross_component_metadata (__main__.TestComponentFunctionality.test_qlibrary_transmon_cross_component_metadata) +Test component_metadata in qubits.transmon_cross.py. ... ok +test_qlibrary_transmon_cross_fl_component_metadata (__main__.TestComponentFunctionality.test_qlibrary_transmon_cross_fl_component_metadata) +Test component_metadata in qubits.transmon_cross_fl.py. ... ok +test_qlibrary_transmon_pocket_6_component_metadata (__main__.TestComponentFunctionality.test_qlibrary_transmon_pocket_6_component_metadata) +Test component_metadata in qubits.transmon_pcket_6.py. ... ok +test_qlibrary_transmon_pocket_cl_component_metadata (__main__.TestComponentFunctionality.test_qlibrary_transmon_pocket_cl_component_metadata) +Test component_metadata in qubits/transmon_pocket_cl.py. ... ok +test_qlibrary_transmon_pocket_component_metadata (__main__.TestComponentFunctionality.test_qlibrary_transmon_pocket_component_metadata) +Test component_metadata in qubits.transmon_pocket.py. ... ok +test_qlibrary_transmon_pocket_teeth_component_metadata (__main__.TestComponentFunctionality.test_qlibrary_transmon_pocket_teeth_component_metadata) +Test component_metadata in qubits.transmon_pcket_teeth.py. ... ok + +---------------------------------------------------------------------- +Ran 38 tests in 0.194s + +OK +test_design_all_component_names_id (__main__.TestDesign.test_design_all_component_names_id) +Test all_component_names_id functionality in design_base.py. ... ok +test_design_connect_pins (__main__.TestDesign.test_design_connect_pins) +Test connect_pins functionality in design_base.py. ... ok +test_design_copy_multiple_qcomponents (__main__.TestDesign.test_design_copy_multiple_qcomponents) +Test the functionality of copy_multiple_qcomponents in ... ok +test_design_copy_qcomponent (__main__.TestDesign.test_design_copy_qcomponent) +Test the functionlaity of copy_qcomponent in design_base.py. ... ok +test_design_default_component_name (__main__.TestDesign.test_design_default_component_name) +Test automatic naming of components. ... 02:34PM 53s WARNING [rename_component]: Called design.rename_component, component_id(3, is already using res_3. +ok +test_design_delete_all_components (__main__.TestDesign.test_design_delete_all_components) +Test deleteing a component in design_base.py. ... ok +test_design_delete_all_pins (__main__.TestDesign.test_design_delete_all_pins) +Test delete_all_pins functionality in design_base.py. ... ok +test_design_delete_component (__main__.TestDesign.test_design_delete_component) +Test deleteing a component in design_base.py. ... ok +test_design_get_and_set_design_name (__main__.TestDesign.test_design_get_and_set_design_name) +Test getting the design name in design_base.py. ... ok +test_design_get_chip_layer (__main__.TestDesign.test_design_get_chip_layer) +Test getting chip size in design_base.py. ... ok +test_design_get_chip_size (__main__.TestDesign.test_design_get_chip_size) +Test getting chip size in design_base.py. ... ok +test_design_get_chip_z (__main__.TestDesign.test_design_get_chip_z) +Test getting chip z in design_base.py. ... ok +test_design_get_list_of_tables_in_metadata (__main__.TestDesign.test_design_get_list_of_tables_in_metadata) +Tests the get_list_of_tables_in_metadata function in design_base.py ... ok +test_design_get_new_qcomponent_name_id (__main__.TestDesign.test_design_get_new_qcomponent_name_id) +Test _get_new_qcomponent_name_id in design_base.py. ... ok +test_design_get_units (__main__.TestDesign.test_design_get_units) +Test get units in design_base.py. ... ok +test_design_instantiate_design_components (__main__.TestDesign.test_design_instantiate_design_components) +Test the instantiation of Components. ... ok +test_design_instantiate_design_planar (__main__.TestDesign.test_design_instantiate_design_planar) +Test the instantiation of DesignPlanar. ... ok +test_design_instantiate_qdesign (__main__.TestDesign.test_design_instantiate_qdesign) +Test the instantiation of QDesign. ... ok +test_design_instantiate_qnet (__main__.TestDesign.test_design_instantiate_qnet) +Test the instantiation of QNet. ... ok +test_design_interface_components_find_id (__main__.TestDesign.test_design_interface_components_find_id) +Test finding the id from the name in interface_components.py. ... 02:34PM 53s WARNING [find_id]: In Components.find_id(), the name=my_name-3 is not used in design._components +ok +test_design_interface_components_get_list_ints (__main__.TestDesign.test_design_interface_components_get_list_ints) +Test geting the list ints in interface_components.py. ... 02:34PM 53s WARNING [find_id]: In Components.find_id(), the name=nope is not used in design._components +ok +test_design_planar_get_x_y_for_chip (__main__.TestDesign.test_design_planar_get_x_y_for_chip) +Test get_x_y_for_chip in design_planar.py. ... ok +test_design_qnet_add_pins_to_table (__main__.TestDesign.test_design_qnet_add_pins_to_table) +Test add_pins_to_table in net_info.py. ... ok +test_design_qnet_delete_all_pins_for_component_id (__main__.TestDesign.test_design_qnet_delete_all_pins_for_component_id) +Test delete all pins for a given component id in net_info.py. ... ok +test_design_qnet_delete_net_id (__main__.TestDesign.test_design_qnet_delete_net_id) +Test delete a given net id in net_info.py. ... ok +test_design_qnet_get_components_and_pins_for_netid (__main__.TestDesign.test_design_qnet_get_components_and_pins_for_netid) +Test get_components_Sand_pins_for_netid in net_info.py. ... ok +test_design_rename_component (__main__.TestDesign.test_design_rename_component) +Test renaming component in design_base.py. ... ok +test_design_rename_variable (__main__.TestDesign.test_design_rename_variable) +Test rename_variable in QDesign class ... ok +test_design_rename_variables (__main__.TestDesign.test_design_rename_variables) +Test variable renaming in design_base.py. ... ok +test_design_update_metadata (__main__.TestDesign.test_design_update_metadata) +Test the update of metadata in design_base.py. ... ok + +---------------------------------------------------------------------- +Ran 30 tests in 0.515s + +OK +test_renderer_ansys_renderer_element_table_data (__main__.TestRenderers.test_renderer_ansys_renderer_element_table_data) +Test element_table_data in QAnsysRenderer. ... ok +test_renderer_ansys_renderer_get_clean_name (__main__.TestRenderers.test_renderer_ansys_renderer_get_clean_name) +Test get_clean_name in ansys_renderer.py ... ok +test_renderer_ansys_renderer_name (__main__.TestRenderers.test_renderer_ansys_renderer_name) +Test name in QAnsysRenderer. ... ok +test_renderer_ansys_renderer_name_delim (__main__.TestRenderers.test_renderer_ansys_renderer_name_delim) +Test NAME_DELIM in QAnsysRenderer. ... ok +test_renderer_gds_check_cheese (__main__.TestRenderers.test_renderer_gds_check_cheese) +Test check_cheese in gds_renderer.py. ... ok +test_renderer_gds_check_either_cheese (__main__.TestRenderers.test_renderer_gds_check_either_cheese) +Test check_either_cheese in gds_renderer.py. ... 02:34PM 56s WARNING [_check_either_cheese]: layer=0 is not in chip=main either in no_cheese_view_in_file or cheese_view_in_file from self.options. +02:34PM 56s WARNING [_check_either_cheese]: Chip=fake is not either in no_cheese_view_in_file or cheese_view_in_file from self.options. +ok +test_renderer_gds_check_no_cheese (__main__.TestRenderers.test_renderer_gds_check_no_cheese) +Test check_no_cheese in gds_renderer.py. ... ok +test_renderer_gdsrenderer_check_qcomps (__main__.TestRenderers.test_renderer_gdsrenderer_check_qcomps) +Test check_qcomps in gds_renderer.py. ... 02:34PM 56s WARNING [_check_qcomps]: The component=Q2 in highlight_qcomponents not in QDesign. The GDS data not generated. +02:34PM 56s WARNING [_check_qcomps]: The component=Q2 in highlight_qcomponents not in QDesign. The GDS data not generated. +ok +test_renderer_gdsrenderer_high_level (__main__.TestRenderers.test_renderer_gdsrenderer_high_level) +Test that high level defaults were not accidentally changed in ... ok +test_renderer_gdsrenderer_inclusive_bound (__main__.TestRenderers.test_renderer_gdsrenderer_inclusive_bound) +Test functionality of inclusive_bound in gds_renderer.py. ... ok +test_renderer_gdsrenderer_midpoint_xy (__main__.TestRenderers.test_renderer_gdsrenderer_midpoint_xy) +Test midpoint_xy in gds_renderer.py. ... ok +test_renderer_gdsrenderer_options (__main__.TestRenderers.test_renderer_gdsrenderer_options) +Test that default_options in QGDSRenderer were not accidentally ... ok +test_renderer_gdsrenderer_update_units (__main__.TestRenderers.test_renderer_gdsrenderer_update_units) +Test update_units in gds_renderer.py. ... ok +test_renderer_get_chip_names (__main__.TestRenderers.test_renderer_get_chip_names) +Test functionality of get_chip_names in gds_renderer.py. ... ok +test_renderer_hfss_render_options (__main__.TestRenderers.test_renderer_hfss_render_options) +Test that defaults in QHFSSRender were not accidentally changed. ... ok +test_renderer_instanitate_qansys_renderer (__main__.TestRenderers.test_renderer_instanitate_qansys_renderer) +Test instantiation of QAnsysRenderer in ansys_renderer.py ... ok +test_renderer_instantiate_gdsrender (__main__.TestRenderers.test_renderer_instantiate_gdsrender) +Test instantiation of QGDSRenderer in gds_renderer.py. ... ok +test_renderer_instantiate_mplinteraction (__main__.TestRenderers.test_renderer_instantiate_mplinteraction) +Test instantiation of MplInteraction in mpl_interaction.py. ... ok +test_renderer_instantiate_qgmsh_renderer (__main__.TestRenderers.test_renderer_instantiate_qgmsh_renderer) +Test instantiation of QGmshRenderer in gmsh_renderer.py. ... ok +test_renderer_instantiate_qhfss_renderer (__main__.TestRenderers.test_renderer_instantiate_qhfss_renderer) +Test instantiation of QHFSSRenderer in hfss_renderer.py. ... ok +test_renderer_instantiate_qq3d_renderer (__main__.TestRenderers.test_renderer_instantiate_qq3d_renderer) +Test instantiation of QQ3DRenderer in q3d_renderer.py. ... ok +test_renderer_mpl_interaction_disconnect (__main__.TestRenderers.test_renderer_mpl_interaction_disconnect) +Test disconnect in MplInteraction in mpl_interaction.py. ... ok +test_renderer_qansys_renderer_options (__main__.TestRenderers.test_renderer_qansys_renderer_options) +Test that defaults in QAnsysRenderer were not accidentally changed. ... ok +test_renderer_qansysrenderer_default_setup (__main__.TestRenderers.test_renderer_qansysrenderer_default_setup) +Test that default_setup in QAnsysRenderer have not been accidentally changed. ... ok +test_renderer_qgmsh_renderer_name (__main__.TestRenderers.test_renderer_qgmsh_renderer_name) +Test name in QGmshRenderer. ... ok +test_renderer_qgmsh_renderer_options (__main__.TestRenderers.test_renderer_qgmsh_renderer_options) +Test that default_options in QGmshRenderer were not accidentally ... Warning : Gmsh has aleady been initialized +ok +test_renderer_qq3d_render_options (__main__.TestRenderers.test_renderer_qq3d_render_options) +Test that defaults in QQ3DRenderer were not accidentally changed. ... ok +test_renderer_renderer_base_element_table_data (__main__.TestRenderers.test_renderer_renderer_base_element_table_data) +Test element_table_data in QRenderer. ... ok +test_renderer_renderer_base_name (__main__.TestRenderers.test_renderer_renderer_base_name) +Test name in QRenderer. ... ok +test_renderer_renderer_gui_base_name (__main__.TestRenderers.test_renderer_renderer_gui_base_name) +Test name in QRenderer. ... ok +test_renderer_scale_max_bounds (__main__.TestRenderers.test_renderer_scale_max_bounds) +Test functionality of scale_max_bounds in gds_renderer.py. ... ok +test_renderer_setup_renderers (__main__.TestRenderers.test_renderer_setup_renderers) +Test setup_renderers in setup_defauts.py. ... ok +test_successful_get_convergence (__main__.TestRenderers.test_successful_get_convergence) +Test get_convergence returns the correct Boolean when converged ... ok +test_unsuccessful_get_convergence (__main__.TestRenderers.test_unsuccessful_get_convergence) +Test get_convergence returns the correct Boolean when not converged ... ok + +---------------------------------------------------------------------- +Ran 34 tests in 0.279s + +OK +test_toolbox_metal_about (__main__.TestToolboxMetal.test_toolbox_metal_about) +Test that about in about.py produces about text without any ... ok +test_toolbox_metal_aligned_pts (__main__.TestToolboxMetal.test_toolbox_metal_aligned_pts) +Test functionality of aligned_pts in toolbox_metal.py. ... ok +test_toolbox_metal_are_all_chipnames_in_design (__main__.TestToolboxMetal.test_toolbox_metal_are_all_chipnames_in_design) +Test functionality of are_all_chipnames_in_design in toolbox_metal.py. ... 02:34PM 59s ERROR [_init_dataframe]: Not able to read file.File:/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/qiskit_metal/tests/test_data/planar_chip.txt not read. Check the name and path. +ERROR +test_toolbox_metal_chip_names_not_in_design (__main__.TestToolboxMetal.test_toolbox_metal_chip_names_not_in_design) +Test functionality of chip_names_not_in_design in toolbox_metal.py. ... 02:34PM 59s ERROR [_init_dataframe]: Not able to read file.File:/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/qiskit_metal/tests/test_data/planar_chip.txt not read. Check the name and path. +ERROR +test_toolbox_metal_chip_size_not_in_chipname_within_design (__main__.TestToolboxMetal.test_toolbox_metal_chip_size_not_in_chipname_within_design) +Test functionality of chip_size_not_in_chipname_within_design in toolbox_metal.py. ... 02:34PM 59s ERROR [_init_dataframe]: Not able to read file.File:/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/qiskit_metal/tests/test_data/planar_chip.txt not read. Check the name and path. +ERROR +test_toolbox_metal_cross (__main__.TestToolboxMetal.test_toolbox_metal_cross) +Test functionality of cross in toolbox_metal.py. ... ok +test_toolbox_metal_determine_larger_box (__main__.TestToolboxMetal.test_toolbox_metal_determine_larger_box) +Test functionality of determine_larger_box in toolbox_metal.py. ... ok +test_toolbox_metal_dot (__main__.TestToolboxMetal.test_toolbox_metal_dot) +Test functionality of dot in toolbox_metal.py. ... ok +test_toolbox_metal_ensure_component_box_smaller_than_chip_box_ (__main__.TestToolboxMetal.test_toolbox_metal_ensure_component_box_smaller_than_chip_box_) +Test functionality of ensure_component_box_smaller_than_chip_box in toolbox_metal.py ... 02:34PM 59s ERROR [_init_dataframe]: Not able to read file.File:/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/qiskit_metal/tests/test_data/planar_chip.txt not read. Check the name and path. +ERROR +test_toolbox_metal_extract_value_unit (__main__.TestToolboxMetal.test_toolbox_metal_extract_value_unit) +Test functionality of extract_value_unit in toolbox_metal.py. ... ok +test_toolbox_metal_fix_units (__main__.TestToolboxMetal.test_toolbox_metal_fix_units) +Test functionality of fix_units in toolbox_metal.py. ... ok +test_toolbox_metal_get_bounds_of_path_and_poly_tables (__main__.TestToolboxMetal.test_toolbox_metal_get_bounds_of_path_and_poly_tables) +Test functionality of get_bounds_of_path_and_poly_tables in toolbox_metal.py ... 02:34PM 59s ERROR [_init_dataframe]: Not able to read file.File:/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/qiskit_metal/tests/test_data/planar_chip.txt not read. Check the name and path. +ERROR +test_toolbox_metal_get_box_for_xy_bounds (__main__.TestToolboxMetal.test_toolbox_metal_get_box_for_xy_bounds) +Test functionality of get_box_for_xy_bounds in toolbox_metal.py. ... 02:34PM 59s ERROR [_init_dataframe]: Not able to read file.File:/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/qiskit_metal/tests/test_data/planar_chip.txt not read. Check the name and path. +ERROR +test_toolbox_metal_get_layer_datatype_when_fill_is_true (__main__.TestToolboxMetal.test_toolbox_metal_get_layer_datatype_when_fill_is_true) +Test functionality of get_layer_datatype_when_fill_is_true in toolbox_metal.py. ... 02:34PM 59s ERROR [_init_dataframe]: Not able to read file.File:/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/qiskit_metal/tests/test_data/planar_chip.txt not read. Check the name and path. +ERROR +test_toolbox_metal_get_platform_info (__main__.TestToolboxMetal.test_toolbox_metal_get_platform_info) +Test that get_platform_info in about.py returns a string with the platform information without any errors. ... ok +test_toolbox_metal_get_properties_for_layer_datatype (__main__.TestToolboxMetal.test_toolbox_metal_get_properties_for_layer_datatype) +Test functionality of get_properties_for_layer_datatype in toolbox_metal.py. ... 02:34PM 59s ERROR [_init_dataframe]: Not able to read file.File:/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/qiskit_metal/tests/test_data/planar_chip.txt not read. Check the name and path. +ERROR +test_toolbox_metal_get_unique_chip_names (__main__.TestToolboxMetal.test_toolbox_metal_get_unique_chip_names) +Test functionality of get_unique_chip_names in toolbox_metal.py. ... 02:34PM 59s ERROR [_init_dataframe]: Not able to read file.File:/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/qiskit_metal/tests/test_data/planar_chip.txt not read. Check the name and path. +ERROR +test_toolbox_metal_get_unique_layer_ints (__main__.TestToolboxMetal.test_toolbox_metal_get_unique_layer_ints) +Test functionality of get_unique_layer_ints in toolbox_metal.py. ... 02:34PM 59s ERROR [_init_dataframe]: Not able to read file.File:/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/qiskit_metal/tests/test_data/planar_chip.txt not read. Check the name and path. +ERROR +test_toolbox_metal_get_x_y_for_chip (__main__.TestToolboxMetal.test_toolbox_metal_get_x_y_for_chip) +Test functionality of get_x_y_for_chip in toolbox_metal.py. ... 02:34PM 59s ERROR [_init_dataframe]: Not able to read file.File:/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/qiskit_metal/tests/test_data/planar_chip.txt not read. Check the name and path. +ERROR +test_toolbox_metal_instantiation_incorrect_qt_exception (__main__.TestToolboxMetal.test_toolbox_metal_instantiation_incorrect_qt_exception) +Test instantiation of IncorrectQtException. ... ok +test_toolbox_metal_instantiation_input_error (__main__.TestToolboxMetal.test_toolbox_metal_instantiation_input_error) +Test instantiation of InputError. ... ok +test_toolbox_metal_instantiation_qiskit_metal_design_error (__main__.TestToolboxMetal.test_toolbox_metal_instantiation_qiskit_metal_design_error) +Test instantiation of QiskitMetalDesignError. ... ok +test_toolbox_metal_instantiation_qiskit_metal_exceptions (__main__.TestToolboxMetal.test_toolbox_metal_instantiation_qiskit_metal_exceptions) +Test instantiation of QiskitMetalExceptions. ... ok +test_toolbox_metal_instantiation_qlibrary_gui_exception (__main__.TestToolboxMetal.test_toolbox_metal_instantiation_qlibrary_gui_exception) +Test instantiation of QLibraryGUIException. ... ok +test_toolbox_metal_is_for_ast_eval (__main__.TestToolboxMetal.test_toolbox_metal_is_for_ast_eval) +Test is_for_ast_eval in toolbox_metal.py. ... ok +test_toolbox_metal_is_layer_data_unique (__main__.TestToolboxMetal.test_toolbox_metal_is_layer_data_unique) +Test functionality of is_layer_data_unique in toolbox_metal.py. ... 02:34PM 59s ERROR [_init_dataframe]: Not able to read file.File:/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/qiskit_metal/tests/test_data/planar_chip.txt not read. Check the name and path. +ERROR +test_toolbox_metal_is_numeric_possible (__main__.TestToolboxMetal.test_toolbox_metal_is_numeric_possible) +Test is_numeric_possible in toolbox_metal.py. ... ok +test_toolbox_metal_is_true (__main__.TestToolboxMetal.test_toolbox_metal_is_true) +Test is_true in toolbox_metal.py. ... ok +test_toolbox_metal_is_variable_name (__main__.TestToolboxMetal.test_toolbox_metal_is_variable_name) +Test is_variable_name in toolbox_metal.py. ... ok +test_toolbox_metal_layer_stack_handler_pilot_error (__main__.TestToolboxMetal.test_toolbox_metal_layer_stack_handler_pilot_error) +Test functionality of layer_stack_handler_pilot_error in toolbox_metal.py. ... 02:34PM 59s ERROR [_init_dataframe]: Not able to read file.File:/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/qiskit_metal/tests/test_data/planar_chip.txt not read. Check the name and path. +ERROR +test_toolbox_metal_open_docs (__main__.TestToolboxMetal.test_toolbox_metal_open_docs) +Test that open_docs in about.py opens qiskit_metal documentation in HTML without any ... ok +test_toolbox_metal_parse_entry (__main__.TestToolboxMetal.test_toolbox_metal_parse_entry) +Test functionality of parse_entry in toolbox_metal.py. ... ok +test_toolbox_metal_parse_options (__main__.TestToolboxMetal.test_toolbox_metal_parse_options) +Test parse_options in toolbox_metal.py. ... ok +test_toolbox_metal_parse_string_to_float (__main__.TestToolboxMetal.test_toolbox_metal_parse_string_to_float) +Test _parse_string_to_float in toolbox_metal.py. ... ok +test_toolbox_metal_parse_units (__main__.TestToolboxMetal.test_toolbox_metal_parse_units) +Test functionality of parse_units in toolbox_metal.py. ... ok +test_toolbox_metal_parse_value (__main__.TestToolboxMetal.test_toolbox_metal_parse_value) +Test parse_value in toolbox_metal.py. ... ok +test_toolbox_metal_parsing_true_str (__main__.TestToolboxMetal.test_toolbox_metal_parsing_true_str) +Test that TRUE_STR in parsing.py has not accidentally changed. ... ok +test_toolbox_metal_read_csv_df (__main__.TestToolboxMetal.test_toolbox_metal_read_csv_df) +Test functionality of read_csv_df in toolbox_metal.py. ... 02:34PM 59s ERROR [_init_dataframe]: Not able to read file.File:/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/qiskit_metal/tests/test_data/planar_chip.txt not read. Check the name and path. +ERROR +test_toolbox_metal_round (__main__.TestToolboxMetal.test_toolbox_metal_round) +Test functionality of round in toolbox_metal.py. ... ok +test_toolbox_metal_set_decimal_precision (__main__.TestToolboxMetal.test_toolbox_metal_set_decimal_precision) +Test functionality of set_decimal_precision in toolbox_metal.py. ... ok +test_toolbox_metal_warning_properties (__main__.TestToolboxMetal.test_toolbox_metal_warning_properties) +Test functionality of _warning_properties in toolbox_metal.py. ... 02:34PM 59s ERROR [_init_dataframe]: Not able to read file.File:/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/qiskit_metal/tests/test_data/planar_chip.txt not read. Check the name and path. +ERROR +test_toolbox_metal_warning_search (__main__.TestToolboxMetal.test_toolbox_metal_warning_search) +Test functionality of _warning_search in toolbox_metal.py. ... 02:34PM 59s ERROR [_init_dataframe]: Not able to read file.File:/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/qiskit_metal/tests/test_data/planar_chip.txt not read. Check the name and path. +ERROR +test_toolbox_metal_warning_search_minus_chip (__main__.TestToolboxMetal.test_toolbox_metal_warning_search_minus_chip) +Test functionality of _warning_search_minus_chip in toolbox_metal.py. ... 02:34PM 59s ERROR [_init_dataframe]: Not able to read file.File:/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/qiskit_metal/tests/test_data/planar_chip.txt not read. Check the name and path. +ERROR + +====================================================================== +ERROR: test_toolbox_metal_are_all_chipnames_in_design (__main__.TestToolboxMetal.test_toolbox_metal_are_all_chipnames_in_design) +Test functionality of are_all_chipnames_in_design in toolbox_metal.py. +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/test_toolbox_metal.py", line 473, in test_toolbox_metal_are_all_chipnames_in_design + multiplanar_design = MultiPlanar(metadata={}, + ^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 59, in __init__ + self.ls = self._add_layer_stack() + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 77, in _add_layer_stack + return LayerStackHandler(self) + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 62, in __init__ + self.is_layer_data_unique() + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 215, in is_layer_data_unique + layer_nums = self.get_unique_layer_ints() + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 256, in get_unique_layer_ints + layers = self.ls_df['layer'] + ~~~~~~~~~~^^^^^^^^^ +TypeError: 'NoneType' object is not subscriptable + +====================================================================== +ERROR: test_toolbox_metal_chip_names_not_in_design (__main__.TestToolboxMetal.test_toolbox_metal_chip_names_not_in_design) +Test functionality of chip_names_not_in_design in toolbox_metal.py. +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/test_toolbox_metal.py", line 541, in test_toolbox_metal_chip_names_not_in_design + multiplanar_design = MultiPlanar(metadata={}, + ^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 59, in __init__ + self.ls = self._add_layer_stack() + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 77, in _add_layer_stack + return LayerStackHandler(self) + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 62, in __init__ + self.is_layer_data_unique() + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 215, in is_layer_data_unique + layer_nums = self.get_unique_layer_ints() + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 256, in get_unique_layer_ints + layers = self.ls_df['layer'] + ~~~~~~~~~~^^^^^^^^^ +TypeError: 'NoneType' object is not subscriptable + +====================================================================== +ERROR: test_toolbox_metal_chip_size_not_in_chipname_within_design (__main__.TestToolboxMetal.test_toolbox_metal_chip_size_not_in_chipname_within_design) +Test functionality of chip_size_not_in_chipname_within_design in toolbox_metal.py. +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/test_toolbox_metal.py", line 567, in test_toolbox_metal_chip_size_not_in_chipname_within_design + multiplanar_design = MultiPlanar(metadata={}, + ^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 59, in __init__ + self.ls = self._add_layer_stack() + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 77, in _add_layer_stack + return LayerStackHandler(self) + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 62, in __init__ + self.is_layer_data_unique() + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 215, in is_layer_data_unique + layer_nums = self.get_unique_layer_ints() + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 256, in get_unique_layer_ints + layers = self.ls_df['layer'] + ~~~~~~~~~~^^^^^^^^^ +TypeError: 'NoneType' object is not subscriptable + +====================================================================== +ERROR: test_toolbox_metal_ensure_component_box_smaller_than_chip_box_ (__main__.TestToolboxMetal.test_toolbox_metal_ensure_component_box_smaller_than_chip_box_) +Test functionality of ensure_component_box_smaller_than_chip_box in toolbox_metal.py +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/test_toolbox_metal.py", line 399, in test_toolbox_metal_ensure_component_box_smaller_than_chip_box_ + multiplanar_design = MultiPlanar(metadata={}, + ^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 59, in __init__ + self.ls = self._add_layer_stack() + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 77, in _add_layer_stack + return LayerStackHandler(self) + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 62, in __init__ + self.is_layer_data_unique() + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 215, in is_layer_data_unique + layer_nums = self.get_unique_layer_ints() + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 256, in get_unique_layer_ints + layers = self.ls_df['layer'] + ~~~~~~~~~~^^^^^^^^^ +TypeError: 'NoneType' object is not subscriptable + +====================================================================== +ERROR: test_toolbox_metal_get_bounds_of_path_and_poly_tables (__main__.TestToolboxMetal.test_toolbox_metal_get_bounds_of_path_and_poly_tables) +Test functionality of get_bounds_of_path_and_poly_tables in toolbox_metal.py +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/test_toolbox_metal.py", line 367, in test_toolbox_metal_get_bounds_of_path_and_poly_tables + multiplanar_design = MultiPlanar(metadata={}, + ^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 59, in __init__ + self.ls = self._add_layer_stack() + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 77, in _add_layer_stack + return LayerStackHandler(self) + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 62, in __init__ + self.is_layer_data_unique() + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 215, in is_layer_data_unique + layer_nums = self.get_unique_layer_ints() + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 256, in get_unique_layer_ints + layers = self.ls_df['layer'] + ~~~~~~~~~~^^^^^^^^^ +TypeError: 'NoneType' object is not subscriptable + +====================================================================== +ERROR: test_toolbox_metal_get_box_for_xy_bounds (__main__.TestToolboxMetal.test_toolbox_metal_get_box_for_xy_bounds) +Test functionality of get_box_for_xy_bounds in toolbox_metal.py. +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/test_toolbox_metal.py", line 440, in test_toolbox_metal_get_box_for_xy_bounds + multiplanar_design = MultiPlanar(metadata={}, + ^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 59, in __init__ + self.ls = self._add_layer_stack() + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 77, in _add_layer_stack + return LayerStackHandler(self) + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 62, in __init__ + self.is_layer_data_unique() + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 215, in is_layer_data_unique + layer_nums = self.get_unique_layer_ints() + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 256, in get_unique_layer_ints + layers = self.ls_df['layer'] + ~~~~~~~~~~^^^^^^^^^ +TypeError: 'NoneType' object is not subscriptable + +====================================================================== +ERROR: test_toolbox_metal_get_layer_datatype_when_fill_is_true (__main__.TestToolboxMetal.test_toolbox_metal_get_layer_datatype_when_fill_is_true) +Test functionality of get_layer_datatype_when_fill_is_true in toolbox_metal.py. +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/test_toolbox_metal.py", line 591, in test_toolbox_metal_get_layer_datatype_when_fill_is_true + multiplanar_design = MultiPlanar(metadata={}, + ^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 59, in __init__ + self.ls = self._add_layer_stack() + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 77, in _add_layer_stack + return LayerStackHandler(self) + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 62, in __init__ + self.is_layer_data_unique() + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 215, in is_layer_data_unique + layer_nums = self.get_unique_layer_ints() + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 256, in get_unique_layer_ints + layers = self.ls_df['layer'] + ~~~~~~~~~~^^^^^^^^^ +TypeError: 'NoneType' object is not subscriptable + +====================================================================== +ERROR: test_toolbox_metal_get_properties_for_layer_datatype (__main__.TestToolboxMetal.test_toolbox_metal_get_properties_for_layer_datatype) +Test functionality of get_properties_for_layer_datatype in toolbox_metal.py. +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/test_toolbox_metal.py", line 633, in test_toolbox_metal_get_properties_for_layer_datatype + multiplanar_design = MultiPlanar(metadata={}, + ^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 59, in __init__ + self.ls = self._add_layer_stack() + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 77, in _add_layer_stack + return LayerStackHandler(self) + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 62, in __init__ + self.is_layer_data_unique() + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 215, in is_layer_data_unique + layer_nums = self.get_unique_layer_ints() + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 256, in get_unique_layer_ints + layers = self.ls_df['layer'] + ~~~~~~~~~~^^^^^^^^^ +TypeError: 'NoneType' object is not subscriptable + +====================================================================== +ERROR: test_toolbox_metal_get_unique_chip_names (__main__.TestToolboxMetal.test_toolbox_metal_get_unique_chip_names) +Test functionality of get_unique_chip_names in toolbox_metal.py. +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/test_toolbox_metal.py", line 714, in test_toolbox_metal_get_unique_chip_names + multiplanar_design = MultiPlanar(metadata={}, + ^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 59, in __init__ + self.ls = self._add_layer_stack() + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 77, in _add_layer_stack + return LayerStackHandler(self) + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 62, in __init__ + self.is_layer_data_unique() + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 215, in is_layer_data_unique + layer_nums = self.get_unique_layer_ints() + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 256, in get_unique_layer_ints + layers = self.ls_df['layer'] + ~~~~~~~~~~^^^^^^^^^ +TypeError: 'NoneType' object is not subscriptable + +====================================================================== +ERROR: test_toolbox_metal_get_unique_layer_ints (__main__.TestToolboxMetal.test_toolbox_metal_get_unique_layer_ints) +Test functionality of get_unique_layer_ints in toolbox_metal.py. +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/test_toolbox_metal.py", line 739, in test_toolbox_metal_get_unique_layer_ints + multiplanar_design = MultiPlanar(metadata={}, + ^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 59, in __init__ + self.ls = self._add_layer_stack() + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 77, in _add_layer_stack + return LayerStackHandler(self) + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 62, in __init__ + self.is_layer_data_unique() + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 215, in is_layer_data_unique + layer_nums = self.get_unique_layer_ints() + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 256, in get_unique_layer_ints + layers = self.ls_df['layer'] + ~~~~~~~~~~^^^^^^^^^ +TypeError: 'NoneType' object is not subscriptable + +====================================================================== +ERROR: test_toolbox_metal_get_x_y_for_chip (__main__.TestToolboxMetal.test_toolbox_metal_get_x_y_for_chip) +Test functionality of get_x_y_for_chip in toolbox_metal.py. +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/test_toolbox_metal.py", line 506, in test_toolbox_metal_get_x_y_for_chip + multiplanar_design = MultiPlanar(metadata={}, + ^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 59, in __init__ + self.ls = self._add_layer_stack() + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 77, in _add_layer_stack + return LayerStackHandler(self) + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 62, in __init__ + self.is_layer_data_unique() + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 215, in is_layer_data_unique + layer_nums = self.get_unique_layer_ints() + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 256, in get_unique_layer_ints + layers = self.ls_df['layer'] + ~~~~~~~~~~^^^^^^^^^ +TypeError: 'NoneType' object is not subscriptable + +====================================================================== +ERROR: test_toolbox_metal_is_layer_data_unique (__main__.TestToolboxMetal.test_toolbox_metal_is_layer_data_unique) +Test functionality of is_layer_data_unique in toolbox_metal.py. +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/test_toolbox_metal.py", line 664, in test_toolbox_metal_is_layer_data_unique + multiplanar_design = MultiPlanar(metadata={}, + ^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 59, in __init__ + self.ls = self._add_layer_stack() + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 77, in _add_layer_stack + return LayerStackHandler(self) + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 62, in __init__ + self.is_layer_data_unique() + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 215, in is_layer_data_unique + layer_nums = self.get_unique_layer_ints() + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 256, in get_unique_layer_ints + layers = self.ls_df['layer'] + ~~~~~~~~~~^^^^^^^^^ +TypeError: 'NoneType' object is not subscriptable + +====================================================================== +ERROR: test_toolbox_metal_layer_stack_handler_pilot_error (__main__.TestToolboxMetal.test_toolbox_metal_layer_stack_handler_pilot_error) +Test functionality of layer_stack_handler_pilot_error in toolbox_metal.py. +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/test_toolbox_metal.py", line 839, in test_toolbox_metal_layer_stack_handler_pilot_error + multiplanar_design = MultiPlanar(metadata={}, + ^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 59, in __init__ + self.ls = self._add_layer_stack() + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 77, in _add_layer_stack + return LayerStackHandler(self) + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 62, in __init__ + self.is_layer_data_unique() + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 215, in is_layer_data_unique + layer_nums = self.get_unique_layer_ints() + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 256, in get_unique_layer_ints + layers = self.ls_df['layer'] + ~~~~~~~~~~^^^^^^^^^ +TypeError: 'NoneType' object is not subscriptable + +====================================================================== +ERROR: test_toolbox_metal_read_csv_df (__main__.TestToolboxMetal.test_toolbox_metal_read_csv_df) +Test functionality of read_csv_df in toolbox_metal.py. +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/test_toolbox_metal.py", line 689, in test_toolbox_metal_read_csv_df + multiplanar_design = MultiPlanar(metadata={}, + ^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 59, in __init__ + self.ls = self._add_layer_stack() + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 77, in _add_layer_stack + return LayerStackHandler(self) + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 62, in __init__ + self.is_layer_data_unique() + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 215, in is_layer_data_unique + layer_nums = self.get_unique_layer_ints() + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 256, in get_unique_layer_ints + layers = self.ls_df['layer'] + ~~~~~~~~~~^^^^^^^^^ +TypeError: 'NoneType' object is not subscriptable + +====================================================================== +ERROR: test_toolbox_metal_warning_properties (__main__.TestToolboxMetal.test_toolbox_metal_warning_properties) +Test functionality of _warning_properties in toolbox_metal.py. +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/test_toolbox_metal.py", line 764, in test_toolbox_metal_warning_properties + multiplanar_design = MultiPlanar(metadata={}, + ^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 59, in __init__ + self.ls = self._add_layer_stack() + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 77, in _add_layer_stack + return LayerStackHandler(self) + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 62, in __init__ + self.is_layer_data_unique() + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 215, in is_layer_data_unique + layer_nums = self.get_unique_layer_ints() + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 256, in get_unique_layer_ints + layers = self.ls_df['layer'] + ~~~~~~~~~~^^^^^^^^^ +TypeError: 'NoneType' object is not subscriptable + +====================================================================== +ERROR: test_toolbox_metal_warning_search (__main__.TestToolboxMetal.test_toolbox_metal_warning_search) +Test functionality of _warning_search in toolbox_metal.py. +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/test_toolbox_metal.py", line 789, in test_toolbox_metal_warning_search + multiplanar_design = MultiPlanar(metadata={}, + ^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 59, in __init__ + self.ls = self._add_layer_stack() + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 77, in _add_layer_stack + return LayerStackHandler(self) + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 62, in __init__ + self.is_layer_data_unique() + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 215, in is_layer_data_unique + layer_nums = self.get_unique_layer_ints() + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 256, in get_unique_layer_ints + layers = self.ls_df['layer'] + ~~~~~~~~~~^^^^^^^^^ +TypeError: 'NoneType' object is not subscriptable + +====================================================================== +ERROR: test_toolbox_metal_warning_search_minus_chip (__main__.TestToolboxMetal.test_toolbox_metal_warning_search_minus_chip) +Test functionality of _warning_search_minus_chip in toolbox_metal.py. +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/test_toolbox_metal.py", line 814, in test_toolbox_metal_warning_search_minus_chip + multiplanar_design = MultiPlanar(metadata={}, + ^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 59, in __init__ + self.ls = self._add_layer_stack() + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 77, in _add_layer_stack + return LayerStackHandler(self) + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 62, in __init__ + self.is_layer_data_unique() + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 215, in is_layer_data_unique + layer_nums = self.get_unique_layer_ints() + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 256, in get_unique_layer_ints + layers = self.ls_df['layer'] + ~~~~~~~~~~^^^^^^^^^ +TypeError: 'NoneType' object is not subscriptable + +---------------------------------------------------------------------- +Ran 43 tests in 0.469s + +FAILED (errors=17) + +Qiskit Metal 0.1.2 + +Basic +____________________________________ + Python 3.12.7 | packaged by conda-forge | (main, Oct 4 2024, 15:57:01) [Clang 17.0.6 ] + Platform Darwin arm64 + Installation path /Users/shanto/Programming/qiskit-metal/qiskit_metal + +Packages +____________________________________ + Numpy 1.26.4 + Qutip 5.0.4 + +Rendering +____________________________________ + Matplotlib 3.9.2 + +GUI +____________________________________ + PySide6 version 6.8.0.2 + Qt version 6.8.0 + SIP version Not installed + +IBM Quantum Team +test_example_test (__main__.TestSpeed.test_example_test) +Example test - Play with me to get comfortable with @timeout. ... ok + +---------------------------------------------------------------------- +Ran 1 test in 4.006s + +OK +test_qgeometry_element_columns (__main__.TestElements.test_qgeometry_element_columns) +Test that ELEMENT_COLUMNS was not accidentally changed in ... ERROR +test_qgeometry_get_all_unique_layers (__main__.TestElements.test_qgeometry_get_all_unique_layers) +Test get_all_unique_layers functionality in elment_handler.py. ... ok +test_qgeometry_instantiate_q_geometry_tables (__main__.TestElements.test_qgeometry_instantiate_q_geometry_tables) +Test instantiation of QGeometryTables. ... ok +test_qgeometry_is_qgeometry_table (__main__.TestElements.test_qgeometry_is_qgeometry_table) +Test is_qgeometry_table in qgeometries_handler.py. ... ok +test_qgeometry_q_element_add_qgeometry (__main__.TestElements.test_qgeometry_q_element_add_qgeometry) +Test add_qgeometry in QGeometryTables class in ... ok +test_qgeometry_q_element_add_renderer_extension (__main__.TestElements.test_qgeometry_q_element_add_renderer_extension) +Test add_renderer_extension in QGeometryTables class in ... ok +test_qgeometry_q_element_check_element_type (__main__.TestElements.test_qgeometry_q_element_check_element_type) +Test check_element_type in QGeometryTables class in ... ok +test_qgeometry_q_element_clear_all_tables (__main__.TestElements.test_qgeometry_q_element_clear_all_tables) +Test clear_all_tables in QGeometryTables class in ... ok +test_qgeometry_q_element_constants (__main__.TestElements.test_qgeometry_q_element_constants) +Test that constants in QGeometryTables class in element_handler.py ... ok +test_qgeometry_q_element_create_tables (__main__.TestElements.test_qgeometry_q_element_create_tables) +Test create_tables in QGeometryTables class in ... ok +test_qgeometry_q_element_delete_component_id (__main__.TestElements.test_qgeometry_q_element_delete_component_id) +Test delete_component_id in QGeometryTables class in ... ok +test_qgeometry_q_element_get_component (__main__.TestElements.test_qgeometry_q_element_get_component) +Test get_component in QGeometryTables class in ... 02:35PM 09s WARNING [find_id]: In Components.find_id(), the name=not-real is not used in design._components +02:35PM 09s WARNING [__getitem__]: In Components.__getitem__, name=not-real is not registered in the design class. Return None for QComponent. +02:35PM 09s WARNING [find_id]: In Components.find_id(), the name=not-real is not used in design._components +02:35PM 09s WARNING [__getitem__]: In Components.__getitem__, name=not-real is not registered in the design class. Return None for QComponent. +02:35PM 09s WARNING [find_id]: In Components.find_id(), the name=not-real is not used in design._components +02:35PM 09s WARNING [__getitem__]: In Components.__getitem__, name=not-real is not registered in the design class. Return None for QComponent. +ok +test_qgeometry_q_element_get_component_bounds (__main__.TestElements.test_qgeometry_q_element_get_component_bounds) +Test get_component_bounds in QGeometryTables class in ... ok +test_qgeometry_q_element_get_element_types (__main__.TestElements.test_qgeometry_q_element_get_element_types) +Test get_element_types in QGeometryTables class in ... ok +test_qgeometry_q_element_get_rname (__main__.TestElements.test_qgeometry_q_element_get_rname) +Test get_rname in QGeometryTables class in element_handler.py. ... ok +test_qgeometry_true_bools (__main__.TestElements.test_qgeometry_true_bools) +Test that TRUE_BOOLS was not accidentally changed in ... ok + +====================================================================== +ERROR: test_qgeometry_element_columns (__main__.TestElements.test_qgeometry_element_columns) +Test that ELEMENT_COLUMNS was not accidentally changed in +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/test_qgeometries.py", line 63, in test_qgeometry_element_columns + import imp +ModuleNotFoundError: No module named 'imp' + +---------------------------------------------------------------------- +Ran 16 tests in 0.310s + +FAILED (errors=1) +test_draw_basic_buffer (__main__.TestDraw.test_draw_basic_buffer) +Test buffer in basic.py. ... ok +test_draw_basic_flip_merge (__main__.TestDraw.test_draw_basic_flip_merge) +Test flip_merge in basic.py. ... ok +test_draw_basic_is_rectangle (__main__.TestDraw.test_draw_basic_is_rectangle) +Test is_rectangle in basic.py. ... ok +test_draw_basic_rectangle (__main__.TestDraw.test_draw_basic_rectangle) +Test rectangle in basic.py. ... ok +test_draw_basic_rotate (__main__.TestDraw.test_draw_basic_rotate) +Test rotate in basic.py. ... ok +test_draw_basic_rotate_position (__main__.TestDraw.test_draw_basic_rotate_position) +Test rotate_position in basic.py. ... ok +test_draw_basic_scale (__main__.TestDraw.test_draw_basic_scale) +Test scale in basic.py. ... ok +test_draw_basic_subtract (__main__.TestDraw.test_draw_basic_subtract) +Test subtract in basic.py. ... ok +test_draw_basic_translate (__main__.TestDraw.test_draw_basic_translate) +Test translate in basic.py. ... ok +test_draw_basic_union (__main__.TestDraw.test_draw_basic_union) +Test union in basic.py. ... ok +test_draw_get_distance (__main__.TestDraw.test_draw_get_distance) +Test the functionality of get_distance in utility.py. ... ok +test_draw_instantiate_vector (__main__.TestDraw.test_draw_instantiate_vector) +Test instantiation of Vector class. ... ok +test_draw_normed (__main__.TestDraw.test_draw_normed) +Test functionality of normed in utility.py. ... ok +test_draw_utility_array_chop (__main__.TestDraw.test_draw_utility_array_chop) +Test array_chop in utility.py. ... ok +test_draw_utility_check_duplicate_list (__main__.TestDraw.test_draw_utility_check_duplicate_list) +Test check_duplicate_list in utility.py. ... ok +test_draw_utility_flatten_all_filter (__main__.TestDraw.test_draw_utility_flatten_all_filter) +Test flatten_all_filter in utility.py. ... ok +test_draw_utility_get_all_geoms (__main__.TestDraw.test_draw_utility_get_all_geoms) +Test get_all_geoms in utility.py. ... ok +test_draw_utility_get_poly_pts (__main__.TestDraw.test_draw_utility_get_poly_pts) +Test get_poly_pts in utility.py. ... ok +test_draw_utility_intersect (__main__.TestDraw.test_draw_utility_intersect) +Test intersect in utility.py. ... ok +test_draw_utility_remove_colinear_pts (__main__.TestDraw.test_draw_utility_remove_colinear_pts) +Test remove_colinear_pts in utility.py. ... ok +test_draw_utility_vec_unit_planar (__main__.TestDraw.test_draw_utility_vec_unit_planar) +Test vec_unit_planar in utility.py. ... ok +test_draw_vec3d_add (__main__.TestDraw.test_draw_vec3d_add) +Test add in the Vec3D class in utility.py ... ok +test_draw_vec3d_angle_azimuth (__main__.TestDraw.test_draw_vec3d_angle_azimuth) +Test angle_azimuth in the Vec3D class in utility.py ... ok +test_draw_vec3d_angle_between (__main__.TestDraw.test_draw_vec3d_angle_between) +Test angle_between in the Vec3D class in utility.py ... ok +test_draw_vec3d_angle_elevation (__main__.TestDraw.test_draw_vec3d_angle_elevation) +Test angle_elevation in the Vec3D class in utility.py ... ok +test_draw_vec3d_cross (__main__.TestDraw.test_draw_vec3d_cross) +Test cross in the Vec3D class in utility.py ... ok +test_draw_vec3d_dot (__main__.TestDraw.test_draw_vec3d_dot) +Test dot in the Vec3D class in utility.py ... ok +test_draw_vec3d_get_distance (__main__.TestDraw.test_draw_vec3d_get_distance) +Test get_distance in the Vec3D class in utility.py ... ok +test_draw_vec3d_norm (__main__.TestDraw.test_draw_vec3d_norm) +Test norm in the Vec3D class in utility.py ... ok +test_draw_vec3d_normed (__main__.TestDraw.test_draw_vec3d_normed) +Test normed in the Vec3D class in utility.py ... ok +test_draw_vec3d_rotate (__main__.TestDraw.test_draw_vec3d_rotate) +Test rotate in the Vec3D class in utility.py ... ok +test_draw_vec3d_scale (__main__.TestDraw.test_draw_vec3d_scale) +Test scale in the Vec3D class in utility.py ... ok +test_draw_vec3d_snap_unit_vector (__main__.TestDraw.test_draw_vec3d_snap_unit_vector) +Test snap_unit_vector in Vec3D class in utility.py. ... ok +test_draw_vec3d_sub (__main__.TestDraw.test_draw_vec3d_sub) +Test sub in the Vec3D class in utility.py ... ok +test_draw_vec3d_translate (__main__.TestDraw.test_draw_vec3d_translate) +Test translate in the Vec3D class in utility.py ... ok +test_draw_vec3d_two_points_described (__main__.TestDraw.test_draw_vec3d_two_points_described) +Test two_points_described in Vec3D class in utility.py. ... ok +test_draw_vector_add_z (__main__.TestDraw.test_draw_vector_add_z) +Test add_z in Vector class in utility.py. ... ok +test_draw_vector_angle_between (__main__.TestDraw.test_draw_vector_angle_between) +Test angle_between in Vector class in utility.py. ... ok +test_draw_vector_are_same (__main__.TestDraw.test_draw_vector_are_same) +Test are_same in Vector class in utility.py. ... ok +test_draw_vector_is_zero (__main__.TestDraw.test_draw_vector_is_zero) +Test is_zero in Vector class in utility.py. ... ok +test_draw_vector_norm (__main__.TestDraw.test_draw_vector_norm) +Test norm in Vector class in utility.py. ... ok +test_draw_vector_normal_z (__main__.TestDraw.test_draw_vector_normal_z) +Test that normal_z in Vector class was not accidentally changed. ... ok +test_draw_vector_rotate (__main__.TestDraw.test_draw_vector_rotate) +Test rotate in the Vector class in utility.py. ... ok +test_draw_vector_rotate_around_point (__main__.TestDraw.test_draw_vector_rotate_around_point) +Test rotate_around_point in the Vector class in utility.py. ... ok +test_draw_vector_snap_unit_vector (__main__.TestDraw.test_draw_vector_snap_unit_vector) +Test snap_unit_vector in Vector class in utility.py. ... ok +test_draw_vector_two_points_described (__main__.TestDraw.test_draw_vector_two_points_described) +Test two_points_described in Vector class in utility.py. ... ok + +---------------------------------------------------------------------- +Ran 46 tests in 0.004s + +OK +test_qlibrary_instantiate_basequbit (__main__.TestComponentInstantiation.test_qlibrary_instantiate_basequbit) +Test the instantiation of basequbit. ... 02:35PM 13s ERROR [rebuild]: ERROR in building component name=my_name, error= +02:35PM 13s ERROR [rebuild]: ERROR in building component name=my_name2, error= +ok +test_qlibrary_instantiate_circle_caterpillar (__main__.TestComponentInstantiation.test_qlibrary_instantiate_circle_caterpillar) +Test the instantiation of CircleCaterpillar. ... ok +test_qlibrary_instantiate_circle_raster (__main__.TestComponentInstantiation.test_qlibrary_instantiate_circle_raster) +Test the instantiation of CircleRaster. ... ok +test_qlibrary_instantiate_cpw_finger_cap (__main__.TestComponentInstantiation.test_qlibrary_instantiate_cpw_finger_cap) +Test the instantiation of CapNInterdigital. ... ok +test_qlibrary_instantiate_cpw_hanger_t (__main__.TestComponentInstantiation.test_qlibrary_instantiate_cpw_hanger_t) +Test the instantiation of CoupledLineTee. ... ok +test_qlibrary_instantiate_cpw_t (__main__.TestComponentInstantiation.test_qlibrary_instantiate_cpw_t) +Test the instantiation of LineTee. ... ok +test_qlibrary_instantiate_cpw_t_finger_cap (__main__.TestComponentInstantiation.test_qlibrary_instantiate_cpw_t_finger_cap) +Test the instantiation of CapNInterdigitalTee. ... ok +test_qlibrary_instantiate_launch_v1 (__main__.TestComponentInstantiation.test_qlibrary_instantiate_launch_v1) +Test the instantiation of LaunchpadWirebond. ... ok +test_qlibrary_instantiate_launch_v2 (__main__.TestComponentInstantiation.test_qlibrary_instantiate_launch_v2) +Test the instantiation of LaunchpadWirebondCoupled. ... ok +test_qlibrary_instantiate_my_q_component (__main__.TestComponentInstantiation.test_qlibrary_instantiate_my_q_component) +Test the instantiation of MyQComponent. ... ok +test_qlibrary_instantiate_n_gon (__main__.TestComponentInstantiation.test_qlibrary_instantiate_n_gon) +Test the instantiation of NGon. ... ok +test_qlibrary_instantiate_n_square_spiral (__main__.TestComponentInstantiation.test_qlibrary_instantiate_n_square_spiral) +Test the instantiation of NSquareSpiral. ... ok +test_qlibrary_instantiate_open_to_ground (__main__.TestComponentInstantiation.test_qlibrary_instantiate_open_to_ground) +Test the instantiation of openToGround. ... ok +test_qlibrary_instantiate_q_route (__main__.TestComponentInstantiation.test_qlibrary_instantiate_q_route) +Test the instantiation of QRoute. ... 02:35PM 13s WARNING [__init__]: Component does not exist. test_qroute has not been built. Please check your pin_input values. +ok +test_qlibrary_instantiate_q_route_lead (__main__.TestComponentInstantiation.test_qlibrary_instantiate_q_route_lead) +Test the instantiation of QRouteLead. ... ok +test_qlibrary_instantiate_q_route_point (__main__.TestComponentInstantiation.test_qlibrary_instantiate_q_route_point) +Test the instantiation of QRoutePoint. ... ok +test_qlibrary_instantiate_qcomponent (__main__.TestComponentInstantiation.test_qlibrary_instantiate_qcomponent) +Test the instantiaion of QComponent. ... 02:35PM 13s ERROR [rebuild]: ERROR in building component name=my_name, error= +02:35PM 13s ERROR [rebuild]: ERROR in building component name=my_name2, error= +ok +test_qlibrary_instantiate_rectangle (__main__.TestComponentInstantiation.test_qlibrary_instantiate_rectangle) +Test the instantiation of Rectangle. ... ok +test_qlibrary_instantiate_rectangle_hollow (__main__.TestComponentInstantiation.test_qlibrary_instantiate_rectangle_hollow) +Test the instantiation of RectangleHollow. ... ok +test_qlibrary_instantiate_resonator_rectangle_spiral (__main__.TestComponentInstantiation.test_qlibrary_instantiate_resonator_rectangle_spiral) +Test the instantiation of ResonatorCoilRect. ... ok +test_qlibrary_instantiate_route_anchors (__main__.TestComponentInstantiation.test_qlibrary_instantiate_route_anchors) +Test the instantiation of RouteAnchors. ... 02:35PM 13s WARNING [__init__]: Component does not exist. my_name2 has not been built. Please check your pin_input values. +02:35PM 13s WARNING [__init__]: Component does not exist. my_name3 has not been built. Please check your pin_input values. +ok +test_qlibrary_instantiate_route_frame_path (__main__.TestComponentInstantiation.test_qlibrary_instantiate_route_frame_path) +Test the instantiation of RouteFramed. ... ok +test_qlibrary_instantiate_route_meander (__main__.TestComponentInstantiation.test_qlibrary_instantiate_route_meander) +Test the instantiation of RouteMeander. ... ok +test_qlibrary_instantiate_route_mixed (__main__.TestComponentInstantiation.test_qlibrary_instantiate_route_mixed) +Test the instantiation of RouteMixed. ... ok +test_qlibrary_instantiate_route_pathfinder (__main__.TestComponentInstantiation.test_qlibrary_instantiate_route_pathfinder) +Test the instantiation of RoutePathfinder. ... 02:35PM 13s WARNING [__init__]: Component does not exist. my_name2 has not been built. Please check your pin_input values. +02:35PM 13s WARNING [__init__]: Component does not exist. my_name3 has not been built. Please check your pin_input values. +ok +test_qlibrary_instantiate_route_straight (__main__.TestComponentInstantiation.test_qlibrary_instantiate_route_straight) +Test the instantiation of RouteStraight. ... 02:35PM 13s WARNING [__init__]: Component does not exist. my_name2 has not been built. Please check your pin_input values. +02:35PM 13s WARNING [__init__]: Component does not exist. my_name3 has not been built. Please check your pin_input values. +ok +test_qlibrary_instantiate_short_to_ground (__main__.TestComponentInstantiation.test_qlibrary_instantiate_short_to_ground) +Test the instantiation of shortToGround. ... ok +test_qlibrary_instantiate_three_finger_cap_v1 (__main__.TestComponentInstantiation.test_qlibrary_instantiate_three_finger_cap_v1) +Test the instantiation of Cap3Interdigital. ... ok +test_qlibrary_qubits_jj_dolan_instantiate (__main__.TestComponentInstantiation.test_qlibrary_qubits_jj_dolan_instantiate) +Test the instantiaion of jj_dolan. ... ok +test_qlibrary_qubits_jj_manhattan_instantiate (__main__.TestComponentInstantiation.test_qlibrary_qubits_jj_manhattan_instantiate) +Test the instantiaion of jj_dolan. ... ok +test_qlibrary_qubits_squid_loop (__main__.TestComponentInstantiation.test_qlibrary_qubits_squid_loop) +Test the instantiation of SQUID_LOOP. ... ok +test_qlibrary_qubits_star_qubit (__main__.TestComponentInstantiation.test_qlibrary_qubits_star_qubit) +Test the instantiation of StarQubit. ... ok +test_qlibrary_qubits_transmon_concentric (__main__.TestComponentInstantiation.test_qlibrary_qubits_transmon_concentric) +Test the instantiation of TransmonConcentric. ... ok +test_qlibrary_qubits_transmon_cross (__main__.TestComponentInstantiation.test_qlibrary_qubits_transmon_cross) +Test the instantiation of TransmonCross. ... ok +test_qlibrary_qubits_transmon_cross_fl (__main__.TestComponentInstantiation.test_qlibrary_qubits_transmon_cross_fl) +Test the instantiation of TransmonCrossFL. ... ok +test_qlibrary_qubits_transmon_pocket (__main__.TestComponentInstantiation.test_qlibrary_qubits_transmon_pocket) +Test the instantiation of TransmonPocket. ... ok +test_qlibrary_qubits_transmon_pocket_6 (__main__.TestComponentInstantiation.test_qlibrary_qubits_transmon_pocket_6) +Test the instantiation of TransmonPocket6. ... ok +test_qlibrary_qubits_transmon_pocket_cl (__main__.TestComponentInstantiation.test_qlibrary_qubits_transmon_pocket_cl) +Test the instantiation of TransmonPocketCL. ... ok +test_qlibrary_qubits_transmon_pocket_teeth (__main__.TestComponentInstantiation.test_qlibrary_qubits_transmon_pocket_teeth) +Test the instantiation of TransmonPocketTeeth. ... ok +test_qlibrary_qubits_tunable_coupler_01 (__main__.TestComponentInstantiation.test_qlibrary_qubits_tunable_coupler_01) +Test the instantiation of TunableCoupler01. ... ok + +---------------------------------------------------------------------- +Ran 40 tests in 0.829s + +OK +test_analyses_cpw_effective_dielectric_constant (__main__.TestAnalyses.test_analyses_cpw_effective_dielectric_constant) +Test the functionality of effective_dielectric_constant in ... ok +test_analyses_cpw_elliptic_int_constants (__main__.TestAnalyses.test_analyses_cpw_elliptic_int_constants) +Test the functionality of elliptic_int_constants in ... ok +test_analyses_cpw_guided_wavelength (__main__.TestAnalyses.test_analyses_cpw_guided_wavelength) +Test the functionality of guided_wavelength in ... ok +test_analyses_cpw_lumped_cpw (__main__.TestAnalyses.test_analyses_cpw_lumped_cpw) +Test the functionality of lumped_cpw in cpw_calculations.py. ... ok +test_analyses_hamiltonian_ho_wavefunction (__main__.TestAnalyses.test_analyses_hamiltonian_ho_wavefunction) +Test the wavefunction function in the HO_waefunction.py file. ... ok +test_analyses_lumped_chargeline_t1 (__main__.TestAnalyses.test_analyses_lumped_chargeline_t1) +Test the functionality of chargeline_T1 in lumped_capacitives.py. ... ok +test_analyses_lumped_chi (__main__.TestAnalyses.test_analyses_lumped_chi) +Test the functionality of chi in lumped_capacitives.py. ... ok +test_analyses_lumped_cos_to_mega_and_delta (__main__.TestAnalyses.test_analyses_lumped_cos_to_mega_and_delta) +Test the functionality of cos_to_mega_and_delta in ... ok +test_analyses_lumped_df_reorder_matrix_basis (__main__.TestAnalyses.test_analyses_lumped_df_reorder_matrix_basis) +Test the functionality of df_reorder_matrix_basis in ... ok +test_analyses_lumped_get_c_and_ic (__main__.TestAnalyses.test_analyses_lumped_get_c_and_ic) +Test the functionality of get_C_and_Ic in lumped_capacitives.py. ... ok +test_analyses_lumped_levels_vs_ng_real_units (__main__.TestAnalyses.test_analyses_lumped_levels_vs_ng_real_units) +Test the functionality of levels_vs_ng_real_units in ... ok +test_analyses_lumped_load_q3d_capacitance_matrix (__main__.TestAnalyses.test_analyses_lumped_load_q3d_capacitance_matrix) +Test the functionality of load_q3d_capacitance_matrix in ... ok +test_analyses_lumped_move_index_to (__main__.TestAnalyses.test_analyses_lumped_move_index_to) +Test the functionality of move_index_to in lumped_capacitives.py. ... ok +test_analyses_lumped_readin_q3d_matrix (__main__.TestAnalyses.test_analyses_lumped_readin_q3d_matrix) +Test the functionality of readin_q3d_matrix in ... ok +test_analyses_lumped_transmon_props (__main__.TestAnalyses.test_analyses_lumped_transmon_props) +Test the functionality of lumped_transmon_props in ... ok +test_analysis_kappa_calculation_kappa_in (__main__.TestAnalyses.test_analysis_kappa_calculation_kappa_in) +Test the kappa_in function in kappa_calculation.py. ... ok +test_analysis_lumped_ic_from_ej (__main__.TestAnalyses.test_analysis_lumped_ic_from_ej) +Test the Ic_from_Ej function in lumped_capacitives.py. ... ok +test_analysis_lumped_ic_from_lj (__main__.TestAnalyses.test_analysis_lumped_ic_from_lj) +Test the Ic_from_Lj function in lumped_capacitives.py. ... ok +test_analysis_sweeper_option_value (__main__.TestAnalyses.test_analysis_sweeper_option_value) +Test the option_value function in the Sweeper class ... ok +test_analysis_transmon_charge_basis_anharm (__main__.TestAnalyses.test_analysis_transmon_charge_basis_anharm) +Test the anharm function in the Hcpb class. ... ok +test_analysis_transmon_charge_basis_evaluek (__main__.TestAnalyses.test_analysis_transmon_charge_basis_evaluek) +Test the evaluek function in the Hcpb class. ... ok +test_analysis_transmon_charge_basis_evec_k (__main__.TestAnalyses.test_analysis_transmon_charge_basis_evec_k) +Test the evec_k function in the Hcpb class. ... ok +test_analysis_transmon_charge_basis_fij (__main__.TestAnalyses.test_analysis_transmon_charge_basis_fij) +Test the fij function in the Hcpb class. ... ok +test_analysis_transmon_charge_basis_n_ij (__main__.TestAnalyses.test_analysis_transmon_charge_basis_n_ij) +Test the n_ij function in the Hcpb class. ... ok + +---------------------------------------------------------------------- +Ran 24 tests in 5.730s + +OK + Current function value: 0.000000 + Iterations: 37 + Function evaluations: 312 + Gradient evaluations: 100 +====> Running the entire test suite now... +Running test_default_options.py tests... + +Running test_analyses_1_inst_options.py tests... + +Running test_qlibrary_2_options.py tests... + +Running test_toolbox_python.py tests... + +Running test_gui_basic.py tests... + +Running test_qlibrary_3_functionality.py tests... + +Running test_designs.py tests... + +Running test_renderers.py tests... + +Running test_toolbox_metal.py tests... + +Running test_speed.py tests... + +Running test_qgeometries.py tests... + +Running test_draw.py tests... + +Running test_qlibrary_1_instantiate.py tests... + +Running test_analyses_2_functionality.py tests... + +All tests complete +One or more tests have FAILED! +Scroll up to review the results diff --git a/qiskit_metal/tests/test_toolbox_metal.py b/qiskit_metal/tests/test_toolbox_metal.py index e0edacbb6..31e61bf03 100644 --- a/qiskit_metal/tests/test_toolbox_metal.py +++ b/qiskit_metal/tests/test_toolbox_metal.py @@ -363,7 +363,7 @@ def test_toolbox_metal_determine_larger_box(self): def test_toolbox_metal_get_bounds_of_path_and_poly_tables(self): """Test functionality of get_bounds_of_path_and_poly_tables in toolbox_metal.py""" - ls_file_path = ("./qiskit_metal/tests/test_data/planar_chip.txt") + ls_file_path = ("./test_data/planar_chip.txt") multiplanar_design = MultiPlanar(metadata={}, overwrite_enabled=True, layer_stack_filename=ls_file_path) @@ -395,7 +395,7 @@ def test_toolbox_metal_get_bounds_of_path_and_poly_tables(self): def test_toolbox_metal_ensure_component_box_smaller_than_chip_box_(self): """Test functionality of ensure_component_box_smaller_than_chip_box in toolbox_metal.py""" - ls_file_path = ("./qiskit_metal/tests/test_data/planar_chip.txt") + ls_file_path = ("./test_data/planar_chip.txt") multiplanar_design = MultiPlanar(metadata={}, overwrite_enabled=True, layer_stack_filename=ls_file_path) @@ -436,7 +436,7 @@ def test_toolbox_metal_ensure_component_box_smaller_than_chip_box_(self): def test_toolbox_metal_get_box_for_xy_bounds(self): """Test functionality of get_box_for_xy_bounds in toolbox_metal.py.""" - ls_file_path = ("./qiskit_metal/tests/test_data/planar_chip.txt") + ls_file_path = ("./test_data/planar_chip.txt") multiplanar_design = MultiPlanar(metadata={}, overwrite_enabled=True, layer_stack_filename=ls_file_path) @@ -469,7 +469,7 @@ def test_toolbox_metal_get_box_for_xy_bounds(self): def test_toolbox_metal_are_all_chipnames_in_design(self): """Test functionality of are_all_chipnames_in_design in toolbox_metal.py.""" - ls_file_path = ("./qiskit_metal/tests/test_data/planar_chip.txt") + ls_file_path = ("./test_data/planar_chip.txt") multiplanar_design = MultiPlanar(metadata={}, overwrite_enabled=True, layer_stack_filename=ls_file_path) @@ -502,7 +502,7 @@ def test_toolbox_metal_are_all_chipnames_in_design(self): def test_toolbox_metal_get_x_y_for_chip(self): """Test functionality of get_x_y_for_chip in toolbox_metal.py.""" - ls_file_path = ("./qiskit_metal/tests/test_data/planar_chip.txt") + ls_file_path = ("./test_data/planar_chip.txt") multiplanar_design = MultiPlanar(metadata={}, overwrite_enabled=True, layer_stack_filename=ls_file_path) @@ -537,7 +537,7 @@ def test_toolbox_metal_get_x_y_for_chip(self): def test_toolbox_metal_chip_names_not_in_design(self): """Test functionality of chip_names_not_in_design in toolbox_metal.py.""" - ls_file_path = ("./qiskit_metal/tests/test_data/planar_chip.txt") + ls_file_path = ("./test_data/planar_chip.txt") multiplanar_design = MultiPlanar(metadata={}, overwrite_enabled=True, layer_stack_filename=ls_file_path) @@ -563,7 +563,7 @@ def test_toolbox_metal_chip_names_not_in_design(self): def test_toolbox_metal_chip_size_not_in_chipname_within_design(self): """Test functionality of chip_size_not_in_chipname_within_design in toolbox_metal.py.""" - ls_file_path = ("./qiskit_metal/tests/test_data/planar_chip.txt") + ls_file_path = ("./test_data/planar_chip.txt") multiplanar_design = MultiPlanar(metadata={}, overwrite_enabled=True, layer_stack_filename=ls_file_path) @@ -587,7 +587,7 @@ def test_toolbox_metal_chip_size_not_in_chipname_within_design(self): def test_toolbox_metal_get_layer_datatype_when_fill_is_true(self): """Test functionality of get_layer_datatype_when_fill_is_true in toolbox_metal.py.""" - ls_file_path = ("./qiskit_metal/tests/test_data/planar_chip.txt") + ls_file_path = ("./test_data/planar_chip.txt") multiplanar_design = MultiPlanar(metadata={}, overwrite_enabled=True, layer_stack_filename=ls_file_path) @@ -629,7 +629,7 @@ def test_toolbox_metal_get_layer_datatype_when_fill_is_true(self): def test_toolbox_metal_get_properties_for_layer_datatype(self): """Test functionality of get_properties_for_layer_datatype in toolbox_metal.py.""" - ls_file_path = ("./qiskit_metal/tests/test_data/planar_chip.txt") + ls_file_path = ("./test_data/planar_chip.txt") multiplanar_design = MultiPlanar(metadata={}, overwrite_enabled=True, layer_stack_filename=ls_file_path) @@ -660,7 +660,7 @@ def test_toolbox_metal_get_properties_for_layer_datatype(self): def test_toolbox_metal_is_layer_data_unique(self): """Test functionality of is_layer_data_unique in toolbox_metal.py.""" - ls_file_path = ("./qiskit_metal/tests/test_data/planar_chip.txt") + ls_file_path = ("./test_data/planar_chip.txt") multiplanar_design = MultiPlanar(metadata={}, overwrite_enabled=True, layer_stack_filename=ls_file_path) @@ -685,7 +685,7 @@ def test_toolbox_metal_is_layer_data_unique(self): def test_toolbox_metal_read_csv_df(self): """Test functionality of read_csv_df in toolbox_metal.py.""" - ls_file_path = ("./qiskit_metal/tests/test_data/planar_chip.txt") + ls_file_path = ("./test_data/planar_chip.txt") multiplanar_design = MultiPlanar(metadata={}, overwrite_enabled=True, layer_stack_filename=ls_file_path) @@ -710,7 +710,7 @@ def test_toolbox_metal_read_csv_df(self): def test_toolbox_metal_get_unique_chip_names(self): """Test functionality of get_unique_chip_names in toolbox_metal.py.""" - ls_file_path = ("./qiskit_metal/tests/test_data/planar_chip.txt") + ls_file_path = ("./test_data/planar_chip.txt") multiplanar_design = MultiPlanar(metadata={}, overwrite_enabled=True, layer_stack_filename=ls_file_path) @@ -735,7 +735,7 @@ def test_toolbox_metal_get_unique_chip_names(self): def test_toolbox_metal_get_unique_layer_ints(self): """Test functionality of get_unique_layer_ints in toolbox_metal.py.""" - ls_file_path = ("./qiskit_metal/tests/test_data/planar_chip.txt") + ls_file_path = ("./test_data/planar_chip.txt") multiplanar_design = MultiPlanar(metadata={}, overwrite_enabled=True, layer_stack_filename=ls_file_path) @@ -760,7 +760,7 @@ def test_toolbox_metal_get_unique_layer_ints(self): def test_toolbox_metal_warning_properties(self): """Test functionality of _warning_properties in toolbox_metal.py.""" - ls_file_path = ("./qiskit_metal/tests/test_data/planar_chip.txt") + ls_file_path = ("./test_data/planar_chip.txt") multiplanar_design = MultiPlanar(metadata={}, overwrite_enabled=True, layer_stack_filename=ls_file_path) @@ -785,7 +785,7 @@ def test_toolbox_metal_warning_properties(self): def test_toolbox_metal_warning_search(self): """Test functionality of _warning_search in toolbox_metal.py.""" - ls_file_path = ("./qiskit_metal/tests/test_data/planar_chip.txt") + ls_file_path = ("./test_data/planar_chip.txt") multiplanar_design = MultiPlanar(metadata={}, overwrite_enabled=True, layer_stack_filename=ls_file_path) @@ -810,7 +810,7 @@ def test_toolbox_metal_warning_search(self): def test_toolbox_metal_warning_search_minus_chip(self): """Test functionality of _warning_search_minus_chip in toolbox_metal.py.""" - ls_file_path = ("./qiskit_metal/tests/test_data/planar_chip.txt") + ls_file_path = ("./test_data/planar_chip.txt") multiplanar_design = MultiPlanar(metadata={}, overwrite_enabled=True, layer_stack_filename=ls_file_path) @@ -835,7 +835,7 @@ def test_toolbox_metal_warning_search_minus_chip(self): def test_toolbox_metal_layer_stack_handler_pilot_error(self): """Test functionality of layer_stack_handler_pilot_error in toolbox_metal.py.""" - ls_file_path = ("./qiskit_metal/tests/test_data/planar_chip.txt") + ls_file_path = ("./test_data/planar_chip.txt") multiplanar_design = MultiPlanar(metadata={}, overwrite_enabled=True, layer_stack_filename=ls_file_path) From 03fe275871f8cafc00a2805809dd24be5b8a45f3 Mon Sep 17 00:00:00 2001 From: shanto268 Date: Sun, 17 Nov 2024 16:31:51 -0800 Subject: [PATCH 17/46] docs: got rid of log files --- qiskit_metal/tests/mes.md | 22 - qiskit_metal/tests/test_results.txt | 1057 --------------------------- 2 files changed, 1079 deletions(-) delete mode 100644 qiskit_metal/tests/mes.md delete mode 100644 qiskit_metal/tests/test_results.txt diff --git a/qiskit_metal/tests/mes.md b/qiskit_metal/tests/mes.md deleted file mode 100644 index 2ec6a0672..000000000 --- a/qiskit_metal/tests/mes.md +++ /dev/null @@ -1,22 +0,0 @@ -Hi @zlatko-minev, - -Upon running some initial tests, it does not seem like the `pyside6-port` branch is ready to be merged... Below is a brief report summarizing the issues observed during the testing process: - -## Environment - -- **System:** macOS 15.1 -- **Python Version:** 3.10.6 (via Conda environment with Anaconda3 as the manager) -- **Setup:** Tested in a fresh Conda environment using the `environment.yml` file in the PR branch. -- **Tests:** - - Executed using `run_all_tests.py` - - Design workflow files used in our lab that work with the current `main` branch - ---- - - -## Issues - -**tldr;** - -[Explain the issues and link to the txt file for the entire error log] - diff --git a/qiskit_metal/tests/test_results.txt b/qiskit_metal/tests/test_results.txt deleted file mode 100644 index 586b4fb36..000000000 --- a/qiskit_metal/tests/test_results.txt +++ /dev/null @@ -1,1057 +0,0 @@ -test_qlibrary_short_to_ground_component_metadata (__main__.TestComponentFunctionality.test_qlibrary_short_to_ground_component_metadata) -Test component_metadata in component/short_to_ground.py. ... ok -test_qlibrary_squid_loop_component_metadata (__main__.TestComponentFunctionality.test_qlibrary_squid_loop_component_metadata) -Test component_metadata in qubits.squid_loop.py. ... ok -test_qlibrary_star_qubit_component_metadata (__main__.TestComponentFunctionality.test_qlibrary_star_qubit_component_metadata) -Test component_metadata in qubits.transmon_cross.py. ... ok -test_qlibrary_straight_path_component_metadata (__main__.TestComponentFunctionality.test_qlibrary_straight_path_component_metadata) -Test component_metadata in tlines/straight_path.py. ... ok -test_qlibrary_template_component_metadata (__main__.TestComponentFunctionality.test_qlibrary_template_component_metadata) -Test component_metadata in _template.py. ... ok -test_qlibrary_transmon_coupler_01_component_metadata (__main__.TestComponentFunctionality.test_qlibrary_transmon_coupler_01_component_metadata) -Test component_metadata in qubits.tunable_coupler_01.py. ... ok -test_qlibrary_transmon_cross_component_metadata (__main__.TestComponentFunctionality.test_qlibrary_transmon_cross_component_metadata) -Test component_metadata in qubits.transmon_cross.py. ... ok -test_qlibrary_transmon_cross_fl_component_metadata (__main__.TestComponentFunctionality.test_qlibrary_transmon_cross_fl_component_metadata) -Test component_metadata in qubits.transmon_cross_fl.py. ... ok -test_qlibrary_transmon_pocket_6_component_metadata (__main__.TestComponentFunctionality.test_qlibrary_transmon_pocket_6_component_metadata) -Test component_metadata in qubits.transmon_pcket_6.py. ... ok -test_qlibrary_transmon_pocket_cl_component_metadata (__main__.TestComponentFunctionality.test_qlibrary_transmon_pocket_cl_component_metadata) -Test component_metadata in qubits/transmon_pocket_cl.py. ... ok -test_qlibrary_transmon_pocket_component_metadata (__main__.TestComponentFunctionality.test_qlibrary_transmon_pocket_component_metadata) -Test component_metadata in qubits.transmon_pocket.py. ... ok -test_qlibrary_transmon_pocket_teeth_component_metadata (__main__.TestComponentFunctionality.test_qlibrary_transmon_pocket_teeth_component_metadata) -Test component_metadata in qubits.transmon_pcket_teeth.py. ... ok - ----------------------------------------------------------------------- -Ran 38 tests in 0.194s - -OK -test_design_all_component_names_id (__main__.TestDesign.test_design_all_component_names_id) -Test all_component_names_id functionality in design_base.py. ... ok -test_design_connect_pins (__main__.TestDesign.test_design_connect_pins) -Test connect_pins functionality in design_base.py. ... ok -test_design_copy_multiple_qcomponents (__main__.TestDesign.test_design_copy_multiple_qcomponents) -Test the functionality of copy_multiple_qcomponents in ... ok -test_design_copy_qcomponent (__main__.TestDesign.test_design_copy_qcomponent) -Test the functionlaity of copy_qcomponent in design_base.py. ... ok -test_design_default_component_name (__main__.TestDesign.test_design_default_component_name) -Test automatic naming of components. ... 02:34PM 53s WARNING [rename_component]: Called design.rename_component, component_id(3, is already using res_3. -ok -test_design_delete_all_components (__main__.TestDesign.test_design_delete_all_components) -Test deleteing a component in design_base.py. ... ok -test_design_delete_all_pins (__main__.TestDesign.test_design_delete_all_pins) -Test delete_all_pins functionality in design_base.py. ... ok -test_design_delete_component (__main__.TestDesign.test_design_delete_component) -Test deleteing a component in design_base.py. ... ok -test_design_get_and_set_design_name (__main__.TestDesign.test_design_get_and_set_design_name) -Test getting the design name in design_base.py. ... ok -test_design_get_chip_layer (__main__.TestDesign.test_design_get_chip_layer) -Test getting chip size in design_base.py. ... ok -test_design_get_chip_size (__main__.TestDesign.test_design_get_chip_size) -Test getting chip size in design_base.py. ... ok -test_design_get_chip_z (__main__.TestDesign.test_design_get_chip_z) -Test getting chip z in design_base.py. ... ok -test_design_get_list_of_tables_in_metadata (__main__.TestDesign.test_design_get_list_of_tables_in_metadata) -Tests the get_list_of_tables_in_metadata function in design_base.py ... ok -test_design_get_new_qcomponent_name_id (__main__.TestDesign.test_design_get_new_qcomponent_name_id) -Test _get_new_qcomponent_name_id in design_base.py. ... ok -test_design_get_units (__main__.TestDesign.test_design_get_units) -Test get units in design_base.py. ... ok -test_design_instantiate_design_components (__main__.TestDesign.test_design_instantiate_design_components) -Test the instantiation of Components. ... ok -test_design_instantiate_design_planar (__main__.TestDesign.test_design_instantiate_design_planar) -Test the instantiation of DesignPlanar. ... ok -test_design_instantiate_qdesign (__main__.TestDesign.test_design_instantiate_qdesign) -Test the instantiation of QDesign. ... ok -test_design_instantiate_qnet (__main__.TestDesign.test_design_instantiate_qnet) -Test the instantiation of QNet. ... ok -test_design_interface_components_find_id (__main__.TestDesign.test_design_interface_components_find_id) -Test finding the id from the name in interface_components.py. ... 02:34PM 53s WARNING [find_id]: In Components.find_id(), the name=my_name-3 is not used in design._components -ok -test_design_interface_components_get_list_ints (__main__.TestDesign.test_design_interface_components_get_list_ints) -Test geting the list ints in interface_components.py. ... 02:34PM 53s WARNING [find_id]: In Components.find_id(), the name=nope is not used in design._components -ok -test_design_planar_get_x_y_for_chip (__main__.TestDesign.test_design_planar_get_x_y_for_chip) -Test get_x_y_for_chip in design_planar.py. ... ok -test_design_qnet_add_pins_to_table (__main__.TestDesign.test_design_qnet_add_pins_to_table) -Test add_pins_to_table in net_info.py. ... ok -test_design_qnet_delete_all_pins_for_component_id (__main__.TestDesign.test_design_qnet_delete_all_pins_for_component_id) -Test delete all pins for a given component id in net_info.py. ... ok -test_design_qnet_delete_net_id (__main__.TestDesign.test_design_qnet_delete_net_id) -Test delete a given net id in net_info.py. ... ok -test_design_qnet_get_components_and_pins_for_netid (__main__.TestDesign.test_design_qnet_get_components_and_pins_for_netid) -Test get_components_Sand_pins_for_netid in net_info.py. ... ok -test_design_rename_component (__main__.TestDesign.test_design_rename_component) -Test renaming component in design_base.py. ... ok -test_design_rename_variable (__main__.TestDesign.test_design_rename_variable) -Test rename_variable in QDesign class ... ok -test_design_rename_variables (__main__.TestDesign.test_design_rename_variables) -Test variable renaming in design_base.py. ... ok -test_design_update_metadata (__main__.TestDesign.test_design_update_metadata) -Test the update of metadata in design_base.py. ... ok - ----------------------------------------------------------------------- -Ran 30 tests in 0.515s - -OK -test_renderer_ansys_renderer_element_table_data (__main__.TestRenderers.test_renderer_ansys_renderer_element_table_data) -Test element_table_data in QAnsysRenderer. ... ok -test_renderer_ansys_renderer_get_clean_name (__main__.TestRenderers.test_renderer_ansys_renderer_get_clean_name) -Test get_clean_name in ansys_renderer.py ... ok -test_renderer_ansys_renderer_name (__main__.TestRenderers.test_renderer_ansys_renderer_name) -Test name in QAnsysRenderer. ... ok -test_renderer_ansys_renderer_name_delim (__main__.TestRenderers.test_renderer_ansys_renderer_name_delim) -Test NAME_DELIM in QAnsysRenderer. ... ok -test_renderer_gds_check_cheese (__main__.TestRenderers.test_renderer_gds_check_cheese) -Test check_cheese in gds_renderer.py. ... ok -test_renderer_gds_check_either_cheese (__main__.TestRenderers.test_renderer_gds_check_either_cheese) -Test check_either_cheese in gds_renderer.py. ... 02:34PM 56s WARNING [_check_either_cheese]: layer=0 is not in chip=main either in no_cheese_view_in_file or cheese_view_in_file from self.options. -02:34PM 56s WARNING [_check_either_cheese]: Chip=fake is not either in no_cheese_view_in_file or cheese_view_in_file from self.options. -ok -test_renderer_gds_check_no_cheese (__main__.TestRenderers.test_renderer_gds_check_no_cheese) -Test check_no_cheese in gds_renderer.py. ... ok -test_renderer_gdsrenderer_check_qcomps (__main__.TestRenderers.test_renderer_gdsrenderer_check_qcomps) -Test check_qcomps in gds_renderer.py. ... 02:34PM 56s WARNING [_check_qcomps]: The component=Q2 in highlight_qcomponents not in QDesign. The GDS data not generated. -02:34PM 56s WARNING [_check_qcomps]: The component=Q2 in highlight_qcomponents not in QDesign. The GDS data not generated. -ok -test_renderer_gdsrenderer_high_level (__main__.TestRenderers.test_renderer_gdsrenderer_high_level) -Test that high level defaults were not accidentally changed in ... ok -test_renderer_gdsrenderer_inclusive_bound (__main__.TestRenderers.test_renderer_gdsrenderer_inclusive_bound) -Test functionality of inclusive_bound in gds_renderer.py. ... ok -test_renderer_gdsrenderer_midpoint_xy (__main__.TestRenderers.test_renderer_gdsrenderer_midpoint_xy) -Test midpoint_xy in gds_renderer.py. ... ok -test_renderer_gdsrenderer_options (__main__.TestRenderers.test_renderer_gdsrenderer_options) -Test that default_options in QGDSRenderer were not accidentally ... ok -test_renderer_gdsrenderer_update_units (__main__.TestRenderers.test_renderer_gdsrenderer_update_units) -Test update_units in gds_renderer.py. ... ok -test_renderer_get_chip_names (__main__.TestRenderers.test_renderer_get_chip_names) -Test functionality of get_chip_names in gds_renderer.py. ... ok -test_renderer_hfss_render_options (__main__.TestRenderers.test_renderer_hfss_render_options) -Test that defaults in QHFSSRender were not accidentally changed. ... ok -test_renderer_instanitate_qansys_renderer (__main__.TestRenderers.test_renderer_instanitate_qansys_renderer) -Test instantiation of QAnsysRenderer in ansys_renderer.py ... ok -test_renderer_instantiate_gdsrender (__main__.TestRenderers.test_renderer_instantiate_gdsrender) -Test instantiation of QGDSRenderer in gds_renderer.py. ... ok -test_renderer_instantiate_mplinteraction (__main__.TestRenderers.test_renderer_instantiate_mplinteraction) -Test instantiation of MplInteraction in mpl_interaction.py. ... ok -test_renderer_instantiate_qgmsh_renderer (__main__.TestRenderers.test_renderer_instantiate_qgmsh_renderer) -Test instantiation of QGmshRenderer in gmsh_renderer.py. ... ok -test_renderer_instantiate_qhfss_renderer (__main__.TestRenderers.test_renderer_instantiate_qhfss_renderer) -Test instantiation of QHFSSRenderer in hfss_renderer.py. ... ok -test_renderer_instantiate_qq3d_renderer (__main__.TestRenderers.test_renderer_instantiate_qq3d_renderer) -Test instantiation of QQ3DRenderer in q3d_renderer.py. ... ok -test_renderer_mpl_interaction_disconnect (__main__.TestRenderers.test_renderer_mpl_interaction_disconnect) -Test disconnect in MplInteraction in mpl_interaction.py. ... ok -test_renderer_qansys_renderer_options (__main__.TestRenderers.test_renderer_qansys_renderer_options) -Test that defaults in QAnsysRenderer were not accidentally changed. ... ok -test_renderer_qansysrenderer_default_setup (__main__.TestRenderers.test_renderer_qansysrenderer_default_setup) -Test that default_setup in QAnsysRenderer have not been accidentally changed. ... ok -test_renderer_qgmsh_renderer_name (__main__.TestRenderers.test_renderer_qgmsh_renderer_name) -Test name in QGmshRenderer. ... ok -test_renderer_qgmsh_renderer_options (__main__.TestRenderers.test_renderer_qgmsh_renderer_options) -Test that default_options in QGmshRenderer were not accidentally ... Warning : Gmsh has aleady been initialized -ok -test_renderer_qq3d_render_options (__main__.TestRenderers.test_renderer_qq3d_render_options) -Test that defaults in QQ3DRenderer were not accidentally changed. ... ok -test_renderer_renderer_base_element_table_data (__main__.TestRenderers.test_renderer_renderer_base_element_table_data) -Test element_table_data in QRenderer. ... ok -test_renderer_renderer_base_name (__main__.TestRenderers.test_renderer_renderer_base_name) -Test name in QRenderer. ... ok -test_renderer_renderer_gui_base_name (__main__.TestRenderers.test_renderer_renderer_gui_base_name) -Test name in QRenderer. ... ok -test_renderer_scale_max_bounds (__main__.TestRenderers.test_renderer_scale_max_bounds) -Test functionality of scale_max_bounds in gds_renderer.py. ... ok -test_renderer_setup_renderers (__main__.TestRenderers.test_renderer_setup_renderers) -Test setup_renderers in setup_defauts.py. ... ok -test_successful_get_convergence (__main__.TestRenderers.test_successful_get_convergence) -Test get_convergence returns the correct Boolean when converged ... ok -test_unsuccessful_get_convergence (__main__.TestRenderers.test_unsuccessful_get_convergence) -Test get_convergence returns the correct Boolean when not converged ... ok - ----------------------------------------------------------------------- -Ran 34 tests in 0.279s - -OK -test_toolbox_metal_about (__main__.TestToolboxMetal.test_toolbox_metal_about) -Test that about in about.py produces about text without any ... ok -test_toolbox_metal_aligned_pts (__main__.TestToolboxMetal.test_toolbox_metal_aligned_pts) -Test functionality of aligned_pts in toolbox_metal.py. ... ok -test_toolbox_metal_are_all_chipnames_in_design (__main__.TestToolboxMetal.test_toolbox_metal_are_all_chipnames_in_design) -Test functionality of are_all_chipnames_in_design in toolbox_metal.py. ... 02:34PM 59s ERROR [_init_dataframe]: Not able to read file.File:/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/qiskit_metal/tests/test_data/planar_chip.txt not read. Check the name and path. -ERROR -test_toolbox_metal_chip_names_not_in_design (__main__.TestToolboxMetal.test_toolbox_metal_chip_names_not_in_design) -Test functionality of chip_names_not_in_design in toolbox_metal.py. ... 02:34PM 59s ERROR [_init_dataframe]: Not able to read file.File:/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/qiskit_metal/tests/test_data/planar_chip.txt not read. Check the name and path. -ERROR -test_toolbox_metal_chip_size_not_in_chipname_within_design (__main__.TestToolboxMetal.test_toolbox_metal_chip_size_not_in_chipname_within_design) -Test functionality of chip_size_not_in_chipname_within_design in toolbox_metal.py. ... 02:34PM 59s ERROR [_init_dataframe]: Not able to read file.File:/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/qiskit_metal/tests/test_data/planar_chip.txt not read. Check the name and path. -ERROR -test_toolbox_metal_cross (__main__.TestToolboxMetal.test_toolbox_metal_cross) -Test functionality of cross in toolbox_metal.py. ... ok -test_toolbox_metal_determine_larger_box (__main__.TestToolboxMetal.test_toolbox_metal_determine_larger_box) -Test functionality of determine_larger_box in toolbox_metal.py. ... ok -test_toolbox_metal_dot (__main__.TestToolboxMetal.test_toolbox_metal_dot) -Test functionality of dot in toolbox_metal.py. ... ok -test_toolbox_metal_ensure_component_box_smaller_than_chip_box_ (__main__.TestToolboxMetal.test_toolbox_metal_ensure_component_box_smaller_than_chip_box_) -Test functionality of ensure_component_box_smaller_than_chip_box in toolbox_metal.py ... 02:34PM 59s ERROR [_init_dataframe]: Not able to read file.File:/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/qiskit_metal/tests/test_data/planar_chip.txt not read. Check the name and path. -ERROR -test_toolbox_metal_extract_value_unit (__main__.TestToolboxMetal.test_toolbox_metal_extract_value_unit) -Test functionality of extract_value_unit in toolbox_metal.py. ... ok -test_toolbox_metal_fix_units (__main__.TestToolboxMetal.test_toolbox_metal_fix_units) -Test functionality of fix_units in toolbox_metal.py. ... ok -test_toolbox_metal_get_bounds_of_path_and_poly_tables (__main__.TestToolboxMetal.test_toolbox_metal_get_bounds_of_path_and_poly_tables) -Test functionality of get_bounds_of_path_and_poly_tables in toolbox_metal.py ... 02:34PM 59s ERROR [_init_dataframe]: Not able to read file.File:/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/qiskit_metal/tests/test_data/planar_chip.txt not read. Check the name and path. -ERROR -test_toolbox_metal_get_box_for_xy_bounds (__main__.TestToolboxMetal.test_toolbox_metal_get_box_for_xy_bounds) -Test functionality of get_box_for_xy_bounds in toolbox_metal.py. ... 02:34PM 59s ERROR [_init_dataframe]: Not able to read file.File:/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/qiskit_metal/tests/test_data/planar_chip.txt not read. Check the name and path. -ERROR -test_toolbox_metal_get_layer_datatype_when_fill_is_true (__main__.TestToolboxMetal.test_toolbox_metal_get_layer_datatype_when_fill_is_true) -Test functionality of get_layer_datatype_when_fill_is_true in toolbox_metal.py. ... 02:34PM 59s ERROR [_init_dataframe]: Not able to read file.File:/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/qiskit_metal/tests/test_data/planar_chip.txt not read. Check the name and path. -ERROR -test_toolbox_metal_get_platform_info (__main__.TestToolboxMetal.test_toolbox_metal_get_platform_info) -Test that get_platform_info in about.py returns a string with the platform information without any errors. ... ok -test_toolbox_metal_get_properties_for_layer_datatype (__main__.TestToolboxMetal.test_toolbox_metal_get_properties_for_layer_datatype) -Test functionality of get_properties_for_layer_datatype in toolbox_metal.py. ... 02:34PM 59s ERROR [_init_dataframe]: Not able to read file.File:/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/qiskit_metal/tests/test_data/planar_chip.txt not read. Check the name and path. -ERROR -test_toolbox_metal_get_unique_chip_names (__main__.TestToolboxMetal.test_toolbox_metal_get_unique_chip_names) -Test functionality of get_unique_chip_names in toolbox_metal.py. ... 02:34PM 59s ERROR [_init_dataframe]: Not able to read file.File:/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/qiskit_metal/tests/test_data/planar_chip.txt not read. Check the name and path. -ERROR -test_toolbox_metal_get_unique_layer_ints (__main__.TestToolboxMetal.test_toolbox_metal_get_unique_layer_ints) -Test functionality of get_unique_layer_ints in toolbox_metal.py. ... 02:34PM 59s ERROR [_init_dataframe]: Not able to read file.File:/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/qiskit_metal/tests/test_data/planar_chip.txt not read. Check the name and path. -ERROR -test_toolbox_metal_get_x_y_for_chip (__main__.TestToolboxMetal.test_toolbox_metal_get_x_y_for_chip) -Test functionality of get_x_y_for_chip in toolbox_metal.py. ... 02:34PM 59s ERROR [_init_dataframe]: Not able to read file.File:/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/qiskit_metal/tests/test_data/planar_chip.txt not read. Check the name and path. -ERROR -test_toolbox_metal_instantiation_incorrect_qt_exception (__main__.TestToolboxMetal.test_toolbox_metal_instantiation_incorrect_qt_exception) -Test instantiation of IncorrectQtException. ... ok -test_toolbox_metal_instantiation_input_error (__main__.TestToolboxMetal.test_toolbox_metal_instantiation_input_error) -Test instantiation of InputError. ... ok -test_toolbox_metal_instantiation_qiskit_metal_design_error (__main__.TestToolboxMetal.test_toolbox_metal_instantiation_qiskit_metal_design_error) -Test instantiation of QiskitMetalDesignError. ... ok -test_toolbox_metal_instantiation_qiskit_metal_exceptions (__main__.TestToolboxMetal.test_toolbox_metal_instantiation_qiskit_metal_exceptions) -Test instantiation of QiskitMetalExceptions. ... ok -test_toolbox_metal_instantiation_qlibrary_gui_exception (__main__.TestToolboxMetal.test_toolbox_metal_instantiation_qlibrary_gui_exception) -Test instantiation of QLibraryGUIException. ... ok -test_toolbox_metal_is_for_ast_eval (__main__.TestToolboxMetal.test_toolbox_metal_is_for_ast_eval) -Test is_for_ast_eval in toolbox_metal.py. ... ok -test_toolbox_metal_is_layer_data_unique (__main__.TestToolboxMetal.test_toolbox_metal_is_layer_data_unique) -Test functionality of is_layer_data_unique in toolbox_metal.py. ... 02:34PM 59s ERROR [_init_dataframe]: Not able to read file.File:/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/qiskit_metal/tests/test_data/planar_chip.txt not read. Check the name and path. -ERROR -test_toolbox_metal_is_numeric_possible (__main__.TestToolboxMetal.test_toolbox_metal_is_numeric_possible) -Test is_numeric_possible in toolbox_metal.py. ... ok -test_toolbox_metal_is_true (__main__.TestToolboxMetal.test_toolbox_metal_is_true) -Test is_true in toolbox_metal.py. ... ok -test_toolbox_metal_is_variable_name (__main__.TestToolboxMetal.test_toolbox_metal_is_variable_name) -Test is_variable_name in toolbox_metal.py. ... ok -test_toolbox_metal_layer_stack_handler_pilot_error (__main__.TestToolboxMetal.test_toolbox_metal_layer_stack_handler_pilot_error) -Test functionality of layer_stack_handler_pilot_error in toolbox_metal.py. ... 02:34PM 59s ERROR [_init_dataframe]: Not able to read file.File:/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/qiskit_metal/tests/test_data/planar_chip.txt not read. Check the name and path. -ERROR -test_toolbox_metal_open_docs (__main__.TestToolboxMetal.test_toolbox_metal_open_docs) -Test that open_docs in about.py opens qiskit_metal documentation in HTML without any ... ok -test_toolbox_metal_parse_entry (__main__.TestToolboxMetal.test_toolbox_metal_parse_entry) -Test functionality of parse_entry in toolbox_metal.py. ... ok -test_toolbox_metal_parse_options (__main__.TestToolboxMetal.test_toolbox_metal_parse_options) -Test parse_options in toolbox_metal.py. ... ok -test_toolbox_metal_parse_string_to_float (__main__.TestToolboxMetal.test_toolbox_metal_parse_string_to_float) -Test _parse_string_to_float in toolbox_metal.py. ... ok -test_toolbox_metal_parse_units (__main__.TestToolboxMetal.test_toolbox_metal_parse_units) -Test functionality of parse_units in toolbox_metal.py. ... ok -test_toolbox_metal_parse_value (__main__.TestToolboxMetal.test_toolbox_metal_parse_value) -Test parse_value in toolbox_metal.py. ... ok -test_toolbox_metal_parsing_true_str (__main__.TestToolboxMetal.test_toolbox_metal_parsing_true_str) -Test that TRUE_STR in parsing.py has not accidentally changed. ... ok -test_toolbox_metal_read_csv_df (__main__.TestToolboxMetal.test_toolbox_metal_read_csv_df) -Test functionality of read_csv_df in toolbox_metal.py. ... 02:34PM 59s ERROR [_init_dataframe]: Not able to read file.File:/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/qiskit_metal/tests/test_data/planar_chip.txt not read. Check the name and path. -ERROR -test_toolbox_metal_round (__main__.TestToolboxMetal.test_toolbox_metal_round) -Test functionality of round in toolbox_metal.py. ... ok -test_toolbox_metal_set_decimal_precision (__main__.TestToolboxMetal.test_toolbox_metal_set_decimal_precision) -Test functionality of set_decimal_precision in toolbox_metal.py. ... ok -test_toolbox_metal_warning_properties (__main__.TestToolboxMetal.test_toolbox_metal_warning_properties) -Test functionality of _warning_properties in toolbox_metal.py. ... 02:34PM 59s ERROR [_init_dataframe]: Not able to read file.File:/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/qiskit_metal/tests/test_data/planar_chip.txt not read. Check the name and path. -ERROR -test_toolbox_metal_warning_search (__main__.TestToolboxMetal.test_toolbox_metal_warning_search) -Test functionality of _warning_search in toolbox_metal.py. ... 02:34PM 59s ERROR [_init_dataframe]: Not able to read file.File:/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/qiskit_metal/tests/test_data/planar_chip.txt not read. Check the name and path. -ERROR -test_toolbox_metal_warning_search_minus_chip (__main__.TestToolboxMetal.test_toolbox_metal_warning_search_minus_chip) -Test functionality of _warning_search_minus_chip in toolbox_metal.py. ... 02:34PM 59s ERROR [_init_dataframe]: Not able to read file.File:/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/qiskit_metal/tests/test_data/planar_chip.txt not read. Check the name and path. -ERROR - -====================================================================== -ERROR: test_toolbox_metal_are_all_chipnames_in_design (__main__.TestToolboxMetal.test_toolbox_metal_are_all_chipnames_in_design) -Test functionality of are_all_chipnames_in_design in toolbox_metal.py. ----------------------------------------------------------------------- -Traceback (most recent call last): - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/test_toolbox_metal.py", line 473, in test_toolbox_metal_are_all_chipnames_in_design - multiplanar_design = MultiPlanar(metadata={}, - ^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 59, in __init__ - self.ls = self._add_layer_stack() - ^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 77, in _add_layer_stack - return LayerStackHandler(self) - ^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 62, in __init__ - self.is_layer_data_unique() - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 215, in is_layer_data_unique - layer_nums = self.get_unique_layer_ints() - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 256, in get_unique_layer_ints - layers = self.ls_df['layer'] - ~~~~~~~~~~^^^^^^^^^ -TypeError: 'NoneType' object is not subscriptable - -====================================================================== -ERROR: test_toolbox_metal_chip_names_not_in_design (__main__.TestToolboxMetal.test_toolbox_metal_chip_names_not_in_design) -Test functionality of chip_names_not_in_design in toolbox_metal.py. ----------------------------------------------------------------------- -Traceback (most recent call last): - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/test_toolbox_metal.py", line 541, in test_toolbox_metal_chip_names_not_in_design - multiplanar_design = MultiPlanar(metadata={}, - ^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 59, in __init__ - self.ls = self._add_layer_stack() - ^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 77, in _add_layer_stack - return LayerStackHandler(self) - ^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 62, in __init__ - self.is_layer_data_unique() - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 215, in is_layer_data_unique - layer_nums = self.get_unique_layer_ints() - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 256, in get_unique_layer_ints - layers = self.ls_df['layer'] - ~~~~~~~~~~^^^^^^^^^ -TypeError: 'NoneType' object is not subscriptable - -====================================================================== -ERROR: test_toolbox_metal_chip_size_not_in_chipname_within_design (__main__.TestToolboxMetal.test_toolbox_metal_chip_size_not_in_chipname_within_design) -Test functionality of chip_size_not_in_chipname_within_design in toolbox_metal.py. ----------------------------------------------------------------------- -Traceback (most recent call last): - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/test_toolbox_metal.py", line 567, in test_toolbox_metal_chip_size_not_in_chipname_within_design - multiplanar_design = MultiPlanar(metadata={}, - ^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 59, in __init__ - self.ls = self._add_layer_stack() - ^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 77, in _add_layer_stack - return LayerStackHandler(self) - ^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 62, in __init__ - self.is_layer_data_unique() - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 215, in is_layer_data_unique - layer_nums = self.get_unique_layer_ints() - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 256, in get_unique_layer_ints - layers = self.ls_df['layer'] - ~~~~~~~~~~^^^^^^^^^ -TypeError: 'NoneType' object is not subscriptable - -====================================================================== -ERROR: test_toolbox_metal_ensure_component_box_smaller_than_chip_box_ (__main__.TestToolboxMetal.test_toolbox_metal_ensure_component_box_smaller_than_chip_box_) -Test functionality of ensure_component_box_smaller_than_chip_box in toolbox_metal.py ----------------------------------------------------------------------- -Traceback (most recent call last): - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/test_toolbox_metal.py", line 399, in test_toolbox_metal_ensure_component_box_smaller_than_chip_box_ - multiplanar_design = MultiPlanar(metadata={}, - ^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 59, in __init__ - self.ls = self._add_layer_stack() - ^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 77, in _add_layer_stack - return LayerStackHandler(self) - ^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 62, in __init__ - self.is_layer_data_unique() - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 215, in is_layer_data_unique - layer_nums = self.get_unique_layer_ints() - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 256, in get_unique_layer_ints - layers = self.ls_df['layer'] - ~~~~~~~~~~^^^^^^^^^ -TypeError: 'NoneType' object is not subscriptable - -====================================================================== -ERROR: test_toolbox_metal_get_bounds_of_path_and_poly_tables (__main__.TestToolboxMetal.test_toolbox_metal_get_bounds_of_path_and_poly_tables) -Test functionality of get_bounds_of_path_and_poly_tables in toolbox_metal.py ----------------------------------------------------------------------- -Traceback (most recent call last): - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/test_toolbox_metal.py", line 367, in test_toolbox_metal_get_bounds_of_path_and_poly_tables - multiplanar_design = MultiPlanar(metadata={}, - ^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 59, in __init__ - self.ls = self._add_layer_stack() - ^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 77, in _add_layer_stack - return LayerStackHandler(self) - ^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 62, in __init__ - self.is_layer_data_unique() - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 215, in is_layer_data_unique - layer_nums = self.get_unique_layer_ints() - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 256, in get_unique_layer_ints - layers = self.ls_df['layer'] - ~~~~~~~~~~^^^^^^^^^ -TypeError: 'NoneType' object is not subscriptable - -====================================================================== -ERROR: test_toolbox_metal_get_box_for_xy_bounds (__main__.TestToolboxMetal.test_toolbox_metal_get_box_for_xy_bounds) -Test functionality of get_box_for_xy_bounds in toolbox_metal.py. ----------------------------------------------------------------------- -Traceback (most recent call last): - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/test_toolbox_metal.py", line 440, in test_toolbox_metal_get_box_for_xy_bounds - multiplanar_design = MultiPlanar(metadata={}, - ^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 59, in __init__ - self.ls = self._add_layer_stack() - ^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 77, in _add_layer_stack - return LayerStackHandler(self) - ^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 62, in __init__ - self.is_layer_data_unique() - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 215, in is_layer_data_unique - layer_nums = self.get_unique_layer_ints() - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 256, in get_unique_layer_ints - layers = self.ls_df['layer'] - ~~~~~~~~~~^^^^^^^^^ -TypeError: 'NoneType' object is not subscriptable - -====================================================================== -ERROR: test_toolbox_metal_get_layer_datatype_when_fill_is_true (__main__.TestToolboxMetal.test_toolbox_metal_get_layer_datatype_when_fill_is_true) -Test functionality of get_layer_datatype_when_fill_is_true in toolbox_metal.py. ----------------------------------------------------------------------- -Traceback (most recent call last): - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/test_toolbox_metal.py", line 591, in test_toolbox_metal_get_layer_datatype_when_fill_is_true - multiplanar_design = MultiPlanar(metadata={}, - ^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 59, in __init__ - self.ls = self._add_layer_stack() - ^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 77, in _add_layer_stack - return LayerStackHandler(self) - ^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 62, in __init__ - self.is_layer_data_unique() - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 215, in is_layer_data_unique - layer_nums = self.get_unique_layer_ints() - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 256, in get_unique_layer_ints - layers = self.ls_df['layer'] - ~~~~~~~~~~^^^^^^^^^ -TypeError: 'NoneType' object is not subscriptable - -====================================================================== -ERROR: test_toolbox_metal_get_properties_for_layer_datatype (__main__.TestToolboxMetal.test_toolbox_metal_get_properties_for_layer_datatype) -Test functionality of get_properties_for_layer_datatype in toolbox_metal.py. ----------------------------------------------------------------------- -Traceback (most recent call last): - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/test_toolbox_metal.py", line 633, in test_toolbox_metal_get_properties_for_layer_datatype - multiplanar_design = MultiPlanar(metadata={}, - ^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 59, in __init__ - self.ls = self._add_layer_stack() - ^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 77, in _add_layer_stack - return LayerStackHandler(self) - ^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 62, in __init__ - self.is_layer_data_unique() - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 215, in is_layer_data_unique - layer_nums = self.get_unique_layer_ints() - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 256, in get_unique_layer_ints - layers = self.ls_df['layer'] - ~~~~~~~~~~^^^^^^^^^ -TypeError: 'NoneType' object is not subscriptable - -====================================================================== -ERROR: test_toolbox_metal_get_unique_chip_names (__main__.TestToolboxMetal.test_toolbox_metal_get_unique_chip_names) -Test functionality of get_unique_chip_names in toolbox_metal.py. ----------------------------------------------------------------------- -Traceback (most recent call last): - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/test_toolbox_metal.py", line 714, in test_toolbox_metal_get_unique_chip_names - multiplanar_design = MultiPlanar(metadata={}, - ^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 59, in __init__ - self.ls = self._add_layer_stack() - ^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 77, in _add_layer_stack - return LayerStackHandler(self) - ^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 62, in __init__ - self.is_layer_data_unique() - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 215, in is_layer_data_unique - layer_nums = self.get_unique_layer_ints() - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 256, in get_unique_layer_ints - layers = self.ls_df['layer'] - ~~~~~~~~~~^^^^^^^^^ -TypeError: 'NoneType' object is not subscriptable - -====================================================================== -ERROR: test_toolbox_metal_get_unique_layer_ints (__main__.TestToolboxMetal.test_toolbox_metal_get_unique_layer_ints) -Test functionality of get_unique_layer_ints in toolbox_metal.py. ----------------------------------------------------------------------- -Traceback (most recent call last): - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/test_toolbox_metal.py", line 739, in test_toolbox_metal_get_unique_layer_ints - multiplanar_design = MultiPlanar(metadata={}, - ^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 59, in __init__ - self.ls = self._add_layer_stack() - ^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 77, in _add_layer_stack - return LayerStackHandler(self) - ^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 62, in __init__ - self.is_layer_data_unique() - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 215, in is_layer_data_unique - layer_nums = self.get_unique_layer_ints() - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 256, in get_unique_layer_ints - layers = self.ls_df['layer'] - ~~~~~~~~~~^^^^^^^^^ -TypeError: 'NoneType' object is not subscriptable - -====================================================================== -ERROR: test_toolbox_metal_get_x_y_for_chip (__main__.TestToolboxMetal.test_toolbox_metal_get_x_y_for_chip) -Test functionality of get_x_y_for_chip in toolbox_metal.py. ----------------------------------------------------------------------- -Traceback (most recent call last): - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/test_toolbox_metal.py", line 506, in test_toolbox_metal_get_x_y_for_chip - multiplanar_design = MultiPlanar(metadata={}, - ^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 59, in __init__ - self.ls = self._add_layer_stack() - ^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 77, in _add_layer_stack - return LayerStackHandler(self) - ^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 62, in __init__ - self.is_layer_data_unique() - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 215, in is_layer_data_unique - layer_nums = self.get_unique_layer_ints() - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 256, in get_unique_layer_ints - layers = self.ls_df['layer'] - ~~~~~~~~~~^^^^^^^^^ -TypeError: 'NoneType' object is not subscriptable - -====================================================================== -ERROR: test_toolbox_metal_is_layer_data_unique (__main__.TestToolboxMetal.test_toolbox_metal_is_layer_data_unique) -Test functionality of is_layer_data_unique in toolbox_metal.py. ----------------------------------------------------------------------- -Traceback (most recent call last): - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/test_toolbox_metal.py", line 664, in test_toolbox_metal_is_layer_data_unique - multiplanar_design = MultiPlanar(metadata={}, - ^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 59, in __init__ - self.ls = self._add_layer_stack() - ^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 77, in _add_layer_stack - return LayerStackHandler(self) - ^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 62, in __init__ - self.is_layer_data_unique() - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 215, in is_layer_data_unique - layer_nums = self.get_unique_layer_ints() - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 256, in get_unique_layer_ints - layers = self.ls_df['layer'] - ~~~~~~~~~~^^^^^^^^^ -TypeError: 'NoneType' object is not subscriptable - -====================================================================== -ERROR: test_toolbox_metal_layer_stack_handler_pilot_error (__main__.TestToolboxMetal.test_toolbox_metal_layer_stack_handler_pilot_error) -Test functionality of layer_stack_handler_pilot_error in toolbox_metal.py. ----------------------------------------------------------------------- -Traceback (most recent call last): - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/test_toolbox_metal.py", line 839, in test_toolbox_metal_layer_stack_handler_pilot_error - multiplanar_design = MultiPlanar(metadata={}, - ^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 59, in __init__ - self.ls = self._add_layer_stack() - ^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 77, in _add_layer_stack - return LayerStackHandler(self) - ^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 62, in __init__ - self.is_layer_data_unique() - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 215, in is_layer_data_unique - layer_nums = self.get_unique_layer_ints() - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 256, in get_unique_layer_ints - layers = self.ls_df['layer'] - ~~~~~~~~~~^^^^^^^^^ -TypeError: 'NoneType' object is not subscriptable - -====================================================================== -ERROR: test_toolbox_metal_read_csv_df (__main__.TestToolboxMetal.test_toolbox_metal_read_csv_df) -Test functionality of read_csv_df in toolbox_metal.py. ----------------------------------------------------------------------- -Traceback (most recent call last): - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/test_toolbox_metal.py", line 689, in test_toolbox_metal_read_csv_df - multiplanar_design = MultiPlanar(metadata={}, - ^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 59, in __init__ - self.ls = self._add_layer_stack() - ^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 77, in _add_layer_stack - return LayerStackHandler(self) - ^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 62, in __init__ - self.is_layer_data_unique() - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 215, in is_layer_data_unique - layer_nums = self.get_unique_layer_ints() - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 256, in get_unique_layer_ints - layers = self.ls_df['layer'] - ~~~~~~~~~~^^^^^^^^^ -TypeError: 'NoneType' object is not subscriptable - -====================================================================== -ERROR: test_toolbox_metal_warning_properties (__main__.TestToolboxMetal.test_toolbox_metal_warning_properties) -Test functionality of _warning_properties in toolbox_metal.py. ----------------------------------------------------------------------- -Traceback (most recent call last): - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/test_toolbox_metal.py", line 764, in test_toolbox_metal_warning_properties - multiplanar_design = MultiPlanar(metadata={}, - ^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 59, in __init__ - self.ls = self._add_layer_stack() - ^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 77, in _add_layer_stack - return LayerStackHandler(self) - ^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 62, in __init__ - self.is_layer_data_unique() - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 215, in is_layer_data_unique - layer_nums = self.get_unique_layer_ints() - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 256, in get_unique_layer_ints - layers = self.ls_df['layer'] - ~~~~~~~~~~^^^^^^^^^ -TypeError: 'NoneType' object is not subscriptable - -====================================================================== -ERROR: test_toolbox_metal_warning_search (__main__.TestToolboxMetal.test_toolbox_metal_warning_search) -Test functionality of _warning_search in toolbox_metal.py. ----------------------------------------------------------------------- -Traceback (most recent call last): - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/test_toolbox_metal.py", line 789, in test_toolbox_metal_warning_search - multiplanar_design = MultiPlanar(metadata={}, - ^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 59, in __init__ - self.ls = self._add_layer_stack() - ^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 77, in _add_layer_stack - return LayerStackHandler(self) - ^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 62, in __init__ - self.is_layer_data_unique() - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 215, in is_layer_data_unique - layer_nums = self.get_unique_layer_ints() - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 256, in get_unique_layer_ints - layers = self.ls_df['layer'] - ~~~~~~~~~~^^^^^^^^^ -TypeError: 'NoneType' object is not subscriptable - -====================================================================== -ERROR: test_toolbox_metal_warning_search_minus_chip (__main__.TestToolboxMetal.test_toolbox_metal_warning_search_minus_chip) -Test functionality of _warning_search_minus_chip in toolbox_metal.py. ----------------------------------------------------------------------- -Traceback (most recent call last): - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/test_toolbox_metal.py", line 814, in test_toolbox_metal_warning_search_minus_chip - multiplanar_design = MultiPlanar(metadata={}, - ^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 59, in __init__ - self.ls = self._add_layer_stack() - ^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/designs/design_multiplanar.py", line 77, in _add_layer_stack - return LayerStackHandler(self) - ^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 62, in __init__ - self.is_layer_data_unique() - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 215, in is_layer_data_unique - layer_nums = self.get_unique_layer_ints() - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/toolbox_metal/layer_stack_handler.py", line 256, in get_unique_layer_ints - layers = self.ls_df['layer'] - ~~~~~~~~~~^^^^^^^^^ -TypeError: 'NoneType' object is not subscriptable - ----------------------------------------------------------------------- -Ran 43 tests in 0.469s - -FAILED (errors=17) - -Qiskit Metal 0.1.2 - -Basic -____________________________________ - Python 3.12.7 | packaged by conda-forge | (main, Oct 4 2024, 15:57:01) [Clang 17.0.6 ] - Platform Darwin arm64 - Installation path /Users/shanto/Programming/qiskit-metal/qiskit_metal - -Packages -____________________________________ - Numpy 1.26.4 - Qutip 5.0.4 - -Rendering -____________________________________ - Matplotlib 3.9.2 - -GUI -____________________________________ - PySide6 version 6.8.0.2 - Qt version 6.8.0 - SIP version Not installed - -IBM Quantum Team -test_example_test (__main__.TestSpeed.test_example_test) -Example test - Play with me to get comfortable with @timeout. ... ok - ----------------------------------------------------------------------- -Ran 1 test in 4.006s - -OK -test_qgeometry_element_columns (__main__.TestElements.test_qgeometry_element_columns) -Test that ELEMENT_COLUMNS was not accidentally changed in ... ERROR -test_qgeometry_get_all_unique_layers (__main__.TestElements.test_qgeometry_get_all_unique_layers) -Test get_all_unique_layers functionality in elment_handler.py. ... ok -test_qgeometry_instantiate_q_geometry_tables (__main__.TestElements.test_qgeometry_instantiate_q_geometry_tables) -Test instantiation of QGeometryTables. ... ok -test_qgeometry_is_qgeometry_table (__main__.TestElements.test_qgeometry_is_qgeometry_table) -Test is_qgeometry_table in qgeometries_handler.py. ... ok -test_qgeometry_q_element_add_qgeometry (__main__.TestElements.test_qgeometry_q_element_add_qgeometry) -Test add_qgeometry in QGeometryTables class in ... ok -test_qgeometry_q_element_add_renderer_extension (__main__.TestElements.test_qgeometry_q_element_add_renderer_extension) -Test add_renderer_extension in QGeometryTables class in ... ok -test_qgeometry_q_element_check_element_type (__main__.TestElements.test_qgeometry_q_element_check_element_type) -Test check_element_type in QGeometryTables class in ... ok -test_qgeometry_q_element_clear_all_tables (__main__.TestElements.test_qgeometry_q_element_clear_all_tables) -Test clear_all_tables in QGeometryTables class in ... ok -test_qgeometry_q_element_constants (__main__.TestElements.test_qgeometry_q_element_constants) -Test that constants in QGeometryTables class in element_handler.py ... ok -test_qgeometry_q_element_create_tables (__main__.TestElements.test_qgeometry_q_element_create_tables) -Test create_tables in QGeometryTables class in ... ok -test_qgeometry_q_element_delete_component_id (__main__.TestElements.test_qgeometry_q_element_delete_component_id) -Test delete_component_id in QGeometryTables class in ... ok -test_qgeometry_q_element_get_component (__main__.TestElements.test_qgeometry_q_element_get_component) -Test get_component in QGeometryTables class in ... 02:35PM 09s WARNING [find_id]: In Components.find_id(), the name=not-real is not used in design._components -02:35PM 09s WARNING [__getitem__]: In Components.__getitem__, name=not-real is not registered in the design class. Return None for QComponent. -02:35PM 09s WARNING [find_id]: In Components.find_id(), the name=not-real is not used in design._components -02:35PM 09s WARNING [__getitem__]: In Components.__getitem__, name=not-real is not registered in the design class. Return None for QComponent. -02:35PM 09s WARNING [find_id]: In Components.find_id(), the name=not-real is not used in design._components -02:35PM 09s WARNING [__getitem__]: In Components.__getitem__, name=not-real is not registered in the design class. Return None for QComponent. -ok -test_qgeometry_q_element_get_component_bounds (__main__.TestElements.test_qgeometry_q_element_get_component_bounds) -Test get_component_bounds in QGeometryTables class in ... ok -test_qgeometry_q_element_get_element_types (__main__.TestElements.test_qgeometry_q_element_get_element_types) -Test get_element_types in QGeometryTables class in ... ok -test_qgeometry_q_element_get_rname (__main__.TestElements.test_qgeometry_q_element_get_rname) -Test get_rname in QGeometryTables class in element_handler.py. ... ok -test_qgeometry_true_bools (__main__.TestElements.test_qgeometry_true_bools) -Test that TRUE_BOOLS was not accidentally changed in ... ok - -====================================================================== -ERROR: test_qgeometry_element_columns (__main__.TestElements.test_qgeometry_element_columns) -Test that ELEMENT_COLUMNS was not accidentally changed in ----------------------------------------------------------------------- -Traceback (most recent call last): - File "/Users/shanto/Programming/qiskit-metal/qiskit_metal/tests/test_qgeometries.py", line 63, in test_qgeometry_element_columns - import imp -ModuleNotFoundError: No module named 'imp' - ----------------------------------------------------------------------- -Ran 16 tests in 0.310s - -FAILED (errors=1) -test_draw_basic_buffer (__main__.TestDraw.test_draw_basic_buffer) -Test buffer in basic.py. ... ok -test_draw_basic_flip_merge (__main__.TestDraw.test_draw_basic_flip_merge) -Test flip_merge in basic.py. ... ok -test_draw_basic_is_rectangle (__main__.TestDraw.test_draw_basic_is_rectangle) -Test is_rectangle in basic.py. ... ok -test_draw_basic_rectangle (__main__.TestDraw.test_draw_basic_rectangle) -Test rectangle in basic.py. ... ok -test_draw_basic_rotate (__main__.TestDraw.test_draw_basic_rotate) -Test rotate in basic.py. ... ok -test_draw_basic_rotate_position (__main__.TestDraw.test_draw_basic_rotate_position) -Test rotate_position in basic.py. ... ok -test_draw_basic_scale (__main__.TestDraw.test_draw_basic_scale) -Test scale in basic.py. ... ok -test_draw_basic_subtract (__main__.TestDraw.test_draw_basic_subtract) -Test subtract in basic.py. ... ok -test_draw_basic_translate (__main__.TestDraw.test_draw_basic_translate) -Test translate in basic.py. ... ok -test_draw_basic_union (__main__.TestDraw.test_draw_basic_union) -Test union in basic.py. ... ok -test_draw_get_distance (__main__.TestDraw.test_draw_get_distance) -Test the functionality of get_distance in utility.py. ... ok -test_draw_instantiate_vector (__main__.TestDraw.test_draw_instantiate_vector) -Test instantiation of Vector class. ... ok -test_draw_normed (__main__.TestDraw.test_draw_normed) -Test functionality of normed in utility.py. ... ok -test_draw_utility_array_chop (__main__.TestDraw.test_draw_utility_array_chop) -Test array_chop in utility.py. ... ok -test_draw_utility_check_duplicate_list (__main__.TestDraw.test_draw_utility_check_duplicate_list) -Test check_duplicate_list in utility.py. ... ok -test_draw_utility_flatten_all_filter (__main__.TestDraw.test_draw_utility_flatten_all_filter) -Test flatten_all_filter in utility.py. ... ok -test_draw_utility_get_all_geoms (__main__.TestDraw.test_draw_utility_get_all_geoms) -Test get_all_geoms in utility.py. ... ok -test_draw_utility_get_poly_pts (__main__.TestDraw.test_draw_utility_get_poly_pts) -Test get_poly_pts in utility.py. ... ok -test_draw_utility_intersect (__main__.TestDraw.test_draw_utility_intersect) -Test intersect in utility.py. ... ok -test_draw_utility_remove_colinear_pts (__main__.TestDraw.test_draw_utility_remove_colinear_pts) -Test remove_colinear_pts in utility.py. ... ok -test_draw_utility_vec_unit_planar (__main__.TestDraw.test_draw_utility_vec_unit_planar) -Test vec_unit_planar in utility.py. ... ok -test_draw_vec3d_add (__main__.TestDraw.test_draw_vec3d_add) -Test add in the Vec3D class in utility.py ... ok -test_draw_vec3d_angle_azimuth (__main__.TestDraw.test_draw_vec3d_angle_azimuth) -Test angle_azimuth in the Vec3D class in utility.py ... ok -test_draw_vec3d_angle_between (__main__.TestDraw.test_draw_vec3d_angle_between) -Test angle_between in the Vec3D class in utility.py ... ok -test_draw_vec3d_angle_elevation (__main__.TestDraw.test_draw_vec3d_angle_elevation) -Test angle_elevation in the Vec3D class in utility.py ... ok -test_draw_vec3d_cross (__main__.TestDraw.test_draw_vec3d_cross) -Test cross in the Vec3D class in utility.py ... ok -test_draw_vec3d_dot (__main__.TestDraw.test_draw_vec3d_dot) -Test dot in the Vec3D class in utility.py ... ok -test_draw_vec3d_get_distance (__main__.TestDraw.test_draw_vec3d_get_distance) -Test get_distance in the Vec3D class in utility.py ... ok -test_draw_vec3d_norm (__main__.TestDraw.test_draw_vec3d_norm) -Test norm in the Vec3D class in utility.py ... ok -test_draw_vec3d_normed (__main__.TestDraw.test_draw_vec3d_normed) -Test normed in the Vec3D class in utility.py ... ok -test_draw_vec3d_rotate (__main__.TestDraw.test_draw_vec3d_rotate) -Test rotate in the Vec3D class in utility.py ... ok -test_draw_vec3d_scale (__main__.TestDraw.test_draw_vec3d_scale) -Test scale in the Vec3D class in utility.py ... ok -test_draw_vec3d_snap_unit_vector (__main__.TestDraw.test_draw_vec3d_snap_unit_vector) -Test snap_unit_vector in Vec3D class in utility.py. ... ok -test_draw_vec3d_sub (__main__.TestDraw.test_draw_vec3d_sub) -Test sub in the Vec3D class in utility.py ... ok -test_draw_vec3d_translate (__main__.TestDraw.test_draw_vec3d_translate) -Test translate in the Vec3D class in utility.py ... ok -test_draw_vec3d_two_points_described (__main__.TestDraw.test_draw_vec3d_two_points_described) -Test two_points_described in Vec3D class in utility.py. ... ok -test_draw_vector_add_z (__main__.TestDraw.test_draw_vector_add_z) -Test add_z in Vector class in utility.py. ... ok -test_draw_vector_angle_between (__main__.TestDraw.test_draw_vector_angle_between) -Test angle_between in Vector class in utility.py. ... ok -test_draw_vector_are_same (__main__.TestDraw.test_draw_vector_are_same) -Test are_same in Vector class in utility.py. ... ok -test_draw_vector_is_zero (__main__.TestDraw.test_draw_vector_is_zero) -Test is_zero in Vector class in utility.py. ... ok -test_draw_vector_norm (__main__.TestDraw.test_draw_vector_norm) -Test norm in Vector class in utility.py. ... ok -test_draw_vector_normal_z (__main__.TestDraw.test_draw_vector_normal_z) -Test that normal_z in Vector class was not accidentally changed. ... ok -test_draw_vector_rotate (__main__.TestDraw.test_draw_vector_rotate) -Test rotate in the Vector class in utility.py. ... ok -test_draw_vector_rotate_around_point (__main__.TestDraw.test_draw_vector_rotate_around_point) -Test rotate_around_point in the Vector class in utility.py. ... ok -test_draw_vector_snap_unit_vector (__main__.TestDraw.test_draw_vector_snap_unit_vector) -Test snap_unit_vector in Vector class in utility.py. ... ok -test_draw_vector_two_points_described (__main__.TestDraw.test_draw_vector_two_points_described) -Test two_points_described in Vector class in utility.py. ... ok - ----------------------------------------------------------------------- -Ran 46 tests in 0.004s - -OK -test_qlibrary_instantiate_basequbit (__main__.TestComponentInstantiation.test_qlibrary_instantiate_basequbit) -Test the instantiation of basequbit. ... 02:35PM 13s ERROR [rebuild]: ERROR in building component name=my_name, error= -02:35PM 13s ERROR [rebuild]: ERROR in building component name=my_name2, error= -ok -test_qlibrary_instantiate_circle_caterpillar (__main__.TestComponentInstantiation.test_qlibrary_instantiate_circle_caterpillar) -Test the instantiation of CircleCaterpillar. ... ok -test_qlibrary_instantiate_circle_raster (__main__.TestComponentInstantiation.test_qlibrary_instantiate_circle_raster) -Test the instantiation of CircleRaster. ... ok -test_qlibrary_instantiate_cpw_finger_cap (__main__.TestComponentInstantiation.test_qlibrary_instantiate_cpw_finger_cap) -Test the instantiation of CapNInterdigital. ... ok -test_qlibrary_instantiate_cpw_hanger_t (__main__.TestComponentInstantiation.test_qlibrary_instantiate_cpw_hanger_t) -Test the instantiation of CoupledLineTee. ... ok -test_qlibrary_instantiate_cpw_t (__main__.TestComponentInstantiation.test_qlibrary_instantiate_cpw_t) -Test the instantiation of LineTee. ... ok -test_qlibrary_instantiate_cpw_t_finger_cap (__main__.TestComponentInstantiation.test_qlibrary_instantiate_cpw_t_finger_cap) -Test the instantiation of CapNInterdigitalTee. ... ok -test_qlibrary_instantiate_launch_v1 (__main__.TestComponentInstantiation.test_qlibrary_instantiate_launch_v1) -Test the instantiation of LaunchpadWirebond. ... ok -test_qlibrary_instantiate_launch_v2 (__main__.TestComponentInstantiation.test_qlibrary_instantiate_launch_v2) -Test the instantiation of LaunchpadWirebondCoupled. ... ok -test_qlibrary_instantiate_my_q_component (__main__.TestComponentInstantiation.test_qlibrary_instantiate_my_q_component) -Test the instantiation of MyQComponent. ... ok -test_qlibrary_instantiate_n_gon (__main__.TestComponentInstantiation.test_qlibrary_instantiate_n_gon) -Test the instantiation of NGon. ... ok -test_qlibrary_instantiate_n_square_spiral (__main__.TestComponentInstantiation.test_qlibrary_instantiate_n_square_spiral) -Test the instantiation of NSquareSpiral. ... ok -test_qlibrary_instantiate_open_to_ground (__main__.TestComponentInstantiation.test_qlibrary_instantiate_open_to_ground) -Test the instantiation of openToGround. ... ok -test_qlibrary_instantiate_q_route (__main__.TestComponentInstantiation.test_qlibrary_instantiate_q_route) -Test the instantiation of QRoute. ... 02:35PM 13s WARNING [__init__]: Component does not exist. test_qroute has not been built. Please check your pin_input values. -ok -test_qlibrary_instantiate_q_route_lead (__main__.TestComponentInstantiation.test_qlibrary_instantiate_q_route_lead) -Test the instantiation of QRouteLead. ... ok -test_qlibrary_instantiate_q_route_point (__main__.TestComponentInstantiation.test_qlibrary_instantiate_q_route_point) -Test the instantiation of QRoutePoint. ... ok -test_qlibrary_instantiate_qcomponent (__main__.TestComponentInstantiation.test_qlibrary_instantiate_qcomponent) -Test the instantiaion of QComponent. ... 02:35PM 13s ERROR [rebuild]: ERROR in building component name=my_name, error= -02:35PM 13s ERROR [rebuild]: ERROR in building component name=my_name2, error= -ok -test_qlibrary_instantiate_rectangle (__main__.TestComponentInstantiation.test_qlibrary_instantiate_rectangle) -Test the instantiation of Rectangle. ... ok -test_qlibrary_instantiate_rectangle_hollow (__main__.TestComponentInstantiation.test_qlibrary_instantiate_rectangle_hollow) -Test the instantiation of RectangleHollow. ... ok -test_qlibrary_instantiate_resonator_rectangle_spiral (__main__.TestComponentInstantiation.test_qlibrary_instantiate_resonator_rectangle_spiral) -Test the instantiation of ResonatorCoilRect. ... ok -test_qlibrary_instantiate_route_anchors (__main__.TestComponentInstantiation.test_qlibrary_instantiate_route_anchors) -Test the instantiation of RouteAnchors. ... 02:35PM 13s WARNING [__init__]: Component does not exist. my_name2 has not been built. Please check your pin_input values. -02:35PM 13s WARNING [__init__]: Component does not exist. my_name3 has not been built. Please check your pin_input values. -ok -test_qlibrary_instantiate_route_frame_path (__main__.TestComponentInstantiation.test_qlibrary_instantiate_route_frame_path) -Test the instantiation of RouteFramed. ... ok -test_qlibrary_instantiate_route_meander (__main__.TestComponentInstantiation.test_qlibrary_instantiate_route_meander) -Test the instantiation of RouteMeander. ... ok -test_qlibrary_instantiate_route_mixed (__main__.TestComponentInstantiation.test_qlibrary_instantiate_route_mixed) -Test the instantiation of RouteMixed. ... ok -test_qlibrary_instantiate_route_pathfinder (__main__.TestComponentInstantiation.test_qlibrary_instantiate_route_pathfinder) -Test the instantiation of RoutePathfinder. ... 02:35PM 13s WARNING [__init__]: Component does not exist. my_name2 has not been built. Please check your pin_input values. -02:35PM 13s WARNING [__init__]: Component does not exist. my_name3 has not been built. Please check your pin_input values. -ok -test_qlibrary_instantiate_route_straight (__main__.TestComponentInstantiation.test_qlibrary_instantiate_route_straight) -Test the instantiation of RouteStraight. ... 02:35PM 13s WARNING [__init__]: Component does not exist. my_name2 has not been built. Please check your pin_input values. -02:35PM 13s WARNING [__init__]: Component does not exist. my_name3 has not been built. Please check your pin_input values. -ok -test_qlibrary_instantiate_short_to_ground (__main__.TestComponentInstantiation.test_qlibrary_instantiate_short_to_ground) -Test the instantiation of shortToGround. ... ok -test_qlibrary_instantiate_three_finger_cap_v1 (__main__.TestComponentInstantiation.test_qlibrary_instantiate_three_finger_cap_v1) -Test the instantiation of Cap3Interdigital. ... ok -test_qlibrary_qubits_jj_dolan_instantiate (__main__.TestComponentInstantiation.test_qlibrary_qubits_jj_dolan_instantiate) -Test the instantiaion of jj_dolan. ... ok -test_qlibrary_qubits_jj_manhattan_instantiate (__main__.TestComponentInstantiation.test_qlibrary_qubits_jj_manhattan_instantiate) -Test the instantiaion of jj_dolan. ... ok -test_qlibrary_qubits_squid_loop (__main__.TestComponentInstantiation.test_qlibrary_qubits_squid_loop) -Test the instantiation of SQUID_LOOP. ... ok -test_qlibrary_qubits_star_qubit (__main__.TestComponentInstantiation.test_qlibrary_qubits_star_qubit) -Test the instantiation of StarQubit. ... ok -test_qlibrary_qubits_transmon_concentric (__main__.TestComponentInstantiation.test_qlibrary_qubits_transmon_concentric) -Test the instantiation of TransmonConcentric. ... ok -test_qlibrary_qubits_transmon_cross (__main__.TestComponentInstantiation.test_qlibrary_qubits_transmon_cross) -Test the instantiation of TransmonCross. ... ok -test_qlibrary_qubits_transmon_cross_fl (__main__.TestComponentInstantiation.test_qlibrary_qubits_transmon_cross_fl) -Test the instantiation of TransmonCrossFL. ... ok -test_qlibrary_qubits_transmon_pocket (__main__.TestComponentInstantiation.test_qlibrary_qubits_transmon_pocket) -Test the instantiation of TransmonPocket. ... ok -test_qlibrary_qubits_transmon_pocket_6 (__main__.TestComponentInstantiation.test_qlibrary_qubits_transmon_pocket_6) -Test the instantiation of TransmonPocket6. ... ok -test_qlibrary_qubits_transmon_pocket_cl (__main__.TestComponentInstantiation.test_qlibrary_qubits_transmon_pocket_cl) -Test the instantiation of TransmonPocketCL. ... ok -test_qlibrary_qubits_transmon_pocket_teeth (__main__.TestComponentInstantiation.test_qlibrary_qubits_transmon_pocket_teeth) -Test the instantiation of TransmonPocketTeeth. ... ok -test_qlibrary_qubits_tunable_coupler_01 (__main__.TestComponentInstantiation.test_qlibrary_qubits_tunable_coupler_01) -Test the instantiation of TunableCoupler01. ... ok - ----------------------------------------------------------------------- -Ran 40 tests in 0.829s - -OK -test_analyses_cpw_effective_dielectric_constant (__main__.TestAnalyses.test_analyses_cpw_effective_dielectric_constant) -Test the functionality of effective_dielectric_constant in ... ok -test_analyses_cpw_elliptic_int_constants (__main__.TestAnalyses.test_analyses_cpw_elliptic_int_constants) -Test the functionality of elliptic_int_constants in ... ok -test_analyses_cpw_guided_wavelength (__main__.TestAnalyses.test_analyses_cpw_guided_wavelength) -Test the functionality of guided_wavelength in ... ok -test_analyses_cpw_lumped_cpw (__main__.TestAnalyses.test_analyses_cpw_lumped_cpw) -Test the functionality of lumped_cpw in cpw_calculations.py. ... ok -test_analyses_hamiltonian_ho_wavefunction (__main__.TestAnalyses.test_analyses_hamiltonian_ho_wavefunction) -Test the wavefunction function in the HO_waefunction.py file. ... ok -test_analyses_lumped_chargeline_t1 (__main__.TestAnalyses.test_analyses_lumped_chargeline_t1) -Test the functionality of chargeline_T1 in lumped_capacitives.py. ... ok -test_analyses_lumped_chi (__main__.TestAnalyses.test_analyses_lumped_chi) -Test the functionality of chi in lumped_capacitives.py. ... ok -test_analyses_lumped_cos_to_mega_and_delta (__main__.TestAnalyses.test_analyses_lumped_cos_to_mega_and_delta) -Test the functionality of cos_to_mega_and_delta in ... ok -test_analyses_lumped_df_reorder_matrix_basis (__main__.TestAnalyses.test_analyses_lumped_df_reorder_matrix_basis) -Test the functionality of df_reorder_matrix_basis in ... ok -test_analyses_lumped_get_c_and_ic (__main__.TestAnalyses.test_analyses_lumped_get_c_and_ic) -Test the functionality of get_C_and_Ic in lumped_capacitives.py. ... ok -test_analyses_lumped_levels_vs_ng_real_units (__main__.TestAnalyses.test_analyses_lumped_levels_vs_ng_real_units) -Test the functionality of levels_vs_ng_real_units in ... ok -test_analyses_lumped_load_q3d_capacitance_matrix (__main__.TestAnalyses.test_analyses_lumped_load_q3d_capacitance_matrix) -Test the functionality of load_q3d_capacitance_matrix in ... ok -test_analyses_lumped_move_index_to (__main__.TestAnalyses.test_analyses_lumped_move_index_to) -Test the functionality of move_index_to in lumped_capacitives.py. ... ok -test_analyses_lumped_readin_q3d_matrix (__main__.TestAnalyses.test_analyses_lumped_readin_q3d_matrix) -Test the functionality of readin_q3d_matrix in ... ok -test_analyses_lumped_transmon_props (__main__.TestAnalyses.test_analyses_lumped_transmon_props) -Test the functionality of lumped_transmon_props in ... ok -test_analysis_kappa_calculation_kappa_in (__main__.TestAnalyses.test_analysis_kappa_calculation_kappa_in) -Test the kappa_in function in kappa_calculation.py. ... ok -test_analysis_lumped_ic_from_ej (__main__.TestAnalyses.test_analysis_lumped_ic_from_ej) -Test the Ic_from_Ej function in lumped_capacitives.py. ... ok -test_analysis_lumped_ic_from_lj (__main__.TestAnalyses.test_analysis_lumped_ic_from_lj) -Test the Ic_from_Lj function in lumped_capacitives.py. ... ok -test_analysis_sweeper_option_value (__main__.TestAnalyses.test_analysis_sweeper_option_value) -Test the option_value function in the Sweeper class ... ok -test_analysis_transmon_charge_basis_anharm (__main__.TestAnalyses.test_analysis_transmon_charge_basis_anharm) -Test the anharm function in the Hcpb class. ... ok -test_analysis_transmon_charge_basis_evaluek (__main__.TestAnalyses.test_analysis_transmon_charge_basis_evaluek) -Test the evaluek function in the Hcpb class. ... ok -test_analysis_transmon_charge_basis_evec_k (__main__.TestAnalyses.test_analysis_transmon_charge_basis_evec_k) -Test the evec_k function in the Hcpb class. ... ok -test_analysis_transmon_charge_basis_fij (__main__.TestAnalyses.test_analysis_transmon_charge_basis_fij) -Test the fij function in the Hcpb class. ... ok -test_analysis_transmon_charge_basis_n_ij (__main__.TestAnalyses.test_analysis_transmon_charge_basis_n_ij) -Test the n_ij function in the Hcpb class. ... ok - ----------------------------------------------------------------------- -Ran 24 tests in 5.730s - -OK - Current function value: 0.000000 - Iterations: 37 - Function evaluations: 312 - Gradient evaluations: 100 -====> Running the entire test suite now... -Running test_default_options.py tests... - -Running test_analyses_1_inst_options.py tests... - -Running test_qlibrary_2_options.py tests... - -Running test_toolbox_python.py tests... - -Running test_gui_basic.py tests... - -Running test_qlibrary_3_functionality.py tests... - -Running test_designs.py tests... - -Running test_renderers.py tests... - -Running test_toolbox_metal.py tests... - -Running test_speed.py tests... - -Running test_qgeometries.py tests... - -Running test_draw.py tests... - -Running test_qlibrary_1_instantiate.py tests... - -Running test_analyses_2_functionality.py tests... - -All tests complete -One or more tests have FAILED! -Scroll up to review the results From 31b612e153201c423a2e9354fdd07e1b3e150c09 Mon Sep 17 00:00:00 2001 From: shanto268 Date: Sun, 17 Nov 2024 16:46:30 -0800 Subject: [PATCH 18/46] fix: changed requirements + fixed the Paths --- qiskit_metal/tests/test_toolbox_metal.py | 65 ++++++++++++------------ requirements.txt | 40 +++++++-------- 2 files changed, 52 insertions(+), 53 deletions(-) diff --git a/qiskit_metal/tests/test_toolbox_metal.py b/qiskit_metal/tests/test_toolbox_metal.py index 31e61bf03..2c2218762 100644 --- a/qiskit_metal/tests/test_toolbox_metal.py +++ b/qiskit_metal/tests/test_toolbox_metal.py @@ -19,27 +19,28 @@ """Qiskit Metal unit tests analyses functionality.""" import unittest -import numpy as np +from pathlib import Path from typing import Union -from qiskit_metal.toolbox_metal import about -from qiskit_metal.toolbox_metal import parsing -from qiskit_metal.toolbox_metal import math_and_overrides -from qiskit_metal.toolbox_metal import bounds_for_path_and_poly_tables -from qiskit_metal.toolbox_metal.bounds_for_path_and_poly_tables import BoundsForPathAndPolyTables -from qiskit_metal.toolbox_metal.layer_stack_handler import LayerStackHandler -from qiskit_metal.toolbox_metal.exceptions import QiskitMetalExceptions -from qiskit_metal.toolbox_metal.exceptions import QiskitMetalDesignError -from qiskit_metal.toolbox_metal.exceptions import IncorrectQtException -from qiskit_metal.toolbox_metal.exceptions import QLibraryGUIException -from qiskit_metal.toolbox_metal.exceptions import InputError -from qiskit_metal.tests.assertions import AssertionsMixin -from qiskit_metal.qlibrary.qubits.transmon_concentric import TransmonConcentric +import numpy as np + from qiskit_metal.designs.design_multiplanar import MultiPlanar +from qiskit_metal.qlibrary.qubits.transmon_concentric import TransmonConcentric from qiskit_metal.qlibrary.qubits.transmon_pocket_6 import TransmonPocket6 +from qiskit_metal.tests.assertions import AssertionsMixin from qiskit_metal.tests.test_data.quad_coupler import QuadCoupler +from qiskit_metal.toolbox_metal import (about, bounds_for_path_and_poly_tables, + math_and_overrides, parsing) +from qiskit_metal.toolbox_metal.bounds_for_path_and_poly_tables import \ + BoundsForPathAndPolyTables +from qiskit_metal.toolbox_metal.exceptions import (IncorrectQtException, + InputError, + QiskitMetalDesignError, + QiskitMetalExceptions, + QLibraryGUIException) +from qiskit_metal.toolbox_metal.layer_stack_handler import LayerStackHandler - +TEST_DATA = Path(__file__).parent / "test_data" class TestToolboxMetal(unittest.TestCase, AssertionsMixin): """Unit test class.""" @@ -363,7 +364,7 @@ def test_toolbox_metal_determine_larger_box(self): def test_toolbox_metal_get_bounds_of_path_and_poly_tables(self): """Test functionality of get_bounds_of_path_and_poly_tables in toolbox_metal.py""" - ls_file_path = ("./test_data/planar_chip.txt") + ls_file_path = TEST_DATA / 'planar_chip.txt' multiplanar_design = MultiPlanar(metadata={}, overwrite_enabled=True, layer_stack_filename=ls_file_path) @@ -395,7 +396,7 @@ def test_toolbox_metal_get_bounds_of_path_and_poly_tables(self): def test_toolbox_metal_ensure_component_box_smaller_than_chip_box_(self): """Test functionality of ensure_component_box_smaller_than_chip_box in toolbox_metal.py""" - ls_file_path = ("./test_data/planar_chip.txt") + ls_file_path = TEST_DATA / 'planar_chip.txt' multiplanar_design = MultiPlanar(metadata={}, overwrite_enabled=True, layer_stack_filename=ls_file_path) @@ -436,7 +437,7 @@ def test_toolbox_metal_ensure_component_box_smaller_than_chip_box_(self): def test_toolbox_metal_get_box_for_xy_bounds(self): """Test functionality of get_box_for_xy_bounds in toolbox_metal.py.""" - ls_file_path = ("./test_data/planar_chip.txt") + ls_file_path = TEST_DATA / 'planar_chip.txt' multiplanar_design = MultiPlanar(metadata={}, overwrite_enabled=True, layer_stack_filename=ls_file_path) @@ -469,7 +470,7 @@ def test_toolbox_metal_get_box_for_xy_bounds(self): def test_toolbox_metal_are_all_chipnames_in_design(self): """Test functionality of are_all_chipnames_in_design in toolbox_metal.py.""" - ls_file_path = ("./test_data/planar_chip.txt") + ls_file_path = TEST_DATA / 'planar_chip.txt' multiplanar_design = MultiPlanar(metadata={}, overwrite_enabled=True, layer_stack_filename=ls_file_path) @@ -502,7 +503,7 @@ def test_toolbox_metal_are_all_chipnames_in_design(self): def test_toolbox_metal_get_x_y_for_chip(self): """Test functionality of get_x_y_for_chip in toolbox_metal.py.""" - ls_file_path = ("./test_data/planar_chip.txt") + ls_file_path = TEST_DATA / 'planar_chip.txt' multiplanar_design = MultiPlanar(metadata={}, overwrite_enabled=True, layer_stack_filename=ls_file_path) @@ -537,7 +538,7 @@ def test_toolbox_metal_get_x_y_for_chip(self): def test_toolbox_metal_chip_names_not_in_design(self): """Test functionality of chip_names_not_in_design in toolbox_metal.py.""" - ls_file_path = ("./test_data/planar_chip.txt") + ls_file_path = TEST_DATA / 'planar_chip.txt' multiplanar_design = MultiPlanar(metadata={}, overwrite_enabled=True, layer_stack_filename=ls_file_path) @@ -563,7 +564,7 @@ def test_toolbox_metal_chip_names_not_in_design(self): def test_toolbox_metal_chip_size_not_in_chipname_within_design(self): """Test functionality of chip_size_not_in_chipname_within_design in toolbox_metal.py.""" - ls_file_path = ("./test_data/planar_chip.txt") + ls_file_path = TEST_DATA / 'planar_chip.txt' multiplanar_design = MultiPlanar(metadata={}, overwrite_enabled=True, layer_stack_filename=ls_file_path) @@ -587,7 +588,7 @@ def test_toolbox_metal_chip_size_not_in_chipname_within_design(self): def test_toolbox_metal_get_layer_datatype_when_fill_is_true(self): """Test functionality of get_layer_datatype_when_fill_is_true in toolbox_metal.py.""" - ls_file_path = ("./test_data/planar_chip.txt") + ls_file_path = TEST_DATA / 'planar_chip.txt' multiplanar_design = MultiPlanar(metadata={}, overwrite_enabled=True, layer_stack_filename=ls_file_path) @@ -629,7 +630,7 @@ def test_toolbox_metal_get_layer_datatype_when_fill_is_true(self): def test_toolbox_metal_get_properties_for_layer_datatype(self): """Test functionality of get_properties_for_layer_datatype in toolbox_metal.py.""" - ls_file_path = ("./test_data/planar_chip.txt") + ls_file_path = TEST_DATA / 'planar_chip.txt' multiplanar_design = MultiPlanar(metadata={}, overwrite_enabled=True, layer_stack_filename=ls_file_path) @@ -660,7 +661,7 @@ def test_toolbox_metal_get_properties_for_layer_datatype(self): def test_toolbox_metal_is_layer_data_unique(self): """Test functionality of is_layer_data_unique in toolbox_metal.py.""" - ls_file_path = ("./test_data/planar_chip.txt") + ls_file_path = TEST_DATA / 'planar_chip.txt' multiplanar_design = MultiPlanar(metadata={}, overwrite_enabled=True, layer_stack_filename=ls_file_path) @@ -685,7 +686,7 @@ def test_toolbox_metal_is_layer_data_unique(self): def test_toolbox_metal_read_csv_df(self): """Test functionality of read_csv_df in toolbox_metal.py.""" - ls_file_path = ("./test_data/planar_chip.txt") + ls_file_path = TEST_DATA / 'planar_chip.txt' multiplanar_design = MultiPlanar(metadata={}, overwrite_enabled=True, layer_stack_filename=ls_file_path) @@ -710,7 +711,7 @@ def test_toolbox_metal_read_csv_df(self): def test_toolbox_metal_get_unique_chip_names(self): """Test functionality of get_unique_chip_names in toolbox_metal.py.""" - ls_file_path = ("./test_data/planar_chip.txt") + ls_file_path = TEST_DATA / 'planar_chip.txt' multiplanar_design = MultiPlanar(metadata={}, overwrite_enabled=True, layer_stack_filename=ls_file_path) @@ -735,7 +736,7 @@ def test_toolbox_metal_get_unique_chip_names(self): def test_toolbox_metal_get_unique_layer_ints(self): """Test functionality of get_unique_layer_ints in toolbox_metal.py.""" - ls_file_path = ("./test_data/planar_chip.txt") + ls_file_path = TEST_DATA / 'planar_chip.txt' multiplanar_design = MultiPlanar(metadata={}, overwrite_enabled=True, layer_stack_filename=ls_file_path) @@ -760,7 +761,7 @@ def test_toolbox_metal_get_unique_layer_ints(self): def test_toolbox_metal_warning_properties(self): """Test functionality of _warning_properties in toolbox_metal.py.""" - ls_file_path = ("./test_data/planar_chip.txt") + ls_file_path = TEST_DATA / 'planar_chip.txt' multiplanar_design = MultiPlanar(metadata={}, overwrite_enabled=True, layer_stack_filename=ls_file_path) @@ -785,7 +786,7 @@ def test_toolbox_metal_warning_properties(self): def test_toolbox_metal_warning_search(self): """Test functionality of _warning_search in toolbox_metal.py.""" - ls_file_path = ("./test_data/planar_chip.txt") + ls_file_path = TEST_DATA / 'planar_chip.txt' multiplanar_design = MultiPlanar(metadata={}, overwrite_enabled=True, layer_stack_filename=ls_file_path) @@ -810,7 +811,7 @@ def test_toolbox_metal_warning_search(self): def test_toolbox_metal_warning_search_minus_chip(self): """Test functionality of _warning_search_minus_chip in toolbox_metal.py.""" - ls_file_path = ("./test_data/planar_chip.txt") + ls_file_path = TEST_DATA / 'planar_chip.txt' multiplanar_design = MultiPlanar(metadata={}, overwrite_enabled=True, layer_stack_filename=ls_file_path) @@ -835,7 +836,7 @@ def test_toolbox_metal_warning_search_minus_chip(self): def test_toolbox_metal_layer_stack_handler_pilot_error(self): """Test functionality of layer_stack_handler_pilot_error in toolbox_metal.py.""" - ls_file_path = ("./test_data/planar_chip.txt") + ls_file_path = TEST_DATA / 'planar_chip.txt' multiplanar_design = MultiPlanar(metadata={}, overwrite_enabled=True, layer_stack_filename=ls_file_path) diff --git a/requirements.txt b/requirements.txt index 5bc52a6c1..8580d3c3f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,22 +1,20 @@ -addict==2.4.0 -descartes==1.1.0 -gdspy==1.6.12 -geopandas==0.12.2 -ipython==8.10.0 -matplotlib==3.7.0 -numpy==1.24.2 -pandas==1.5.3 -pint==0.20.1 -pyEPR-quantum==0.8.5.7 -pygments==2.14.0 +addict +descartes +gdspy>=1.5.2 +geopandas +ipython +matplotlib +numpy +pandas +pint +pyEPR-quantum>=0.8.5.7 +pygments pyside6 -qdarkstyle==3.1 -qutip==4.7.1 -scipy==1.10.0 -shapely==2.0.1 -scqubits==3.1.0 -gmsh==4.11.1 -pyaedt==0.6.46 -pyyaml==6.0 -cython<3.0.0 -# jupyter (if you need a fresh install) or ipykernel (if you prefer to make of this a new kernel to use from an existing jupyter install) +qdarkstyle +qutip +scipy +shapely +scqubits +gmsh +pyaedt==0.6.46 #since conda-forge doesn't have pyaedt, we have to manually pip install or completely switch to virtualenv . virtualenv uses less memory than conda. +# jupyter (if you need a fresh install) or ipykernel (if you prefer to make of this a new kernel to use from an existing jupyter install) \ No newline at end of file From deb78136cc897aa8bac194cb092b187e29f22aea Mon Sep 17 00:00:00 2001 From: shanto268 Date: Sun, 17 Nov 2024 16:52:35 -0800 Subject: [PATCH 19/46] docs: added pyyaml and cython to reqs --- requirements.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/requirements.txt b/requirements.txt index 8580d3c3f..7423651c5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -16,5 +16,7 @@ scipy shapely scqubits gmsh +pyyaml==6.0 +cython<3.0.0 pyaedt==0.6.46 #since conda-forge doesn't have pyaedt, we have to manually pip install or completely switch to virtualenv . virtualenv uses less memory than conda. # jupyter (if you need a fresh install) or ipykernel (if you prefer to make of this a new kernel to use from an existing jupyter install) \ No newline at end of file From 566918cabb2f9bd2d1c828dece96085af7240371 Mon Sep 17 00:00:00 2001 From: shanto268 Date: Sun, 17 Nov 2024 16:58:17 -0800 Subject: [PATCH 20/46] docs: fixing the requirements --- requirements.txt | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/requirements.txt b/requirements.txt index 7423651c5..bf48a4c31 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,22 +1,21 @@ -addict -descartes -gdspy>=1.5.2 -geopandas -ipython -matplotlib -numpy -pandas -pint -pyEPR-quantum>=0.8.5.7 -pygments +addict==2.4.0 +descartes==1.1.0 +gdspy==1.6.12 +geopandas==0.12.2 +ipython==8.10.0 +matplotlib==3.7.0 +numpy==1.24.2 +pandas==1.5.3 +pint==0.20.1 +pyEPR-quantum==0.8.5.7 +pygments==2.14.0 pyside6 -qdarkstyle -qutip -scipy -shapely -scqubits -gmsh +qdarkstyle==3.1 +qutip==4.7.1 +scipy==1.10.0 +shapely==2.0.1 +scqubits==3.1.0 +gmsh==4.11.1 +pyaedt==0.6.46 pyyaml==6.0 -cython<3.0.0 -pyaedt==0.6.46 #since conda-forge doesn't have pyaedt, we have to manually pip install or completely switch to virtualenv . virtualenv uses less memory than conda. -# jupyter (if you need a fresh install) or ipykernel (if you prefer to make of this a new kernel to use from an existing jupyter install) \ No newline at end of file +cython<3.0.0 \ No newline at end of file From a87652e17f1bfb92ed4d3077e1745be6f463586a Mon Sep 17 00:00:00 2001 From: shanto268 Date: Sun, 17 Nov 2024 17:09:32 -0800 Subject: [PATCH 21/46] docs: Fix linting issues to satisfy CI checks --- .../table_view_all_components.py | 5 +++- qiskit_metal/tests/run_all_tests.py | 23 +++++++++---------- qiskit_metal/tests/test_toolbox_metal.py | 2 ++ 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/qiskit_metal/_gui/widgets/all_components/table_view_all_components.py b/qiskit_metal/_gui/widgets/all_components/table_view_all_components.py index b09820994..bc502e866 100644 --- a/qiskit_metal/_gui/widgets/all_components/table_view_all_components.py +++ b/qiskit_metal/_gui/widgets/all_components/table_view_all_components.py @@ -47,7 +47,10 @@ def __init__(self, parent: QtWidgets.QWidget): parent (QWidget): Parent widget """ QTableView.__init__(self, parent) - QWidget_PlaceholderText.__init__(self, "No QComponents to show.\n\nCreate components from the QLibrary.", self) + QWidget_PlaceholderText.__init__( + self, + "No QComponents to show.\n\nCreate components from the QLibrary.", + self) # Connect signals self.clicked.connect(self.viewClicked) diff --git a/qiskit_metal/tests/run_all_tests.py b/qiskit_metal/tests/run_all_tests.py index 29db43701..698d92411 100644 --- a/qiskit_metal/tests/run_all_tests.py +++ b/qiskit_metal/tests/run_all_tests.py @@ -24,34 +24,33 @@ ERRORS_EXIST = 0 # Open log files - with open("test_results.log", "w") as results_log, open("test_errors.log", "w") as errors_log: + with open("test_results.log", + "w") as results_log, open("test_errors.log", "w") as errors_log: for entry in LIST_OF_FILES: if fnmatch.fnmatch(entry, PATTERN): if entry != sys.argv[0]: print(f"Running {entry} tests...") results_log.write(f"Running {entry} tests...\n") - + # Run the test and capture output - result = subprocess.run( - f"python {entry}", - shell=True, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - text=True - ) - + result = subprocess.run(f"python {entry}", + shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True) + # Write the stdout and stderr to test_results.log results_log.write(result.stdout) results_log.write(result.stderr) results_log.write("\n") - + # If there's an error, write it to test_errors.log if result.returncode != 0: ERRORS_EXIST += 1 errors_log.write(f"Error in {entry}:\n") errors_log.write(result.stderr) errors_log.write("\n") - + print("") print("All tests complete") diff --git a/qiskit_metal/tests/test_toolbox_metal.py b/qiskit_metal/tests/test_toolbox_metal.py index 2c2218762..8ff387a92 100644 --- a/qiskit_metal/tests/test_toolbox_metal.py +++ b/qiskit_metal/tests/test_toolbox_metal.py @@ -41,6 +41,8 @@ from qiskit_metal.toolbox_metal.layer_stack_handler import LayerStackHandler TEST_DATA = Path(__file__).parent / "test_data" + + class TestToolboxMetal(unittest.TestCase, AssertionsMixin): """Unit test class.""" From b9ad48cdac9a6cd6a69eff9186b6b4e721d82948 Mon Sep 17 00:00:00 2001 From: shanto268 Date: Sun, 17 Nov 2024 17:15:46 -0800 Subject: [PATCH 22/46] docs: Update upload-artifact to v3 in docs workflow --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1c23484e3..1c3df23af 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -147,7 +147,7 @@ jobs: sudo apt install -y graphviz=2.42.2-6 pandoc=2.9.2.1-3ubuntu2 qtbase5-dev=5.15.3+dfsg-2ubuntu0.2 qt5-qmake=5.15.3+dfsg-2ubuntu0.2 - name: Build Docs run: tox -edocs - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: name: html_docs path: docs/_build/html From 06b5b2ecb39850089c741c7c8dda066ecfb4587b Mon Sep 17 00:00:00 2001 From: shanto268 Date: Mon, 18 Nov 2024 20:08:16 -0800 Subject: [PATCH 23/46] fix: added missing QFileSystemModel import --- environment.yml | 37 ++++++++++--------- .../qlibrary_display/proxy_model_qlibrary.py | 2 +- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/environment.yml b/environment.yml index 3097f8864..bb2eb813c 100644 --- a/environment.yml +++ b/environment.yml @@ -3,25 +3,26 @@ channels: - conda-forge dependencies: - python=3.10.* - - addict - - descartes - - gdspy>=1.5.2 - - geopandas - - ipython - - matplotlib - - numpy - - pandas - - pint - - pyepr-quantum>=0.8.5.7 - - pygments - - qdarkstyle - - qutip - - scipy - - shapely + - addict==2.4.0 + - descartes==1.1.0 + - geopandas==0.12.2 + - ipython==8.10.0 + - matplotlib==3.7.0 + - numpy==1.24.2 + - pandas==1.5.3 + - pint==0.20.1 + - pyEPR-quantum==0.8.5.7 + - pygments==2.14.0 + - qdarkstyle==3.1 + - qutip==4.7.1 + - scipy==1.10.0 + - shapely==2.0.1 + - scqubits==3.1.0 - jupyter - - scqubits + - cython<3.0.0 - pip - pip: - - pyaedt - - gmsh + - pyaedt==0.6.46 + - gmsh==4.11.1 + - gdspy==1.6.12 - pyside6 diff --git a/qiskit_metal/_gui/widgets/qlibrary_display/proxy_model_qlibrary.py b/qiskit_metal/_gui/widgets/qlibrary_display/proxy_model_qlibrary.py index 453fef666..1c36d0b80 100644 --- a/qiskit_metal/_gui/widgets/qlibrary_display/proxy_model_qlibrary.py +++ b/qiskit_metal/_gui/widgets/qlibrary_display/proxy_model_qlibrary.py @@ -18,7 +18,7 @@ import typing from PySide6.QtCore import QModelIndex, QSize, QSortFilterProxyModel, Qt -from PySide6.QtWidgets import QWidget +from PySide6.QtWidgets import QFileSystemModel, QWidget class LibraryFileProxyModel(QSortFilterProxyModel): From 2ce4996033e0ff11d87149f4da4628c2d87520c4 Mon Sep 17 00:00:00 2001 From: Zlatko Minev Date: Tue, 31 Dec 2024 08:33:24 -0500 Subject: [PATCH 24/46] Bumping Qiskit Metal version Bumping Qiskit Metal version. Overdue. --- qiskit_metal/__init__.py | 2 +- setup.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/qiskit_metal/__init__.py b/qiskit_metal/__init__.py index cc489422c..d1f21f84a 100644 --- a/qiskit_metal/__init__.py +++ b/qiskit_metal/__init__.py @@ -15,7 +15,7 @@ # pylint: disable=wrong-import-order # pylint: disable=wrong-import-position """Qiskit Metal""" -__version__ = '0.1.5' +__version__ = '0.5.0' __license__ = "Apache 2.0" __copyright__ = 'Copyright IBM 2019-2020' __author__ = 'Zlatko Minev, Thomas McConkey, and them IBM Quantum Team' diff --git a/setup.py b/setup.py index c5410fe34..7fc686af0 100644 --- a/setup.py +++ b/setup.py @@ -11,6 +11,7 @@ -v, --verbose Give more output. """ + # pylint: disable=invalid-name from pathlib import Path @@ -27,7 +28,7 @@ setup( name="qiskit_metal", - version="0.1.5", + version="0.5.0", description="Qiskit Metal | for quantum device design & analysis", long_description=long_description, long_description_content_type="text/markdown", From 7714dee4b5ba39794ce117939792b12378ba5bbd Mon Sep 17 00:00:00 2001 From: Zlatko Minev Date: Tue, 31 Dec 2024 08:57:41 -0500 Subject: [PATCH 25/46] Added mermaid diagram and overview --- README_ARCH.md | 158 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 157 insertions(+), 1 deletion(-) diff --git a/README_ARCH.md b/README_ARCH.md index fa66077ca..ada3e7627 100644 --- a/README_ARCH.md +++ b/README_ARCH.md @@ -4,7 +4,163 @@ The high level Metal architecture is diagramed in the overview below. The user * [Overview](/docs/overview.rst) * [Workflow](/docs/workflow.rst) -## Required Attributes + +## Big Picture Architecutre Overview + +### Diagram + +```mermaid + %%{init: {"flowchart": {"htmlLabels": true}} }%% + graph TB + classDef core fill:#87cefa,stroke:#000000; + classDef gui fill:#FFDDC1,stroke:#000000; + classDef renderer fill:#DBB9FF,stroke:#000000; + classDef utility fill:#FFD700,stroke:#000000; + classDef design fill:#90EE90,stroke:#000000; + classDef analysis fill:#FFB6C1,stroke:#000000; + + subgraph Qiskit_Metal + subgraph Core + QLibraryComponents["QLibrary Components"] + QDesign["QDesign"] + QComponent["QComponent"] + QRoute["QRoute"] + BaseQubit["BaseQubit"] + end + + subgraph GUI + MetalGUI["MetalGUI"] + ElementsWindow["ElementsWindow"] + NetListWindow["NetListWindow"] + ComponentWidget["ComponentWidget"] + QTableView_AllComponents["QTableView_AllComponents"] + QTreeView_Options["QTreeView_Options"] + QTextEditLogger["QTextEditLogger"] + end + + subgraph Renderers + QRenderer["QRenderer"] + QRendererGui["QRendererGui"] + QGDSRenderer["QGDSRenderer"] + QAnsysRenderer["QAnsysRenderer"] + QHFSSRenderer["QHFSSRenderer"] + QQ3DRenderer["QQ3DRenderer"] + QPyaedt["QPyaedt"] + QGmshRenderer["QGmshRenderer"] + QElmerRenderer["QElmerRenderer"] + end + + subgraph Analyses + Hamiltonian["Hamiltonian"] + Sweep_Options["Sweep_Options"] + end + + subgraph Utilities + Parsing["Parsing"] + Exceptions["Exceptions"] + Logging["Logging"] + Toolbox["Toolbox"] + end + end + + QLibraryComponents --> QDesign + QRenderer --> QDesign + QRendererGui --> QRenderer + MetalGUI --> QRendererGui + MetalGUI --> QLibraryComponents + MetalGUI --> QDesign + MetalGUI --> ElementsWindow + MetalGUI --> NetListWindow + MetalGUI --> ComponentWidget + MetalGUI --> QTableView_AllComponents + MetalGUI --> QTreeView_Options + MetalGUI --> QTextEditLogger + QGDSRenderer --> QRenderer + QAnsysRenderer --> QRenderer + QHFSSRenderer --> QRenderer + QQ3DRenderer --> QRenderer + QPyaedt --> QRenderer + QGmshRenderer --> QRenderer + QElmerRenderer --> QRenderer + Parsing --> QDesign + Exceptions --> QDesign + Logging --> QDesign + Toolbox --> QDesign + QDesign --> QComponent + QDesign --> QRoute + QDesign --> BaseQubit + Hamiltonian --> QDesign + Sweep_Options --> QDesign + + class QLibraryComponents,QDesign,QComponent,QRoute,BaseQubit core; + class MetalGUI,ElementsWindow,NetListWindow,ComponentWidget,QTableView_AllComponents,QTreeView_Options,QTextEditLogger gui; + class QRenderer,QRendererGui,QGDSRenderer,QAnsysRenderer,QHFSSRenderer,QQ3DRenderer,QPyaedt,QGmshRenderer,QElmerRenderer renderer; + class Parsing,Exceptions,Logging,Toolbox utility; + class Hamiltonian,Sweep_Options analysis; +``` + + + +The **Qiskit Metal** codebase is organized into several key modules, each with a distinct role in enabling the design, analysis, and visualization of quantum circuits. Below is an overview of the primary components and their interactions: + +### Core +The **Core** module serves as the backbone of Qiskit Metal, housing essential elements for design and component creation: +- **QLibrary Components**: Predefined library of quantum circuit elements, such as qubits and resonators, that can be used in designs. +- **QDesign**: The central design framework that integrates all components and handles design rules. +- **QComponent**: Base class for all components in the design. +- **QRoute**: Specialized class for managing connections between components. +- **BaseQubit**: Represents foundational qubit structures used in circuit designs. + +### GUI +The **GUI** module provides tools for user-friendly interaction with Qiskit Metal: +- **MetalGUI**: The primary graphical interface for managing designs and visualizations. +- **ElementsWindow**: Displays available circuit elements. +- **NetListWindow**: Shows the connections between components. +- **ComponentWidget**: Offers detailed views and controls for individual components. +- **QTableView_AllComponents**: Lists all components in the design. +- **QTreeView_Options**: Presents configuration options in a tree structure. +- **QTextEditLogger**: Logs activities and messages for troubleshooting and feedback. + +### Renderers +The **Renderers** module facilitates exporting designs to external tools for electromagnetic simulation and layout rendering: +- **QRenderer**: Base class for all renderers. +- **QRendererGui**: GUI interface for managing renderers. +- Specialized renderers like: + - **QGDSRenderer** + - **QAnsysRenderer** + - **QHFSSRenderer** + - **QQ3DRenderer** + - **QPyaedt** + - **QGmshRenderer** + - **QElmerRenderer** + +These renderers enable integration with industry-standard tools for detailed simulation and fabrication. + +### Analyses +The **Analyses** module includes tools for performing simulations and extracting insights from designs: +- **Hamiltonian**: Supports calculations of Hamiltonian parameters. +- **Sweep Options**: Provides tools for parametric sweeps and optimizations. + +### Utilities +The **Utilities** module supports the overall functionality of Qiskit Metal by offering supplementary tools: +- **Parsing**: Manages data parsing for design input and output. +- **Exceptions**: Handles error reporting and debugging. +- **Logging**: Tracks system activities and events. +- **Toolbox**: Provides miscellaneous helper functions. + +--- + +### Key Interactions +- The **Core** modules form the foundation and integrate tightly with the **Renderers**, **GUI**, and **Analyses** modules. +- The **GUI** depends on the **Core** and **Renderers** to provide visualization and interactivity. +- The **Renderers** serve as bridges between Qiskit Metal and external tools, interacting with the **Core** to export designs. +- The **Analyses** modules leverage the **Core** to extract meaningful data for optimization and validation. +- The **Utilities** modules provide essential supporting functionalities across the entire codebase. + +This modular structure ensures scalability, flexibility, and ease of use for designing, analyzing, and fabricating quantum circuits. + + +## Required Attributes for Custom Components ### QLibrary Components A base qlibrary component contains several attributes and a method that must be overridden by qlibrary components that extend the base. From 54c1685ae3e7248227b2dc797889b4055a38ac49 Mon Sep 17 00:00:00 2001 From: Zlatko Minev Date: Tue, 31 Dec 2024 09:01:26 -0500 Subject: [PATCH 26/46] Update README_ARCH.md: Fixed meramid theme Update README_ARCH.md: Fixed meramid theme --- README_ARCH.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README_ARCH.md b/README_ARCH.md index ada3e7627..7c4ae9e03 100644 --- a/README_ARCH.md +++ b/README_ARCH.md @@ -10,7 +10,7 @@ The high level Metal architecture is diagramed in the overview below. The user ### Diagram ```mermaid - %%{init: {"flowchart": {"htmlLabels": true}} }%% + %%{init: {"flowchart": {"htmlLabels": true}, 'theme':'forest'} }%% graph TB classDef core fill:#87cefa,stroke:#000000; classDef gui fill:#FFDDC1,stroke:#000000; From 65459514689d7be3d223ecbfd43f03eae34370b4 Mon Sep 17 00:00:00 2001 From: Zlatko Minev Date: Tue, 31 Dec 2024 09:10:53 -0500 Subject: [PATCH 27/46] Update README.md --- README.md | 167 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 167 insertions(+) diff --git a/README.md b/README.md index 96bcff0a3..70f57d5cc 100644 --- a/README.md +++ b/README.md @@ -106,11 +106,176 @@ We use [GitHub issues](https://github.com/Qiskit/qiskit-metal/issues) for tracki [join the Qiskit Slack community](https://qisk.it/join-slack) and use our [Qiskit Slack channel](https://qiskit.slack.com) for discussion and simple questions. For questions that are more suited for a forum we use the Qiskit tag in the [Stack Exchange](https://quantumcomputing.stackexchange.com/questions/tagged/qiskit). + ## Next Steps Now you're set up and ready to check out some of the other examples from our [Qiskit Metal Tutorials](https://github.com/Qiskit/qiskit-metal/blob/main/tutorials/) repository or [Qiskit Metal Documentation](https://qiskit-community.github.io/qiskit-metal/tut/). + + +--- + +# Big Picture Architecutre Overview + +### Diagram + +```mermaid + %%{init: {"flowchart": {"htmlLabels": true}} }%% + graph TB + classDef core fill:#87cefa,stroke:#000000; + classDef gui fill:#FFDDC1,stroke:#000000; + classDef renderer fill:#DBB9FF,stroke:#000000; + classDef utility fill:#FFD700,stroke:#000000; + classDef design fill:#90EE90,stroke:#000000; + classDef analysis fill:#FFB6C1,stroke:#000000; + + subgraph Qiskit_Metal + subgraph Core + QLibraryComponents["QLibrary Components"] + QDesign["QDesign"] + QComponent["QComponent"] + QRoute["QRoute"] + BaseQubit["BaseQubit"] + end + + subgraph GUI + MetalGUI["MetalGUI"] + ElementsWindow["ElementsWindow"] + NetListWindow["NetListWindow"] + ComponentWidget["ComponentWidget"] + QTableView_AllComponents["QTableView_AllComponents"] + QTreeView_Options["QTreeView_Options"] + QTextEditLogger["QTextEditLogger"] + end + + subgraph Renderers + QRenderer["QRenderer"] + QRendererGui["QRendererGui"] + QGDSRenderer["QGDSRenderer"] + QAnsysRenderer["QAnsysRenderer"] + QHFSSRenderer["QHFSSRenderer"] + QQ3DRenderer["QQ3DRenderer"] + QPyaedt["QPyaedt"] + QGmshRenderer["QGmshRenderer"] + QElmerRenderer["QElmerRenderer"] + end + + subgraph Analyses + Hamiltonian["Hamiltonian"] + Sweep_Options["Sweep_Options"] + end + + subgraph Utilities + Parsing["Parsing"] + Exceptions["Exceptions"] + Logging["Logging"] + Toolbox["Toolbox"] + end + end + + QLibraryComponents --> QDesign + QRenderer --> QDesign + QRendererGui --> QRenderer + MetalGUI --> QRendererGui + MetalGUI --> QLibraryComponents + MetalGUI --> QDesign + MetalGUI --> ElementsWindow + MetalGUI --> NetListWindow + MetalGUI --> ComponentWidget + MetalGUI --> QTableView_AllComponents + MetalGUI --> QTreeView_Options + MetalGUI --> QTextEditLogger + QGDSRenderer --> QRenderer + QAnsysRenderer --> QRenderer + QHFSSRenderer --> QRenderer + QQ3DRenderer --> QRenderer + QPyaedt --> QRenderer + QGmshRenderer --> QRenderer + QElmerRenderer --> QRenderer + Parsing --> QDesign + Exceptions --> QDesign + Logging --> QDesign + Toolbox --> QDesign + QDesign --> QComponent + QDesign --> QRoute + QDesign --> BaseQubit + Hamiltonian --> QDesign + Sweep_Options --> QDesign + + class QLibraryComponents,QDesign,QComponent,QRoute,BaseQubit core; + class MetalGUI,ElementsWindow,NetListWindow,ComponentWidget,QTableView_AllComponents,QTreeView_Options,QTextEditLogger gui; + class QRenderer,QRendererGui,QGDSRenderer,QAnsysRenderer,QHFSSRenderer,QQ3DRenderer,QPyaedt,QGmshRenderer,QElmerRenderer renderer; + class Parsing,Exceptions,Logging,Toolbox utility; + class Hamiltonian,Sweep_Options analysis; +``` + + + +The **Qiskit Metal** codebase is organized into several key modules, each with a distinct role in enabling the design, analysis, and visualization of quantum circuits. Below is an overview of the primary components and their interactions: + +### Core +The **Core** module serves as the backbone of Qiskit Metal, housing essential elements for design and component creation: +- **QLibrary Components**: Predefined library of quantum circuit elements, such as qubits and resonators, that can be used in designs. +- **QDesign**: The central design framework that integrates all components and handles design rules. +- **QComponent**: Base class for all components in the design. +- **QRoute**: Specialized class for managing connections between components. +- **BaseQubit**: Represents foundational qubit structures used in circuit designs. + +### GUI +The **GUI** module provides tools for user-friendly interaction with Qiskit Metal: +- **MetalGUI**: The primary graphical interface for managing designs and visualizations. +- **ElementsWindow**: Displays available circuit elements. +- **NetListWindow**: Shows the connections between components. +- **ComponentWidget**: Offers detailed views and controls for individual components. +- **QTableView_AllComponents**: Lists all components in the design. +- **QTreeView_Options**: Presents configuration options in a tree structure. +- **QTextEditLogger**: Logs activities and messages for troubleshooting and feedback. + +### Renderers +The **Renderers** module facilitates exporting designs to external tools for electromagnetic simulation and layout rendering: +- **QRenderer**: Base class for all renderers. +- **QRendererGui**: GUI interface for managing renderers. +- Specialized renderers like: + - **QGDSRenderer** + - **QAnsysRenderer** + - **QHFSSRenderer** + - **QQ3DRenderer** + - **QPyaedt** + - **QGmshRenderer** + - **QElmerRenderer** + +These renderers enable integration with industry-standard tools for detailed simulation and fabrication. + +### Analyses +The **Analyses** module includes tools for performing simulations and extracting insights from designs: +- **Hamiltonian**: Supports calculations of Hamiltonian parameters. +- **Sweep Options**: Provides tools for parametric sweeps and optimizations. + +### Utilities +The **Utilities** module supports the overall functionality of Qiskit Metal by offering supplementary tools: +- **Parsing**: Manages data parsing for design input and output. +- **Exceptions**: Handles error reporting and debugging. +- **Logging**: Tracks system activities and events. +- **Toolbox**: Provides miscellaneous helper functions. + + + +### Key Interactions +- The **Core** modules form the foundation and integrate tightly with the **Renderers**, **GUI**, and **Analyses** modules. +- The **GUI** depends on the **Core** and **Renderers** to provide visualization and interactivity. +- The **Renderers** serve as bridges between Qiskit Metal and external tools, interacting with the **Core** to export designs. +- The **Analyses** modules leverage the **Core** to extract meaningful data for optimization and validation. +- The **Utilities** modules provide essential supporting functionalities across the entire codebase. + +This modular structure ensures scalability, flexibility, and ease of use for designing, analyzing, and fabricating quantum circuits. + + +--- + +# Backmatter + ## Authors and Citation Qiskit Metal is the work of [many people](https://github.com/Qiskit/qiskit-metal/pulse/monthly) who contribute to the project at different levels. Metal was conceived and developed by [Zlatko Minev](https://www.zlatko-minev.com) at IBM; then co-led with Thomas McConkey. If you use Qiskit Metal, please cite as per the included [BibTeX file](https://github.com/Qiskit/qiskit-metal/blob/main/Qiskit_Metal.bib). For icon attributions, see [here](https://github.com/Qiskit/qiskit-metal/blob/main/qiskit_metal/_gui/_imgs/icon_attributions.txt). + ## Changelog and Release Notes The changelog provides a quick overview of notable changes for a given release. @@ -122,3 +287,5 @@ Additionally, as part of each release detailed release notes are written to docu ## License [Apache License 2.0](https://github.com/Qiskit/qiskit-metal/blob/main/LICENSE.txt) + + From e481012349e4878550c9876cb10047b3373aa482 Mon Sep 17 00:00:00 2001 From: Zlatko Minev Date: Tue, 31 Dec 2024 09:11:48 -0500 Subject: [PATCH 28/46] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 70f57d5cc..90287be1d 100644 --- a/README.md +++ b/README.md @@ -119,7 +119,7 @@ Now you're set up and ready to check out some of the other examples from our ### Diagram ```mermaid - %%{init: {"flowchart": {"htmlLabels": true}} }%% + %%{init: {"flowchart": {"htmlLabels": true}, 'theme':'forest'} }%% graph TB classDef core fill:#87cefa,stroke:#000000; classDef gui fill:#FFDDC1,stroke:#000000; From fb8081b10d98818ae4ccd823b3df1ffef1a39e0f Mon Sep 17 00:00:00 2001 From: Zlatko Minev Date: Tue, 31 Dec 2024 09:16:44 -0500 Subject: [PATCH 29/46] Update README.md --- README.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 90287be1d..e2dddb9b4 100644 --- a/README.md +++ b/README.md @@ -112,12 +112,19 @@ Now you're set up and ready to check out some of the other examples from our [Qiskit Metal Tutorials](https://github.com/Qiskit/qiskit-metal/blob/main/tutorials/) repository or [Qiskit Metal Documentation](https://qiskit-community.github.io/qiskit-metal/tut/). + +## Authors and Citation +Qiskit Metal is the work of [many people](https://github.com/Qiskit/qiskit-metal/pulse/monthly) who contribute to the project at different levels. Metal was conceived and developed by [Zlatko Minev](https://www.zlatko-minev.com) at IBM; then co-led with Thomas McConkey. If you use Qiskit Metal, please cite as per the included [BibTeX file](https://github.com/Qiskit/qiskit-metal/blob/main/Qiskit_Metal.bib). For icon attributions, see [here](https://github.com/Qiskit/qiskit-metal/blob/main/qiskit_metal/_gui/_imgs/icon_attributions.txt). + + --- # Big Picture Architecutre Overview ### Diagram +The **Qiskit Metal** codebase is organized into several key modules, each with a distinct role in enabling the design, analysis, and visualization of quantum circuits. Below is an overview of the primary components and their interactions: + ```mermaid %%{init: {"flowchart": {"htmlLabels": true}, 'theme':'forest'} }%% graph TB @@ -209,9 +216,6 @@ Now you're set up and ready to check out some of the other examples from our ``` - -The **Qiskit Metal** codebase is organized into several key modules, each with a distinct role in enabling the design, analysis, and visualization of quantum circuits. Below is an overview of the primary components and their interactions: - ### Core The **Core** module serves as the backbone of Qiskit Metal, housing essential elements for design and component creation: - **QLibrary Components**: Predefined library of quantum circuit elements, such as qubits and resonators, that can be used in designs. @@ -273,9 +277,6 @@ This modular structure ensures scalability, flexibility, and ease of use for des # Backmatter -## Authors and Citation -Qiskit Metal is the work of [many people](https://github.com/Qiskit/qiskit-metal/pulse/monthly) who contribute to the project at different levels. Metal was conceived and developed by [Zlatko Minev](https://www.zlatko-minev.com) at IBM; then co-led with Thomas McConkey. If you use Qiskit Metal, please cite as per the included [BibTeX file](https://github.com/Qiskit/qiskit-metal/blob/main/Qiskit_Metal.bib). For icon attributions, see [here](https://github.com/Qiskit/qiskit-metal/blob/main/qiskit_metal/_gui/_imgs/icon_attributions.txt). - ## Changelog and Release Notes The changelog provides a quick overview of notable changes for a given release. From d76f76c758ab8fecf3dbd6d9e2b9b818278cda99 Mon Sep 17 00:00:00 2001 From: Zlatko Minev Date: Tue, 31 Dec 2024 09:17:59 -0500 Subject: [PATCH 30/46] Update README.md --- README.md | 48 ++++++++++++++++++------------------------------ 1 file changed, 18 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index e2dddb9b4..58c0941f7 100644 --- a/README.md +++ b/README.md @@ -112,18 +112,13 @@ Now you're set up and ready to check out some of the other examples from our [Qiskit Metal Tutorials](https://github.com/Qiskit/qiskit-metal/blob/main/tutorials/) repository or [Qiskit Metal Documentation](https://qiskit-community.github.io/qiskit-metal/tut/). - -## Authors and Citation -Qiskit Metal is the work of [many people](https://github.com/Qiskit/qiskit-metal/pulse/monthly) who contribute to the project at different levels. Metal was conceived and developed by [Zlatko Minev](https://www.zlatko-minev.com) at IBM; then co-led with Thomas McConkey. If you use Qiskit Metal, please cite as per the included [BibTeX file](https://github.com/Qiskit/qiskit-metal/blob/main/Qiskit_Metal.bib). For icon attributions, see [here](https://github.com/Qiskit/qiskit-metal/blob/main/qiskit_metal/_gui/_imgs/icon_attributions.txt). - - --- # Big Picture Architecutre Overview ### Diagram -The **Qiskit Metal** codebase is organized into several key modules, each with a distinct role in enabling the design, analysis, and visualization of quantum circuits. Below is an overview of the primary components and their interactions: +The **Qiskit Metal** codebase is organized into several key modules, each with a distinct role in enabling the design, analysis, and visualization of quantum circuits. Below is an overview of the primary components and their interactions, discussed deeper in the [Architecture Readme](README_ARCH.md) and the docs: ```mermaid %%{init: {"flowchart": {"htmlLabels": true}, 'theme':'forest'} }%% @@ -146,12 +141,12 @@ The **Qiskit Metal** codebase is organized into several key modules, each with a subgraph GUI MetalGUI["MetalGUI"] - ElementsWindow["ElementsWindow"] - NetListWindow["NetListWindow"] - ComponentWidget["ComponentWidget"] - QTableView_AllComponents["QTableView_AllComponents"] - QTreeView_Options["QTreeView_Options"] - QTextEditLogger["QTextEditLogger"] + + + + + + end subgraph Renderers @@ -185,12 +180,12 @@ The **Qiskit Metal** codebase is organized into several key modules, each with a MetalGUI --> QRendererGui MetalGUI --> QLibraryComponents MetalGUI --> QDesign - MetalGUI --> ElementsWindow + ElementsWindow MetalGUI --> NetListWindow MetalGUI --> ComponentWidget MetalGUI --> QTableView_AllComponents MetalGUI --> QTreeView_Options - MetalGUI --> QTextEditLogger + MetalGUI --> QTextEditLogger --> QGDSRenderer --> QRenderer QAnsysRenderer --> QRenderer QHFSSRenderer --> QRenderer @@ -209,7 +204,7 @@ The **Qiskit Metal** codebase is organized into several key modules, each with a Sweep_Options --> QDesign class QLibraryComponents,QDesign,QComponent,QRoute,BaseQubit core; - class MetalGUI,ElementsWindow,NetListWindow,ComponentWidget,QTableView_AllComponents,QTreeView_Options,QTextEditLogger gui; + class MetalGUI gui; class QRenderer,QRendererGui,QGDSRenderer,QAnsysRenderer,QHFSSRenderer,QQ3DRenderer,QPyaedt,QGmshRenderer,QElmerRenderer renderer; class Parsing,Exceptions,Logging,Toolbox utility; class Hamiltonian,Sweep_Options analysis; @@ -224,16 +219,6 @@ The **Core** module serves as the backbone of Qiskit Metal, housing essential el - **QRoute**: Specialized class for managing connections between components. - **BaseQubit**: Represents foundational qubit structures used in circuit designs. -### GUI -The **GUI** module provides tools for user-friendly interaction with Qiskit Metal: -- **MetalGUI**: The primary graphical interface for managing designs and visualizations. -- **ElementsWindow**: Displays available circuit elements. -- **NetListWindow**: Shows the connections between components. -- **ComponentWidget**: Offers detailed views and controls for individual components. -- **QTableView_AllComponents**: Lists all components in the design. -- **QTreeView_Options**: Presents configuration options in a tree structure. -- **QTextEditLogger**: Logs activities and messages for troubleshooting and feedback. - ### Renderers The **Renderers** module facilitates exporting designs to external tools for electromagnetic simulation and layout rendering: - **QRenderer**: Base class for all renderers. @@ -254,12 +239,12 @@ The **Analyses** module includes tools for performing simulations and extracting - **Hamiltonian**: Supports calculations of Hamiltonian parameters. - **Sweep Options**: Provides tools for parametric sweeps and optimizations. + +### GUI +The **GUI** module provides tools for user-friendly interaction with Qiskit Metal. The **MetalGUI** clas is the primary graphical interface for managing designs and visualizations. It is discussed in more depth in the [Architecture Readme](README_ARCH.md). + ### Utilities -The **Utilities** module supports the overall functionality of Qiskit Metal by offering supplementary tools: -- **Parsing**: Manages data parsing for design input and output. -- **Exceptions**: Handles error reporting and debugging. -- **Logging**: Tracks system activities and events. -- **Toolbox**: Provides miscellaneous helper functions. +The **Utilities** module supports the overall functionality of Qiskit Metal by offering supplementary tools. @@ -277,6 +262,9 @@ This modular structure ensures scalability, flexibility, and ease of use for des # Backmatter +## Authors and Citation +Qiskit Metal is the work of [many people](https://github.com/Qiskit/qiskit-metal/pulse/monthly) who contribute to the project at different levels. Metal was conceived and developed by [Zlatko Minev](https://www.zlatko-minev.com) at IBM; then co-led with Thomas McConkey. If you use Qiskit Metal, please cite as per the included [BibTeX file](https://github.com/Qiskit/qiskit-metal/blob/main/Qiskit_Metal.bib). For icon attributions, see [here](https://github.com/Qiskit/qiskit-metal/blob/main/qiskit_metal/_gui/_imgs/icon_attributions.txt). + ## Changelog and Release Notes The changelog provides a quick overview of notable changes for a given release. From ea3e2e41fa2a3473d4544dfc19e97106f31475b3 Mon Sep 17 00:00:00 2001 From: Zlatko Minev Date: Tue, 31 Dec 2024 09:18:35 -0500 Subject: [PATCH 31/46] fix mermaid js --- README.md | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/README.md b/README.md index 58c0941f7..ef6a7ea83 100644 --- a/README.md +++ b/README.md @@ -141,12 +141,6 @@ The **Qiskit Metal** codebase is organized into several key modules, each with a subgraph GUI MetalGUI["MetalGUI"] - - - - - - end subgraph Renderers @@ -180,12 +174,6 @@ The **Qiskit Metal** codebase is organized into several key modules, each with a MetalGUI --> QRendererGui MetalGUI --> QLibraryComponents MetalGUI --> QDesign - ElementsWindow - MetalGUI --> NetListWindow - MetalGUI --> ComponentWidget - MetalGUI --> QTableView_AllComponents - MetalGUI --> QTreeView_Options - MetalGUI --> QTextEditLogger --> QGDSRenderer --> QRenderer QAnsysRenderer --> QRenderer QHFSSRenderer --> QRenderer From df2347fbc918b23f7fb72ea94ee33bbc0da08b8e Mon Sep 17 00:00:00 2001 From: Zlatko Minev Date: Sun, 19 Jan 2025 19:56:34 -0500 Subject: [PATCH 32/46] Clean up readmes --- README.md | 6 +- README_ARCH.md => README_Architecture.md | 0 README_Tutorials.md | 74 ++++++++++++------------ 3 files changed, 40 insertions(+), 40 deletions(-) rename README_ARCH.md => README_Architecture.md (100%) diff --git a/README.md b/README.md index ef6a7ea83..98425c480 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ We're excited to share that we're nearing the completion of porting Qiskit Metal from PySide2 to PySide6! This update enables native support for M* Macs (Apple Silicon) and includes several other enhancements for the upcoming release. Please take a moment to review and provide feedback on [Pull Request #1002](https://github.com/qiskit-community/qiskit-metal/pull/1002) before we proceed with merging and tagging. Your input is invaluable to ensure the release meets everyone's expectations. Thank you for your continued contributions! ## Installation -If you are interested in customizing your experience, or if you are unable to install qiskit-metal using the `pip install` instructions below, consider installing directly the source code, following the instructions in the [documentation](https://qiskit-community.github.io/qiskit-metal/installation.html) and/or the [installation instructions for developers](https://github.com/Qiskit/qiskit-metal/blob/main/README_developers.md). +If you are interested in customizing your experience, or if you are unable to install qiskit-metal using the `pip install` instructions below, consider installing directly the source code, following the instructions in the [documentation](https://qiskit-community.github.io/qiskit-metal/installation.html) and/or the [installation instructions for developers](https://github.com/Qiskit/qiskit-metal/blob/main/README_Developers.md). For normal use, please continue reading. @@ -118,7 +118,7 @@ Now you're set up and ready to check out some of the other examples from our ### Diagram -The **Qiskit Metal** codebase is organized into several key modules, each with a distinct role in enabling the design, analysis, and visualization of quantum circuits. Below is an overview of the primary components and their interactions, discussed deeper in the [Architecture Readme](README_ARCH.md) and the docs: +The **Qiskit Metal** codebase is organized into several key modules, each with a distinct role in enabling the design, analysis, and visualization of quantum circuits. Below is an overview of the primary components and their interactions, discussed deeper in the [Architecture Readme](README_Architecture.md) and the docs: ```mermaid %%{init: {"flowchart": {"htmlLabels": true}, 'theme':'forest'} }%% @@ -229,7 +229,7 @@ The **Analyses** module includes tools for performing simulations and extracting ### GUI -The **GUI** module provides tools for user-friendly interaction with Qiskit Metal. The **MetalGUI** clas is the primary graphical interface for managing designs and visualizations. It is discussed in more depth in the [Architecture Readme](README_ARCH.md). +The **GUI** module provides tools for user-friendly interaction with Qiskit Metal. The **MetalGUI** clas is the primary graphical interface for managing designs and visualizations. It is discussed in more depth in the [Architecture Readme](README_Architecture.md). ### Utilities The **Utilities** module supports the overall functionality of Qiskit Metal by offering supplementary tools. diff --git a/README_ARCH.md b/README_Architecture.md similarity index 100% rename from README_ARCH.md rename to README_Architecture.md diff --git a/README_Tutorials.md b/README_Tutorials.md index b32a45554..683a89cef 100644 --- a/README_Tutorials.md +++ b/README_Tutorials.md @@ -1,42 +1,42 @@ -# Tutorials - Access and Schedule +# 📚 Tutorials - Access and Schedule -Through June 2021 we are offering live tutorials and Q&A. +Recordings of live tutorials and Q&A sessions with researchers, developers, and the community. -[Sign up](https://airtable.com/shrxQEgKqZCf319F3) to receive updates and the invite to the upcoming sessions. +[VIDEOS: YouTube Playlist of tutorial recordings - click here](https://www.youtube.com/playlist?list=PLOFEBzvs-VvqHl5ZqVmhB_FcSqmLufsjb). -The streaming will also be recorded and made available [here](https://www.youtube.com/playlist?list=PLOFEBzvs-VvqHl5ZqVmhB_FcSqmLufsjb) for offline review. +Join the [Qiskit](https://qisk.it/join-slack) `#metal` Slack channel to request topics of interest, give feedback, and participate in all Qiskit Metal discussions. -Join the [Qiskit](https://qisk.it/join-slack) `#metal` slack channel to request topics of interest, to give us feedback and to participate to all qiskit metal discussions. +## 🗓️ Recording Log -## Current Schedule -| Date | Type | Topic | -| -------------------- | -------------------- | ------------------------------------ | -| April 1 | Tutorial | [Introduction to Qiskit Metal.](https://youtu.be/NCNv3YPvveM) | -| April 8 | Tutorial | Overview: Qubit chip design-flow. [Part 1](https://youtu.be/bsrsKZLTkTo) | -| April 15 | Tutorial | Overview: Qubit chip design-flow. [Part 2](https://youtu.be/fj1hpAqZfmg) | -| April 22 | Forum | First impressions - The Qiskit Metal team will take questions regarding what you learned, experienced and achieved so far. You can also share. | | -| April 29 | Tutorial | [QComponents](https://youtu.be/ljzWF3dNHEU): How to use, modify and extend the qiskit-metal library. | -| May 6 | Forum | Q&A - The Qiskit Metal team will take questions regarding customizing qiskit-metal design. You can also share your component work and ideas with us. | | -| May 6 | Offline Recordings | Tutorials on analysis methods:
  • [Method 1: Capacitance and frequency control](https://youtu.be/rY7Os7B9sg0)
  • [Method 2: Eigenmode and Energy Participation Ratio](https://youtu.be/mvT9Fb7UGH4)
  • [Theory: Energy Participation Ratio](https://youtu.be/ITCkKfjxcbc)
  • [Summary EPR Quantization with Code Example](https://youtu.be/FXmPyYEyL9U)
  • [Finish Eigenmode + Method 3: Impedance Analysis](https://youtu.be/4jBVdHzmJdw)
  • [Continue Impedance Analysis: Example](https://youtu.be/Bi8ZVAq-0tw)
| | -| May 13 | Tutorial | [Quantum Analysis 101](https://youtu.be/QIr2Rlj1cpI) | -| May 20 | Tutorial | [Introduction to the transmon qubit](https://youtu.be/6KgOaU1BAxg) | -| May 27 | Tutorial | [Physics of the Cooper Pair Box Transmon](https://youtu.be/Ql8AS4Iay-Q) | -| June 3 | Tutorial |
  • [Parametric Sweeps](https://youtu.be/ZRsk5dvH1K0)
  • [Github contribution how-to](https://youtu.be/rJWo1Pt19vI)
  • | -| June 10 → July 8 | >Break< | No tutorials | -| July 15 | Tutorial |
    • [Energy Participation Ratio in Qiskit Metal](https://youtu.be/HJNKG5z6Jys)
    • [New Feature sneak peek - LOM analysis for composite systems](https://youtu.be/XpnTJSBjb8E)
    • [New Feature - Export design to script](https://youtu.be/JpoD3SjObHc)
    | -| July 22 → Sept 16 | >Break< | No tutorials | -| Sept 23 | Tutorial | [Making a QComponent from scratch](https://youtu.be/5iEOJDMWXDE) | -| Oct 7 | Tutorial | [New LOM Analysis Methodology - Part 1](https://youtu.be/S8Wx2Lo2CxQ) | -| Oct 21 | Tutorial | [New LOM Analysis Methodology - Part 2](https://youtu.be/b2azGJ-RCjk) | -| Nov 4 | Tutorial | [New LOM Analysis Methodology - Part 3](https://youtu.be/kWFYYUa0V3k) | -| Nov 18 | Forum | Q&A - The Qiskit Metal team will take any question | -| Jan 13, 2022 | Forum | Q&A - The Qiskit Metal team will take any question | -| Jan 27, 2022 | Forum | Helping users generate a custom component. -| Feb 10, 2022 | Tutorial |
    • [GUI icons](https://youtu.be/aE2Dsc67S8w)
    • [Jaynes Cummings model](https://youtu.be/dtwL_K-TJtY)
    • [template_options, options, default_options](https://youtu.be/qKLyEyW7cbQ)| -| Feb 24, 2022 | Tutorial | [Flip chip by guest speaker, Sandoko Kosen.](https://youtu.be/BUojR6Uti5Q)| -| Mar 10, 2022 | Forum| Metal community provide feedback.| -| Mar 24, 2022 | Tutorial | [Time Evolution for the CR gate](https://www.youtube.com/watch?v=icDryjZrUQ4)| -| Aug 4, 2022 | Tutorial | [Open-Source Rendering and Simulation Solution for Qiskit Metal](https://youtu.be/sA0uXtCAhWw)| -| Aug 11, 2022 | Tutorial | [Qiskit Metal E21. Quantum Spice Web App - Sneak Peak](https://youtu.be/3UE57DaG-HI)| -| Feb 2, 2023 | Tutorial | [Qiskit Metal E22. Open-Source Simulation Renderers for Metal — Gmsh and ElmerFEM](https://youtu.be/84j3l_9fHko)| -| 2022 → ... | TBD | Topics to potentially schedule:
      • Analysis deep dives (as needed)
      • What happens frequently when analyzing a chip.
      • Metal use cases: Common problems with pins, ports, fillet matches meander distance
      • GDS fabrication option, use cases
      • QRenderers: How to use, modify and add new renderers
      • New QAnalysis/QRenderer structure and usage
      • ...
      | + +| 📅 Date | 📌 Type | 📝 Topic | +| ------------------ | ----------- | ------- | +| **April 1** | Tutorial | [Introduction to Qiskit Metal](https://youtu.be/NCNv3YPvveM) | +| **April 8** | Tutorial | Overview: Qubit chip design-flow. [Part 1](https://youtu.be/bsrsKZLTkTo) | +| **April 15** | Tutorial | Overview: Qubit chip design-flow. [Part 2](https://youtu.be/fj1hpAqZfmg) | +| **April 22** | Forum | First impressions - Qiskit Metal team answers questions and invites feedback. | +| **April 29** | Tutorial | [QComponents](https://youtu.be/ljzWF3dNHEU): How to use, modify, and extend the Qiskit Metal library. | +| **May 6** | Forum | Q&A - Customizing Qiskit Metal designs. Share your components and ideas with us. | +| **May 6** | Offline Recordings | Tutorials on analysis methods:
      • [Capacitance and frequency control](https://youtu.be/rY7Os7B9sg0)
      • [Eigenmode & Energy Participation Ratio](https://youtu.be/mvT9Fb7UGH4)
      • [Energy Participation Ratio Theory](https://youtu.be/ITCkKfjxcbc)
      • [EPR Quantization with Code Example](https://youtu.be/FXmPyYEyL9U)
      • [Finish Eigenmode + Impedance Analysis](https://youtu.be/4jBVdHzmJdw)
      • [Impedance Analysis Example](https://youtu.be/Bi8ZVAq-0tw)
      | +| **May 13** | Tutorial | [Quantum Analysis 101](https://youtu.be/QIr2Rlj1cpI) | +| **May 20** | Tutorial | [Introduction to the Transmon Qubit](https://youtu.be/6KgOaU1BAxg) | +| **May 27** | Tutorial | [Physics of the Cooper Pair Box Transmon](https://youtu.be/Ql8AS4Iay-Q) | +| **June 3** | Tutorial |
      • [Parametric Sweeps](https://youtu.be/ZRsk5dvH1K0)
      • [Github Contribution How-to](https://youtu.be/rJWo1Pt19vI)
      | +| **June 10 → July 8** | Break | No tutorials during this period. | +| **July 15** | Tutorial |
      • [Energy Participation Ratio in Qiskit Metal](https://youtu.be/HJNKG5z6Jys)
      • [New Feature: LOM Analysis for Composite Systems](https://youtu.be/XpnTJSBjb8E)
      • [New Feature: Export Design to Script](https://youtu.be/JpoD3SjObHc)
      | +| **July 22 → Sept 16** | Break | No tutorials during this period. | +| **Sept 23** | Tutorial | [Making a QComponent from Scratch](https://youtu.be/5iEOJDMWXDE) | +| **Oct 7** | Tutorial | [New LOM Analysis Methodology - Part 1](https://youtu.be/S8Wx2Lo2CxQ) | +| **Oct 21** | Tutorial | [New LOM Analysis Methodology - Part 2](https://youtu.be/b2azGJ-RCjk) | +| **Nov 4** | Tutorial | [New LOM Analysis Methodology - Part 3](https://youtu.be/kWFYYUa0V3k) | +| **Nov 18** | Forum | Q&A - Ask anything to the Qiskit Metal team. | +| **Jan 13, 2022** | Forum | Q&A - Open discussion with the Qiskit Metal team. | +| **Jan 27, 2022** | Forum | Helping users generate a custom component. | +| **Feb 10, 2022** | Tutorial |
      • [GUI Icons](https://youtu.be/aE2Dsc67S8w)
      • [Jaynes Cummings Model](https://youtu.be/dtwL_K-TJtY)
      • [Template Options, Default Options](https://youtu.be/qKLyEyW7cbQ)
      | +| **Feb 24, 2022** | Tutorial | [Flip Chip by Guest Speaker, Sandoko Kosen](https://youtu.be/BUojR6Uti5Q) | +| **Mar 10, 2022** | Forum | Metal community feedback session. | +| **Mar 24, 2022** | Tutorial | [Time Evolution for the CR Gate](https://www.youtube.com/watch?v=icDryjZrUQ4) | +| **Aug 4, 2022** | Tutorial | [Open-Source Rendering and Simulation Solution for Qiskit Metal](https://youtu.be/sA0uXtCAhWw) | +| **Aug 11, 2022** | Tutorial | [Qiskit Metal E21: Quantum Spice Web App - Sneak Peak](https://youtu.be/3UE57DaG-HI) | +| **Feb 2, 2023** | Tutorial | [Qiskit Metal E22: Open-Source Simulation Renderers — Gmsh & ElmerFEM](https://youtu.be/84j3l_9fHko) | +| **2022 → ...** | TBD | Potential Topics:
      • Analysis Deep Dives (as needed)
      • Common Chip Analysis Issues
      • Metal Use Cases: Pin, Port, Fillet Matching
      • GDS Fabrication Options
      • QRenderers: How to Use & Modify
      • New QAnalysis/QRenderer Structure
      • ...
      | From 444b4cab442afe1f59caaeac2478eb59d6ed00a9 Mon Sep 17 00:00:00 2001 From: Zlatko Minev Date: Sun, 26 Jan 2025 16:40:51 -0500 Subject: [PATCH 33/46] pylint --- .pylintrc | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.pylintrc b/.pylintrc index b5c307a08..fc036d79e 100644 --- a/.pylintrc +++ b/.pylintrc @@ -6,7 +6,7 @@ # A comma-separated list of package or module names from where C extensions may # be loaded. Extensions are loading into the active Python interpreter and may # run arbitrary code. -extension-pkg-whitelist=PySide6 +extension-pkg-whitelist=PySide6,gdstk # Add files or directories to the blacklist. They should be base names, not # paths. @@ -91,7 +91,7 @@ disable=apply-builtin,         dict-values-not-iterating,         dict-view-method,         div-method, -        eq-without-hash, +;         eq-without-hash,         exception-escape,         exception-message-attribute,         execfile-builtin, @@ -108,21 +108,21 @@ disable=apply-builtin,         intern-builtin,         invalid-str-codec,         locally-disabled, -        logging-fstring-interpolation  # fstrings inside logging + logging-fstring-interpolation, # fstrings inside logging         long-builtin, -        long-suffix, +;         long-suffix,         map-builtin-not-iterating,         metaclass-assignment, missing-module-docstring,         next-method-called,         next-method-defined,         no-absolute-import, -        non-ascii-bytes-literal, +;         non-ascii-bytes-literal,         nonzero-method,         oct-method,         old-division, -        old-ne-operator, -        old-octal-literal, +;         old-ne-operator, +;         old-octal-literal,         old-raise-syntax,         parameter-unpacking,         print-statement, @@ -339,8 +339,8 @@ max-module-lines=1000 # separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. # `trailing-comma` allows a space between comma and closing bracket: (a, ). # `empty-line` allows space-only lines. -no-space-check=trailing-comma, - dict-separator +; no-space-check=trailing-comma, +; dict-separator # Allow the body of a class to be on the same line as the declaration if body # contains single statement. From 9589b47d9ab228481f583df58d9544dac41db506 Mon Sep 17 00:00:00 2001 From: Zlatko Minev Date: Sun, 26 Jan 2025 16:41:08 -0500 Subject: [PATCH 34/46] contributions update --- CONTRIBUTING.md | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6b9aaf03c..b075bd494 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -43,15 +43,16 @@ https://google.github.io/styleguide/pyguide.html) for auto formatting. The custo #### VSCode Setup +Steps: +1. Install the following extensions: `python` and `yapf` if you have not yet. +2. Add the following workspace setting in the workspace `settings.json`. + If you are using VSCode for your code editor, you can add these settings to your `settings.json` to enforce your code to our style. Make sure to add PySide2 to the linter: -``` +```json { "python.linting.pylintEnabled": true, "python.linting.enabled": true, - "python.linting.pylintArgs": [ - "--extension-pkg-whitelist=PySide2" - ], "python.formatting.provider": "yapf", "editor.formatOnSave": true, "files.trimTrailingWhitespace": true, @@ -59,6 +60,21 @@ to your `settings.json` to enforce your code to our style. Make sure to add PySi } ``` + +In newer versions of VS Code: +```json +{ + "editor.formatOnSave": true, + "files.trimTrailingWhitespace": true, + "files.trimFinalNewlines": true, + "editor.defaultFormatter": "eeyore.yapf", + "notebook.defaultFormatter": "eeyore.yapf", + "[python]": { + "editor.defaultFormatter": "eeyore.yapf" + } +} +``` + ### Code Review Code review is done in the open and open to anyone. While only maintainers have access to merge commits, providing feedback on pull requests is very valuable and helpful. It is also a good mechanism to learn about the code base. You can view a list of all open pull requests to review any open pull requests and provide feedback on it. From cf577a59b5203b2593f645abc14515cbaff9489c Mon Sep 17 00:00:00 2001 From: Zlatko Minev Date: Sun, 26 Jan 2025 16:42:22 -0500 Subject: [PATCH 35/46] GUI Styles minot rupdate and install --- .gitignore | 1 + docs/installation.rst | 66 ++++++++----------- qiskit_metal/_gui/styles/metal_dark/TODO.txt | 11 +++- .../_gui/styles/metal_dark/qss/_styles.scss | 5 ++ qiskit_metal/_gui/styles/metal_dark/style.qss | 5 ++ 5 files changed, 48 insertions(+), 40 deletions(-) diff --git a/.gitignore b/.gitignore index ebd21023e..ac4d4e024 100644 --- a/.gitignore +++ b/.gitignore @@ -57,6 +57,7 @@ instance/ # User Folders: .scrapy _sandbox_/ +_debug/ qiskit_metal/qlibrary/user_components/* !qiskit_metal/qlibrary/user_components/__init__.py !qiskit_metal/qlibrary/user_components/my_qcomponent.py diff --git a/docs/installation.rst b/docs/installation.rst index 2252b07eb..9d43433d9 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -4,6 +4,19 @@ Installation ************ +~~~~~~~~~~~~~~~~~~~~~~~ +Outline of Installation +~~~~~~~~~~~~~~~~~~~~~~~ + +* **Basic Installation**: Quick setup instructions for PyPI deployment. +* **Advanced Installation**: Detailed options for different environments. + - **Conda environment setup** (preferred setup): Instructions for creating a new or using an existing conda environment. + - **Without conda**: Alternative setup using Python virtual environments. +* **Other** + * **Optional Jupyter Lab**: Steps to integrate the environment with Jupyter Lab. + * **Installation hints**: Tips and troubleshooting for setting up the environment. + * **Common Issues**: FAQ and solutions to common problems. + ~~~~~~~~~~~~~~~~~~ Basic Installation ~~~~~~~~~~~~~~~~~~ @@ -67,7 +80,7 @@ Option 1: A new environment ^^^^^^^^^^^^^^^^^^^^^^^^^^^ The most reliable way to set up a qiskit_metal environment is to build one from scratch using the provided conda environment specification file `environment.yml`. -To do so, first navigate to the folder created by the clone. For example: +To do so, first navigate to the root folder created by the code clone. For example: :: @@ -85,7 +98,7 @@ This creates a new environment with name `` with all the necessary lib Then it activates the new environment. Finally installs the local qiskit-metal code inside that environment. -The `-e` flag install qiskit\_metal in `editable mode `_. +The `-e` flag installs qiskit\_metal in `editable mode `_. You can add the `-v` flag for verbose on-screen log information. @@ -98,7 +111,7 @@ To do so, execute these commands in the top-level of the repository: :: - conda env update -n environment.yml + conda env update -n -f environment.yml conda activate python -m pip install --no-deps -e . @@ -108,15 +121,15 @@ Notes: * Remember the period (".") at the end of the third command. * **Important**: Remember to `conda activate ` if you intend to use qiskit-metal. See what a `conda environment is `_ -At this point you can already use qiskit-metal through jupyter notebook. -However, if you prefer using jupyter lab, you will need to execute a couple of extra steps. +At this point you can already use qiskit-metal through Jupyter Notebook. +However, if you prefer using JupyterLab, you will need to execute a couple of extra steps. ^^^^^^^^^^^^^^^^^^^^^^ -(Optional) Jupyter lab +(Optional) Jupyter Lab ^^^^^^^^^^^^^^^^^^^^^^ -Launching jupyter lab will execute python code in the conda `base` environment by default. +Launching JupyterLab will execute Python code in the conda `base` environment by default. -To change environment to the Qiskit Metal one you just finished setting up, denoted by ``, which we usually just call `metal`, you will need first to add to jupyter lab's list of available kernels. +To change environment to the Qiskit Metal one you just finished setting up, denoted by ``, which we usually just call `metal`, you will need first to add to JupyterLab's list of available kernels. From the command line, run the following lines (inside an active environment): @@ -128,40 +141,19 @@ From the command line, run the following lines (inside an active envi Using the above command, you will now have the current conda environment in any Jupyter notebook. -Once inside `jupyter lab`, you can switch to the newly created Metal kernel to use qiskit-metal. Use the Menu `Kernel>Change Kernel`. - -------------------------------------------- -Subsequent updates of the conda environment -------------------------------------------- - -Package dependencies will evolve over time and could at some point require a new version of a library. -For example, we can anticipate updating `pyEPR-quantum` to enable Ansys interactions previously unsupported. -To update your local install, simply execute the metal package install command - -:: - - python -m pip install -ve . - -Alternatively, you can remove your conda environment by executing the commands below and later re-create a new environment following the original install instructions in section 1. - -:: - - conda env list - conda env remove -n - -We discourage using conda commands to update packages after the install of Qiskit Metal. -Indeed, since Qiskit Metal is installed using pip, the subsequent use of conda commands can introduce inconsistencies that could render your environment unusable. +Once inside `JupyterLab`, you can switch to the newly created Metal kernel to use qiskit-metal. Use the Menu `Kernel>Change Kernel`. ------------------------------------------------------------ Without conda: Virtual environment setup (alternative setup) ------------------------------------------------------------ -**On Windows, do this first:** It is recommended that you first install `Visual C++ 14.0`, it is required for a successful install of `gdspy`. -If you do not have `Visual C++ 14.0` installed you will be notified to install it when `gdspy` attempts to install. +**On Windows, do this first:** It is recommended that you first install `Visual C++ 14.0`, required for a successful install of `gdspy`. +If you do not have `Visual C++ 14.0` installed, you will be notified to install it when `gdspy` attempts to install. You can do this by downloading and installing `C++ Build Tools `_. Be sure to select the latest versions of `MSVCv142 - VS 2019 C++ x64/x86 build tools` and `Windows 10 SDK` in the installer as suggested in `this wiki `_ referenced by the gdspy documentation. To use a Python virtual environment, execute these commands in the top-level of the repository: + :: python -m venv @@ -169,9 +161,7 @@ To use a Python virtual environment, execute these commands in the top-level of python -m pip install -U pip python -m pip install -r requirements.txt -r requirements-dev.txt -e . - -where `` is where you want the Python virtual environment to be installed. -On Windows, replace `source /bin/activate` with `.\\Scripts\activate`. +On Windows, replace `source /bin/activate` with `.\Scripts\activate`. ------------------ Installation hints @@ -181,9 +171,9 @@ Here are some things to consider when setting up a development environment: * If using a virtual environment, make sure `pip` is up to date. In initial environment testing, PySide2 is installable with only the latest version of `pip`. -* Add the path of your qiskit-metal folder to your PATH +* Add the path of your qiskit-metal folder to your PATH. -* Library errors when activating conda environments, or initializing jupyter notebook/lab, indicate a conflict between python libraries in the base and sub environments. Go ahead and manually delete the library from the base environment `site-packages` folder, shows in the error message. You might need to reinstall them in the sub environment, or create a new one. +* Library errors when activating conda environments or initializing Jupyter Notebook/Lab indicate a conflict between Python libraries in the base and sub-environments. Go ahead and manually delete the library from the base environment `site-packages` folder shown in the error message. You might need to reinstall them in the sub-environment or create a new one. -------------------------- Setting up precommit hooks diff --git a/qiskit_metal/_gui/styles/metal_dark/TODO.txt b/qiskit_metal/_gui/styles/metal_dark/TODO.txt index e93f18f71..8fe2f8614 100644 --- a/qiskit_metal/_gui/styles/metal_dark/TODO.txt +++ b/qiskit_metal/_gui/styles/metal_dark/TODO.txt @@ -2,11 +2,18 @@ Remember to modify the highlight color to red for the QToolbar hover QToolBar QToolButton:hover { border: 1px solid #e74d10; - ... + ... +2025-01: Added to style.qss for teh New Component Button and added to _style.scss: +``` + QPushButton#create_qcomp_button { + border: 1px solid #e74d10; + border-radius: 1px; + } +``` -How to update stylesheet +How to update stylesheet gui.load_stylesheet('metal_dark') \ No newline at end of file diff --git a/qiskit_metal/_gui/styles/metal_dark/qss/_styles.scss b/qiskit_metal/_gui/styles/metal_dark/qss/_styles.scss index 1e12763c1..203caa80a 100755 --- a/qiskit_metal/_gui/styles/metal_dark/qss/_styles.scss +++ b/qiskit_metal/_gui/styles/metal_dark/qss/_styles.scss @@ -2271,3 +2271,8 @@ PlotWidget { /* Fix cut labels in plots #134 */ padding: 0px; } + +QPushButton#create_qcomp_button { + border: 1px solid #e74d10; + border-radius: 1px; + } diff --git a/qiskit_metal/_gui/styles/metal_dark/style.qss b/qiskit_metal/_gui/styles/metal_dark/style.qss index 4948a7bc8..1ae8e5f2a 100644 --- a/qiskit_metal/_gui/styles/metal_dark/style.qss +++ b/qiskit_metal/_gui/styles/metal_dark/style.qss @@ -2199,3 +2199,8 @@ PlotWidget { /* Fix cut labels in plots #134 */ padding: 0px; } + +QPushButton#create_qcomp_button { + border: 1px solid #e74d10; + border-radius: 1px; +} From 6b7b258d40ffe7912b25332c5bbf413ac5530e8d Mon Sep 17 00:00:00 2001 From: Zlatko Minev Date: Sun, 26 Jan 2025 16:43:13 -0500 Subject: [PATCH 36/46] MPL fix on issue of aspect ratio --- .gitignore | 1 + .../renderers/renderer_mpl/mpl_canvas.py | 21 +++++++++++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index ac4d4e024..b89021976 100644 --- a/.gitignore +++ b/.gitignore @@ -93,6 +93,7 @@ celerybeat-schedule # virtualenv .venv venv/ +venvz/ ENV/ # Spyder project settings diff --git a/qiskit_metal/renderers/renderer_mpl/mpl_canvas.py b/qiskit_metal/renderers/renderer_mpl/mpl_canvas.py index e717d1292..d7f0efa29 100644 --- a/qiskit_metal/renderers/renderer_mpl/mpl_canvas.py +++ b/qiskit_metal/renderers/renderer_mpl/mpl_canvas.py @@ -559,11 +559,16 @@ def style_axis(self, ax, num: int): ax (axis): The axis num (int): Not used """ - ax.set_aspect(1) + # ax.set_aspect(1) + # # If 'box', change the physical dimensions of the Axes. If 'datalim', + # # change the x or y data limits. + # ax.set_adjustable('datalim') - # If 'box', change the physical dimensions of the Axes. If 'datalim', - # change the x or y data limits. - ax.set_adjustable('datalim') + # Allow flexible container sizing while maintaining data scale + ax.set_aspect('auto') + + # Ensure data units are equal + ax.set_box_aspect(None) ax.set_xlabel('x position (mm)') ax.set_ylabel('y position (mm)') @@ -594,6 +599,14 @@ def style_axis(self, ax, num: int): #[left, bottom, width, height] # ax.set_position([0,0,1,1]) + # Set axis scales to be equal + ax.set_xscale('linear') + ax.set_yscale('linear') + + # Update axis limits to maintain square units + ax.set_adjustable('datalim') + ax.set_anchor('C') # Center the plot + def style_figure(self): """Style a figure.""" pass # self.figure.tight_layout() From 626909fcf4bc1aba7b8f14fc2d1f9fd3441f8735 Mon Sep 17 00:00:00 2001 From: Zlatko Minev Date: Sun, 26 Jan 2025 16:43:58 -0500 Subject: [PATCH 37/46] ### Gui 1. Added traceback reporting in the logging. 2. Fixed - "metal: WARNING: endResetModel called on LibraryFileProxyModel(0x17fda8200) without calling beginResetModel first (No context available from Qt)" 3. Fixed MPL Rendere axes issue "Ignoring fixed y limits to fulfill fixed data aspect with adjustable data limits. Ignoring fixed x limits to fulfill fixed data aspect with adjustable data limits." 4. Added red border style to new component UI create button to underscore --- qiskit_metal/_gui/elements_window.py | 36 ++++++++----- qiskit_metal/_gui/main_window.py | 16 ++++-- qiskit_metal/_gui/net_list_window.py | 35 +++++++----- .../_gui/utility/_handle_qt_messages.py | 52 ++++++++++++------ qiskit_metal/_gui/utility/_toolbox_qt.py | 26 +++++---- .../table_model_all_components.py | 50 ++++++++++------- .../_gui/widgets/bases/dict_tree_base.py | 54 ++++++++++++------- .../model_view/tree_model_param_entry.py | 22 ++++++-- .../qlibrary_display/proxy_model_qlibrary.py | 15 ++++-- requirements.txt | 34 ++++++------ 10 files changed, 220 insertions(+), 120 deletions(-) diff --git a/qiskit_metal/_gui/elements_window.py b/qiskit_metal/_gui/elements_window.py index 4c93bf21e..dad0af05a 100644 --- a/qiskit_metal/_gui/elements_window.py +++ b/qiskit_metal/_gui/elements_window.py @@ -15,7 +15,6 @@ from typing import TYPE_CHECKING -import numpy as np from PySide6 import QtCore, QtWidgets from PySide6.QtCore import QAbstractTableModel, QModelIndex from PySide6.QtWidgets import QMainWindow @@ -108,13 +107,13 @@ class ElementTableModel(QAbstractTableModel): __timer_interval = 500 # ms def __init__(self, gui, parent=None, element_type='poly'): - super().__init__(parent=parent) """ Args: gui (MetalGUI): The GUI parent (QMainWindowExtension): Parent window. Defaults to None. element_type (str): The element type. Defaults to 'poly'. """ + super().__init__(parent=parent) self.logger = gui.logger self.gui = gui self._row_count = -1 @@ -165,7 +164,12 @@ def refresh(self): Completely rebuild the model. """ - self.modelReset.emit() + self.beginResetModel() + try: + # parent_index = self.createIndex(0, 0, self.root) + self._row_count = self.rowCount(None) + finally: + self.endResetModel() def refresh_auto(self): """Update row count etc.""" @@ -175,16 +179,22 @@ def refresh_auto(self): if self._row_count != new_count: #self.logger.info('Number of components changed') - # When a model is reset it should be considered that all - # information previously retrieved from it is invalid. - # This includes but is not limited to the rowCount() and - # columnCount(), flags(), data retrieved through data(), and roleNames(). - # This will loose the current selection. - self.modelReset.emit() + # Wrap the reset logic in beginResetModel and endResetModel + self.beginResetModel() + try: + + # When a model is reset it should be considered that all + # information previously retrieved from it is invalid. + # This includes but is not limited to the rowCount() and + # columnCount(), flags(), data retrieved through data(), and roleNames(). + # This will loose the current selection. + # self.modelReset.emit() - self._row_count = new_count + self._row_count = new_count + finally: + self.endResetModel() - def rowCount(self, parent: QModelIndex = None): + def rowCount(self, parent: QModelIndex = None) -> int: """Counts all the rows. Args: @@ -193,11 +203,13 @@ def rowCount(self, parent: QModelIndex = None): Returns: int: The number of rows """ + if parent is None: + parent = QModelIndex() if self.table is None: return 0 return self.table.shape[0] - def columnCount(self, parent: QModelIndex = None): + def columnCount(self, parent: QModelIndex = None): #pylint: disable=unused-argument """Counts all the columns. Args: diff --git a/qiskit_metal/_gui/main_window.py b/qiskit_metal/_gui/main_window.py index 6bcee8131..472d553ac 100644 --- a/qiskit_metal/_gui/main_window.py +++ b/qiskit_metal/_gui/main_window.py @@ -55,7 +55,7 @@ pass if TYPE_CHECKING: - from ..renderers.renderer_mpl.mpl_canvas import PlotCanvas + from ..renderers.renderer_mpl.mpl_canvas import PlotCanvas # pylint: disable=syntax-error class QMainWindowExtension(QMainWindowExtensionBase): @@ -724,15 +724,21 @@ def dockLibrary_filter_onChanged(self, text): """ view = self.ui.dockLibrary_tree_view dock = self.ui.dockLibrary - dock.proxy_library_model.filter_text = text + proxy_model = dock.proxy_library_model - dock.proxy_library_model.setFilterWildcard(text) + # Wrap changes to filter_text and setFilterWildcard with reset calls + proxy_model.beginResetModel() + try: + proxy_model.filter_text = text + proxy_model.setFilterWildcard(text) + finally: + proxy_model.endResetModel() view.setRootIndex( - dock.proxy_library_model.mapFromSource( + proxy_model.mapFromSource( dock.library_model.index(dock.library_model.rootPath()))) - if len(text) >= 1 and dock.proxy_library_model.rowCount() > 0: + if len(text) >= 1 and proxy_model.rowCount() > 0: view.expandAll() else: view.collapseAll() diff --git a/qiskit_metal/_gui/net_list_window.py b/qiskit_metal/_gui/net_list_window.py index 641347816..bb90f39cd 100644 --- a/qiskit_metal/_gui/net_list_window.py +++ b/qiskit_metal/_gui/net_list_window.py @@ -15,8 +15,7 @@ from typing import TYPE_CHECKING -import numpy as np -from PySide6 import QtCore, QtWidgets +from PySide6 import QtCore from PySide6.QtCore import QAbstractTableModel, QModelIndex from PySide6.QtWidgets import QMainWindow @@ -88,13 +87,13 @@ class NetListTableModel(QAbstractTableModel): __timer_interval = 500 # ms def __init__(self, gui, parent=None): - super().__init__(parent=parent) """ Args: gui (MetalGUI): The GUI parent (QMainWindowExtension): Parent window. Defaults to None. element_type (str): The element type. Defaults to 'poly'. """ + super().__init__(parent=parent) self.logger = gui.logger self.gui = gui self._row_count = -1 @@ -139,7 +138,11 @@ def refresh(self): Completely rebuild the model. """ - self.modelReset.emit() + self.beginResetModel() + try: + self._row_count = self.rowCount() + finally: + self.endResetModel() def refresh_auto(self): """Update row count etc.""" @@ -149,16 +152,22 @@ def refresh_auto(self): if self._row_count != new_count: #self.logger.info('Number of components changed') - # When a model is reset it should be considered that all - # information previously retrieved from it is invalid. - # This includes but is not limited to the rowCount() and - # columnCount(), flags(), data retrieved through data(), and roleNames(). - # This will loose the current selection. - self.modelReset.emit() + # Wrap the reset logic in beginResetModel and endResetModel + self.beginResetModel() + try: + + # When a model is reset it should be considered that all + # information previously retrieved from it is invalid. + # This includes but is not limited to the rowCount() and + # columnCount(), flags(), data retrieved through data(), and roleNames(). + # This will loose the current selection. + # self.modelReset.emit() - self._row_count = new_count + self._row_count = new_count + finally: + self.endResetModel() - def rowCount(self, parent: QModelIndex = None): + def rowCount(self, parent: QModelIndex = None): # pylint: disable=unused-argument """Counts all the rows. Args: @@ -171,7 +180,7 @@ def rowCount(self, parent: QModelIndex = None): return 0 return self.net_info.shape[0] - def columnCount(self, parent: QModelIndex = None): + def columnCount(self, parent: QModelIndex = None): # pylint: disable=unused-argument """Counts all the columns. Args: diff --git a/qiskit_metal/_gui/utility/_handle_qt_messages.py b/qiskit_metal/_gui/utility/_handle_qt_messages.py index f873ce182..c8d519b8e 100644 --- a/qiskit_metal/_gui/utility/_handle_qt_messages.py +++ b/qiskit_metal/_gui/utility/_handle_qt_messages.py @@ -66,10 +66,30 @@ def _qt_message_handler(mode, context, message): mode = 'FATAL' else: mode = 'DEBUG' + # logger.log( + # getattr(logging, 'CRITICAL'), 'line: %d, func: %s(), file: %s' % + # (context.line, context.function, context.file) + ' %s: %s\n' % + # (mode, message)) + + # Log basic message details + base_message = f"{mode}: {message}" + + # Include context if available + if context.file and context.function: + base_message += ( + f" (File: {context.file}, Line: {context.line}, Function: {context.function})" + ) + else: + base_message += " (No context available from Qt)" + + # Capture Python traceback for additional details + python_traceback = "".join(traceback.format_stack(limit=10)) + + # Log the message with the Python traceback logger.log( - getattr(logging, 'CRITICAL'), 'line: %d, func: %s(), file: %s' % - (context.line, context.function, context.file) + ' %s: %s\n' % - (mode, message)) + getattr(logging, mode, logging.DEBUG), + f"{base_message}\nPython Traceback (most recent call last):\n{python_traceback}" + ) ####################################################################################### @@ -85,19 +105,19 @@ def do_debug(msg, name='info'): name (str): info wran, debug, etc. Defaults to 'info'. """ - if 0: - # This just gives the qt main loop traceback. Not useful. - callers = [] - for i in range(1, 20): - try: - stack = inspect.stack()[i] - callers += [f'{stack.function}[{stack.lineno}]'] - except Exception as e: # pylint: disable=broad-except - print("Exception during do_debug exception handling: " + - e.__repr__()) - callers = reversed(callers) - callers = '\n'.join(callers) - msg = callers + "\n" + str(msg) + '\n' + # if 0: + # # This just gives the qt main loop traceback. Not useful. + # callers = [] + # for i in range(1, 20): + # try: + # stack = inspect.stack()[i] + # callers += [f'{stack.function}[{stack.lineno}]'] + # except Exception as e: # pylint: disable=broad-except + # print("Exception during do_debug exception handling: " + + # e.__repr__()) + # callers = reversed(callers) + # callers = '\n'.join(callers) + # msg = callers + "\n" + str(msg) + '\n' getattr(logger, name)(msg) diff --git a/qiskit_metal/_gui/utility/_toolbox_qt.py b/qiskit_metal/_gui/utility/_toolbox_qt.py index 9d681a669..c974df572 100644 --- a/qiskit_metal/_gui/utility/_toolbox_qt.py +++ b/qiskit_metal/_gui/utility/_toolbox_qt.py @@ -12,8 +12,11 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. """This is a utility module used for qt.""" +# pylint: disable=invalid-name -from PySide6 import QtCore, QtWidgets +from types import MethodType + +# from PySide6 import QtCore, QtWidgets from PySide6.QtCore import QTimer from PySide6.QtGui import QColor from PySide6.QtWidgets import QDockWidget @@ -44,27 +47,31 @@ def blend_colors(color1: QColor, #------------------------------------------------------------------------------------------ -STYLE_HIGHLIGHT = r""" +STYLE_HIGHLIGHT_ = r""" QWidget { outline: 3px solid red; border: 3px solid red; }""" -def doShowHighlighWidget(self: QDockWidget, - timeout=1500, - STYLE_HIGHLIGHT=STYLE_HIGHLIGHT): +def doShowHighlighWidget(self: QDockWidget, timeout=1500, style_highlight=None): """Highlight temporarily, raise, show the widget. - Force resets the style at the component to None after a period. + Force resets the style at the component to None after a period. """ - self.setStyleSheet(STYLE_HIGHLIGHT) + if style_highlight is None: + style_highlight = STYLE_HIGHLIGHT_ + self.setStyleSheet(style_highlight) self.show() self.raise_() def doResetStyle(self: 'QDockWidget'): + """Reset the style of the widget.""" self.setStyleSheet('') - self.doResetStyle = doResetStyle.__get__(self, type(self)) + # Bind the method dynamically to the instance using MethodType + self.doResetStyle = MethodType(doResetStyle, self) + + # self.doResetStyle = doResetStyle.__get__(self, type(self)) # monkey patch class instance: # https://stackoverflow.com/questions/28127874/monkey-patching-python-an-instance-method @@ -93,6 +100,7 @@ def doResetStyle(self: 'QDockWidget'): # # frame.setWindowFlags(QtCore.Qt.FramelessWindowHint) # # frame.setAttribute(QtCore.Qt.WA_TranslucentBackground) -# # Alternative see: https://stackoverflow.com/questions/58458323/how-to-use-qt-stylesheet-to-customize-only-partial-qwidget-border +# # Alternative see: +# https://stackoverflow.com/questions/58458323/how-to-use-qt-stylesheet-to-customize-only-partial-qwidget-border #------------------------------------------------------------------------------------------ diff --git a/qiskit_metal/_gui/widgets/all_components/table_model_all_components.py b/qiskit_metal/_gui/widgets/all_components/table_model_all_components.py index bd4271bd4..d74541011 100644 --- a/qiskit_metal/_gui/widgets/all_components/table_model_all_components.py +++ b/qiskit_metal/_gui/widgets/all_components/table_model_all_components.py @@ -12,13 +12,13 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. -import numpy as np -from PySide6 import QtCore, QtWidgets +# pylint: disable=invalid-name + +from PySide6 import QtCore from PySide6.QtCore import QAbstractTableModel, QModelIndex, Qt -from PySide6.QtGui import QBrush, QColor, QFont, QIcon, QPixmap -from PySide6.QtWidgets import QTableView +from PySide6.QtGui import QBrush, QColor, QFont, QIcon -from ...utility._handle_qt_messages import slot_catch_error +# from ...utility._handle_qt_messages import slot_catch_error from ...utility._toolbox_qt import blend_colors from typing import TYPE_CHECKING @@ -84,9 +84,13 @@ def _create_timer(self): def refresh(self): """Force refresh. - Completly rebuild the model. + Completely rebuild the model. """ - self.modelReset.emit() + self.beginResetModel() + try: + self._row_count = self.rowCount() + finally: + self.endResetModel() def refresh_auto(self): """Automatic refresh, update row count, view, etc.""" @@ -95,19 +99,25 @@ def refresh_auto(self): # if the number of rows have changed if self._row_count != new_count: - #self.logger.info('Number of components changed') + # self.logger.info('Number of components changed') + + # Wrap the reset logic in beginResetModel and endResetModel + self.beginResetModel() + try: - # When a model is reset it should be considered that all - # information previously retrieved from it is invalid. - # This includes but is not limited to the rowCount() and - # columnCount(), flags(), data retrieved through data(), and roleNames(). - # This will loose the current selection. - self.modelReset.emit() + # When a model is reset it should be considered that all + # information previously retrieved from it is invalid. + # This includes but is not limited to the rowCount() and + # columnCount(), flags(), data retrieved through data(), and roleNames(). + # This will loose the current selection. + # self.modelReset.emit() + + self._row_count = new_count + finally: + self.endResetModel() # for some reason the horizontal header is hidden even if i call this in init self._tableView.horizontalHeader().show() - - self._row_count = new_count self.update_view() def update_view(self): @@ -115,7 +125,7 @@ def update_view(self): if self._tableView: self._tableView.resizeColumnsToContents() - def rowCount(self, parent: QModelIndex = None): + def rowCount(self, parent: QModelIndex = None): # pylint: disable=unused-argument """Returns the number of rows. Args: @@ -135,7 +145,7 @@ def rowCount(self, parent: QModelIndex = None): self._tableView.show_placeholder_text() return 0 - def columnCount(self, parent: QModelIndex = None): + def columnCount(self, parent: QModelIndex = None): # pylint: disable=unused-argument """Returns the number of columns. Args: @@ -248,5 +258,7 @@ def data(self, index: QModelIndex, role: int = Qt.DisplayRole): elif role == Qt.ToolTipRole or role == Qt.StatusTipRole: component = self.design.components[component_name] - text = f"""Component name= "{component.name}" instance of class "{component.__class__.__name__}" from module "{component.__class__.__module__}" """ + text = f"""Component name= "{component.name}" instance of """\ + f"""class "{component.__class__.__name__}" from module""" \ + f"""{component.__class__.__module__}" """ return text diff --git a/qiskit_metal/_gui/widgets/bases/dict_tree_base.py b/qiskit_metal/_gui/widgets/bases/dict_tree_base.py index e7448adea..b57c4c543 100644 --- a/qiskit_metal/_gui/widgets/bases/dict_tree_base.py +++ b/qiskit_metal/_gui/widgets/bases/dict_tree_base.py @@ -12,20 +12,16 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. """Dict tree base.""" +# pylint: disable=invalid-name import ast -from pathlib import Path from typing import Union, TYPE_CHECKING -import numpy as np -import PySide6 -from PySide6 import QtCore, QtGui, QtWidgets +from PySide6 import QtCore from PySide6.QtCore import QAbstractItemModel, QModelIndex, QTimer, Qt from PySide6.QtGui import QFont -from PySide6.QtWidgets import (QAbstractItemView, QApplication, QFileDialog, - QWidget, QTreeView, QLabel, QMainWindow, - QMessageBox, QTabWidget) -from .... import logger +from PySide6.QtWidgets import (QWidget, QTreeView) +# from .... import logger if TYPE_CHECKING: from ....designs.design_base import QDesign @@ -234,7 +230,7 @@ def __init__(self, parent: QWidget, gui: 'MetalGUI', view: QTreeView, super().__init__(parent=parent) self.logger = gui.logger self._gui = gui - self._rowCount = -1 + self._row_count = -1 self._view = view self.optionstype = child if self.optionstype == 'component': @@ -277,10 +273,22 @@ def auto_refresh(self): If so, completely rebuild the model and tree. """ # TODO: Check if new nodes have been added; if so, rebuild model. - newRowCount = self.rowCount(self.createIndex(0, 0)) - if self._rowCount != newRowCount: - self.modelReset.emit() - self._rowCount = newRowCount + new_row_count = self.rowCount(self.createIndex(0, 0)) + if self._row_count != new_row_count: + # Wrap the reset logic in beginResetModel and endResetModel + self.beginResetModel() + try: + + # When a model is reset it should be considered that all + # information previously retrieved from it is invalid. + # This includes but is not limited to the rowCount() and + # columnCount(), flags(), data retrieved through data(), and roleNames(). + # This will loose the current selection. + # self.modelReset.emit() + + self._row_count = new_row_count + finally: + self.endResetModel() if self._view: self._view.autoresize_columns() @@ -289,8 +297,13 @@ def refresh(self): Completely rebuild the model and tree. """ - self.load() # rebuild the tree - self.modelReset.emit() + self.beginResetModel() # TODO: BEFORE OR AFTER ? + try: + self.load() # rebuild the tree + parent_index = self.createIndex(0, 0, self.root) + self._row_count = self.rowCount(parent_index) + finally: + self.endResetModel() def getPaths(self, curdict: dict, curpath: list): """Recursively finds and saves all root-to-leaf paths in model.""" @@ -357,7 +370,7 @@ def rowCount(self, parent: QModelIndex): return 0 return len(node) - def columnCount(self, parent: QModelIndex): + def columnCount(self, parent: QModelIndex): # pylint: disable=unused-argument """Get the number of columns. Args: @@ -452,12 +465,13 @@ def setData(self, lbl = node.label # option key self.logger.info( - f'Setting {self.optionstype} option {lbl:>10s}: old value={old_value}; new value={value};' - ) + f'Setting {self.optionstype} option {lbl:>10s}:' + f' old value={old_value}; new value={value};') ##### Parse value if not str ############################## # Somewhat legacy code for extended handling of non string options - # These days we tend to have all options be strings, so not so releavnt, but keep here for now + # These days we tend to have all options be strings, + # so not so releavnt, but keep here for now # to allow extended use in te future if not isinstance(old_value, str): processed_value, used_ast = parse_param_from_str( @@ -592,7 +606,7 @@ def parse_param_from_str(text): try: # crude way to handle list and values value = ast.literal_eval(text) used_ast = True - except Exception as exception: + except Exception: # as exception pass # print(exception) return value, used_ast diff --git a/qiskit_metal/_gui/widgets/create_component_window/model_view/tree_model_param_entry.py b/qiskit_metal/_gui/widgets/create_component_window/model_view/tree_model_param_entry.py index 294790b9e..766a506d5 100644 --- a/qiskit_metal/_gui/widgets/create_component_window/model_view/tree_model_param_entry.py +++ b/qiskit_metal/_gui/widgets/create_component_window/model_view/tree_model_param_entry.py @@ -376,7 +376,7 @@ def __init__(self, design (QDesign): Current design using the model """ super().__init__(parent=parent) - self._rowCount = -1 # pylint: disable=invalid-name + self._row_count = -1 # pylint: disable=invalid-name self.root = BranchNode('') self.view = view self._design = design @@ -497,10 +497,22 @@ def auto_refresh(self): completely rebuild the model and tree. """ # TODO: Check if new nodes have been added; if so, rebuild model. - newRowCount = self.rowCount(self.createIndex(0, 0)) # pylint: disable=invalid-name - if self._rowCount != newRowCount: - self.modelReset.emit() - self._rowCount = newRowCount + new_row_count = self.rowCount(self.createIndex(0, 0)) # pylint: disable=invalid-name + if self._row_count != new_row_count: + # Wrap the reset logic in beginResetModel and endResetModel + self.beginResetModel() + try: + + # When a model is reset it should be considered that all + # information previously retrieved from it is invalid. + # This includes but is not limited to the rowCount() and + # columnCount(), flags(), data retrieved through data(), and roleNames(). + # This will loose the current selection. + # self.modelReset.emit() + + self._row_count = new_row_count + finally: + self.endResetModel() def getPaths(self, curdict: OrderedDict, curpath: list): # pylint: disable=invalid-name """Recursively finds and saves all root-to-leaf paths in model""" diff --git a/qiskit_metal/_gui/widgets/qlibrary_display/proxy_model_qlibrary.py b/qiskit_metal/_gui/widgets/qlibrary_display/proxy_model_qlibrary.py index 1c36d0b80..0a88cbebc 100644 --- a/qiskit_metal/_gui/widgets/qlibrary_display/proxy_model_qlibrary.py +++ b/qiskit_metal/_gui/widgets/qlibrary_display/proxy_model_qlibrary.py @@ -14,10 +14,11 @@ """ Proxy Model to clean display of QComponents in Library tab """ +# pylint: disable=invalid-name import typing -from PySide6.QtCore import QModelIndex, QSize, QSortFilterProxyModel, Qt +from PySide6.QtCore import QModelIndex, QSortFilterProxyModel, Qt from PySide6.QtWidgets import QFileSystemModel, QWidget @@ -38,7 +39,9 @@ def __init__(self, parent: QWidget = None): # (Aren't hidden (begin w/ .), don't begin with __init__, don't begin with _template, etc. AND end in .py) OR (don't begin with __pycache__ and don't have a '.' in the name # pylint: disable=line-too-long # (QComponent files) OR (Directories) self.accepted_files__regex = r"(^((?!\.))(?!base)(?!__init__)(?!_template)(?!_parsed)(?!__pycache__).*\.py)|(?!__pycache__)(^([^.]+)$)" # pylint: disable=line-too-long + self.beginResetModel() self.setFilterRegularExpression(self.accepted_files__regex) + self.endResetModel() self.filter_text = "" def filterAcceptsColumn( @@ -78,11 +81,11 @@ def filterAcceptsRow( relativeFilename] if relativeFilename in nameCache else None #fi = source_model.fileInfo(index) - if displayName != None: + if displayName is not None: found = (self.filter_text in relativeFilename) or (self.filter_text in displayName) else: - found = (self.filter_text in relativeFilename) + found = self.filter_text in relativeFilename accept = (not relativeFilename.startswith("_")) and found return accept @@ -101,6 +104,10 @@ def data(self, # allow editable if role == Qt.EditRole: - return self.data(index, Qt.DisplayRole) + self.beginResetModel() + try: + return self.data(index, Qt.DisplayRole) + finally: + self.endResetModel() return super().data(index, role) diff --git a/requirements.txt b/requirements.txt index bf48a4c31..ca4fa4602 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,21 +1,21 @@ -addict==2.4.0 -descartes==1.1.0 -gdspy==1.6.12 -geopandas==0.12.2 -ipython==8.10.0 -matplotlib==3.7.0 -numpy==1.24.2 +addict>=2.4.0 +descartes>=1.1.0 +gdstk>=0.9 +geopandas>=0.12.2 +ipython>=8.10.0 +matplotlib>=3.7.0 +numpy>=1.24.2 pandas==1.5.3 -pint==0.20.1 +pint~=0.20.1 pyEPR-quantum==0.8.5.7 -pygments==2.14.0 +pygments>=2.14.0 pyside6 -qdarkstyle==3.1 -qutip==4.7.1 -scipy==1.10.0 -shapely==2.0.1 -scqubits==3.1.0 -gmsh==4.11.1 -pyaedt==0.6.46 -pyyaml==6.0 +qdarkstyle~=3.1 +qutip>=4.7.1 +scipy~=1.10.0 +shapely~=2.0.1 +scqubits~=3.1.0 +gmsh~=4.11.1 +pyaedt>=0.6.46 +pyyaml>=6.0 cython<3.0.0 \ No newline at end of file From f10a1210225d9dde1d5dc04e5ea8f26cbb57ff75 Mon Sep 17 00:00:00 2001 From: Zlatko Minev Date: Sun, 26 Jan 2025 16:45:05 -0500 Subject: [PATCH 38/46] Changelog --- changelog.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 changelog.md diff --git a/changelog.md b/changelog.md new file mode 100644 index 000000000..da204a78e --- /dev/null +++ b/changelog.md @@ -0,0 +1,23 @@ +# Changelog Note Scratchpad for Developers + +This log is used by developers to jot notes. + +For the offical user-facing changelog for a particular release can be found in the correspondent Github release page. For example, you can find the changelog for the `0.0.4` release [here](https://github.com/Qiskit/qiskit-metal/releases/tag/0.0.4) + +The changelog for all releases can be found in the release page: [![Releases](https://img.shields.io/github/release/Qiskit/qiskit-metal.svg?style=popout-square)](https://github.com/Qiskit/qiskit-metal/releases) + +## QISKIT METAL v0.5 (2025) + +Adressing massive package changes and ports: +- pyqt5 to pyside6 - massive port of the GUI. +- GDSPY to GDSTK +- PYAEDT to ansys and v1.0 new syntax. Major update. Needs lots of testing. + +### Gui +1. Added traceback reporting in the logging. +2. Fixed - "metal: WARNING: endResetModel called on LibraryFileProxyModel(0x17fda8200) without calling beginResetModel first (No context available from Qt)" +3. Fixed MPL Rendere axes issue "Ignoring fixed y limits to fulfill fixed data aspect with adjustable data limits. Ignoring fixed x limits to fulfill fixed data aspect with adjustable data limits." +4. Added red border style to new component UI create button to underscore + +### PYAEDT +FutureWarning: Module 'pyaedt' has become an alias to the new package structure. Please update you imports to use the new architecture based on 'ansys.aedt.core'. In addition, some files have been renamed to follow the PEP 8 naming convention. The old structure and file names will be deprecated in future versions, see https://aedt.docs.pyansys.com/version/stable/release_1_0.html From 00958d59a719e0e543b11c16119908c3f12d4d4f Mon Sep 17 00:00:00 2001 From: Zlatko Minev Date: Sun, 26 Jan 2025 16:46:04 -0500 Subject: [PATCH 39/46] gui emitreset fix --- environment.yml | 38 +++++++++---------- .../variable_table/prop_val_table_model.py | 18 ++++++--- 2 files changed, 31 insertions(+), 25 deletions(-) diff --git a/environment.yml b/environment.yml index bb2eb813c..00f4f9a75 100644 --- a/environment.yml +++ b/environment.yml @@ -2,27 +2,27 @@ name: qiskit-metal channels: - conda-forge dependencies: - - python=3.10.* - - addict==2.4.0 - - descartes==1.1.0 - - geopandas==0.12.2 - - ipython==8.10.0 - - matplotlib==3.7.0 - - numpy==1.24.2 - - pandas==1.5.3 - - pint==0.20.1 + - python>=3.10.* # Let's see if we can float higher in future. + - scqubits==3.1.0 # Very careful to update higher, as it can break things. Want to update in future. + - addict>=2.4.0 + - descartes>=1.1.0 + - geopandas>=0.12.2 + - ipython>=8.10.0 + - matplotlib>=3.7.0 + - numpy>=1.24.2 + - pandas>=1.5.3 + - pint>=0.20.1 - pyEPR-quantum==0.8.5.7 - - pygments==2.14.0 - - qdarkstyle==3.1 - - qutip==4.7.1 - - scipy==1.10.0 - - shapely==2.0.1 - - scqubits==3.1.0 + - pygments>=2.14.0 + - qdarkstyle>=3.1 + - qutip>=4.7.1 + - scipy>=1.10.0 + - shapely>=2.0.1 - jupyter - cython<3.0.0 - pip - pip: - - pyaedt==0.6.46 - - gmsh==4.11.1 - - gdspy==1.6.12 - - pyside6 + - pyaedt>=0.9.0 # Todo: update in future to latest. # Very careful to update higher, as it can break things. Want to update in future. + - gmsh>=4.11.1 + - gdstk>=0.9 # Used to be gdspy>=1.6.12 + - pyside6 # Critical to building gui, can causes lots of problems, careful. diff --git a/qiskit_metal/_gui/widgets/variable_table/prop_val_table_model.py b/qiskit_metal/_gui/widgets/variable_table/prop_val_table_model.py index 5cc8aa693..c0152ab72 100644 --- a/qiskit_metal/_gui/widgets/variable_table/prop_val_table_model.py +++ b/qiskit_metal/_gui/widgets/variable_table/prop_val_table_model.py @@ -42,7 +42,7 @@ def __init__(self, design=None, gui=None, view: 'RightClickView' = None): self._design = design self._gui = gui self._view = view - self._rowCount = -1 + self._row_count = -1 self._start_timer() def set_design(self, design): @@ -52,7 +52,8 @@ def set_design(self, design): design (QDesign): The design """ self._design = design - self.modelReset.emit() + # self.modelReset.emit() + self.auto_refresh() # refresh table or something if needed @property @@ -75,10 +76,15 @@ def _start_timer(self): def auto_refresh(self): """Do an automatic refresh.""" - newRowCount = self.rowCount(self) - if self._rowCount != newRowCount: - self.modelReset.emit() - self._rowCount = newRowCount + new_row_count = self.rowCount(self) + if self._row_count != new_row_count: + # Wrap the reset logic in beginResetModel and endResetModel + self.beginResetModel() + try: + # self.modelReset.emit() + self._row_count = new_row_count + finally: + self.endResetModel() if self._view: self._view.resizeColumnsToContents() From 8f129bb35c8960eca89f1a8177f1afc843c65200 Mon Sep 17 00:00:00 2001 From: Zlatko Minev Date: Sun, 26 Jan 2025 16:46:34 -0500 Subject: [PATCH 40/46] cleanup lint for file skeleton render --- tutorials/resources/skeleton_renderer.py | 60 +++++++++++------------- 1 file changed, 27 insertions(+), 33 deletions(-) diff --git a/tutorials/resources/skeleton_renderer.py b/tutorials/resources/skeleton_renderer.py index 16a6e09a1..25fd37e32 100644 --- a/tutorials/resources/skeleton_renderer.py +++ b/tutorials/resources/skeleton_renderer.py @@ -12,32 +12,17 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. -from qiskit_metal import Dict -import math -from scipy.spatial import distance -import os -import gdspy -import geopandas -import shapely - -from shapely.geometry import LineString as LineString -from copy import deepcopy -from operator import itemgetter -from typing import TYPE_CHECKING -from typing import Dict as Dict_ -from typing import List, Tuple, Union, Any, Iterable -import pandas as pd -from pandas.api.types import is_numeric_dtype +from typing import TYPE_CHECKING, Tuple -import numpy as np +import geopandas +from qiskit_metal import Dict from qiskit_metal.renderers.renderer_base import QRenderer -from qiskit_metal.toolbox_metal.parsing import is_true from qiskit_metal import config if not config.is_building_docs(): from qiskit_metal.toolbox_python.utility_functions import can_write_to_path - from qiskit_metal.toolbox_python.utility_functions import get_range_of_vertex_to_not_fillet + from qiskit_metal.toolbox_python.utility_functions import get_range_of_vertex_to_not_fillet # pylint: disable=unused-import if TYPE_CHECKING: # For linting typechecking, import modules that can't be loaded here under normal conditions. @@ -84,7 +69,8 @@ class QSkeletonRenderer(QRenderer): element_table_data = dict( # Example of adding a column named "skeleton_a_column_name" # with default values of "a_default_value" to the junction table. - # Note: QSkeletonRenderer.name is prefixed to "a_column_name" when the table is appended by QComponents. + # Note: QSkeletonRenderer.name is prefixed + # to "a_column_name" when the table is appended by QComponents. junction=dict(a_column_name='a_default_value')) """element extensions dictionary element_extensions = dict() from base class""" @@ -98,7 +84,8 @@ def __init__(self, Args: design (QDesign): Use QGeometry within QDesign to obtain elements. initiate (bool, optional): True to initiate the renderer. Defaults to True. - render_template (Dict, optional): Typically used by GUI for template options for GDS. Defaults to None. + render_template (Dict, optional): Typically used by GUI for + template options for GDS. Defaults to None. render_options (Dict, optional): Used to overide all options. Defaults to None. """ @@ -138,7 +125,7 @@ def _can_write_to_path(self, file: str) -> int: Returns: int: 1 if access is allowed. Else returns 0, if access not given. """ - status, directory_name = can_write_to_path(file) + status, directory_name = can_write_to_path(file) # pylint: disable=possibly-used-before-assignment if status: return 1 @@ -153,8 +140,9 @@ def check_qcomps(self, that the name of component exists in QDesign. Args: - highlight_qcomponents (list, optional): List of strings which denote the name of QComponents to render. - Defaults to []. Empty list means to render entire design. + highlight_qcomponents (list, optional): List of strings which + denote the name of QComponents to render. + Defaults to []. Empty list means to render entire design. Returns: Tuple[list, int]: @@ -173,10 +161,12 @@ def check_qcomps(self, return unique_qcomponents, 1 # For Subtraction bounding box. - # If list passed to export is the whole chip, then want to use the bounding box from design planar. - # If list is subset of chip, then caluclate a custom bounding box and scale it. + # If list passed to export is the whole chip, + # then want to use the bounding box from design planar. + # If list is subset of chip, then caluclate a + # custom bounding box and scale it. - if len(unique_qcomponents) == len(self.design._components): + if len(unique_qcomponents) == len(self.design._components): # pylint: disable=protected-access # Since user wants all of the chip to be rendered, use the design.planar bounding box. unique_qcomponents[:] = [] @@ -191,9 +181,11 @@ def get_qgeometry_tables_for_skeleton(self, Duplicate names in hightlight_qcomponents will be removed without warning. Args: - highlight_qcomponents (list): List of strings which denote the name of QComponents to render. + highlight_qcomponents (list): List of strings which denote the + name of QComponents to render. If empty, render all comonents in design. - If QComponent names are dupliated, duplicates will be ignored. + If QComponent names are dupliated, + duplicates will be ignored. Returns: Tuple[int, list]: @@ -207,7 +199,8 @@ def get_qgeometry_tables_for_skeleton(self, return 1, table_names_for_highlight for chip_name in self.chip_info: for table_name in self.design.qgeometry.get_element_types(): - # Get table for chip and table_name, and reduce to keep just the list of unique_qcomponents. + # Get table for chip and table_name, and reduce + # to keep just the list of unique_qcomponents. table = self.get_table(table_name, unique_qcomponents, chip_name) @@ -263,8 +256,9 @@ def write_qgeometry_table_names_to_file(self, Args: file_name (str): File name which can also include directory path. If the file exists, it will be overwritten. - highlight_qcomponents (list): List of strings which denote the name of QComponents to render. - If empty, render all qcomponents in qdesign. + highlight_qcomponents (list): List of strings which denote the + name of QComponents to render. + If empty, render all qcomponents in qdesign. Returns: int: 0=file_name can not be written, otherwise 1=file_name has been written @@ -286,7 +280,7 @@ def write_qgeometry_table_names_to_file(self, total_bones_text = 'Number of bones: ' + total_bones + '\n' - if (status == 0): + if status == 0: skeleton_out = open(file_name, 'w') skeleton_out.writelines(total_bones_text) skeleton_out.writelines(table_names_used) From 7c161a45a5e5d9dc8f5504f6f49bf2f28ebae8ec Mon Sep 17 00:00:00 2001 From: Zlatko Minev Date: Sun, 26 Jan 2025 17:04:33 -0500 Subject: [PATCH 41/46] Fixedaspect ratio and cleanuo --- qiskit_metal/_gui/main_window.py | 48 ++++++++++++------- .../_gui/widgets/bases/dict_tree_base.py | 17 +++---- .../renderers/renderer_mpl/mpl_canvas.py | 28 +++++------ 3 files changed, 53 insertions(+), 40 deletions(-) diff --git a/qiskit_metal/_gui/main_window.py b/qiskit_metal/_gui/main_window.py index 472d553ac..fb175f1bb 100644 --- a/qiskit_metal/_gui/main_window.py +++ b/qiskit_metal/_gui/main_window.py @@ -20,8 +20,8 @@ from PySide6.QtCore import Qt, QTimer from PySide6.QtGui import QIcon, QPixmap, QAction -from PySide6.QtWidgets import (QDialog, QDockWidget, QFileDialog, QLabel, - QMainWindow, QMessageBox, QVBoxLayout) +from PySide6.QtWidgets import (QWidget, QDialog, QDockWidget, QFileDialog, + QLabel, QMainWindow, QMessageBox, QVBoxLayout) from PySide6.QtCore import QSortFilterProxyModel from qiskit_metal._gui.widgets.qlibrary_display.delegate_qlibrary import \ LibraryDelegate @@ -126,7 +126,7 @@ def delete_all_components(self): self, 'Delete all components?', "Are you sure you want to clear all Metal components?", - buttons=(QMessageBox.Yes | QMessageBox.No)) + buttons=QMessageBox.Yes | QMessageBox.No) if ret == QMessageBox.Yes: self.logger.info('Delete all components.') self.design.delete_all_components() @@ -147,7 +147,7 @@ def save_design_copy(self): pyscript = self.design.to_python_script() #check whether filename is empty or not. Save file only when filename is non-empty. if len(filename): - with open(filename, 'w') as f: + with open(filename, 'w', encoding='utf-8') as f: f.write(pyscript) @slot_catch_error() @@ -172,7 +172,7 @@ def save_design(self, _=None): pyscript = self.design.to_python_script() #check whether filename is empty or not. Save file only when filename is non-empty. if len(filename): - with open(filename, 'w') as f: + with open(filename, 'w', encoding='utf-8') as f: f.write(pyscript) #make it clear it's saving @@ -262,7 +262,7 @@ def ok_to_close(self): if reply == QMessageBox.Cancel: return False elif reply == QMessageBox.Yes: - wait = self.save_design() + _ = self.save_design() return True return True @@ -360,7 +360,7 @@ def _set_enabled_design_widgets(self, enabled: bool = True): def setEnabled(parent, widgets): for widgetname in widgets: if hasattr(parent, widgetname): - widget = getattr(parent, widgetname) # type: QWidget + widget: 'QWidget' = getattr(parent, widgetname) if widget: widget.setEnabled(enabled) else: @@ -487,8 +487,8 @@ def _add_additional_qactions_tool_bar_view(self): icon = QIcon() icon.addPixmap(QPixmap(iconName), QIcon.Normal, QIcon.Off) - # Function call & monkey patch class instance - dock.doShow = doShowHighlighWidget.__get__(dock, type(dock)) # pylint: disable=assignment-from-no-return + # Function call & monkey patch class instance ala Monkey Patch + dock.doShow = doShowHighlighWidget.__get__(dock, type(dock)) # pylint: disable=assignment-from-no-return, no-value-for-parameter # QT Action with trigger, embed in toolbar action = QAction('', dock, triggered=dock.doShow) @@ -531,9 +531,9 @@ def _setup_plot_widget(self): # Add to the tabbed main view self.ui.mainViewTab.layout().addWidget(self.plot_win) - # add highlight function + # add highlight function ala Monkey Patch obj = self.ui.mainViewTab - obj.doShow = doShowHighlighWidget.__get__(obj, type(obj)) # pylint: disable=assignment-from-no-return + obj.doShow = doShowHighlighWidget.__get__(obj, type(obj)) # pylint: disable=assignment-from-no-return, no-value-for-parameter # Move the dock self._move_dock_to_new_parent(self.ui.dockLog, self.plot_win) @@ -549,7 +549,8 @@ def _move_dock_to_new_parent(self, Args: dock (QDockWidget): Dock to move new_parent (QMainWindow): New parent window - dock_location (Qt dock location): Location of the dock. Defaults to Qt.BottomDockWidgetArea. + dock_location (Qt dock location): Location of the dock. + Defaults to Qt.BottomDockWidgetArea. """ dock.setParent(new_parent) new_parent.addDockWidget(dock_location, dock) @@ -640,10 +641,12 @@ def filter_text_design_onChanged(self, text): def _create_new_component_object_from_qlibrary(self, full_path: str): """ - Must be defined outside of _setup_library_widget to ensure self == MetalGUI and will retain opened ScrollArea + Must be defined outside of _setup_library_widget to ensure + self == MetalGUI and will retain opened ScrollArea Args: - relative_index: QModelIndex of the desired QComponent file in the Qlibrary GUI display + relative_index: QModelIndex of the desired QComponent file in + the Qlibrary GUI display """ try: @@ -679,7 +682,11 @@ def _setup_library_widget(self): dock.library_model.setRootPath(self.QLIBRARY_ROOT) # QSortFilterProxyModel - #QSortFilterProxyModel: sorting items, filtering out items, or both. maps the original model indexes to new indexes, allows a given source model to be restructured as far as views are concerned without requiring any transformations on the underlying data, and without duplicating the data in memory. + #QSortFilterProxyModel: sorting items, filtering out items, or both. + # maps the original model indexes to new indexes, allows a given + # source model to be restructured as far as views are concerned + # without requiring any transformations on the underlying data, and + # without duplicating the data in memory. dock.proxy_library_model = LibraryFileProxyModel() dock.proxy_library_model.setSourceModel(dock.library_model) dock.proxy_library_model.setFilterCaseSensitivity(Qt.CaseInsensitive) @@ -773,7 +780,7 @@ def get_axes(self, num: int = None): return axes @property - def axes(self) -> List['Axes']: + def axes(self) -> List['matplotlib.plt.Axes']: """Returns the axes.""" return self.plot_win.canvas.axes @@ -877,3 +884,12 @@ def gui_create_build_log_window(self, _=None): self.build_log_window = BuildHistoryScrollArea( self.design.build_logs.data()) self.build_log_window.show() + + def save_file(self): + """Save file. Called on exit. + + Raises: + NotImplementedError: Function not written + """ + print("TODO: Save file - not yet implemented here") + raise NotImplementedError() diff --git a/qiskit_metal/_gui/widgets/bases/dict_tree_base.py b/qiskit_metal/_gui/widgets/bases/dict_tree_base.py index b57c4c543..46f9937d0 100644 --- a/qiskit_metal/_gui/widgets/bases/dict_tree_base.py +++ b/qiskit_metal/_gui/widgets/bases/dict_tree_base.py @@ -241,7 +241,7 @@ def __init__(self, parent: QWidget, gui: 'MetalGUI', view: QTreeView, self.paths = [] self._start_timer() - self.load() + self.load() # handles beginResetModel and endResetModel @property def gui(self): @@ -297,13 +297,14 @@ def refresh(self): Completely rebuild the model and tree. """ - self.beginResetModel() # TODO: BEFORE OR AFTER ? - try: - self.load() # rebuild the tree - parent_index = self.createIndex(0, 0, self.root) - self._row_count = self.rowCount(parent_index) - finally: - self.endResetModel() + # self.beginResetModel() # load handles refresh, cant nest + # try: + self.load( + ) # rebuild the tree; handles beginResetModel and endResetModel + parent_index = self.createIndex(0, 0, self.root) + self._row_count = self.rowCount(parent_index) + # finally: + # # self.endResetModel() def getPaths(self, curdict: dict, curpath: list): """Recursively finds and saves all root-to-leaf paths in model.""" diff --git a/qiskit_metal/renderers/renderer_mpl/mpl_canvas.py b/qiskit_metal/renderers/renderer_mpl/mpl_canvas.py index d7f0efa29..7da57a214 100644 --- a/qiskit_metal/renderers/renderer_mpl/mpl_canvas.py +++ b/qiskit_metal/renderers/renderer_mpl/mpl_canvas.py @@ -15,6 +15,7 @@ from typing import TYPE_CHECKING, List +import warnings import matplotlib import matplotlib as mpl import matplotlib.patches as patches @@ -343,6 +344,8 @@ def __init__(self, self.mpl_context = MPL_CONTEXT_DEFAULT.copy() + warnings.filterwarnings("ignore", ".*Ignoring fixed.*") + with mpl.rc_context(rc=self.mpl_context): fig = Figure() @@ -559,13 +562,15 @@ def style_axis(self, ax, num: int): ax (axis): The axis num (int): Not used """ - # ax.set_aspect(1) + ax.set_aspect(1) # # If 'box', change the physical dimensions of the Axes. If 'datalim', # # change the x or y data limits. - # ax.set_adjustable('datalim') + ax.set_adjustable('datalim') + ax.set_anchor('C') # Center the plot - # Allow flexible container sizing while maintaining data scale - ax.set_aspect('auto') + # Set axis scales to be equal + ax.set_xscale('linear') + ax.set_yscale('linear') # Ensure data units are equal ax.set_box_aspect(None) @@ -599,14 +604,6 @@ def style_axis(self, ax, num: int): #[left, bottom, width, height] # ax.set_position([0,0,1,1]) - # Set axis scales to be equal - ax.set_xscale('linear') - ax.set_yscale('linear') - - # Update axis limits to maintain square units - ax.set_adjustable('datalim') - ax.set_anchor('C') # Center the plot - def style_figure(self): """Style a figure.""" pass # self.figure.tight_layout() @@ -746,8 +743,7 @@ def highlight_components(self, component_names: List[str]): component_id = int(component_id) if component_id in self.design._components: - # type: QComponent - component = self.design._components[component_id] + component: "QComponent" = self.design._components[component_id] if 1: # highlight bounding box bounds = component.qgeometry_bounds( @@ -823,8 +819,8 @@ def highlight_components(self, component_names: List[str]): **text_kw, **dict(horizontalalignment='left' if n[0] >= 0 else 'right') } - # type: matplotlib.text.Text - text = ax.text(*(m + dist * n), pin_name, **kw) + text: "matplotlib.text.Text" = ax.text( + *(m + dist * n), pin_name, **kw) text.set_bbox(text_bbox_kw) self._annotations['text'] += [text] From 36c7b1de1eceadc897f8c97bb2f8c9d5fea96e9c Mon Sep 17 00:00:00 2001 From: Zlatko Minev Date: Sun, 26 Jan 2025 17:05:52 -0500 Subject: [PATCH 42/46] Requirements testuing updating --- requirements-dev.txt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 5013de879..472a3a5c6 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,20 +1,20 @@ # Dev tools -jupyter==1.0.0 -jupyterlab==3.6.1 +jupyter>=1.0.0 +jupyterlab>=3.6.1 # Build tools -wheel==0.38.4 +wheel>=0.38.4 -# Formatters -pylint==2.16.2 -yapf==0.32.0 +# Formatters and linters +pylint>=2.16.2 +yapf>=0.32.0 # Doc Build sphinx>=6.0.0 -numpydoc==1.5.0 -nbsphinx==0.8.6 +numpydoc>=1.5.0 +nbsphinx>=0.8.6 qiskit-sphinx-theme~=1.16.0 sphinx-intl~=2.1.0 # Unit tests -pytest==7.2.1 +pytest~=7.2.1 \ No newline at end of file From f7ec17be0ce35701b490094b645c2a3ac8404607 Mon Sep 17 00:00:00 2001 From: Zlatko Minev Date: Sun, 26 Jan 2025 17:08:32 -0500 Subject: [PATCH 43/46] Changelog --- changelog.md | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/changelog.md b/changelog.md index da204a78e..eda15be2d 100644 --- a/changelog.md +++ b/changelog.md @@ -8,16 +8,26 @@ The changelog for all releases can be found in the release page: [![Releases](ht ## QISKIT METAL v0.5 (2025) -Adressing massive package changes and ports: -- pyqt5 to pyside6 - massive port of the GUI. -- GDSPY to GDSTK -- PYAEDT to ansys and v1.0 new syntax. Major update. Needs lots of testing. - -### Gui -1. Added traceback reporting in the logging. -2. Fixed - "metal: WARNING: endResetModel called on LibraryFileProxyModel(0x17fda8200) without calling beginResetModel first (No context available from Qt)" -3. Fixed MPL Rendere axes issue "Ignoring fixed y limits to fulfill fixed data aspect with adjustable data limits. Ignoring fixed x limits to fulfill fixed data aspect with adjustable data limits." -4. Added red border style to new component UI create button to underscore - -### PYAEDT -FutureWarning: Module 'pyaedt' has become an alias to the new package structure. Please update you imports to use the new architecture based on 'ansys.aedt.core'. In addition, some files have been renamed to follow the PEP 8 naming convention. The old structure and file names will be deprecated in future versions, see https://aedt.docs.pyansys.com/version/stable/release_1_0.html +### Major Updates + +This release addresses significant package changes and ports: + +- **PyQt5 to PySide6**: A complete overhaul of the GUI. +- **GDSPY to GDSTK**: Replaced GDSPY with the more robust GDSTK library. +- **PYAEDT to Ansys (v1.0)**: Major update with a new syntax. Extensive testing required. +- **Installation Improvements**: Transitioned to `venv` for faster environment setup, moving away from `conda`. Also, most package versions have been floated and upgraded. + +--- + +### GUI Enhancements + +1. **Traceback Reporting**: Added detailed traceback reporting in the logging system to aid debugging. +2. **Model Reset Issue**: Fixed the issue causing the warning: *"metal: WARNING: endResetModel called on LibraryFileProxyModel(0x17fda8200) without calling beginResetModel first (No context available from Qt)"*. +3. **MPL Renderer Issue**: Resolved the error: *"Ignoring fixed y limits to fulfill fixed data aspect with adjustable data limits. Ignoring fixed x limits to fulfill fixed data aspect with adjustable data limits."*. +4. **UI Button Update**: Added a red border style to the "Create Component" button in the UI for better visibility. + +--- + +### PYAEDT Update + +- **FutureWarning**: The `pyaedt` module has been restructured and is now an alias for the new package structure based on `ansys.aedt.core`. To avoid issues in future versions, please update your imports to use the new architecture. Additionally, several files have been renamed to follow the PEP 8 naming conventions. For more information, refer to the [Ansys AEDT documentation](https://aedt.docs.pyansys.com/version/stable/release_1_0.html). From 2c348ffa91d27ca4127762a2d4376382e7f1ee8d Mon Sep 17 00:00:00 2001 From: Zlatko Minev Date: Sun, 26 Jan 2025 17:08:41 -0500 Subject: [PATCH 44/46] GDS RENDERED with GDSTK --- .../renderers/renderer_gds/gds_renderer.py | 1440 +++++++++-------- 1 file changed, 774 insertions(+), 666 deletions(-) diff --git a/qiskit_metal/renderers/renderer_gds/gds_renderer.py b/qiskit_metal/renderers/renderer_gds/gds_renderer.py index c6e2e7670..6e39c38c0 100644 --- a/qiskit_metal/renderers/renderer_gds/gds_renderer.py +++ b/qiskit_metal/renderers/renderer_gds/gds_renderer.py @@ -16,21 +16,19 @@ from copy import deepcopy from operator import itemgetter -from typing import TYPE_CHECKING -#from typing import Dict as Dict_ -from typing import Tuple, Union -#from typing import List, Any, Iterable -import math +from typing import TYPE_CHECKING, Tuple, Union, Dict as DictType + import os -from shapely.geometry import LineString -#from pandas.api.types import is_numeric_dtype +import math +import pandas as pd +import numpy as np -import gdspy -import geopandas +import gdstk import shapely +import geopandas + from scipy.spatial import distance -import pandas as pd -import numpy as np +from shapely.geometry import LineString from qiskit_metal.renderers.renderer_base import QRenderer from qiskit_metal.renderers.renderer_gds.make_cheese import Cheesing @@ -40,9 +38,11 @@ from ... import Dict from .. import config + if not config.is_building_docs(): from qiskit_metal.toolbox_python.utility_functions import can_write_to_path - from qiskit_metal.toolbox_python.utility_functions import get_range_of_vertex_to_not_fillet + from qiskit_metal.toolbox_python.utility_functions import ( + get_range_of_vertex_to_not_fillet,) if TYPE_CHECKING: # For linting typechecking, import modules that can't be loaded here under normal conditions. @@ -51,6 +51,36 @@ from qiskit_metal.designs import QDesign +def _new_cell(lib: "gdstk.Library", name: str, + overwrite_duplicate: bool) -> "gdstk.Cell": + """Helper to create or overwrite a gdstk cell in a library. + + Args: + lib (gdstk.Library): Library to hold the new cell. + name (str): Name of the new cell. + overwrite_duplicate (bool): If True, remove existing cell of same name, then recreate. + + Returns: + gdstk.Cell: The newly created cell. + """ + existing = next((c for c in lib.cells if c.name == name), None) + if existing and overwrite_duplicate: + lib.remove(existing) + new_cell = gdstk.Cell(name) + lib.add(new_cell) + return new_cell + + +def _rename_cell(cell: "gdstk.Cell", new_name: str) -> None: + """Helper to rename a gdstk cell. + + Args: + cell (gdstk.Cell): Cell object to rename. + new_name (str): New name for the cell. + """ + cell.name = new_name + + class QGDSRenderer(QRenderer): """Extends QRenderer to export GDS formatted files. The methods which a user will need for GDS export should be found within this class. @@ -118,29 +148,26 @@ class QGDSRenderer(QRenderer): # render_options. # Type: Dict[str, str] default_options = Dict( - # Before converting LINESTRING to FlexPath for GDS, check for fillet # errors for LINESTRINGS in QGeometry in QGeometry due to short # segments. If true, break up the LINESTRING so any segment which is # shorter than the scaled-fillet by "fillet_scale_factor" will be # separated so the short segment will not be fillet'ed. - short_segments_to_not_fillet='True', - check_short_segments_by_scaling_fillet='2.0', - + short_segments_to_not_fillet="True", + check_short_segments_by_scaling_fillet="2.0", # DO NOT MODIFY `gds_unit`. Gets overwritten by ``set_units``. # gdspy unit is 1 meter. gds_units appear to ONLY be used during # write_gds(). Note that gds_unit will be overwritten from the design # units, during init(). + # Moving to Gdstk, the default unit is 1 µm (10⁻⁶ m), but we overwrite this. # WARNING: this cannot be changed since it is only used during the # init once. - gds_unit='1', # 1m - + gds_unit="1", # 1m (one meter, if you want to set 1 um, set 1e-6) # Implement creating a ground plane which is scaled from largest # bounding box, then QGeometry which is marked as subtract will be # removed from ground_plane. Then the balance of QGeometry will be # placed placed in same layer as ground_plane. - ground_plane='True', - + ground_plane="True", # By default, export_to_gds() will create a positive_mask for every # chip and layer. Within the Dict, there needs to be an entry for each # chip. Each chip has a list of layers that should export as a @@ -148,7 +175,6 @@ class QGDSRenderer(QRenderer): # for that layer. If user wants to export to a negative_mask for all # layers, every layer_number MUST be in list. negative_mask=Dict(main=[]), - # For the gds file, Show/Don't Show intermediate steps? # If false, show the intermediate steps in the exported gds file. # If true, show the geometries on either neg_datatype_fabricate or pos_datatype_fabricate. @@ -156,8 +182,7 @@ class QGDSRenderer(QRenderer): # delete for negative mask: TOP_main_#_NoCheese_99, TOP_main_#_one_hole # delete for positive mask: TOP_main_#_NoCheese_99, TOP_main_#_one_hole, # ground_main_# - fabricate='False', - + fabricate="False", # corners: ('natural', 'miter', 'bevel', 'round', 'smooth', # 'circular bend', callable, list) # Type of joins. A callable must receive 6 arguments @@ -165,8 +190,7 @@ class QGDSRenderer(QRenderer): # the center and width of the path) # and return a list of vertices that make the join. # A list can be used to define the join for each parallel path. - corners='circular bend', - + corners="circular bend", # tolerance > precision # Precision used for gds lib, boolean operations and FlexPath should # likely be kept the same. They can be different, but increases odds @@ -177,95 +201,81 @@ class QGDSRenderer(QRenderer): # to pop up if set precision too fine, # but 1nm seems to be the finest precision we use anyhow. # FOR NOW SPECIFY IN METERS. - tolerance='0.00001', # 10.0 um - + tolerance="0.00001", # 10.0 um # With input from fab people, any of the weird artifacts # (like unwanted gaps) that are less than 1nm in size can be ignored. # They don't even show up in the fabricated masks. # So, the precision of e-9 (so 1 nm) should be good as a default. # FOR NOW SPECIFY IN METERS. - precision='0.000000001', # 1.0 nm - + precision="0.000000001", # 1.0 nm # Since Qiskit Metal GUI, does not require a width for LineString, GDS, # will provide a default value. - width_LineString='10um', - + width_LineString="10um", # The file is expected to be in GDS format. The cell will be placed # into gds Metal output without being edited. The name of the cell can # be placed as options for a component, i.e. placing within a qubit. # During export, the cell will NOT be edited, just imported. - path_filename='../resources/Fake_Junctions.GDS', - + path_filename="../resources/Fake_Junctions.GDS", # For junction table, when cell from default_options.path_filename does # not fit into linestring, QGDSRender will create two pads and add to # junction to fill the location of lineString. The junction_pad_overlap # is from the junction cell to the newly created pads. - junction_pad_overlap='5um', - + junction_pad_overlap="5um", # Vertex limit for FlexPath # max_points (integer) – If the number of points in the polygonal path # boundary is greater than max_points, it will be fractured in smaller # polygons with at most max_points each. If max_points is zero, - # no fracture will occur. GDSpy uses 199 as the default. The historical + # no fracture will occur. GDSII used 199 as the default because the historical # max value of vertices for a poly/path was 199 (fabrication equipment # restrictions). The hard max limit that a GDSII file can - # handle is 8191. - max_points='199', - + # handle is 8191. Gdstk allows arbitary numbers as does most modern software. + max_points="199", # Cheesing is denoted by each chip and layer. cheese=Dict( - #Cheesing is NOT completed - datatype='100', - + # Cheesing is NOT completed + datatype="100", # Expect to mostly cheese a square, but allow for expansion. # 0 is rectangle, 1 is circle - shape='0', + shape="0", # rectangle - cheese_0_x='25um', - cheese_0_y='25um', + cheese_0_x="25um", + cheese_0_y="25um", # circle - cheese_1_radius='100um', - + cheese_1_radius="100um", # Identify which layers to view in gds output file, for each chip view_in_file=Dict(main={1: True}), - # delta spacing between holes - delta_x='100um', - delta_y='100um', - + delta_x="100um", + delta_y="100um", # Keep a buffer around the perimeter of chip, that will # not need cheesing. - edge_nocheese='200um'), - + edge_nocheese="200um", + ), # Think of this as a keep-out region for cheesing. no_cheese=Dict( # For every layer, if there is a ground plane, do cheesing and # place the output on the datatype number (sub-layer number) - datatype='99', - buffer='25um', - - #The styles of caps are specified by integer values: + datatype="99", + buffer="25um", + # The styles of caps are specified by integer values: # 1 (round), 2 (flat), 3 (square). - cap_style='2', - + cap_style="2", # The styles of joins between offset segments are specified by # integer values: # 1 (round), 2 (mitre), and 3 (bevel). - join_style='2', - + join_style="2", # Identify which layers to view in gds output file, for each chip view_in_file=Dict(main={1: True}), ), - # (float): Scale box of components to render. # Should be greater than 1.0. For benefit of the GUI, keep this the # last entry in the dict. GUI shows a note regarding bound_box. - bounding_box_scale_x='1.2', - bounding_box_scale_y='1.2', + bounding_box_scale_x="1.2", + bounding_box_scale_y="1.2", ) """Default options""" - name = 'gds' + name = "gds" """Name""" # When additional columns are added to QGeometry, @@ -288,14 +298,16 @@ class QGDSRenderer(QRenderer): element_table_data = dict( # Cell_name must exist in gds file with: path_filename - junction=dict(cell_name='my_other_junction')) + junction=dict(cell_name="my_other_junction")) """Element table data""" - def __init__(self, - design: 'QDesign', - initiate=True, - render_template: Dict = None, - render_options: Dict = None): + def __init__( + self, + design: "QDesign", + initiate=True, + render_template: Dict = None, + render_options: Dict = None, + ): """Create a QRenderer for GDS interface: export and import. Args: @@ -309,35 +321,35 @@ def __init__(self, Defaults to None. """ - super().__init__(design=design, - initiate=initiate, - render_template=render_template, - render_options=render_options) + super().__init__( + design=design, + initiate=initiate, + render_template=render_template, + render_options=render_options, + ) - self.lib = None # type: gdspy.GdsLibrary + self.lib: Union[gdstk.Library, None] = None self.new_gds_library() - self.dict_bounds = Dict() + self.dict_bounds: DictType[str, Dict] = Dict() # Updated each time export_to_gds() is called. - self.chip_info = dict() + self.chip_info: DictType[str, dict] = dict() # check the scale self._check_bounding_box_scale() # if imported, hold the path to file name, otherwise None. - self.imported_junction_gds = None + self.imported_junction_gds: Union[str, None] = None # track only once QGDSRenderer.load() def _initiate_renderer(self): - """Not used by the gds renderer at this time. only returns True. - """ + """Not used by the gds renderer at this time. Only returns True.""" return True def _close_renderer(self): - """Not used by the gds renderer at this time. only returns True. - """ + """Not used by the gds renderer at this time. Only returns True.""" return True def render_design(self): @@ -353,27 +365,22 @@ def _check_bounding_box_scale(self): self.options.bounding_box_scale_y) if bounding_box_scale_x < 1: - self.options[ - 'bounding_box_scale_x'] = QGDSRenderer.default_options.bounding_box_scale_x + self.options["bounding_box_scale_x"] = ( + QGDSRenderer.default_options.bounding_box_scale_x) self.logger.warning( - 'Expected float and number greater than or equal to' - ' 1.0 for bounding_box_scale_x. User' - f'provided bounding_box_scale_x = {bounding_box_scale_x}' - ', using default_options.bounding_box_scale_x.') + "Expected float and number greater than or equal to" + " 1.0 for bounding_box_scale_x. User" + f"provided bounding_box_scale_x = {bounding_box_scale_x}" + ", using default_options.bounding_box_scale_x.") if bounding_box_scale_y < 1: - self.options[ - 'bounding_box_scale_y'] = QGDSRenderer.default_options.bounding_box_scale_y + self.options["bounding_box_scale_y"] = ( + QGDSRenderer.default_options.bounding_box_scale_y) self.logger.warning( - 'Expected float and number greater than or equal to 1.0 for ' - 'bounding_box_scale_y. User provided ' - f'bounding_box_scale_y = {bounding_box_scale_y}, ' - 'using default_options.bounding_box_scale_y.') - - @staticmethod - def _clear_library(): - """Clear current library.""" - gdspy.current_library.cells.clear() + "Expected float and number greater than or equal to 1.0 for " + "bounding_box_scale_y. User provided " + f"bounding_box_scale_y = {bounding_box_scale_y}, " + "using default_options.bounding_box_scale_y.") def _can_write_to_path(self, file: str) -> int: """Check if can write file. @@ -384,11 +391,11 @@ def _can_write_to_path(self, file: str) -> int: Returns: int: 1 if access is allowed. Else returns 0, if access not given. """ - status, directory_name = can_write_to_path(file) + status, directory_name = can_write_to_path(file) # pylint: disable=possibly-used-before-assignment if status: return 1 - self.logger.warning('Not able to write to directory.' + self.logger.warning("Not able to write to directory." f'File:"{file}" not written.' f' Checked directory:"{directory_name}".') return 0 @@ -398,7 +405,7 @@ def _update_units(self): Warning: DOES NOT CHANGE THE CURRENT LIB """ - self.options['gds_unit'] = 1.0 / self.design.parse_value('1 meter') + self.options["gds_unit"] = 1.0 / self.design.parse_value("1 meter") def _separate_subtract_shapes(self, chip_name: str, table_name: str, table: geopandas.GeoSeries) -> None: @@ -412,18 +419,17 @@ def _separate_subtract_shapes(self, chip_name: str, table_name: str, table (geopandas.GeoSeries): Table with similar qgeometries. """ # pylint: disable=singleton-comparison - subtract_true = table[table['subtract'] == True] + subtract_true = table[table["subtract"] == True] - subtract_false = table[table['subtract'] == False] + subtract_false = table[table["subtract"] == False] - setattr(self, f'{chip_name}_{table_name}_subtract_true', subtract_true) - setattr(self, f'{chip_name}_{table_name}_subtract_false', + setattr(self, f"{chip_name}_{table_name}_subtract_true", subtract_true) + setattr(self, f"{chip_name}_{table_name}_subtract_false", subtract_false) @staticmethod def _get_bounds( - gs_table: geopandas.GeoDataFrame - ) -> Tuple[float, float, float, float]: + gs_table: geopandas.GeoDataFrame,) -> Tuple[float, float, float, float]: """Get the bounds for all of the elements in gs_table. Args: @@ -458,10 +464,12 @@ def _inclusive_bound(all_bounds: list) -> tuple: if len(all_bounds) == 0: return (0.0, 0.0, 0.0, 0.0) - inclusive_tuple = (min(all_bounds, key=itemgetter(0))[0], - min(all_bounds, key=itemgetter(1))[1], - max(all_bounds, key=itemgetter(2))[2], - max(all_bounds, key=itemgetter(3))[3]) + inclusive_tuple = ( + min(all_bounds, key=itemgetter(0))[0], + min(all_bounds, key=itemgetter(1))[1], + max(all_bounds, key=itemgetter(2))[2], + max(all_bounds, key=itemgetter(3))[3], + ) return inclusive_tuple @staticmethod @@ -514,20 +522,22 @@ def _scale_max_bounds(self, chip_name: str, center_x = (minx + maxx) / 2 center_y = (miny + maxy) / 2 - scaled_width = (maxx - minx) * \ - self.parse_value(self.options.bounding_box_scale_x) - scaled_height = (maxy - miny) * \ - self.parse_value(self.options.bounding_box_scale_y) + scaled_width = (maxx - minx) * self.parse_value( + self.options.bounding_box_scale_x) + scaled_height = (maxy - miny) * self.parse_value( + self.options.bounding_box_scale_y) # Scaled inclusive bounding box by self.options.bounding_box_scale_x # and self.options.bounding_box_scale_y. - scaled_box = (center_x - (.5 * scaled_width), - center_y - (.5 * scaled_height), - center_x + (.5 * scaled_width), - center_y + (.5 * scaled_height)) + scaled_box = ( + center_x - (0.5 * scaled_width), + center_y - (0.5 * scaled_height), + center_x + (0.5 * scaled_width), + center_y + (0.5 * scaled_height), + ) - self.dict_bounds[chip_name]['scaled_box'] = scaled_box - self.dict_bounds[chip_name]['inclusive_box'] = (minx, miny, maxx, maxy) + self.dict_bounds[chip_name]["scaled_box"] = scaled_box + self.dict_bounds[chip_name]["inclusive_box"] = (minx, miny, maxx, maxy) return scaled_box, (minx, miny, maxx, maxy) @@ -558,8 +568,8 @@ def _check_qcomps(self, for qcomp in unique_qcomponents: if qcomp not in self.design.name_to_id: self.logger.warning( - f'The component={qcomp} in highlight_qcomponents not' - ' in QDesign. The GDS data not generated.') + f"The component={qcomp} in highlight_qcomponents not" + " in QDesign. The GDS data not generated.") return unique_qcomponents, 1 # For Subtraction bounding box. @@ -614,12 +624,12 @@ def _create_qgeometry_for_gds(self, # put the QGeometry into GDS format. # There can be more than one chip in QGeometry. # They all export to one gds file. - self.chip_info[chip_name]['all_subtract'] = [] - self.chip_info[chip_name]['all_no_subtract'] = [] + self.chip_info[chip_name]["all_subtract"] = [] + self.chip_info[chip_name]["all_no_subtract"] = [] self.dict_bounds[chip_name] = Dict() - self.dict_bounds[chip_name]['gather'] = [] - self.dict_bounds[chip_name]['for_subtract'] = tuple() + self.dict_bounds[chip_name]["gather"] = [] + self.dict_bounds[chip_name]["for_subtract"] = tuple() all_table_subtracts = [] all_table_no_subtracts = [] @@ -630,33 +640,37 @@ def _create_qgeometry_for_gds(self, table = self._get_table(table_name, unique_qcomponents, chip_name) - if table_name == 'junction': - self.chip_info[chip_name]['junction'] = deepcopy(table) + if table_name == "junction": + self.chip_info[chip_name]["junction"] = deepcopy(table) else: # For every chip, and layer, separate the "subtract" # and "no_subtract" elements and gather bounds. # self.dict_bounds[chip_name] = list_bounds self._gather_subtract_elements_and_bounds( - chip_name, table_name, table, all_table_subtracts, - all_table_no_subtracts) + chip_name, + table_name, + table, + all_table_subtracts, + all_table_no_subtracts, + ) # If list of QComponents provided, use the # bounding_box_scale(x and y), otherwise use self._chips. scaled_max_bound, max_bound = self._scale_max_bounds( - chip_name, self.dict_bounds[chip_name]['gather']) + chip_name, self.dict_bounds[chip_name]["gather"]) if highlight_qcomponents: - self.dict_bounds[chip_name]['for_subtract'] = scaled_max_bound + self.dict_bounds[chip_name]["for_subtract"] = scaled_max_bound else: chip_box, status = self.design.get_x_y_for_chip(chip_name) if status == 0: - self.dict_bounds[chip_name]['for_subtract'] = chip_box + self.dict_bounds[chip_name]["for_subtract"] = chip_box else: - self.dict_bounds[chip_name]['for_subtract'] = max_bound + self.dict_bounds[chip_name]["for_subtract"] = max_bound self.logger.warning( - f'design.get_x_y_for_chip() did NOT return a good ' - f'code for chip={chip_name},for ground subtraction-box' - f' using the size calculated from QGeometry, ' - f'({max_bound}) will be used. ') + f"design.get_x_y_for_chip() did NOT return a good " + f"code for chip={chip_name},for ground subtraction-box" + f" using the size calculated from QGeometry, " + f"({max_bound}) will be used. ") if is_true(self.options.ground_plane): self._handle_ground_plane(chip_name, all_table_subtracts, all_table_no_subtracts) @@ -695,38 +709,38 @@ def _handle_ground_plane(self, chip_name: str, all_table_subtracts: list, copy_no_subtract = deepcopy(all_table_no_subtracts) for item in copy_subtract: - item.drop(item.index[item['layer'] != chip_layer], inplace=True) + item.drop(item.index[item["layer"] != chip_layer], inplace=True) for item_no in copy_no_subtract: - item_no.drop(item_no.index[item_no['layer'] != chip_layer], + item_no.drop(item_no.index[item_no["layer"] != chip_layer], inplace=True) - self.chip_info[chip_name][chip_layer][ - 'all_subtract_true'] = geopandas.GeoDataFrame( - pd.concat(copy_subtract, ignore_index=False)) + self.chip_info[chip_name][chip_layer]["all_subtract_true"] = ( + geopandas.GeoDataFrame( + pd.concat(copy_subtract, ignore_index=False))) - self.chip_info[chip_name][chip_layer][ - 'all_subtract_false'] = geopandas.GeoDataFrame( - pd.concat(copy_no_subtract, ignore_index=False)) + self.chip_info[chip_name][chip_layer]["all_subtract_false"] = ( + geopandas.GeoDataFrame( + pd.concat(copy_no_subtract, ignore_index=False))) self.chip_info[chip_name][chip_layer][ - 'all_subtract_true'].reset_index(inplace=True) + "all_subtract_true"].reset_index(inplace=True) self.chip_info[chip_name][chip_layer][ - 'all_subtract_false'].reset_index(inplace=True) + "all_subtract_false"].reset_index(inplace=True) if is_true(fix_short_segments): self._fix_short_segments_within_table(chip_name, chip_layer, - 'all_subtract_true') + "all_subtract_true") self._fix_short_segments_within_table(chip_name, chip_layer, - 'all_subtract_false') + "all_subtract_false") self.chip_info[chip_name][chip_layer][ - 'q_subtract_true'] = self.chip_info[chip_name][chip_layer][ - 'all_subtract_true'].apply(self._qgeometry_to_gds, axis=1) + "q_subtract_true"] = self.chip_info[chip_name][chip_layer][ + "all_subtract_true"].apply(self._qgeometry_to_gds, axis=1) self.chip_info[chip_name][chip_layer][ - 'q_subtract_false'] = self.chip_info[chip_name][chip_layer][ - 'all_subtract_false'].apply(self._qgeometry_to_gds, axis=1) + "q_subtract_false"] = self.chip_info[chip_name][chip_layer][ + "all_subtract_false"].apply(self._qgeometry_to_gds, axis=1) # Handling Fillet issues. @@ -748,7 +762,7 @@ def _fix_short_segments_within_table(self, chip_name: str, chip_layer: int, # pylint: disable=too-many-locals data_frame = self.chip_info[chip_name][chip_layer][ all_sub_true_or_false] - df_fillet = data_frame[-data_frame['fillet'].isnull()] + df_fillet = data_frame[-data_frame["fillet"].isnull()] if not df_fillet.empty: # Don't edit the table when iterating through the rows. @@ -773,8 +787,8 @@ def _fix_short_segments_within_table(self, chip_name: str, chip_layer: int, df_copy = df_copy.drop(index=del_key) for dummy_new_row, short_shape in the_shapes.items(): - orig_row['geometry'] = short_shape['line'] - orig_row['fillet'] = short_shape['fillet'] + orig_row["geometry"] = short_shape["line"] + orig_row["fillet"] = short_shape["fillet"] # Keep ignore_index=False, otherwise, # the other del_key will not be found. df_copy = df_copy.append(orig_row, ignore_index=False) @@ -834,11 +848,11 @@ def _check_length(self, a_shapely: shapely.geometry.LineString, shorter_lines = dict() - idx_bad_fillet = sorted(all_idx_bad_fillet['reduced_idx']) + idx_bad_fillet = sorted(all_idx_bad_fillet["reduced_idx"]) status = len(idx_bad_fillet) if status: - midpoints = all_idx_bad_fillet['midpoints'] + midpoints = all_idx_bad_fillet["midpoints"] no_fillet_vertices = list() fillet_vertices = list() @@ -851,23 +865,23 @@ def _check_length(self, a_shapely: shapely.geometry.LineString, # Every vertex should not be fillet'd no_fillet_vertices = coords[start:len_coords] shorter_lines[stop] = dict({ - 'line': LineString(no_fillet_vertices), - 'fillet': float('NaN') + "line": LineString(no_fillet_vertices), + "fillet": float("NaN"), }) else: no_fillet_vertices = coords[start:stop + 1] no_fillet_vertices.append(midpoints[stop]) shorter_lines[stop] = dict({ - 'line': LineString(no_fillet_vertices), - 'fillet': float('NaN') + "line": LineString(no_fillet_vertices), + "fillet": float("NaN"), }) elif idx == status - 1 and stop == len_coords - 1: # The last segment no_fillet_vertices = coords[start:stop + 1] no_fillet_vertices.insert(0, midpoints[start - 1]) shorter_lines[stop] = dict({ - 'line': LineString(no_fillet_vertices), - 'fillet': float('NaN') + "line": LineString(no_fillet_vertices), + "fillet": float("NaN") }) else: # Segment in between first and last segment. @@ -875,8 +889,8 @@ def _check_length(self, a_shapely: shapely.geometry.LineString, no_fillet_vertices.insert(0, midpoints[start - 1]) no_fillet_vertices.append(midpoints[stop]) shorter_lines[stop] = dict({ - 'line': LineString(no_fillet_vertices), - 'fillet': float('NaN') + "line": LineString(no_fillet_vertices), + "fillet": float("NaN") }) # Gather the fillet segments. at_vertex = 0 @@ -888,15 +902,15 @@ def _check_length(self, a_shapely: shapely.geometry.LineString, init_tuple = coords[0] fillet_vertices = [init_tuple, midpoints[start - 1]] shorter_lines[start] = dict({ - 'line': LineString(fillet_vertices), - 'fillet': a_fillet + "line": LineString(fillet_vertices), + "fillet": a_fillet }) if idx == 0 and start > 1: fillet_vertices = coords[0:start] fillet_vertices.append(midpoints[start - 1]) shorter_lines[start] = dict({ - 'line': LineString(fillet_vertices), - 'fillet': a_fillet + "line": LineString(fillet_vertices), + "fillet": a_fillet }) if idx == status - 1 and stop != len_coords - 1: # Extra segment after the last no-fillet. @@ -904,8 +918,8 @@ def _check_length(self, a_shapely: shapely.geometry.LineString, fillet_vertices = coords[stop + 1:len_coords] fillet_vertices.insert(0, midpoints[stop]) shorter_lines[len_coords] = dict({ - 'line': LineString(fillet_vertices), - 'fillet': a_fillet + "line": LineString(fillet_vertices), + "fillet": a_fillet }) elif idx == status - 1 and start == 0 and stop != len_coords - 1: # At last tuple, and and start at first index, @@ -913,8 +927,8 @@ def _check_length(self, a_shapely: shapely.geometry.LineString, fillet_vertices = coords[stop + 1:len_coords] fillet_vertices.insert(0, midpoints[stop]) shorter_lines[start] = dict({ - 'line': LineString(fillet_vertices), - 'fillet': a_fillet + "line": LineString(fillet_vertices), + "fillet": a_fillet }) elif idx == status - 1 and stop != len_coords - 1: # At last tuple, and the stop is not last index of coords. @@ -922,16 +936,16 @@ def _check_length(self, a_shapely: shapely.geometry.LineString, fillet_vertices.insert(0, midpoints[at_vertex]) fillet_vertices.append(midpoints[start - 1]) shorter_lines[start] = dict({ - 'line': LineString(fillet_vertices), - 'fillet': a_fillet + "line": LineString(fillet_vertices), + "fillet": a_fillet }) # Extra segment after the last no-fillet. fillet_vertices.clear() fillet_vertices = coords[stop + 1:len_coords] fillet_vertices.insert(0, midpoints[stop]) shorter_lines[len_coords] = dict({ - 'line': LineString(fillet_vertices), - 'fillet': a_fillet + "line": LineString(fillet_vertices), + "fillet": a_fillet }) else: if (start - at_vertex) > 1: @@ -939,8 +953,8 @@ def _check_length(self, a_shapely: shapely.geometry.LineString, fillet_vertices.insert(0, midpoints[at_vertex]) fillet_vertices.append(midpoints[start - 1]) shorter_lines[start] = dict({ - 'line': LineString(fillet_vertices), - 'fillet': a_fillet + "line": LineString(fillet_vertices), + "fillet": a_fillet }) at_vertex = stop # Need to update for every loop. else: @@ -981,27 +995,30 @@ def _identify_vertex_not_to_fillet(self, coords: list, a_fillet: float, # For now, DO NOT allow the user of GDS to provide the precision. # user_precision = int(np.abs(np.log10(precision))) - qdesign_precision = self.design.template_options.PRECISION - - all_idx_bad_fillet['reduced_idx'] = get_range_of_vertex_to_not_fillet( - coords, a_fillet, qdesign_precision, add_endpoints=True) - - midpoints = list() + func = get_range_of_vertex_to_not_fillet # pylint: disable=possibly-used-before-assignment + all_idx_bad_fillet["reduced_idx"] = func( + coords, + a_fillet, + self.design.template_options.PRECISION, + add_endpoints=True) midpoints = [ - QGDSRenderer._midpoint_xy(coords[idx - 1][0], coords[idx - 1][1], - vertex2[0], vertex2[1]) + self._midpoint_xy(coords[idx - 1][0], coords[idx - 1][1], + vertex2[0], vertex2[1]) for idx, vertex2 in enumerate(coords) if idx > 0 ] - all_idx_bad_fillet['midpoints'] = midpoints + all_idx_bad_fillet["midpoints"] = midpoints # Move data around to be useful for GDS - def _gather_subtract_elements_and_bounds(self, chip_name: str, - table_name: str, - table: geopandas.GeoDataFrame, - all_subtracts: list, - all_no_subtracts: list): + def _gather_subtract_elements_and_bounds( + self, + chip_name: str, + table_name: str, + table: geopandas.GeoDataFrame, + all_subtracts: list, + all_no_subtracts: list, + ): """For every chip, and layer, separate the "subtract" and "no_subtract" elements and gather bounds for all the elements in qgeometries. Use format: f'{chip_name}_{table_name}s'. @@ -1021,23 +1038,23 @@ def _gather_subtract_elements_and_bounds(self, chip_name: str, bounds = tuple(self._get_bounds(table)) # Add the bounds of each table to list. - self.dict_bounds[chip_name]['gather'].append(bounds) + self.dict_bounds[chip_name]["gather"].append(bounds) if is_true(self.options.ground_plane): self._separate_subtract_shapes(chip_name, table_name, table) all_subtracts.append( - getattr(self, f'{chip_name}_{table_name}_subtract_true')) + getattr(self, f"{chip_name}_{table_name}_subtract_true")) all_no_subtracts.append( - getattr(self, f'{chip_name}_{table_name}_subtract_false')) + getattr(self, f"{chip_name}_{table_name}_subtract_false")) # Done because ground plane option may be false. # This is not used anywhere currently. # Keep this depreciated code. # polys use gdspy.Polygon; paths use gdspy.LineString - #q_geometries = table.apply(self._qgeometry_to_gds, axis=1) - #setattr(self, f'{chip_name}_{table_name}s', q_geometries) + # q_geometries = table.apply(self._qgeometry_to_gds, axis=1) + # setattr(self, f'{chip_name}_{table_name}s', q_geometries) def _get_table(self, table_name: str, unique_qcomponents: list, chip_name: str) -> geopandas.GeoDataFrame: @@ -1068,31 +1085,34 @@ def _get_table(self, table_name: str, unique_qcomponents: list, ] # Remove QComponents which are not requested. - table = table[table['component'].isin(highlight_id)] + table = table[table["component"].isin(highlight_id)] - table = table[table['chip'] == chip_name] + table = table[table["chip"] == chip_name] return table # To export the data. - def new_gds_library(self) -> gdspy.GdsLibrary: + def new_gds_library(self) -> "gdstk.Library": """Creates a new GDS Library. Deletes the old. Create a new GDS library file. It can contains multiple cells. Returns: - gdspy.GdsLibrary: GDS library which can contain multiple cells. + gdstk.Library: GDS library which can contain multiple cells. """ self._update_units() if self.lib: - self._clear_library() + # Clear old cells from the library + for c in list(self.lib.cells): + self.lib.remove(c) # Create a new GDS library file. It can contains multiple cells. - self.lib = gdspy.GdsLibrary( + self.lib = gdstk.Library( unit=float(self.parse_value(self.options.gds_unit)), - precision=float(self.parse_value(self.options.precision))) + precision=float(self.parse_value(self.options.precision)), + ) return self.lib @@ -1188,8 +1208,8 @@ def _check_either_cheese(self, chip: str, layer: int) -> int: cheese_code = self._check_cheese(chip, layer) if no_cheese_code == 0 or cheese_code == 0: - self.logger.warning('Not able to get no_cheese_view_in_file or ' - 'cheese_view_in_file from self.options.') + self.logger.warning("Not able to get no_cheese_view_in_file or " + "cheese_view_in_file from self.options.") code = 0 return code if no_cheese_code == 1 and cheese_code == 1: @@ -1207,14 +1227,14 @@ def _check_either_cheese(self, chip: str, layer: int) -> int: if no_cheese_code == 3 or cheese_code == 3: code = 5 self.logger.warning( - f'Chip={chip} is not either in no_cheese_view_in_file ' - f'or cheese_view_in_file from self.options.') + f"Chip={chip} is not either in no_cheese_view_in_file " + f"or cheese_view_in_file from self.options.") return code if no_cheese_code == 4 or cheese_code == 4: code = 6 self.logger.warning( - f'layer={layer} is not in chip={chip} either in ' - f'no_cheese_view_in_file or cheese_view_in_file from self.options.' + f"layer={layer} is not in chip={chip} either in " + f"no_cheese_view_in_file or cheese_view_in_file from self.options." ) return code @@ -1240,14 +1260,28 @@ def _populate_cheese(self): if status == 0: minx, miny, maxx, maxy = chip_box - self._cheese_based_on_shape(minx, miny, maxx, maxy, - chip_name, chip_layer, - cheese_sub_layer, - nocheese_sub_layer) - - def _cheese_based_on_shape(self, minx: float, miny: float, maxx: float, - maxy: float, chip_name: str, chip_layer: int, - cheese_sub_layer: int, nocheese_sub_layer: int): + self._cheese_based_on_shape( + minx, + miny, + maxx, + maxy, + chip_name, + chip_layer, + cheese_sub_layer, + nocheese_sub_layer, + ) + + def _cheese_based_on_shape( + self, + minx: float, + miny: float, + maxx: float, + maxy: float, + chip_name: str, + chip_layer: int, + cheese_sub_layer: int, + nocheese_sub_layer: int, + ): """Instantiate class to do cheesing. Args: @@ -1267,9 +1301,9 @@ def _cheese_based_on_shape(self, minx: float, miny: float, maxx: float, max_points = int(self.parse_value(self.options.max_points)) cheese_shape = int(self.parse_value(self.options.cheese.shape)) - all_nocheese = self.chip_info[chip_name][chip_layer]['no_cheese'] + all_nocheese = self.chip_info[chip_name][chip_layer]["no_cheese"] all_nocheese_gds = self.chip_info[chip_name][chip_layer][ - 'no_cheese_gds'] + "no_cheese_gds"] delta_x = float(self.parse_value(self.options.cheese.delta_x)) delta_y = float(self.parse_value(self.options.cheese.delta_y)) edge_nocheese = float( @@ -1281,55 +1315,59 @@ def _cheese_based_on_shape(self, minx: float, miny: float, maxx: float, if cheese_shape == 0: cheese_x = float(self.parse_value(self.options.cheese.cheese_0_x)) cheese_y = float(self.parse_value(self.options.cheese.cheese_0_y)) - a_cheese = Cheesing(all_nocheese, - all_nocheese_gds, - self.lib, - minx, - miny, - maxx, - maxy, - chip_name, - edge_nocheese, - chip_layer, - is_neg_mask, - cheese_sub_layer, - nocheese_sub_layer, - fab, - self.logger, - max_points, - precision, - cheese_shape=cheese_shape, - shape_0_x=cheese_x, - shape_0_y=cheese_y, - delta_x=delta_x, - delta_y=delta_y) + a_cheese = Cheesing( + all_nocheese, + all_nocheese_gds, + self.lib, + minx, + miny, + maxx, + maxy, + chip_name, + edge_nocheese, + chip_layer, + is_neg_mask, + cheese_sub_layer, + nocheese_sub_layer, + fab, + self.logger, + max_points, + precision, + cheese_shape=cheese_shape, + shape_0_x=cheese_x, + shape_0_y=cheese_y, + delta_x=delta_x, + delta_y=delta_y, + ) elif cheese_shape == 1: cheese_radius = float( self.parse_value(self.options.cheese.cheese_1_radius)) - a_cheese = Cheesing(all_nocheese, - all_nocheese_gds, - self.lib, - minx, - miny, - maxx, - maxy, - chip_name, - edge_nocheese, - chip_layer, - is_neg_mask, - cheese_sub_layer, - nocheese_sub_layer, - fab, - self.logger, - max_points, - precision, - cheese_shape=cheese_shape, - shape_1_radius=cheese_radius, - delta_x=delta_x, - delta_y=delta_y) + a_cheese = Cheesing( + all_nocheese, + all_nocheese_gds, + self.lib, + minx, + miny, + maxx, + maxy, + chip_name, + edge_nocheese, + chip_layer, + is_neg_mask, + cheese_sub_layer, + nocheese_sub_layer, + fab, + self.logger, + max_points, + precision, + cheese_shape=cheese_shape, + shape_1_radius=cheese_radius, + delta_x=delta_x, + delta_y=delta_y, + ) else: self.logger.warning( - f'The cheese_shape={cheese_shape} is unknown in QGDSRenderer.') + f"The cheese_shape={cheese_shape} is unknown in QGDSRenderer.") a_cheese = None if a_cheese is not None: @@ -1352,7 +1390,6 @@ def _populate_no_cheese(self): self.options.no_cheese.buffer)) sub_layer = int(self.parse_value(self.options.no_cheese.datatype)) lib = self.lib - fab = is_true(self.options.fabricate) for chip_name, _ in self.chip_info.items(): @@ -1364,45 +1401,42 @@ def _populate_no_cheese(self): if code in (1, 2, 3): if len(self.chip_info[chip_name][chip_layer] - ['all_subtract_true']) != 0: - + ["all_subtract_true"]) != 0: sub_df = self.chip_info[chip_name][chip_layer][ - 'all_subtract_true'] + "all_subtract_true"] no_cheese_multipolygon = self._cheese_buffer_maker( sub_df, chip_name, no_cheese_buffer) - if no_cheese_multipolygon is not None: self.chip_info[chip_name][chip_layer][ - 'no_cheese'] = no_cheese_multipolygon - sub_layer = int( - self.parse_value( - self.options.no_cheese.datatype)) + "no_cheese"] = no_cheese_multipolygon all_nocheese_gds = self._multipolygon_to_gds( no_cheese_multipolygon, chip_layer, sub_layer, no_cheese_buffer) self.chip_info[chip_name][chip_layer][ - 'no_cheese_gds'] = all_nocheese_gds + "no_cheese_gds"] = all_nocheese_gds - # If fabricate.fab is true, then - # do not put nocheese in gds file. if self._check_no_cheese( chip_name, chip_layer) == 1 and not fab: no_cheese_subtract_cell_name = ( - f'TOP_{chip_name}_{chip_layer}' - f'_NoCheese_{sub_layer}') - no_cheese_cell = lib.new_cell( - no_cheese_subtract_cell_name, - overwrite_duplicate=True) - - no_cheese_cell.add(all_nocheese_gds) - - # Keep the cell out to layer, it becomes part of ground. - chip_only_top_name = f'TOP_{chip_name}' - - if no_cheese_cell.get_bounding_box( + f"TOP_{chip_name}_{chip_layer}_NoCheese_{sub_layer}" + ) + no_cheese_cell = _new_cell( + lib, no_cheese_subtract_cell_name, True) + for poly_el in all_nocheese_gds: + if isinstance(poly_el, list): + for sub_poly in poly_el: + no_cheese_cell.add(sub_poly) + else: + no_cheese_cell.add(poly_el) + + chip_only_top_name = f"TOP_{chip_name}" + chip_only_top = next( + (c for c in lib.cells + if c.name == chip_only_top_name), None) + if chip_only_top and no_cheese_cell.bounding_box( ) is not None: - lib.cells[chip_only_top_name].add( - gdspy.CellReference(no_cheese_cell)) + chip_only_top.add( + gdstk.Reference(no_cheese_cell)) else: lib.remove(no_cheese_cell) @@ -1433,13 +1467,13 @@ def _cheese_buffer_maker( poly_sub_df = sub_df[sub_df.geometry.apply( lambda x: isinstance(x, shapely.geometry.polygon.Polygon))] - poly_sub_geo = poly_sub_df['geometry'].tolist() + poly_sub_geo = poly_sub_df["geometry"].tolist() path_sub_df = sub_df[sub_df.geometry.apply( lambda x: isinstance(x, shapely.geometry.linestring.LineString))] - path_sub_geo = path_sub_df['geometry'].tolist() - path_sub_width = path_sub_df['width'].tolist() - #for n in range(len(path_sub_geo)): + path_sub_geo = path_sub_df["geometry"].tolist() + path_sub_width = path_sub_df["width"].tolist() + # for n in range(len(path_sub_geo)): for index, _ in enumerate(path_sub_geo): path_sub_geo[index] = path_sub_geo[index].buffer( path_sub_width[index] / 2, @@ -1451,7 +1485,7 @@ def _cheese_buffer_maker( combo_shapely = draw.union(combo_list) if not combo_shapely.is_empty: - #Can return either Multipolygon or just one polygon. + # Can return either Multipolygon or just one polygon. combo_shapely = combo_shapely.buffer(no_cheese_buffer, cap_style=style_cap, join_style=style_join) @@ -1463,17 +1497,16 @@ def _cheese_buffer_maker( if status == 0: minx, miny, maxx, maxy = chip_box c_minx, c_miny, c_maxx, c_maxy = combo_shapely.bounds - if (c_minx < minx or c_miny < miny or c_maxx > maxx or - c_maxy > maxy): + if c_minx < minx or c_miny < miny or c_maxx > maxx or c_maxy > maxy: self.logger.warning( - f'The bounding box for no-cheese is outside of chip size.\n' - f'Bounding box for chip is {chip_box}.\n' - f'Bounding box with no_cheese buffer is {combo_shapely.bounds}.' + f"The bounding box for no-cheese is outside of chip size.\n" + f"Bounding box for chip is {chip_box}.\n" + f"Bounding box with no_cheese buffer is {combo_shapely.bounds}." ) else: self.logger.warning( - f'design.get_x_y_for_chip() did NOT return a good code for chip={chip_name},' - f'for _cheese_buffer_maker. The chip boundary will not be tested.' + f"design.get_x_y_for_chip() did NOT return a good code for chip={chip_name}," + f"for _cheese_buffer_maker. The chip boundary will not be tested." ) # The type of combo_shapely will be @@ -1493,7 +1526,7 @@ def _get_rectangle_points(self, chip_name: str) -> Tuple[list, list]: """ layers_in_chip = self.design.qgeometry.get_all_unique_layers(chip_name) - minx, miny, maxx, maxy = self.dict_bounds[chip_name]['for_subtract'] + minx, miny, maxx, maxy = self.dict_bounds[chip_name]["for_subtract"] rectangle_points = [(minx, miny), (maxx, miny), (maxx, maxy), (minx, maxy)] @@ -1519,11 +1552,11 @@ def _populate_poly_path_for_export(self): lib = self.new_gds_library() if is_true(self.options.ground_plane): - all_chips_top_name = 'TOP' + all_chips_top_name = "TOP" all_chips_top = lib.new_cell(all_chips_top_name, overwrite_duplicate=True) for chip_name, _ in self.chip_info.items(): - chip_only_top_name = f'TOP_{chip_name}' + chip_only_top_name = f"TOP_{chip_name}" chip_only_top = lib.new_cell(chip_only_top_name, overwrite_duplicate=True) @@ -1531,51 +1564,77 @@ def _populate_poly_path_for_export(self): chip_name) for chip_layer in layers_in_chip: - self._handle_photo_resist(lib, chip_only_top, chip_name, - chip_layer, rectangle_points, - precision, max_points) + self._handle_photo_resist( + lib, + chip_only_top, + chip_name, + chip_layer, + rectangle_points, + precision, + max_points, + ) # If junction table, import the cell and cell to chip_only_top - if 'junction' in self.chip_info[chip_name]: + if "junction" in self.chip_info[chip_name]: self._import_junctions_to_one_cell(chip_name, lib, chip_only_top, layers_in_chip) # put all chips into TOP if chip_only_top.get_bounding_box() is not None: - all_chips_top.add(gdspy.CellReference(chip_only_top)) + all_chips_top.add(gdstk.Reference(chip_only_top)) else: lib.remove(chip_only_top) - def _handle_photo_resist(self, lib: gdspy.GdsLibrary, - chip_only_top: gdspy.library.Cell, chip_name: str, - chip_layer: int, rectangle_points: list, - precision: float, max_points: int): + def _handle_photo_resist( + self, + lib: "gdstk.Library", + chip_only_top: "gdstk.Cell", + chip_name: str, + chip_layer: int, + rectangle_points: list, + precision: float, + max_points: int, + ): """Handle the positive vs negative mask. Args: - lib (gdspy.GdsLibrary): The gdspy library to export. - chip_only_top (gdspy.library.Cell): The gdspy cell for top. + lib (gdstk.Library): The GDS library to export. + chip_only_top (gdstk.Cell): The GDS cell for top. chip_name (str): Name of chip to render. chip_layer (int): Layer of the chip to render. rectangle_points (list): The rectangle to denote the ground for each layer. - precision (float): Used for gdspy. - max_points (int): Used for gdspy. GDSpy uses 199 as the default. + precision (float): Used for GDS python export. + max_points (int): Used for GDS python export, 199 as the default. """ - self.chip_info[chip_name]['subtract_poly'] = gdspy.Polygon( - rectangle_points, chip_layer) + self.chip_info[chip_name]["subtract_poly"] = gdstk.Polygon( + rectangle_points, layer=chip_layer, datatype=10) - ground_cell_name = f'TOP_{chip_name}_{chip_layer}' + ground_cell_name = f"TOP_{chip_name}_{chip_layer}" ground_cell = lib.new_cell(ground_cell_name, overwrite_duplicate=True) if self._is_negative_mask(chip_name, chip_layer): - self._negative_mask(lib, chip_only_top, ground_cell, chip_name, - chip_layer, precision, max_points) + self._negative_mask( + lib, + chip_only_top, + ground_cell, + chip_name, + chip_layer, + precision, + max_points, + ) else: - self._positive_mask(lib, chip_only_top, ground_cell, chip_name, - chip_layer, precision, max_points) + self._positive_mask( + lib, + chip_only_top, + ground_cell, + chip_name, + chip_layer, + precision, + max_points, + ) def _is_negative_mask(self, chip: str, layer: int) -> bool: """Check options to see if negative mask is requested for the @@ -1595,78 +1654,96 @@ def _is_negative_mask(self, chip: str, layer: int) -> bool: return False - def _negative_mask(self, lib: gdspy.GdsLibrary, - chip_only_top: gdspy.library.Cell, - ground_cell: gdspy.library.Cell, chip_name: str, - chip_layer: int, precision: float, max_points: int): + def _negative_mask( + self, + lib: "gdstk.Library", + chip_only_top: "gdstk.Cell", + ground_cell: "gdstk.Cell", + chip_name: str, + chip_layer: int, + precision: float, + max_points: int, + ): """Apply logic for negative_mask. Args: - lib (gdspy.GdsLibrary): The gdspy library to export. - chip_only_top (gdspy.library.Cell): The gdspy cell for top. - ground_cell (gdspy.library.Cell): Cell created for each layer. + lib (gdstk.Library): GDS library. + chip_only_top (gdstk.Cell): The chip's top cell. + ground_cell (gdstk.Cell): The ground cell for this layer. chip_name (str): Name of chip to render. chip_layer (int): Layer of the chip to render. - precision (float): Used for gdspy. - max_points (int): Used for gdspy. GDSpy uses 199 as the default. + precision (float): GDS geometry precision. + max_points (int): GDS geometry max points, default is 199. """ - if len(self.chip_info[chip_name][chip_layer]['q_subtract_true']) != 0: + if len(self.chip_info[chip_name][chip_layer]["q_subtract_true"]) != 0: # When subtract==True for chip and layer. - subtract_true_cell_name = f'SUBTRACT_true_{chip_name}_{chip_layer}' + subtract_true_cell_name = f"SUBTRACT_true_{chip_name}_{chip_layer}" subtract_true_cell = lib.new_cell(subtract_true_cell_name, overwrite_duplicate=True) subtract_true_cell.add( - self.chip_info[chip_name][chip_layer]['q_subtract_true']) + self.chip_info[chip_name][chip_layer]["q_subtract_true"]) - #When subtract==False for chip and layer. - subtract_false_cell_name = f'SUBTRACT_false_{chip_name}_{chip_layer}' + # When subtract==False for chip and layer. + subtract_false_cell_name = f"SUBTRACT_false_{chip_name}_{chip_layer}" subtract_false_cell = lib.new_cell(subtract_false_cell_name, overwrite_duplicate=True) subtract_false_cell.add( - self.chip_info[chip_name][chip_layer]['q_subtract_false']) + self.chip_info[chip_name][chip_layer]["q_subtract_false"]) + + subtract_true_polygons = subtract_true_cell.polygons + subtract_false_polygons = subtract_false_cell.polygons # Difference for True-False. - diff_geometry = gdspy.boolean(subtract_true_cell.get_polygons(), - subtract_false_cell.get_polygons(), - 'not', - max_points=max_points, - precision=precision, - layer=chip_layer) + diff_geometry = gdstk.boolean( + subtract_true_polygons, + subtract_false_polygons, + "not", + layer=chip_layer, + datatype=10, + precision=precision, + max_points=max_points, + ) lib.remove(subtract_true_cell) lib.remove(subtract_false_cell) if diff_geometry is None: self.design.logger.warning( - 'There is no table named diff_geometry to write.') + "There is no table named diff_geometry to write.") else: ground_cell.add(diff_geometry) QGDSRenderer._add_groundcell_to_chip_only_top(lib, chip_only_top, ground_cell) - def _positive_mask(self, lib: gdspy.GdsLibrary, - chip_only_top: gdspy.library.Cell, - ground_cell: gdspy.library.Cell, chip_name: str, - chip_layer: int, precision: float, max_points: int): - """Apply logic for positive mask. + def _positive_mask( + self, + lib: "gdstk.Library", + chip_only_top: "gdstk.Cell", + ground_cell: "gdstk.Cell", + chip_name: str, + chip_layer: int, + precision: float, + max_points: int, + ): + """Apply logic for positive mask for a chip to render. Args: - lib (gdspy.GdsLibrary): The gdspy library to export. - chip_only_top (gdspy.library.Cell): The gdspy cell for top. - ground_cell (gdspy.library.Cell): Cell created for each layer. - chip_name (str): Name of chip to render. - chip_layer (int): Layer of the chip to render. - precision (float): Used for gdspy. - max_points (int): Used for gdspy. GDSpy uses 199 as the default. + lib (gdstk.Library): GDS library. + chip_only_top (gdstk.Cell): The chip's top cell. + ground_cell (gdstk.Cell): The ground cell for this layer. + chip_name (str): Chip name. + chip_layer (int): Layer index. + precision (float): GDS geometry precision. + max_points (int): GDS geometry max points. """ - if len(self.chip_info[chip_name][chip_layer]['q_subtract_true']) != 0: - subtract_cell_name = f'SUBTRACT_{chip_name}_{chip_layer}' + if len(self.chip_info[chip_name][chip_layer]["q_subtract_true"]) != 0: + subtract_cell_name = f"SUBTRACT_{chip_name}_{chip_layer}" subtract_cell = lib.new_cell(subtract_cell_name, overwrite_duplicate=True) subtract_cell.add( - self.chip_info[chip_name][chip_layer]['q_subtract_true']) + self.chip_info[chip_name][chip_layer]["q_subtract_true"]) # gdspy.boolean() is not documented clearly. If there are multiple # elements to subtract (both poly & path), the way I could @@ -1674,72 +1751,74 @@ def _positive_mask(self, lib: gdspy.GdsLibrary, # the method cell_name.get_polygons(), which appears to convert # all elements within the cell to poly. After the boolean(), # I deleted the cell from lib. The memory is freed up then. - diff_geometry = gdspy.boolean( - self.chip_info[chip_name]['subtract_poly'], - subtract_cell.get_polygons(), - 'not', - max_points=max_points, + diff_geometry = gdstk.boolean( + [self.chip_info[chip_name]["subtract_poly"]], + subtract_cell.polygons, + "not", + layer=chip_layer, + datatype=10, precision=precision, - layer=chip_layer) + max_points=max_points, + ) lib.remove(subtract_cell) if diff_geometry is None: self.design.logger.warning( - 'There is no table named diff_geometry to write.') + "There is no table named diff_geometry to write.") else: - ground_chip_layer_name = f'ground_{chip_name}_{chip_layer}' + ground_chip_layer_name = f"ground_{chip_name}_{chip_layer}" ground_chip_layer = lib.new_cell(ground_chip_layer_name) - #diff_geometry is a polygon set. So put into it's own cell. + # diff_geometry is a polygon set. So put into it's own cell. ground_chip_layer.add(diff_geometry) - ground_cell.add(gdspy.CellReference(ground_chip_layer)) + ground_cell.add(gdstk.Reference(ground_chip_layer)) self._handle_q_subtract_false(chip_name, chip_layer, ground_cell) QGDSRenderer._add_groundcell_to_chip_only_top(lib, chip_only_top, ground_cell) def _handle_q_subtract_false(self, chip_name: str, chip_layer: int, - ground_cell: gdspy.library.Cell): + ground_cell: "gdstk.Cell"): """For each layer, add the subtract=false components to ground. Args: chip_name (str): Name of chip to render. chip_layer (int): Name of layer to render. - ground_cell (gdspy.library.Cell): The cell in lib to add to. + ground_cell (gdstk.Cell): The cell in lib to add to. Cell created for each layer. """ - if self.chip_info[chip_name][chip_layer]['q_subtract_false'] is None: - self.logger.warning(f'There is no table named ' - f'self.chip_info[{chip_name}][q_subtract_false]' - f' to write.') + if self.chip_info[chip_name][chip_layer]["q_subtract_false"] is None: + self.logger.warning(f"There is no table named " + f"self.chip_info[{chip_name}][q_subtract_false]" + f" to write.") else: if len(self.chip_info[chip_name][chip_layer] - ['q_subtract_false']) != 0: + ["q_subtract_false"]) != 0: ground_cell.add( - self.chip_info[chip_name][chip_layer]['q_subtract_false']) + self.chip_info[chip_name][chip_layer]["q_subtract_false"]) @classmethod - def _add_groundcell_to_chip_only_top(cls, lib: gdspy.GdsLibrary, - chip_only_top: gdspy.library.Cell, - ground_cell: gdspy.library.Cell): + def _add_groundcell_to_chip_only_top(cls, lib: "gdstk.Library", + chip_only_top: "gdstk.Cell", + ground_cell: "gdstk.Cell") -> None: """Add the ground cell to the top of cell for chip. Args: - lib (gdspy.GdsLibrary): Holds all of the chips to export to gds. - chip_only_top (gdspy.library.Cell): Cell which for a single chip. - ground_cell (gdspy.library.Cell): The ground cell to add to + lib (gdstk.GdsLibrary): Holds all of the chips to export to gds. + chip_only_top (gdstk.Cell): Cell which for a single chip. + ground_cell (gdstk.Cell): The ground cell to add to chip_only_top. Cell created for each layer. """ # put all cells into TOP_chipname, if not empty. # When checking for bounding box, gdspy will return None if empty. - if ground_cell.get_bounding_box() is not None: - chip_only_top.add(gdspy.CellReference(ground_cell)) + if ground_cell.bounding_box() is not None: + chip_only_top.add(gdstk.Reference(ground_cell)) else: lib.remove(ground_cell) def _get_linestring_characteristics( - self, row: 'pd.Pandas') -> Tuple[Tuple, float, float]: + self, row: "pd.Pandas") -> Tuple[Tuple, float, float]: """Given a row in the Junction table, give the characteristics of LineString in row.geometry. @@ -1764,12 +1843,15 @@ def _get_linestring_characteristics( rotation = math.degrees(math.atan2((maxy - miny), (maxx - minx))) magnitude = np.round( distance.euclidean(row.geometry.coords[0], row.geometry.coords[1]), - for_rounding) + for_rounding, + ) return center, rotation, magnitude def _give_rotation_center_twopads( - self, row: 'pd.Pandas', a_cell_bounding_box: 'np.ndarray') -> Tuple: + self, row: pd.Series, a_cell_bounding_box: np.ndarray + ) -> Tuple[float, Tuple[float, float], Union[gdstk.Polygon, None], Union[ + gdstk.Polygon, None]]: """Calculate the angle for rotation, center of LineString in row.geometry, and if needed create two pads to connect the junction to qubit. @@ -1785,10 +1867,10 @@ def _give_rotation_center_twopads( row.geometry. * 2nd entry is Tuple[float,float]: The midpoint of Linestring from row.geometry in format (x,y). - * 3rd entry is gdspy.polygon.Rectangle: None if Magnitude of + * 3rd entry is gdstk.Rectangle: None if Magnitude of LineString is smaller than width of cell from row.gds_cell_name. Otherwise the rectangle for pad on LEFT of row.gds_cell_name. - * 4th entry is gdspy.polygon.Rectangle: None if Magnitude of + * 4th entry is gdstk.Rectangle: None if Magnitude of LineString is smaller than width of cell from row.gds_cell_name. Otherwise the rectangle for pad on RIGHT of row.gds_cell_name. """ @@ -1805,7 +1887,7 @@ def _give_rotation_center_twopads( jj_x_width = abs(jj_maxx - jj_minx) jj_y_height = abs(jj_maxy - jj_miny) - #jj_center_x = (jj_x_width / 2) + jj_minx + # jj_center_x = (jj_x_width / 2) + jj_minx jj_center_y = (jj_y_height / 2) + jj_miny pad_height = row.width @@ -1814,31 +1896,39 @@ def _give_rotation_center_twopads( # pylint: disable=protected-access text_id = self.design._components[row.component]._name self.logger.warning( - f'In junction table, component={text_id} with name={row.name} ' - f'has width={pad_height} smaller than cell dimension={jj_y_height}.' + f"In junction table, component={text_id} with name={row.name} " + f"has width={pad_height} smaller than cell dimension={jj_y_height}." ) if jj_x_width < magnitude: pad_x_size_minus_overlap = (magnitude - jj_x_width) / 2 pad_miny = jj_center_y - (pad_height / 2) - pad_left = gdspy.Rectangle( - (jj_minx - pad_x_size_minus_overlap, pad_miny), - (jj_minx + junction_pad_overlap, pad_miny + pad_height), + pad_left = gdstk.Polygon( + [ + (jj_minx - pad_x_size_minus_overlap, pad_miny), + (jj_minx + junction_pad_overlap, pad_miny), + (jj_minx + junction_pad_overlap, pad_miny + pad_height), + (jj_minx - pad_x_size_minus_overlap, pad_miny + pad_height), + ], layer=int(row.layer), - datatype=10) - - pad_right = gdspy.Rectangle( - (jj_maxx - junction_pad_overlap, pad_miny), - (jj_maxx + pad_x_size_minus_overlap, pad_miny + pad_height), + datatype=10, + ) + pad_right = gdstk.Polygon( + [ + (jj_maxx - junction_pad_overlap, pad_miny), + (jj_maxx + pad_x_size_minus_overlap, pad_miny), + (jj_maxx + pad_x_size_minus_overlap, pad_miny + pad_height), + (jj_maxx - junction_pad_overlap, pad_miny + pad_height), + ], layer=int(row.layer), - datatype=10) + datatype=10, + ) return rotation, center, pad_left, pad_right + ############ -############ - - def _import_junction_gds_file(self, lib: gdspy.library, + def _import_junction_gds_file(self, lib: "gdstk.Library", directory_name: str) -> bool: """Import the file which contains all junctions for design. If the file has already been imported, just return True. @@ -1847,7 +1937,7 @@ def _import_junction_gds_file(self, lib: gdspy.library, we only need to import file once to get ALL of the junctions. Args: - lib (gdspy.library): The library used to export the entire QDesign. + lib (gdstk.Library): The library used to export the entire QDesign. directory_name (str): The path of directory to read file with junctions. Returns: @@ -1859,20 +1949,24 @@ def _import_junction_gds_file(self, lib: gdspy.library, return True if os.path.isfile(self.options.path_filename): - lib.read_gds(self.options.path_filename, units='convert') + lib.read_gds(self.options.path_filename, units="convert") self.imported_junction_gds = self.options.path_filename return True else: message_str = ( f'Not able to find file:"{self.options.path_filename}". ' - f'Not used to replace junction.' + f"Not used to replace junction." f' Checked directory:"{directory_name}".') self.logger.warning(message_str) return False - def _import_junctions_to_one_cell(self, chip_name: str, lib: gdspy.library, - chip_only_top: gdspy.library.Cell, - layers_in_chip: list): + def _import_junctions_to_one_cell( + self, + chip_name: str, + lib: "gdstk.Library", + chip_only_top: "gdstk.Cell", + layers_in_chip: list, + ): """Given lib, import the gds file from default options. Based on the cell name in QGeometry table, import the cell from the gds file and place it in hierarchy of chip_only_top. In addition, the linestring @@ -1885,8 +1979,8 @@ def _import_junctions_to_one_cell(self, chip_name: str, lib: gdspy.library, Args: chip_name (str): The name of chip. - lib (gdspy.library): The library used to export the entire QDesign. - chip_only_top (gdspy.library.Cell): The cell used for + lib (gdstk.Library): The library used to export the entire QDesign. + chip_only_top (gdstk.Cell): The cell used for just chip_name. layers_in_chip (list): List of all layers in chip. """ @@ -1894,10 +1988,9 @@ def _import_junctions_to_one_cell(self, chip_name: str, lib: gdspy.library, # pylint: disable=too-many-nested-blocks # Make sure the file exists, before trying to read it. - dummy_status, directory_name = can_write_to_path( - self.options.path_filename) + _, directory_name = can_write_to_path(self.options.path_filename) layers_in_junction_table = set( - self.chip_info[chip_name]['junction']['layer']) + self.chip_info[chip_name]["junction"]["layer"]) if self._import_junction_gds_file(lib=lib, directory_name=directory_name): @@ -1907,219 +2000,228 @@ def _import_junctions_to_one_cell(self, chip_name: str, lib: gdspy.library, # Want to export negative mask # Gather the pads into hold_all_pads_cell for same layer. if iter_layer in layers_in_junction_table: - chip_only_top_layer_name = f'TOP_{chip_name}_{iter_layer}' - if chip_only_top_layer_name in lib.cells.keys(): - chip_only_top_layer = lib.cells[ - chip_only_top_layer_name] - hold_all_pads_name = f'r_l_hold_all_pads_{iter_layer}' - hold_all_pads_cell = lib.new_cell( - hold_all_pads_name, overwrite_duplicate=True) - chip_only_top_layer.add( - gdspy.CellReference(hold_all_pads_cell)) - - # Put all junctions into one cell for same layer. - hold_all_jj_cell_name = f'all_jj_imported_{iter_layer}' - hold_all_jj_cell = lib.new_cell( - hold_all_jj_cell_name, overwrite_duplicate=True) + chip_only_top_layer_name = f"TOP_{chip_name}_{iter_layer}" + top_layer_cell = next( + (c for c in lib.cells + if c.name == chip_only_top_layer_name), None) + if top_layer_cell: + hold_all_pads_cell = _new_cell( + lib, f"r_l_hold_all_pads_{iter_layer}", True) + top_layer_cell.add( + gdstk.Reference(hold_all_pads_cell)) + hold_all_jj_cell = _new_cell( + lib, f"all_jj_imported_{iter_layer}", True) self._add_negative_extension_to_jj( - chip_name, iter_layer, lib, chip_only_top, - chip_only_top_layer, hold_all_pads_cell, - hold_all_jj_cell) + chip_name, + iter_layer, + lib, + chip_only_top, + top_layer_cell, + hold_all_pads_cell, + hold_all_jj_cell, + ) else: # By default, make a positive mask. - for row in self.chip_info[chip_name]['junction'].itertuples( + for row in self.chip_info[chip_name]["junction"].itertuples( ): chip_layer = int(row.layer) - ground_cell_name = f'TOP_{chip_name}_{chip_layer}' - - if ground_cell_name in lib.cells.keys( - ) and chip_layer == iter_layer: - chip_layer_cell = lib.cells[ground_cell_name] - - if row.gds_cell_name in lib.cells.keys(): - # When positive mask, just add the pads to chip_only_top + ground_cell_name = f"TOP_{chip_name}_{chip_layer}" + if ground_cell_name in [c.name for c in lib.cells + ] and chip_layer == iter_layer: + chip_layer_cell = next( + (c for c in lib.cells + if c.name == ground_cell_name), None) + if row.gds_cell_name in [c.name for c in lib.cells]: self._add_positive_extension_to_jj( lib, row, chip_layer_cell) else: self.logger.warning( - f'From the "junction" table, the cell named' - f' "{row.gds_cell_name}"", is not in ' - f'file: {self.options.path_filename}.' - f' The cell was not used.') - - def _add_negative_extension_to_jj(self, chip_name: str, jj_layer: int, - lib: gdspy.library, - chip_only_top: gdspy.library.Cell, - chip_only_top_layer: gdspy.library.Cell, - hold_all_pads_cell: gdspy.library.Cell, - hold_all_jj_cell: gdspy.library.Cell): - """Manipulate existing geometries for the layer that the junctions need + f"Cell={row.gds_cell_name} from junction" + f"table not found in {self.options.path_filename}." + ) + + def _add_negative_extension_to_jj( + self, + chip_name: str, + jj_layer: int, + lib: "gdstk.Library", + chip_only_top: "gdstk.Cell", + chip_only_top_layer: "gdstk.Cell", + hold_all_pads_cell: "gdstk.Cell", + hold_all_jj_cell: "gdstk.Cell", + ) -> None: + """Gather extension pads & junctions for negative mask usage. + Manipulate existing geometries for the layer that the junctions need to be added. Since boolean subtraction is computationally intensive, the method will gather the pads for a layer, and do the boolean just once. Then add the junctions to difference. Args: - chip_name (str): The name of chip. - jj_layer (int): The layer the - lib (gdspy.library): The library used to export the entire QDesign. - chip_only_top (gdspy.library.Cell): The cell used for - just chip_name. - chip_only_top_layer (gdspy.library.Cell): Cell under chip, - with specific layer. - hold_all_pads_cell (gdspy.library.Cell): Collect all the pads with movement. - hold_all_jj_cell (gdspy.library.Cell): Collect all the jj's with movement. + chip_name (str): Chip name. + jj_layer (int): Layer index for junction. + lib (gdstk.Library): GDS library. + chip_only_top (gdstk.Cell): Chip top cell. + chip_only_top_layer (gdstk.Cell): Chip/layer cell. + hold_all_pads_cell (gdstk.Cell): Cell collecting extension pads. + hold_all_jj_cell (gdstk.Cell): Cell collecting junction references. """ - - boolean_by_layer = self.chip_info[chip_name]['junction'][ - 'layer'] == jj_layer - for row in self.chip_info[chip_name]['junction'][ + boolean_by_layer = self.chip_info[chip_name]["junction"][ + "layer"] == jj_layer + for row in self.chip_info[chip_name]["junction"][ boolean_by_layer].itertuples(): - - if row.gds_cell_name in lib.cells.keys(): - # For negative mask, collect the pads to subtract per layer, - # and subtract from chip_only_top_layer + if row.gds_cell_name in [c.name for c in lib.cells]: self._gather_negative_extension_for_jj(lib, row, hold_all_pads_cell, hold_all_jj_cell) else: self.logger.warning( - f'From the "junction" table, the cell named' - f' "{row.gds_cell_name}", is not in file: ' - f'{self.options.path_filename}. The cell was not used.') + f"Junction cell={row.gds_cell_name} not " + f"n {self.options.path_filename} for negative " + "mask usage.") - diff_r_l_pads_name = f'r_l_pads_diff_{jj_layer}' - diff_pad_cell_layer = lib.new_cell(diff_r_l_pads_name, - overwrite_duplicate=True) - #chip_only_top_layer.add(gdspy.CellReference(diff_pad_cell_layer)) - chip_only_top.add(gdspy.CellReference(diff_pad_cell_layer)) + diff_r_l_pads_name = f"r_l_pads_diff_{jj_layer}" + diff_pad_cell_layer = _new_cell(lib, diff_r_l_pads_name, True) + chip_only_top.add(gdstk.Reference(diff_pad_cell_layer)) - precision = self.parse_value(self.options.precision) + precision = float(self.parse_value(self.options.precision)) max_points = int(self.parse_value(self.options.max_points)) - # Make sure the pads to hold_all_pads_cell is not empty + if chip_only_top_layer.bounding_box() is not None: + boolean_result = gdstk.boolean( + chip_only_top_layer.polygons, + hold_all_pads_cell.polygons, + "not", + precision=precision, + max_points=max_points, + ) + if boolean_result: + for poly in boolean_result: + diff_pad_cell_layer.add(poly) - if chip_only_top_layer.get_bounding_box() is not None: - jj_minus_pads = gdspy.boolean(chip_only_top_layer.get_polygons(), - hold_all_pads_cell.get_polygons(), - 'not', - max_points=max_points, - precision=precision) - diff_pad_cell_layer.add(jj_minus_pads) - if hold_all_jj_cell.get_bounding_box() is not None: - diff_pad_cell_layer.add(gdspy.CellReference(hold_all_jj_cell)) + if hold_all_jj_cell.bounding_box() is not None: + diff_pad_cell_layer.add(gdstk.Reference(hold_all_jj_cell)) self._clean_hierarchy(lib, chip_only_top, chip_only_top_layer, diff_pad_cell_layer, hold_all_pads_cell) @classmethod - def _clean_hierarchy(cls, lib, chip_only_top, chip_only_top_layer, - diff_pad_cell_layer, hold_all_pads_cell): + def _clean_hierarchy( + cls, + lib: "gdstk.Library", + chip_only_top: "gdstk.Cell", + chip_only_top_layer: "gdstk.Cell", + diff_pad_cell_layer: "gdstk.Cell", + hold_all_pads_cell: "gdstk.Cell", + ) -> None: """Delete cell that doesn't have pad nor jjs. Then use same name for correct cell. Also, get rid of cell that had the pads since subtraction happened and we don't need it any more. Args: - lib (gdspy.library): [The library used to export the entire QDesign. - chip_only_top (gdspy.library.Cell): [description] - chip_only_top_layer (gdspy.library.Cell): Cell under chip, + lib (gdstk.Library): [The library used to export the entire QDesign. + chip_only_top (gdstk.Cell): [description] + chip_only_top_layer (gdstk.Cell): Cell under chip, with specific layer. - diff_pad_cell_layer (gdspy.library.Cell): Holds result of top_layer - pads + jjs. - hold_all_pads_cell (gdspy.library.Cell): Collect all the jj's with movement. + diff_pad_cell_layer (gdstk.Cell): Holds result of top_layer - pads + jjs. + hold_all_pads_cell (gdstk.Cell): Collect all the jj's with movement. """ hold_name = chip_only_top_layer.name - lib.remove(hold_name) - lib.rename_cell(diff_pad_cell_layer, hold_name) + lib.remove(chip_only_top_layer) + _rename_cell(diff_pad_cell_layer, hold_name) - #Add to hierarchy only if cell is not empty. - if diff_pad_cell_layer.get_bounding_box() is not None: - chip_only_top.add(gdspy.CellReference(diff_pad_cell_layer)) + if diff_pad_cell_layer.bounding_box() is not None: + chip_only_top.add(gdstk.Reference(diff_pad_cell_layer)) else: lib.remove(diff_pad_cell_layer) - # remove the sub libs before removing hold_all_pads_cells - for _, value in enumerate(hold_all_pads_cell.references): - lib.remove(value.ref_cell.name) + + for ref in list(hold_all_pads_cell.references): + lib.remove(ref.ref_cell) lib.remove(hold_all_pads_cell) def _gather_negative_extension_for_jj( - self, lib: gdspy.library, row: 'pd.core.frame.Pandas', - hold_all_pads_cell: gdspy.library.Cell, - hold_all_jj_cell: gdspy.library.Cell): + self, + lib: "gdstk.Library", + row: pd.Series, + hold_all_pads_cell: "gdstk.Cell", + hold_all_jj_cell: "gdstk.Cell", + ) -> None: """Gather the pads and jjs and put them in separate cells. The the pads can be boolean'd 'not' just once. After boolean for pads, then the jjs will be added to result. The boolean is very time intensive, so just want to do it once. Args: - lib (gdspy.library): The library used to export the entire QDesign. - row (pd.core.frame.Pandas): Each row is from the qgeometry junction table. - hold_all_pads_cell (gdspy.library.Cell): Collect all the pads with movement. - hold_all_jj_cell (gdspy.library.Cell): Collect all the jj's with movement. + lib (gdstk.Library): GDS library. + row (pd.Series): Row from junction table. + hold_all_pads_cell (gdstk.Cell): Collecting extension pads. + hold_all_jj_cell (gdstk.Cell): Collecting junction references. """ - a_cell = lib.extract(row.gds_cell_name) - a_cell_bounding_box = a_cell.get_bounding_box() + a_cell = next((c for c in lib.cells if c.name == row.gds_cell_name), + None) + if a_cell is None: + return + bounding_box = a_cell.bounding_box() + if bounding_box is None: + return rotation, center, pad_left, pad_right = self._give_rotation_center_twopads( - row, a_cell_bounding_box) - - # String for JJ combined with pad Right and pad Left - jj_pad_r_l_name = f'{row.gds_cell_name}_QComponent_is_{row.component}_Name_is_{row.name}_name_is_{row.name}' - temp_cell = lib.new_cell(jj_pad_r_l_name, overwrite_duplicate=True) - + row, bounding_box) + jj_pad_r_l_name = (f"{row.gds_cell_name}_QComponent_is_{row.component}" + f"_Name_is_{row.name}_name_is_{row.name}") + temp_cell = _new_cell(lib, jj_pad_r_l_name, True) if pad_left is not None: temp_cell.add(pad_left) if pad_right is not None: temp_cell.add(pad_right) hold_all_jj_cell.add( - gdspy.CellReference(a_cell, origin=center, rotation=rotation)) + gdstk.Reference(a_cell, origin=center, rotation=rotation)) hold_all_pads_cell.add( - gdspy.CellReference(temp_cell, origin=center, rotation=rotation)) - - def _add_positive_extension_to_jj(self, lib: gdspy.library, - row: 'pd.core.frame.Pandas', - chip_only_top_layer: gdspy.library.Cell): + gdstk.Reference(temp_cell, origin=center, rotation=rotation)) + + def _add_positive_extension_to_jj( + self, + lib: "gdstk.Library", + row: "pd.Series", + chip_layer_cell: "gdstk.Cell", + ): """Get the extension pads, then add or subtract to extracted cell based on positive or negative mask. Args: - lib (gdspy.library): The library used to export the entire QDesign. + lib (gdstk.Library): The library used to export the entire QDesign. row (pd.core.frame.Pandas): Each row is from the qgeometry junction table. - chip_only_top_layer (gdspy.library.Cell): The cell used for + chip_layer_cell (gdstk.Cell): The cell used for chip_name and layer_num. """ - a_cell = lib.extract(row.gds_cell_name) - a_cell_bounding_box = a_cell.get_bounding_box() + a_cell = next((c for c in lib.cells if c.name == row.gds_cell_name), + None) + if a_cell is None: + return + bounding_box = a_cell.bounding_box() + if bounding_box is None: + return rotation, center, pad_left, pad_right = self._give_rotation_center_twopads( - row, a_cell_bounding_box) - - # String for JJ combined with pad Right and pad Left - jj_pad_r_l_name = f'pads_{row.gds_cell_name}_QComponent_is_{row.component}_name_is_{row.name}' - temp_cell = lib.new_cell(jj_pad_r_l_name, overwrite_duplicate=True) - chip_only_top_layer.add( - gdspy.CellReference(a_cell, origin=center, rotation=rotation)) + row, bounding_box) + jj_pad_r_l_name = ( + f"pads_{row.gds_cell_name}_QComponent_is_{row.component}_name_is_{row.name}" + ) + temp_cell = _new_cell(lib, jj_pad_r_l_name, True) if pad_left is not None: - # chip_only_top_layer.add( - # gdspy.CellReference(pad_left, origin=center, rotation=rotation)) - temp_cell.add(pad_left) - if pad_right is not None: - # chip_only_top_layer.add( - # gdspy.CellReference(pad_right, origin=center, - # rotation=rotation)) - temp_cell.add(pad_right) - # "temp_cell" is kept in the lib. - if temp_cell.get_bounding_box() is not None: - chip_only_top_layer.add( - gdspy.CellReference(temp_cell, origin=center, - rotation=rotation)) + chip_layer_cell.add( + gdstk.Reference(a_cell, origin=center, rotation=rotation)) + if temp_cell.bounding_box() is not None: + chip_layer_cell.add( + gdstk.Reference(temp_cell, origin=center, rotation=rotation)) else: lib.remove(temp_cell) @@ -2180,8 +2282,12 @@ def export_to_gds(self, return 0 def _multipolygon_to_gds( - self, multi_poly: shapely.geometry.multipolygon.MultiPolygon, - layer: int, data_type: int, no_cheese_buffer: float) -> list: + self, + multi_poly: shapely.geometry.multipolygon.MultiPolygon, + layer: int, + data_type: int, + no_cheese_buffer: float, # pylint: disable=unused-argument + ) -> list: """Convert a shapely MultiPolygon to corresponding gdspy. Args: @@ -2197,40 +2303,42 @@ def _multipolygon_to_gds( """ # pylint: disable=too-many-locals - dummy_keep_for_future_use = no_cheese_buffer - precision = self.parse_value(self.options.precision) + precision = float(self.parse_value(self.options.precision)) max_points = int(self.parse_value(self.options.max_points)) all_polys = list(multi_poly.geoms) all_gds = list() + for poly in all_polys: - exterior_poly = gdspy.Polygon( - list(poly.exterior.coords), - layer=layer, - datatype=data_type, - ) + exterior_coords = list(poly.exterior.coords) + exterior_poly = gdstk.Polygon(exterior_coords, + layer=layer, + datatype=data_type) - all_interiors = list() if poly.interiors: + holes = [] for hole in poly.interiors: - interior_coords = list(hole.coords) - all_interiors.append(interior_coords) - a_poly_set = gdspy.PolygonSet(all_interiors, - layer=layer, - datatype=data_type) - a_poly = gdspy.boolean(exterior_poly, - a_poly_set, - 'not', - max_points=max_points, - layer=layer, - datatype=data_type, - precision=precision) + hole_coords = list(hole.coords) + holes.append( + gdstk.Polygon(hole_coords, + layer=layer, + datatype=data_type)) + + diff_result = gdstk.boolean( + [exterior_poly], + holes, + "not", + layer=layer, + datatype=data_type, + precision=precision, + max_points=max_points, + ) # Poly fracturing leading to a funny shape. Leave this out of gds output for now. # a_poly.fillet(no_cheese_buffer, # points_per_2pi=128, # max_points=max_points, # precision=precision) - all_gds.append(a_poly) + all_gds.append(diff_result) else: # Poly fracturing leading to a funny shape. Leave this out of gds output for now. # exterior_poly.fillet(no_cheese_buffer, @@ -2238,11 +2346,12 @@ def _multipolygon_to_gds( # max_points=max_points, # precision=precision) all_gds.append(exterior_poly) + return all_gds def _qgeometry_to_gds( self, qgeometry_element: pd.Series - ) -> Union['gdspy.polygon', 'gdspy.FlexPath', None]: + ) -> Union[gdstk.Polygon, gdstk.FlexPath, None]: """Convert the design.qgeometry table to format used by GDS renderer. Convert the class to a series of GDSII elements. @@ -2250,7 +2359,7 @@ def _qgeometry_to_gds( qgeometry_element (pd.Series): Expect a shapely object. Returns: - Union['gdspy.polygon' or 'gdspy.FlexPath' or None]: Convert the + Union['gdstk.Polygon' or 'gdstk.FlexPath' or None]: Convert the class to a series of GDSII format on the input pd.Series. @@ -2272,103 +2381,102 @@ class to a series of GDSII format on the input pd.Series. # pylint: disable=too-many-locals - corners = self.options.corners - tolerance = self.parse_value(self.options.tolerance) + # corners = self.options.corners + # tolerance = self.parse_value(self.options.tolerance) + # WARNING: corners and tolerance are not used in this method. + # TODO: CHECK THIS WORKS AS EXPECTED. + # The gdstk.FlexPath constructor does not support a direct equivalent + # for the corners, tolerance, or bend_radius parameters. + # a minimal conversion was implemented here without recreating the + # full behavior of these parameters. + # Filleting was handled using Shapely's buffer method. + precision = self.parse_value(self.options.precision) max_points = int(self.parse_value(self.options.max_points)) - geom = qgeometry_element.geometry # type: shapely.geometry.base.BaseGeometry + geom = qgeometry_element.geometry + layer_num = int(qgeometry_element.layer) if isinstance(geom, shapely.geometry.Polygon): - exterior_poly = gdspy.Polygon( - list(geom.exterior.coords), - layer=qgeometry_element.layer, + exterior_coords = list(geom.exterior.coords) + exterior_poly = gdstk.Polygon( + exterior_coords, + layer=layer_num, datatype=10, ) - # If polygons have a holes, need to remove it for gdspy. - all_interiors = list() + # Handle holes if geom.interiors: + holes = [] for hole in geom.interiors: - interior_coords = list(hole.coords) - all_interiors.append(interior_coords) - a_poly_set = gdspy.PolygonSet(all_interiors, - layer=qgeometry_element.layer, - datatype=10) - # Since there is max_points in boolean, don't need to do this twice. - # a_poly_set = a_poly_set.fracture(max_points=max_points) - # exterior_poly = exterior_poly.fracture(max_points=max_points) - a_poly = gdspy.boolean(exterior_poly, - a_poly_set, - 'not', - max_points=max_points, - precision=precision, - layer=qgeometry_element.layer, - datatype=10) - return a_poly - - exterior_poly = exterior_poly.fracture(max_points=max_points, - precision=precision) + hole_coords = list(hole.coords) + holes.append( + gdstk.Polygon(hole_coords, layer=layer_num, + datatype=10)) + result = gdstk.boolean( + [exterior_poly], + holes, + "not", + layer=layer_num, + datatype=10, + max_points=max_points, + precision=float(precision), + ) + return result return exterior_poly - if isinstance(geom, shapely.geometry.LineString): - #class gdspy.FlexPath(points, width, offset=0, corners='natural', - #ends='flush', bend_radius=None, tolerance=0.01, precision=0.001, - #max_points=199, gdsii_path=False, width_transform=True, layer=0, - #datatype=0) - - #Only fillet, if number is greater than zero. + if isinstance(geom, shapely.geometry.LineString): use_width = self.parse_value(self.options.width_LineString) - - if math.isnan(qgeometry_element.width): - qcomponent_id = self.parse_value(qgeometry_element.component) - name = self.parse_value(qgeometry_element['name']) - layer_num = self.parse_value(qgeometry_element.layer) - width = self.parse_value(qgeometry_element.width) - self.logger.warning( - f'Since width:{width} for a Path is not a number, ' - f'it will be exported using width_LineString:' - f' {use_width}. The component_id is:{qcomponent_id},' - f' name is:{name}, layer is: {layer_num}') - else: + if not math.isnan(qgeometry_element.width): use_width = qgeometry_element.width - if 'fillet' in qgeometry_element: - - if (math.isnan(qgeometry_element.fillet) or - qgeometry_element.fillet <= 0 or - qgeometry_element.fillet < qgeometry_element.width): - - to_return = gdspy.FlexPath(list(geom.coords), - use_width, - layer=qgeometry_element.layer, - max_points=max_points, - datatype=11) - else: - to_return = gdspy.FlexPath( - list(geom.coords), - use_width, - layer=qgeometry_element.layer, + fillet_val = 0 + if "fillet" in qgeometry_element and not ( + math.isnan(qgeometry_element.fillet) or + qgeometry_element.fillet <= 0 or + qgeometry_element.fillet < qgeometry_element.width): + fillet_val = qgeometry_element.fillet + + if fillet_val > 0: + # Apply fillet using shapely's buffer to create a rounded polygon + buffered = geom.buffer(fillet_val, cap_style=2, join_style=2) + if isinstance(buffered, shapely.geometry.Polygon): + exterior_coords = list(buffered.exterior.coords) + return gdstk.Polygon( + exterior_coords, + layer=layer_num, datatype=11, - max_points=max_points, - corners=corners, - bend_radius=qgeometry_element.fillet, - tolerance=tolerance, - precision=precision) - return to_return - - # Could be junction table with a linestring. - # Look for gds_path_filename in column. - self.logger.warning(f'Linestring did not have fillet in column. ' - f'The qgeometry_element was not drawn.\n' - f'The qgeometry_element within table is:\n' - f'{qgeometry_element}') - return None # Need explicitly to avoid lint warnings. - - self.logger.warning( - f'Unexpected shapely object geometry.' - f'The variable qgeometry_element is {type(geom)}, ' - f'method can currently handle Polygon and FlexPath.') + ) + elif isinstance(buffered, shapely.geometry.MultiPolygon): + polygons = [] + for poly in buffered: + exterior_coords = list(poly.exterior.coords) + polygons.append( + gdstk.Polygon( + exterior_coords, + layer=layer_num, + datatype=11, + )) + return polygons # Return list of polygons for MultiPolygon + else: + self.logger.warning( + f"Buffered geometry type={type(buffered)} not supported." + ) + return None + else: + # No fillet; create a FlexPath as before + path_points = list(geom.coords) + new_flexpath = gdstk.FlexPath( + path_points, + use_width, + layer=layer_num, + datatype=11, + max_points=max_points, + ) + return new_flexpath + + self.logger.warning(f"Unsupported geometry type={type(geom)} in" + " _qgeometry_to_gds. Expected Polygon/LineString.") return None def _get_chip_names(self) -> Dict: @@ -2384,7 +2492,7 @@ def _get_chip_names(self) -> Dict: chip_names = Dict() for table_name in self.design.qgeometry.get_element_types(): table = self.design.qgeometry.tables[table_name] - names = table['chip'].unique().tolist() + names = table["chip"].unique().tolist() chip_names += names unique_list = list(set(chip_names)) From 71a22c20e6c99f0a38076c114425e73cca3208c4 Mon Sep 17 00:00:00 2001 From: Zlatko Minev Date: Sun, 26 Jan 2025 17:08:52 -0500 Subject: [PATCH 45/46] GSTK make cheese --- .../renderers/renderer_gds/make_cheese.py | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/qiskit_metal/renderers/renderer_gds/make_cheese.py b/qiskit_metal/renderers/renderer_gds/make_cheese.py index 368572eb6..798c6c870 100644 --- a/qiskit_metal/renderers/renderer_gds/make_cheese.py +++ b/qiskit_metal/renderers/renderer_gds/make_cheese.py @@ -15,7 +15,7 @@ import logging from typing import Union -import gdspy +# import gdspy # TODO: Replace with gdstk import shapely import numpy as np @@ -35,7 +35,7 @@ def __init__( self, multi_poly: shapely.geometry.multipolygon.MultiPolygon, all_nocheese_gds: list, - lib: gdspy.GdsLibrary, + lib: "gdspy.GdsLibrary", minx: float, miny: float, maxx: float, @@ -166,7 +166,7 @@ def __init__( self.hole = None - def apply_cheesing(self) -> gdspy.GdsLibrary: + def apply_cheesing(self) -> "gdspy.GdsLibrary": """Prototype, not complete. Need to populate self.lib with cheese holes. @@ -228,7 +228,7 @@ def _make_one_hole_at_zero_zero(self): f'The cheese_shape={self.cheese_shape} is unknown in Cheesing class.' ) - def _hole_to_lib(self) -> gdspy.polygon.Polygon: + def _hole_to_lib(self) -> "gdspy.polygon.Polygon": """Convert the self.hole to a gds cell and add to self.lib. Put the hole on datatype_cheese +2. This is expected to change when we agree to some convention. @@ -334,12 +334,12 @@ def _remove_cell_one_hole(self): self.lib.remove(cheese_one_hole_cell_name) def _subtract_from_ground_and_move_under_top_chip_layer( - self, diff_holes_cell: gdspy.library.Cell): + self, diff_holes_cell: "gdstk.Cell"): """Get the existing chip_only_top_name cell, then add the holes to it. Also, add ground_cheesed_cell under chip_only_top_name Args: - diff_holes_cell (gdspy.library.Cell): New cell with cheesed ground + diff_holes_cell (gdstk.Cell): New cell with cheesed ground """ #chip_only_top_name = f'TOP_{self.chip_name}' @@ -358,12 +358,12 @@ def _subtract_from_ground_and_move_under_top_chip_layer( self.lib.remove(diff_holes_cell) def _subtract_keepout_from_hole_grid( - self, gather_holes_cell: gdspy.library.Cell) -> gdspy.library.Cell: + self, gather_holes_cell: "gdstk.Cell") -> "gdstk.Cell": """Given a cell with all the holes, subtract the keepout region. Then return a new cell with the result. Args: - gather_holes_cell (gdspy.library.Cell): Holds a grid of all + gather_holes_cell (gdstk.Cell): Holds a grid of all the holes for cheesing. Returns: @@ -392,7 +392,7 @@ def _subtract_keepout_from_hole_grid( self.lib.remove(temp_keepout_chip_layer_cell) return diff_holes_cell - def _get_all_holes(self) -> gdspy.library.Cell: + def _get_all_holes(self) -> "gdstk.Cell": """Return a cell with a grid of holes. The keepout has not been applied yet. @@ -422,7 +422,7 @@ def _get_all_holes(self) -> gdspy.library.Cell: return gather_holes_cell def _subtract_holes_from_ground( - self, diff_holes_cell) -> Union[gdspy.library.Cell, None]: + self, diff_holes_cell) -> Union["gdstk.Cell", None]: """Get reference to ground cell and then subtract the holes from ground. Place the difference into a new cell, which will eventually be added under Top. @@ -460,11 +460,11 @@ def _subtract_holes_from_ground( f'Cheesing not implemented.') return None - def _move_to_under_top_chip_layer_name(self, a_cell: gdspy.library.Cell): + def _move_to_under_top_chip_layer_name(self, a_cell: "gdstk.Cell"): """Move the cell to under TOP__. Args: - a_cell (gdspy.library.Cell): A GDSPY cell. + a_cell (gdstk.Cell): A GDSPY cell. """ chip_only_top_chip_layer_name = f'TOP_{self.chip_name}_{self.layer}' if chip_only_top_chip_layer_name in self.lib.cells: From 24b34aca18f247dd2af63cc5d5847a2e7c18bc5f Mon Sep 17 00:00:00 2001 From: Zlatko Minev Date: Sun, 26 Jan 2025 17:12:46 -0500 Subject: [PATCH 46/46] Todo for v0.5 --- changelog.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/changelog.md b/changelog.md index eda15be2d..59482b260 100644 --- a/changelog.md +++ b/changelog.md @@ -16,6 +16,10 @@ This release addresses significant package changes and ports: - **GDSPY to GDSTK**: Replaced GDSPY with the more robust GDSTK library. - **PYAEDT to Ansys (v1.0)**: Major update with a new syntax. Extensive testing required. - **Installation Improvements**: Transitioned to `venv` for faster environment setup, moving away from `conda`. Also, most package versions have been floated and upgraded. +- **Docs**: + - Migrate qiskit_sphinx_theme to the new theme + - Add divs on the front page to tuts etc + - Add user content and showcase page ---