From 2f631e02ca70b86f863b25620a888c27d203798d Mon Sep 17 00:00:00 2001 From: Ye11owSub Date: Sat, 17 Aug 2024 11:02:45 +0100 Subject: [PATCH] refactoring shortcut.py --- .github/workflows/build.yml | 14 +- modules/pymol.egg-info/PKG-INFO | 94 ++++ modules/pymol.egg-info/SOURCES.txt | 467 ++++++++++++++++++++ modules/pymol.egg-info/dependency_links.txt | 1 + modules/pymol.egg-info/entry_points.txt | 2 + modules/pymol.egg-info/requires.txt | 6 + modules/pymol.egg-info/top_level.txt | 6 + modules/pymol/cmd.py | 4 +- modules/pymol/shortcut.py | 350 +++++++-------- pyproject.toml | 4 +- testing/tests/api/shortcut.py | 6 +- tests/pymol/test_shortcut.py | 107 +++++ 12 files changed, 867 insertions(+), 194 deletions(-) create mode 100644 modules/pymol.egg-info/PKG-INFO create mode 100644 modules/pymol.egg-info/SOURCES.txt create mode 100644 modules/pymol.egg-info/dependency_links.txt create mode 100644 modules/pymol.egg-info/entry_points.txt create mode 100644 modules/pymol.egg-info/requires.txt create mode 100644 modules/pymol.egg-info/top_level.txt create mode 100644 tests/pymol/test_shortcut.py diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b5462115b..ffd306483 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -29,7 +29,6 @@ jobs: python3-setuptools python3-numpy python3-pil - python3-pytest python3-pip - name: Install collada2gltf @@ -45,13 +44,14 @@ jobs: - name: Build run: | pip install --upgrade pip - pip install -v --config-settings testing=True . + pip install -v --config-settings testing=True .[dev] env: DEBUG: 1 - name: Test run: | pymol -ckqy testing/testing.py --run all + python -m pytest tests -vv build-Windows: @@ -74,7 +74,7 @@ jobs: shell: cmd run: |- CALL %CONDA_ROOT%\\Scripts\\activate.bat - conda install -y -c conda-forge -c schrodinger python cmake libpng freetype pyside6 glew libxml2 numpy=1.26.4 catch2=2.13.3 glm libnetcdf collada2gltf biopython pillow msgpack-python pytest pip python-build + conda install -y -c conda-forge -c schrodinger python cmake libpng freetype pyside6 glew libxml2 numpy=1.26.4 catch2=2.13.3 glm libnetcdf collada2gltf biopython pillow msgpack-python pip python-build - name: Conda info shell: cmd @@ -94,13 +94,14 @@ jobs: shell: cmd run: | CALL %CONDA_ROOT%\\Scripts\\activate.bat - pip install -v --config-settings testing=True . + pip install -v --config-settings testing=True .[dev] - name: Test shell: cmd run: | CALL %CONDA_ROOT%\\Scripts\\activate.bat pymol -ckqy testing\\testing.py --run all + python -m pytest tests -vv build-MacOS: @@ -117,7 +118,7 @@ jobs: bash $CONDA_ROOT.sh -b -p $CONDA_ROOT export PATH="$CONDA_ROOT/bin:$PATH" conda config --set quiet yes - conda install -y -c conda-forge -c schrodinger python cmake libpng freetype pyside6 glew libxml2 numpy=1.26.4 catch2=2.13.3 glm libnetcdf collada2gltf biopython pillow msgpack-python pytest pip python-build + conda install -y -c conda-forge -c schrodinger python cmake libpng freetype pyside6 glew libxml2 numpy=1.26.4 catch2=2.13.3 glm libnetcdf collada2gltf biopython pillow msgpack-python pip python-build conda info - name: Get additional sources @@ -131,9 +132,10 @@ jobs: run: |- export MACOSX_DEPLOYMENT_TARGET=12.0 export PATH="$CONDA_ROOT/bin:$PATH" - pip install -v --config-settings testing=True . + pip install -v --config-settings testing=True .[dev] - name: Test run: |- export PATH="$CONDA_ROOT/bin:$PATH" pymol -ckqy testing/testing.py --run all + python -m pytest tests -vv diff --git a/modules/pymol.egg-info/PKG-INFO b/modules/pymol.egg-info/PKG-INFO new file mode 100644 index 000000000..4231fd57a --- /dev/null +++ b/modules/pymol.egg-info/PKG-INFO @@ -0,0 +1,94 @@ +Metadata-Version: 2.1 +Name: pymol +Version: 3.1.0a0 +Summary: PyMOL is a Python-enhanced molecular graphics tool. +Author-email: Schrodinger +License: + Open-Source PyMOL Copyright Notice + ================================== + + The Open-Source PyMOL source code is copyrighted, but you can freely + use and copy it as long as you don't change or remove any of the + Copyright notices. The Open-Source PyMOL product is made available + under the following open-source license terms: + + ---------------------------------------------------------------------- + Open-Source PyMOL is Copyright (C) Schrodinger, LLC. + + All Rights Reserved + + Permission to use, copy, modify, distribute, and distribute modified + versions of this software and its built-in documentation for any + purpose and without fee is hereby granted, provided that the above + copyright notice appears in all copies and that both the copyright + notice and this permission notice appear in supporting documentation, + and that the name of Schrodinger, LLC not be used in advertising or + publicity pertaining to distribution of the software without specific, + written prior permission. + + SCHRODINGER, LLC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN + NO EVENT SHALL SCHRODINGER, LLC BE LIABLE FOR ANY SPECIAL, INDIRECT OR + CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE + USE OR PERFORMANCE OF THIS SOFTWARE. + ---------------------------------------------------------------------- + + PyMOL Trademark Notice + ====================== + + PyMOL(TM) is a trademark of Schrodinger, LLC. Derivative + software which contains PyMOL source code must be plainly + distinguished from any and all PyMOL products distributed by Schrodinger, + LLC in all publicity, advertising, and documentation. + + The slogans, "Includes PyMOL(TM).", "Based on PyMOL(TM) technology.", + "Contains PyMOL(TM) source code.", and "Built using PyMOL(TM).", may + be used in advertising, publicity, and documentation of derivative + software provided that the notice, "PyMOL is a trademark of Schrodinger, + LLC.", is included in a footnote or at the end of the + document. + + All other endorsements employing the PyMOL trademark require specific, + written prior permission. + + +Project-URL: Homepage, https://pymol.org +Project-URL: Documentation, https://pymol.org/dokuwiki +Project-URL: Repository, https://github.com/schrodinger/pymol-open-source +Project-URL: Bug Tracker, https://github.com/schrodinger/pymol-open-source/issues +Project-URL: Changelog, https://github.com/schrodinger/pymol-open-source/blob/master/ChangeLog +Requires-Python: >=3.9 +Description-Content-Type: text/markdown +License-File: LICENSE +License-File: AUTHORS +Requires-Dist: numpy<2,>=1.26.4 +Provides-Extra: dev +Requires-Dist: numpy<2,>=1.26.4; extra == "dev" +Requires-Dist: pillow==10.3.0; extra == "dev" +Requires-Dist: pytest==8.2.2; extra == "dev" + +[![CI](https://github.com/schrodinger/pymol-open-source/workflows/CI/badge.svg)](https://github.com/schrodinger/pymol-open-source/actions) + + + +# Open-Source PyMOL + +[Open-source foundation](https://pymol.org/#opensource) of the user-sponsored PyMOL molecular visualization system. + +The commercial PyMOL product ("Incentive PyMOL") with maintenance and support is available from https://pymol.org + +## Installation + +See [INSTALL](INSTALL). + +## Contributing + +See [DEVELOPERS](DEVELOPERS). + +## License + +Copyright (c) [Schrodinger, LLC](https://www.schrodinger.com/) + +Published under a BSD-like license, see [LICENSE](LICENSE). diff --git a/modules/pymol.egg-info/SOURCES.txt b/modules/pymol.egg-info/SOURCES.txt new file mode 100644 index 000000000..a20d720bb --- /dev/null +++ b/modules/pymol.egg-info/SOURCES.txt @@ -0,0 +1,467 @@ +AUTHORS +LICENSE +README +README.md +pyproject.toml +setup.py +contrib/champ/champ.c +contrib/champ/champ_module.c +contrib/champ/chiral.c +contrib/champ/err2.c +contrib/champ/feedback2.c +contrib/champ/list.c +contrib/champ/os_memory.c +contrib/champ/sort.c +contrib/champ/strblock.c +contrib/champ/vla.c +contrib/uiuc/plugins/molfile_plugin/src/PlugIOManagerInit.c +contrib/uiuc/plugins/molfile_plugin/src/abinitplugin.c +contrib/uiuc/plugins/molfile_plugin/src/avsplugin.cpp +contrib/uiuc/plugins/molfile_plugin/src/basissetplugin.c +contrib/uiuc/plugins/molfile_plugin/src/bgfplugin.cpp +contrib/uiuc/plugins/molfile_plugin/src/binposplugin.c +contrib/uiuc/plugins/molfile_plugin/src/biomoccaplugin.cpp +contrib/uiuc/plugins/molfile_plugin/src/brixplugin.cpp +contrib/uiuc/plugins/molfile_plugin/src/carplugin.c +contrib/uiuc/plugins/molfile_plugin/src/ccp4plugin.cpp +contrib/uiuc/plugins/molfile_plugin/src/corplugin.c +contrib/uiuc/plugins/molfile_plugin/src/crdplugin.c +contrib/uiuc/plugins/molfile_plugin/src/cubeplugin.cpp +contrib/uiuc/plugins/molfile_plugin/src/dcdplugin.c +contrib/uiuc/plugins/molfile_plugin/src/dlpolyplugin.c +contrib/uiuc/plugins/molfile_plugin/src/dsn6plugin.cpp +contrib/uiuc/plugins/molfile_plugin/src/dtrplugin.cpp +contrib/uiuc/plugins/molfile_plugin/src/dxplugin.cpp +contrib/uiuc/plugins/molfile_plugin/src/edmplugin.cpp +contrib/uiuc/plugins/molfile_plugin/src/fs4plugin.cpp +contrib/uiuc/plugins/molfile_plugin/src/gamessplugin.c +contrib/uiuc/plugins/molfile_plugin/src/graspplugin.cpp +contrib/uiuc/plugins/molfile_plugin/src/grdplugin.cpp +contrib/uiuc/plugins/molfile_plugin/src/gridplugin.cpp +contrib/uiuc/plugins/molfile_plugin/src/gromacsplugin.cpp +contrib/uiuc/plugins/molfile_plugin/src/hash.c +contrib/uiuc/plugins/molfile_plugin/src/inthash.c +contrib/uiuc/plugins/molfile_plugin/src/jsplugin.c +contrib/uiuc/plugins/molfile_plugin/src/maeffplugin.cpp +contrib/uiuc/plugins/molfile_plugin/src/mapplugin.cpp +contrib/uiuc/plugins/molfile_plugin/src/mdfplugin.cpp +contrib/uiuc/plugins/molfile_plugin/src/mol2plugin.cpp +contrib/uiuc/plugins/molfile_plugin/src/moldenplugin.c +contrib/uiuc/plugins/molfile_plugin/src/molemeshplugin.cpp +contrib/uiuc/plugins/molfile_plugin/src/msmsplugin.cpp +contrib/uiuc/plugins/molfile_plugin/src/namdbinplugin.c +contrib/uiuc/plugins/molfile_plugin/src/netcdfplugin.c +contrib/uiuc/plugins/molfile_plugin/src/offplugin.cpp +contrib/uiuc/plugins/molfile_plugin/src/parm7plugin.cpp +contrib/uiuc/plugins/molfile_plugin/src/parmplugin.cpp +contrib/uiuc/plugins/molfile_plugin/src/pbeqplugin.cpp +contrib/uiuc/plugins/molfile_plugin/src/pdbplugin.c +contrib/uiuc/plugins/molfile_plugin/src/pdbxplugin.cpp +contrib/uiuc/plugins/molfile_plugin/src/phiplugin.cpp +contrib/uiuc/plugins/molfile_plugin/src/pltplugin.cpp +contrib/uiuc/plugins/molfile_plugin/src/plyplugin.cpp +contrib/uiuc/plugins/molfile_plugin/src/pqrplugin.c +contrib/uiuc/plugins/molfile_plugin/src/psfplugin.c +contrib/uiuc/plugins/molfile_plugin/src/raster3dplugin.cpp +contrib/uiuc/plugins/molfile_plugin/src/rst7plugin.c +contrib/uiuc/plugins/molfile_plugin/src/situsplugin.cpp +contrib/uiuc/plugins/molfile_plugin/src/spiderplugin.cpp +contrib/uiuc/plugins/molfile_plugin/src/stlplugin.cpp +contrib/uiuc/plugins/molfile_plugin/src/tinkerplugin.c +contrib/uiuc/plugins/molfile_plugin/src/uhbdplugin.cpp +contrib/uiuc/plugins/molfile_plugin/src/vasp5xdatcarplugin.c +contrib/uiuc/plugins/molfile_plugin/src/vaspchgcarplugin.c +contrib/uiuc/plugins/molfile_plugin/src/vaspoutcarplugin.c +contrib/uiuc/plugins/molfile_plugin/src/vaspparchgplugin.c +contrib/uiuc/plugins/molfile_plugin/src/vaspposcarplugin.c +contrib/uiuc/plugins/molfile_plugin/src/vaspxdatcarplugin.c +contrib/uiuc/plugins/molfile_plugin/src/vaspxmlplugin.c +contrib/uiuc/plugins/molfile_plugin/src/vtfplugin.c +contrib/uiuc/plugins/molfile_plugin/src/vtkplugin.cpp +contrib/uiuc/plugins/molfile_plugin/src/xbgfplugin.cpp +contrib/uiuc/plugins/molfile_plugin/src/xsfplugin.cpp +contrib/uiuc/plugins/molfile_plugin/src/xyzplugin.c +layer0/Bezier.cpp +layer0/Block.cpp +layer0/CarveHelper.cpp +layer0/ContourSurf.cpp +layer0/Crystal.cpp +layer0/Err.cpp +layer0/Feedback.cpp +layer0/Field.cpp +layer0/File.cpp +layer0/GFXManager.cpp +layer0/GenericBuffer.cpp +layer0/GraphicsUtil.cpp +layer0/Isosurf.cpp +layer0/Map.cpp +layer0/Match.cpp +layer0/Matrix.cpp +layer0/MemoryDebug.cpp +layer0/MemoryUsage.cpp +layer0/MyPNG.cpp +layer0/Parse.cpp +layer0/Pixmap.cpp +layer0/PostProcess.cpp +layer0/PrintUtils.cpp +layer0/ShaderMgr.cpp +layer0/ShaderPreprocessor.cpp +layer0/ShaderPrg.cpp +layer0/Sphere.cpp +layer0/TTT.cpp +layer0/Tetsurf.cpp +layer0/Texture.cpp +layer0/Tracker.cpp +layer0/Triangle.cpp +layer0/Util.cpp +layer0/Util2.cpp +layer0/Vector.cpp +layer0/Word.cpp +layer0/ccealignmodule.cpp +layer0/marching_cubes.cpp +layer0/os_gl.cpp +layer1/Basis.cpp +layer1/ButMode.cpp +layer1/CGO.cpp +layer1/CGOGL.cpp +layer1/CGORenderer.cpp +layer1/COLLADA.cpp +layer1/Camera.cpp +layer1/Character.cpp +layer1/Color.cpp +layer1/Control.cpp +layer1/Extrude.cpp +layer1/Font.cpp +layer1/FontGLUT.cpp +layer1/FontGLUT8x13.cpp +layer1/FontGLUT9x15.cpp +layer1/FontGLUTHel10.cpp +layer1/FontGLUTHel12.cpp +layer1/FontGLUTHel18.cpp +layer1/FontType.cpp +layer1/Movie.cpp +layer1/Ortho.cpp +layer1/P.cpp +layer1/PConv.cpp +layer1/Picking.cpp +layer1/Pop.cpp +layer1/PyMOLObject.cpp +layer1/Ray.cpp +layer1/Rep.cpp +layer1/Scene.cpp +layer1/SceneMouse.cpp +layer1/ScenePicking.cpp +layer1/SceneRay.cpp +layer1/SceneRender.cpp +layer1/SceneView.cpp +layer1/ScrollBar.cpp +layer1/Seq.cpp +layer1/Setting.cpp +layer1/Shaker.cpp +layer1/SymOp.cpp +layer1/SymOpPConv.cpp +layer1/SymOpTools.cpp +layer1/Symmetry.cpp +layer1/Text.cpp +layer1/TypeFace.cpp +layer1/View.cpp +layer1/Wizard.cpp +layer2/AssemblyHelpers.cpp +layer2/AtomInfo.cpp +layer2/AtomInfoHistory.cpp +layer2/BondTypeHistory.cpp +layer2/CifFile.cpp +layer2/CifMoleculeReader.cpp +layer2/CoordSet.cpp +layer2/DistSet.cpp +layer2/GadgetSet.cpp +layer2/HydrogenAdder.cpp +layer2/MmodTyping.cpp +layer2/MmtfMoleculeReader.cpp +layer2/Mol2Typing.cpp +layer2/MolV3000.cpp +layer2/ObjectAlignment.cpp +layer2/ObjectCGO.cpp +layer2/ObjectCallback.cpp +layer2/ObjectCurve.cpp +layer2/ObjectDist.cpp +layer2/ObjectGadget.cpp +layer2/ObjectGadgetRamp.cpp +layer2/ObjectGroup.cpp +layer2/ObjectMap.cpp +layer2/ObjectMesh.cpp +layer2/ObjectMolecule.cpp +layer2/ObjectMolecule2.cpp +layer2/ObjectMolecule3.cpp +layer2/ObjectSlice.cpp +layer2/ObjectSurface.cpp +layer2/ObjectVolume.cpp +layer2/RepAngle.cpp +layer2/RepCartoon.cpp +layer2/RepCylBond.cpp +layer2/RepDihedral.cpp +layer2/RepDistDash.cpp +layer2/RepDistLabel.cpp +layer2/RepDot.cpp +layer2/RepEllipsoid.cpp +layer2/RepLabel.cpp +layer2/RepMesh.cpp +layer2/RepNonbonded.cpp +layer2/RepNonbondedSphere.cpp +layer2/RepRibbon.cpp +layer2/RepSphere.cpp +layer2/RepSphereGenerate.cpp +layer2/RepSphereImmediate.cpp +layer2/RepSurface.cpp +layer2/RepWireBond.cpp +layer2/Sculpt.cpp +layer2/SculptCache.cpp +layer2/SideChainHelper.cpp +layer2/VFont.cpp +layer3/AtomIterators.cpp +layer3/CifDataValueFormatter.cpp +layer3/Editor.cpp +layer3/Executive.cpp +layer3/ExecutivePython.cpp +layer3/Interactions.cpp +layer3/MaeExportHelpers.cpp +layer3/MoleculeExporter.cpp +layer3/MovieScene.cpp +layer3/PlugIOManager.cpp +layer3/RingFinder.cpp +layer3/Seeker.cpp +layer3/Selector.cpp +layer3/SelectorTmp.cpp +layer3/SpecRec.cpp +layer3/SpecRecSpecial.cpp +layer4/Cmd.cpp +layer4/Menu.cpp +layer4/PopUp.cpp +layer5/PyMOL.cpp +layer5/TestPyMOL.cpp +layer5/main.cpp +modules/chempy/__init__.py +modules/chempy/arc.py +modules/chempy/bond_amber.py +modules/chempy/bond_mmff.py +modules/chempy/bonds.py +modules/chempy/brick.py +modules/chempy/cc1.py +modules/chempy/charge.py +modules/chempy/cif.py +modules/chempy/cpv.py +modules/chempy/dictdb.py +modules/chempy/gamess1.py +modules/chempy/gms.py +modules/chempy/hetatm.py +modules/chempy/io.py +modules/chempy/lst.py +modules/chempy/mae.py +modules/chempy/map.py +modules/chempy/mass.py +modules/chempy/mmd.py +modules/chempy/models.py +modules/chempy/mol.py +modules/chempy/mol2.py +modules/chempy/neighbor.py +modules/chempy/pdb.py +modules/chempy/pkl.py +modules/chempy/place.py +modules/chempy/protein.py +modules/chempy/protein_amber.py +modules/chempy/protein_amber99.py +modules/chempy/protein_mmff.py +modules/chempy/protein_residues.py +modules/chempy/sdf.py +modules/chempy/solvate.py +modules/chempy/water_amber.py +modules/chempy/water_residues.py +modules/chempy/xyz.py +modules/chempy/bmin/__init__.py +modules/chempy/bmin/commands.py +modules/chempy/bmin/realtime.py +modules/chempy/bmin/state.py +modules/chempy/bmin/util.py +modules/chempy/champ/__init__.py +modules/chempy/champ/amber99.py +modules/chempy/champ/assign.py +modules/chempy/champ/formal_charges.py +modules/chempy/fast/__init__.py +modules/chempy/fragments/__init__.py +modules/chempy/mmtf/__init__.py +modules/chempy/mmtf/io.py +modules/chempy/tinker/__init__.py +modules/chempy/tinker/amber.py +modules/chempy/tinker/keyword.py +modules/chempy/tinker/realtime.py +modules/chempy/tinker/state.py +modules/pmg_qt/TextEditor.py +modules/pmg_qt/__init__.py +modules/pmg_qt/advanced_settings_gui.py +modules/pmg_qt/builder.py +modules/pmg_qt/file_dialogs.py +modules/pmg_qt/keymapping.py +modules/pmg_qt/mimic_pmg_tk.py +modules/pmg_qt/mimic_tk.py +modules/pmg_qt/properties_dialog.py +modules/pmg_qt/pymol_gl_widget.py +modules/pmg_qt/pymol_qt_gui.py +modules/pmg_qt/scene_bin_gui.py +modules/pmg_qt/shortcut_menu_gui.py +modules/pmg_qt/volume.py +modules/pmg_qt/forms/__init__.py +modules/pmg_qt/forms/askpartial.ui +modules/pmg_qt/forms/change_confirm.ui +modules/pmg_qt/forms/colors.ui +modules/pmg_qt/forms/create_shortcut.ui +modules/pmg_qt/forms/fetch.ui +modules/pmg_qt/forms/help_shortcut.ui +modules/pmg_qt/forms/load_aln.ui +modules/pmg_qt/forms/load_mae.ui +modules/pmg_qt/forms/load_map.ui +modules/pmg_qt/forms/load_mtz.ui +modules/pmg_qt/forms/load_traj.ui +modules/pmg_qt/forms/movieexport.ui +modules/pmg_qt/forms/pluginitem.ui +modules/pmg_qt/forms/pluginmanager.ui +modules/pmg_qt/forms/png.ui +modules/pmg_qt/forms/props.ui +modules/pmg_qt/forms/render.ui +modules/pmg_qt/forms/save_molecule.ui +modules/pmg_qt/forms/save_object.ui +modules/pmg_qt/forms/shortcut_menu.ui +modules/pmg_qt/syntax/__init__.py +modules/pmg_qt/syntax/pml.py +modules/pmg_qt/syntax/pmlparser.py +modules/pmg_qt/syntax/python.py +modules/pmg_tk/ColorEditor.py +modules/pmg_tk/Demo.py +modules/pmg_tk/PMGApp.py +modules/pmg_tk/PyMOLMapLoad.py +modules/pmg_tk/SetEditor.py +modules/pmg_tk/Setting.py +modules/pmg_tk/TextEditor.py +modules/pmg_tk/__init__.py +modules/pmg_tk/volume.py +modules/pmg_tk/skins/__init__.py +modules/pmg_tk/skins/demo/__init__.py +modules/pmg_tk/skins/normal/ModalWindow.py +modules/pmg_tk/skins/normal/__init__.py +modules/pmg_tk/skins/normal/builder.py +modules/pmg_tk/startup/__init__.py +modules/pymol/__init__.py +modules/pymol/__main__.py +modules/pymol/_gui.py +modules/pymol/api.py +modules/pymol/callback.py +modules/pymol/cgo.py +modules/pymol/cgobuilder.py +modules/pymol/checking.py +modules/pymol/cmd.py +modules/pymol/colorprinting.py +modules/pymol/colorramping.py +modules/pymol/commanding.py +modules/pymol/completing.py +modules/pymol/computing.py +modules/pymol/constants.py +modules/pymol/constants_palette.py +modules/pymol/controlling.py +modules/pymol/creating.py +modules/pymol/diagnosing.py +modules/pymol/editing.py +modules/pymol/editor.py +modules/pymol/experimenting.py +modules/pymol/exporting.py +modules/pymol/externing.py +modules/pymol/feedingback.py +modules/pymol/fitting.py +modules/pymol/gui.py +modules/pymol/headering.py +modules/pymol/helping.py +modules/pymol/importing.py +modules/pymol/internal.py +modules/pymol/invocation.py +modules/pymol/keyboard.py +modules/pymol/keywords.py +modules/pymol/lazyio.py +modules/pymol/locking.py +modules/pymol/menu.py +modules/pymol/monitoring.py +modules/pymol/morphing.py +modules/pymol/movie.py +modules/pymol/moving.py +modules/pymol/mpeg_encode.py +modules/pymol/parser.py +modules/pymol/parsing.py +modules/pymol/povray.py +modules/pymol/preset.py +modules/pymol/pymolhttpd.py +modules/pymol/querying.py +modules/pymol/rpc.py +modules/pymol/save_shortcut.py +modules/pymol/selecting.py +modules/pymol/selector.py +modules/pymol/seqalign.py +modules/pymol/setting.py +modules/pymol/shortcut.py +modules/pymol/shortcut_dict.py +modules/pymol/shortcut_manager.py +modules/pymol/util.py +modules/pymol/vfont.py +modules/pymol/viewing.py +modules/pymol/wizarding.py +modules/pymol/xray.py +modules/pymol/xwin.py +modules/pymol.egg-info/PKG-INFO +modules/pymol.egg-info/SOURCES.txt +modules/pymol.egg-info/dependency_links.txt +modules/pymol.egg-info/entry_points.txt +modules/pymol.egg-info/requires.txt +modules/pymol.egg-info/top_level.txt +modules/pymol/Qt/__init__.py +modules/pymol/Qt/utils.py +modules/pymol/plugins/__init__.py +modules/pymol/plugins/installation.py +modules/pymol/plugins/legacysupport.py +modules/pymol/plugins/managergui.py +modules/pymol/plugins/managergui_qt.py +modules/pymol/plugins/repository.py +modules/pymol/stereochemistry/__init__.py +modules/pymol/wizard/__init__.py +modules/pymol/wizard/annotation.py +modules/pymol/wizard/appearance.py +modules/pymol/wizard/benchmark.py +modules/pymol/wizard/box.py +modules/pymol/wizard/charge.py +modules/pymol/wizard/cleanup.py +modules/pymol/wizard/command.py +modules/pymol/wizard/demo.py +modules/pymol/wizard/density.py +modules/pymol/wizard/distance.py +modules/pymol/wizard/dragging.py +modules/pymol/wizard/filter.py +modules/pymol/wizard/label.py +modules/pymol/wizard/measurement.py +modules/pymol/wizard/message.py +modules/pymol/wizard/mutagenesis.py +modules/pymol/wizard/nucmutagenesis.py +modules/pymol/wizard/openvr.py +modules/pymol/wizard/pair_fit.py +modules/pymol/wizard/pseudoatom.py +modules/pymol/wizard/renaming.py +modules/pymol/wizard/sculpting.py +modules/pymol/wizard/security.py +modules/pymol/wizard/stereodemo.py +modules/pymol/wizard/toggle.py +modules/pymol2/__init__.py +modules/pymol2/cmd2.py +modules/web/examples/__init__.py +modules/web/examples/justhttpd.py +ov/src/OVContext.cpp +ov/src/OVHeap.cpp +ov/src/OVHeapArray.cpp +ov/src/OVLexicon.cpp +ov/src/OVOneToAny.cpp +ov/src/OVOneToOne.cpp +ov/src/OVRandom.cpp +ov/src/ov_utility.cpp \ No newline at end of file diff --git a/modules/pymol.egg-info/dependency_links.txt b/modules/pymol.egg-info/dependency_links.txt new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/modules/pymol.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/modules/pymol.egg-info/entry_points.txt b/modules/pymol.egg-info/entry_points.txt new file mode 100644 index 000000000..3b576c786 --- /dev/null +++ b/modules/pymol.egg-info/entry_points.txt @@ -0,0 +1,2 @@ +[console_scripts] +pymol = pymol:launch diff --git a/modules/pymol.egg-info/requires.txt b/modules/pymol.egg-info/requires.txt new file mode 100644 index 000000000..8ed985b89 --- /dev/null +++ b/modules/pymol.egg-info/requires.txt @@ -0,0 +1,6 @@ +numpy<2,>=1.26.4 + +[dev] +numpy<2,>=1.26.4 +pillow==10.3.0 +pytest==8.2.2 diff --git a/modules/pymol.egg-info/top_level.txt b/modules/pymol.egg-info/top_level.txt new file mode 100644 index 000000000..09f142d05 --- /dev/null +++ b/modules/pymol.egg-info/top_level.txt @@ -0,0 +1,6 @@ +chempy +pmg_qt +pmg_tk +pymol +pymol2 +web diff --git a/modules/pymol/cmd.py b/modules/pymol/cmd.py index 09ae92f9e..c2dcb6da8 100644 --- a/modules/pymol/cmd.py +++ b/modules/pymol/cmd.py @@ -33,6 +33,7 @@ # # In rare cases, certain nonserious error or warning output should # also be suppressed. Set "quiet" to 2 for this behavior. +from pymol.shortcut import Shortcut def _deferred_init_pymol_internals(_pymol): # set up some global session tasks @@ -54,7 +55,7 @@ def _deferred_init_pymol_internals(_pymol): # take care of some deferred initialization - _pymol._view_dict_sc = Shortcut({}) + _pymol._view_dict_sc = Shortcut() # if True: @@ -78,7 +79,6 @@ def _deferred_init_pymol_internals(_pymol): _pymol = pymol - from .shortcut import Shortcut from chempy import io diff --git a/modules/pymol/shortcut.py b/modules/pymol/shortcut.py index ed654b79b..9b5bd3512 100644 --- a/modules/pymol/shortcut.py +++ b/modules/pymol/shortcut.py @@ -1,184 +1,170 @@ -#A* ------------------------------------------------------------------- -#B* This file contains source code for the PyMOL computer program -#C* Copyright (c) Schrodinger, LLC. -#D* ------------------------------------------------------------------- -#E* It is unlawful to modify or remove this copyright notice. -#F* ------------------------------------------------------------------- -#G* Please see the accompanying LICENSE file for further information. -#H* ------------------------------------------------------------------- -#I* Additional authors of this source file include: -#-* -#-* -#-* -#Z* ------------------------------------------------------------------- - -if __name__=='pymol.shortcut': - from . import parsing - from .checking import is_string, is_list - -if True: - def mkabbr(a, m=1): - b = a.split('_') - b[:-1] = [c[0:m] for c in b[:-1]] - return '_'.join(b) - - class Shortcut: - - def __call__(self): - return self - - def __init__(self, keywords=(), filter_leading_underscore=1): - self.filter_leading_underscore = filter_leading_underscore - if filter_leading_underscore: - self.keywords = [x for x in keywords if x[:1]!='_'] - else: - self.keywords = list(keywords) - self.shortcut = {} - self.abbr_dict = {} - self.rebuild() - - def add_one(self,a): - # optimize symbols - hash = self.shortcut - abbr_dict = self.abbr_dict - for b in range(1,len(a)): - sub = a[0:b] - hash[sub] = 0 if sub in hash else a - if '_' in a: - for n in (1, 2): - abbr = mkabbr(a, n) - if a!=abbr: - if abbr in abbr_dict: - if a not in abbr_dict[abbr]: - abbr_dict[abbr].append(a) - else: - abbr_dict[abbr]=[a] - for b in range(abbr.find('_')+1,len(abbr)): - sub = abbr[0:b] - hash[sub] = 0 if sub in hash else a - - def rebuild(self, keywords=None): - if keywords is not None: - if self.filter_leading_underscore: - self.keywords = [x for x in keywords if x[:1]!='_'] - else: - self.keywords = list(keywords) - # optimize symbols - self.shortcut = {} - hash = self.shortcut - self.abbr_dict = {} - abbr_dict = self.abbr_dict - # - for a in self.keywords: - for b in range(1,len(a)): - sub = a[0:b] - hash[sub] = 0 if sub in hash else a - if '_' in a: - for n in (1, 2): - abbr = mkabbr(a, n) - if a!=abbr: - if abbr in abbr_dict: - abbr_dict[abbr].append(a) - else: - abbr_dict[abbr]=[a] - for b in range(abbr.find('_')+1,len(abbr)): - sub = abbr[0:b] - hash[sub] = 0 if sub in hash else a - - self._rebuild_finalize() - - def _rebuild_finalize(self): - hash = self.shortcut - for a, adk in self.abbr_dict.items(): - if len(adk)==1: - hash[a]=adk[0] - for a in self.keywords: - hash[a]=a - - def interpret(self,kee, mode=0): - ''' - Returns None (no hit), str (one hit) or list (multiple hits) - - kee = str: query string, setting prefix or shortcut - mode = 0/1: if mode=1, do prefix search even if kee has exact match - ''' - if not len(kee): # empty string matches everything - return list(self.keywords) - - try: - r = self.shortcut[kee] - except KeyError: - return None - if r and not mode: - return r - - # prefix search - lst_set = set(a for a in self.keywords if a.startswith(kee)) - for abbr, a_list in self.abbr_dict.items(): - if abbr.startswith(kee): - lst_set.update(a_list) - - # no match - if not lst_set: - return None - - # single match: str - lst = list(lst_set) - if len(lst) == 1: - return lst[0] - - # multiple matches: list - return lst - - def has_key(self,kee): - return kee in self.shortcut - - __contains__ = has_key - - def __getitem__(self,kee): - return self.shortcut.get(kee, None) - - def __delitem__(self,kee): - self.keywords.remove(kee) - self.rebuild() - - def append(self,kee): - self.keywords.append(kee) - self.add_one(kee) - self._rebuild_finalize() - - def auto_err(self,kee,descrip=None): - result = None - if kee not in self.shortcut: - if descrip is not None: - msg = "Error: unknown %s: '%s'." % (descrip, kee) - lst = self.interpret('') - if is_list(lst): - if len(lst)<100: - lst.sort() - lst = parsing.list_to_str_list(lst) - msg += " Choices:\n" - msg += "\n".join(lst) - raise parsing.QuietException(msg) - - else: - result = self.interpret(kee) - if not is_string(result): - if descrip is not None: - lst = parsing.list_to_str_list(result) - msg = "Error: ambiguous %s:\n%s" % (descrip, '\n'.join(lst)) - raise parsing.QuietException(msg) +# A* ------------------------------------------------------------------- +# B* This file contains source code for the PyMOL computer program +# C* Copyright (c) Schrodinger, LLC. +# D* ------------------------------------------------------------------- +# E* It is unlawful to modify or remove this copyright notice. +# F* ------------------------------------------------------------------- +# G* Please see the accompanying LICENSE file for further information. +# H* ------------------------------------------------------------------- +# I* Additional authors of this source file include: +# -* +# -* +# -* +# Z* ------------------------------------------------------------------- + +from typing import Iterable, Optional +from collections import defaultdict +from pymol import parsing + +class Shortcut: + def __init__( + self, + keywords: Optional[Iterable] = None, + filter_leading_underscore: bool = True, + ): + keywords = list(keywords) if keywords is not None else [] + self.filter_leading_underscore = filter_leading_underscore + self.keywords = ( + [keyword for keyword in keywords if keyword[:1] != "_"] + if filter_leading_underscore + else keywords + ) + self.shortcut: dict[str, str | int] = {} + self.abbreviation_dict = defaultdict(list) + + for keyword in self.keywords: + self.optimize_symbols(keyword) + + self._rebuild_finalize() + + def __contains__(self, keyword: str) -> bool: + return keyword in self.shortcut + + def __getitem__(self, keyword: str) -> Optional[int | str]: + return self.shortcut.get(keyword) + + def __delitem__(self, keyword: str) -> None: + self.keywords.remove(keyword) + self.rebuild() + + def make_abbreviation(self, s: str, groups_length: int) -> str: + """ + Example 1: + Input: s:'abc_def_ghig', groups_length: 1 + Output: 'a_d_ghig' + Example 2: + Input: s:'abc_def', groups_length: 2 + Output: 'a_def' + """ + groups = s.split("_") + groups[:-1] = [c[0:groups_length] for c in groups[:-1]] + return "_".join(groups) + + def optimize_symbols(self, keyword: str) -> None: + for i in range(1, len(keyword)): + substr = keyword[0:i] + self.shortcut[substr] = 0 if substr in self.shortcut else keyword + + if "_" not in keyword: + return + + for n in (1, 2): + abbreviation = self.make_abbreviation(keyword, n) + if keyword == abbreviation: + return + + if ( + abbreviation in self.abbreviation_dict + and keyword not in self.abbreviation_dict[abbreviation] + ): + self.abbreviation_dict[abbreviation].append(keyword) + + for i in range(abbreviation.find("_") + 1, len(abbreviation)): + sub = abbreviation[0:i] + self.shortcut[sub] = 0 if sub in self.shortcut else keyword + + def rebuild(self, keywords: Optional[Iterable] = None) -> None: + keywords = list(keywords) if keywords is not None else [] + self.keywords = ( + [keyword for keyword in keywords if keyword[:1] != "_"] + if self.filter_leading_underscore + else keywords + ) + # optimize symbols + self.shortcut = {} + self.abbreviation_dict = defaultdict(list) + for keyword in self.keywords: + self.optimize_symbols(keyword) + + self._rebuild_finalize() + + def _rebuild_finalize(self) -> None: + for abbreviation, keywords in self.abbreviation_dict.items(): + if len(keywords) == 1: + self.shortcut[abbreviation] = keywords[0] + for keyword in self.keywords: + self.shortcut[keyword] = keyword + + def interpret( + self, keyword: str, mode: bool = False + ) -> Optional[int | str | list[str]]: + """ + Returns None (no hit), str (one hit) or list (multiple hits) + + keyword = str: query string, setting prefix or shortcut + mode = True/False: if mode=True, do prefix search even if kee has exact match + """ + if keyword == "": + return self.keywords + + result = self.shortcut.get(keyword) + if result is None: + return + if result and not mode: return result -if __name__=='__main__': - sc = Shortcut(['warren','wasteland','electric','well']) - tv = sc.has_key('a') - print(tv==0,tv) - tv = sc.has_key('w') - print(tv==1,tv) - tv = sc.has_key('war') - print(tv==1,tv) - tv = sc.interpret('w') - print(sorted(tv)==['warren', 'wasteland', 'well'],tv) - tv = sc.interpret('e') - print(isinstance(tv, str), tv) + # prefix search + unique_keywords = set( + word for word in self.keywords if word.startswith(keyword) + ) + for abbreviation, keywords in self.abbreviation_dict.items(): + if abbreviation.startswith(keyword): + unique_keywords.update(keywords) + # no match + if not unique_keywords: + return + + # single match: str + # multiple matches: list + return ( + unique_keywords.pop() + if len(unique_keywords) == 1 + else list(unique_keywords) + ) + + def append(self, keyword) -> None: + self.keywords.append(keyword) + self.optimize_symbols(keyword) + self._rebuild_finalize() + + def auto_err( + self, keyword: str, descrip: Optional[str] = None + ) -> Optional[int | str | list[str]]: + result = self.interpret(keyword) + + if result is None and descrip is not None: + msg = f"Error: unknown {descrip}: '{keyword}'." + lst = self.interpret("") + if isinstance(lst, list) and len(lst) < 100: + lst.sort() + lst = parsing.list_to_str_list(lst) + msg += " Choices:\n" + "\n".join(lst) + raise parsing.QuietException(msg) + + if isinstance(result, list) and descrip is not None: + lst = parsing.list_to_str_list(result) + options = "\n".join(lst) + msg = f"Error: ambiguous {descrip}\\n {options}" + raise parsing.QuietException(msg) + + return result diff --git a/pyproject.toml b/pyproject.toml index d8629e40a..15558fd62 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,11 +26,13 @@ requires = [ ] [project.optional-dependencies] -test = [ +dev = [ + "numpy>=1.26.4,<2", "pillow==10.3.0", "pytest==8.2.2", ] + [project.urls] Homepage = "https://pymol.org" Documentation = "https://pymol.org/dokuwiki" diff --git a/testing/tests/api/shortcut.py b/testing/tests/api/shortcut.py index c8d4103d2..a1830b501 100644 --- a/testing/tests/api/shortcut.py +++ b/testing/tests/api/shortcut.py @@ -11,7 +11,7 @@ class TestShortcut(testing.PyMOLTestCase): def testShortcut(self): # build shortcut sc = cmd.Shortcut(words) - + # get all keywords self.assertItemsEqual(words, sc.interpret('')) @@ -33,8 +33,8 @@ def testShortcut(self): self.assertItemsEqual(['foo', 'foo_new'], sc.interpret('f')) self.assertEqual('foo', sc.interpret('foo')) self.assertEqual('foo_new', sc.interpret('foo_')) - - self.assertEqual(False, sc.has_key('')) + + self.assertEqual(False, '' in sc) # abbreviations diff --git a/tests/pymol/test_shortcut.py b/tests/pymol/test_shortcut.py new file mode 100644 index 000000000..1a9b405e6 --- /dev/null +++ b/tests/pymol/test_shortcut.py @@ -0,0 +1,107 @@ +import pytest + +from pymol.shortcut import Shortcut + + +@pytest.fixture +def sc() -> Shortcut: + return Shortcut(["foo", "bar", "baz", "com", "com_bla", "com_xxx"]) + + +@pytest.mark.parametrize( + "keyword, expected_result", + [ + ("a", False), + ("w", True), + ("war", True), + ], +) +def test_contains(keyword: str, expected_result: bool): + shortcut = Shortcut(["warren", "wasteland", "electric", "well"]) + assert (keyword in shortcut) is expected_result + + +def test_interpret(): + shortcut = Shortcut(["warren", "wasteland", "electric", "well"]) + list_result = shortcut.interpret("w") + assert list_result is not None + assert not isinstance(list_result, int) + assert sorted(list_result) == ["warren", "wasteland", "well"] + + string_result = shortcut.interpret("e") + assert list_result is not None + assert string_result == "electric" + + +def test_all_keywords(sc: Shortcut): + assert ["foo", "bar", "baz", "com", "com_bla", "com_xxx"] == sc.interpret("") + + +@pytest.mark.parametrize( + "prefixs, expected_result", + [ + (["f", "fo", "foo"], "foo"), + (["b", "ba"], ["bar", "baz"]), + (["bar"], "bar"), + (["c", "co"], ["com", "com_bla", "com_xxx"]), + (["com"], "com"), + ], +) +def test_full_prefix_hits( + sc: Shortcut, prefixs: list[str], expected_result: str | list[str] +): + for prefix in prefixs: + result = sc.interpret(prefix) + result = sorted(result) if isinstance(result, list) else result + assert expected_result == result + + +def test_append(sc: Shortcut): + sc.append("foo_new") + + assert ["foo", "foo_new"], sc.interpret("f") + assert "foo", sc.interpret("foo") + assert "foo_new", sc.interpret("foo_") + + assert "" not in sc + + +def test_abbreviations(sc: Shortcut): + assert "foo_new" == sc.interpret("f_") + assert "foo_new" == sc.interpret("f_new") + assert "foo_new" == sc.interpret("fo_") + assert "com_xxx" == sc.interpret("c_x") + assert "com_xxx" == sc.interpret("c_xxx") + assert "com_xxx" == sc.interpret("co_x") + + +def test_missing_key(sc: Shortcut): + assert None is sc.interpret("missing_key") + + +def test_auto_error(sc: Shortcut): + assert None is sc.auto_err("") + assert None is sc.auto_err("missing_key") + assert ["com", "com_bla", "com_xxx"] == sc.auto_err("co") + assert "com", sc.auto_err("com") + + +def test_interpret_mode_true(sc: Shortcut): + assert "foo" == sc.interpret("f", True) + assert ["com", "com_bla", "com_xxx"] == sc.interpret("com", True) + + sc.append("foo_new") + assert ["foo", "foo_new"] == sc.interpret("foo", True) + + +def testShortcutRebuild(sc: Shortcut): + coms = ["com", "com_bla", "com_xxx"] + sc.rebuild(coms) + + assert None is sc.interpret("f") + assert None is sc.interpret("foo") + + assert coms == sc.interpret("c") + assert coms == sc.interpret("com", True) + assert "com" == sc.interpret("com") + assert "com_xxx" == sc.interpret("c_x")