import os import sys import socket from pathlib import Path from tempfile import TemporaryDirectory import requests import pymol from pymol import cmd, testing pdbstr = '''ATOM 1 N GLY 22 -1.195 0.201 -0.206 1.00 0.00 N ATOM 2 CA GLY 22 0.230 0.318 -0.502 1.00 0.00 C ATOM 3 C GLY 22 1.059 -0.390 0.542 1.00 0.00 C ATOM 4 O GLY 22 0.545 -0.975 1.499 1.00 0.00 O ATOM 5 H GLY 22 -1.558 -0.333 0.660 1.00 0.00 H ATOM 6 3HA GLY 22 0.482 1.337 -0.514 0.00 0.00 H ATOM 7 HA GLY 22 0.434 -0.159 -1.479 1.00 0.00 H END ''' molstr = '''glycine ChemPy 3D 0 7 6 0 0 1 0 0 0 0 0999 V2000 -1.1946 0.2011 -0.2061 N 0 0 0 0 0 0 0 0 0 0 0 0 0.2304 0.3181 -0.5021 C 0 0 0 0 0 0 0 0 0 0 0 0 1.0594 -0.3899 0.5419 C 0 0 0 0 0 0 0 0 0 0 0 0 0.5454 -0.9749 1.4989 O 0 0 0 0 0 0 0 0 0 0 0 0 -1.5576 -0.3329 0.6599 H 0 0 0 0 0 0 0 0 0 0 0 0 0.4824 1.3374 -0.5137 H 0 0 0 0 0 0 0 0 0 0 0 0 0.4344 -0.1589 -1.4791 H 0 0 0 0 0 0 0 0 0 0 0 0 1 2 1 0 0 0 0 1 5 1 0 0 0 0 2 3 1 0 0 0 0 2 6 1 0 0 0 0 2 7 1 0 0 0 0 3 4 2 0 0 0 0 M END ''' mmodstr = ''' 7 gly 34 2 1 5 1 0 0 0 0 0 0 0 0 -1.195000 0.201000 -0.206000 22G 38 0.00000 0.00000 GLY N 3 1 1 3 1 6 1 7 1 0 0 0 0 0.230000 0.318000 -0.502000 22G 2 0.00000 0.00000 GLY CA 7 2 1 4 2 0 0 0 0 0 0 0 0 1.059000 -0.390000 0.542000 22G 2 0.00000 0.00000 GLY C 15 3 2 0 0 0 0 0 0 0 0 0 0 0.545000 -0.975000 1.499000 22G 75 0.00000 0.00000 GLY O 44 1 1 0 0 0 0 0 0 0 0 0 0 -1.558000 -0.333000 0.660000 22G 21 0.00000 0.00000 GLY H 41 2 1 0 0 0 0 0 0 0 0 0 0 0.482000 1.337000 -0.514000 22G 21 0.00000 0.00000 GLY 3HA 41 2 1 0 0 0 0 0 0 0 0 0 0 0.434000 -0.159000 -1.479000 22G 21 0.00000 0.00000 GLY HA ''' def _get_free_port() -> int: with socket.socket() as s: s.bind(("", 0)) return s.getsockname()[1] class TestImporting(testing.PyMOLTestCase): @testing.requires('network') def testFetch(self): with testing.mkdtemp() as fetch_path: names = [] cmd.set('fetch_path', fetch_path) cmd.set('fetch_host', 'pdb pdbe') cmd.fetch('1avy', '1avy1', type='pdb1') names += ['1avy1'] self.assertItemsEqual(cmd.get_names(), names) self.assertEqual(cmd.count_states('1avy1'), 3) if testing.PYMOL_VERSION_TUPLE < (2, 0): self.skipTest('upstream download URL has changed') cmd.fetch('1avy', type='2fofc') names += ['1avy_2fofc'] self.assertItemsEqual(cmd.get_names(), names) self.assertEqual(cmd.get_type('1avy_2fofc'), 'object:map') def testFetchLocal(self): try: import urllib.parse as urlparse except ImportError: import urlparse if os.getenv('GITHUB_ACTIONS') and sys.platform == 'win32': self.skipTest('Temporarily skip this test in GHA') return # PyMOL 1.8.6 adds full URLs, remove them pdbpaths = pymol.importing.hostPaths['pdb'] if isinstance(pdbpaths, list): pdbpaths[:] = [p for p in pdbpaths if '://' not in p] with testing.mkdtemp() as fetch_path: names = [] cmd.set('fetch_path', fetch_path) cmd.set('fetch_host', urlparse.urlunsplit(['file', '', self.datafile('pdb.mirror'), '', ''])) cmd.fetch('1avy', type='pdb') names += ['1avy'] self.assertItemsEqual(cmd.get_names(), names) cmd.fetch('1avyB', type='pdb') names += ['1avyB'] self.assertItemsEqual(cmd.get_names(), names) self.assertEqual(cmd.get_chains('1avyB'), ['B']) cmd.fetch('1aq5', type='pdb', multiplex=1) names += ['1aq5_%04d' % (i+1) for i in range(20)] self.assertItemsEqual(cmd.get_names(), names) def testFinishObject(self): # Disclaimer: I don't know the relevance of load(..., finish=0) and # finish_object(), but it does call ObjectMoleculeUpdateIDNumbers # so I'll just test that. cmd.load(self.datafile("1ehz-5.pdb"), "m1", finish=0) cmd.alter('all', 'ID = -1') self.assertEqual(cmd.identify('last all'), [-1]) cmd.finish_object('m1') self.assertEqual(cmd.identify('last all'), [224]) # non-existing object name should throw self.assertRaises(pymol.CmdException, lambda: cmd.finish_object('m2')) def testLoad_append_state(self): filename = self.datafile("1ehz-5.pdb") cmd.load(filename) cmd.load(filename, format="pdb") self.assertEqual(cmd.get_names(), ["1ehz-5"]) self.assertEqual(cmd.count_atoms(), 112) self.assertEqual(cmd.count_states(), 2) def testLoad_replace_state(self): filename = self.datafile("1ehz-5.pdb") cmd.load(filename) cmd.load(filename, state=1) self.assertEqual(cmd.get_names(), ["1ehz-5"]) self.assertEqual(cmd.count_atoms(), 112) self.assertEqual(cmd.count_states(), 1) def testLoad_state_skip(self): filename = self.datafile("1ehz-5.pdb") cmd.load(filename) cmd.load(filename, state=3) self.assertEqual(cmd.count_states(), 3) def testLoad_no_zoom(self): view = cmd.get_view() cmd.load(self.datafile("1ehz-5.pdb"), zoom=0) self.assertEqual(view, cmd.get_view()) @testing.requires('incentive') def testLoad_mimic(self): filename = self.datafile("repr.mae") cmd.load(filename, "m0", mimic=0) cmd.load(filename, "m1", mimic=1) self.assertFalse( cmd.get_setting_boolean("stick_ball", "m0.x_ballstick", state=1)) self.assertTrue( cmd.get_setting_boolean("stick_ball", "m1.x_ballstick", state=1)) @testing.requires_version('1.7.3.0') def testLoad_idx(self): cmd.load(self.datafile('desmond/Bace_mapper_20143_3a51a59_e85111a_solvent_11_replica0-out.idx'), state=1) self.assertEqual(cmd.count_states(), 209) self.assertEqual(cmd.count_atoms(), 2482) def testLoad_pqr(self): cmd.load(self.datafile('example.pqr')) charges = [] radii = [] n = cmd.iterate('all', 'charges.append(partial_charge);radii.append(elec_radius)', space=locals()) self.assertEqual(n, 191) self.assertTrue(any(x != 0.0 for x in charges)) self.assertTrue(any(x != 0.0 for x in radii)) @testing.requires_version('2.2') def testLoad_pqr_various(self): import glob pqrdir = self.datafile('pqr') extent_expect = { 19: [[1999.32, 2998.77, -901.70], [2008.4, 3006.35, -898.02]], 36: [[1998.629, 2998.033, -902.509], [2008.765, 3006.347, -898.022]], } for filename in glob.glob(os.path.join(pqrdir, '*.pqr')): cmd.load(filename) n_atom = cmd.count_atoms() extent = cmd.get_extent() self.assertArrayEqual(extent, extent_expect[n_atom], delta=1e-2, msg=filename) if 'chain' in os.path.basename(filename): self.assertEqual(cmd.get_chains(), ['A']) else: self.assertEqual(cmd.get_chains(), ['']) cmd.delete('*') @testing.foreach.product( ['sdf', 'mol2', 'xyz', 'pdb', 'mmd'], [0, 1], ) def testLoad_multi(self, ext, discrete): ''' Load multi-state files with discrete=0/1 and multiplex=0/1 ''' N = 10 filename = self.datafile('ligs3d.' + ext) # mutiplex=0 cmd.load(filename, discrete=discrete, multiplex=0) if testing.PYMOL_VERSION_TUPLE >= (1, 7): self.assertEqual(cmd.count_discrete('*'), discrete) self.assertEqual(cmd.count_states(), N) self.assertEqual(len(cmd.get_object_list()), 1) if ext in ['mmd']: return # mutiplex=1 cmd.delete('*') cmd.load(filename, discrete=discrete, multiplex=1) if testing.PYMOL_VERSION_TUPLE >= (1, 7): self.assertEqual(cmd.count_discrete('*'), discrete * N) self.assertEqual(cmd.count_states(), 1) self.assertEqual(len(cmd.get_object_list()), N) @testing.foreach( ['.ccp4', True], ['.brix', True], ['.spi', False], ) @testing.requires_version('1.7.3.0') def testLoad_map(self, ext, check_extent): filename = self.datafile('emd_1155' + ext) if not os.path.exists(filename): self.skipTest("missing " + filename) cmd.load(filename, 'map1') field = cmd.get_volume_field('map1', copy=0) self.assertEqual(field.shape, (141, 91, 281)) if check_extent: extent = cmd.get_extent('map1') self.assertArrayEqual(extent, [[0.0, 0.0, 0.0], [2296.0, 1476.0, 4592.0]], delta=1e-2) @testing.requires_version('1.7.3.0') def testLoad_cube(self): cmd.load(self.datafile('h2o-elf.cube')) extent = cmd.get_extent('h2o-elf') self.assertArrayEqual(extent, [ [ -0.075, -0.075, -0.075], [ 5.925, 5.925, 5.925]], delta=1e3) field = cmd.get_volume_field('h2o-elf', copy=0) self.assertEqual(field.shape, (40, 40, 40)) self.assertAlmostEqual(field.mean(), 0.06915, delta=1e-4) def _testLoad_dx(self, filename): cmd.load(self.datafile(filename), 'map1') extent = cmd.get_extent('map1') self.assertArrayEqual(extent, [[1.0, 2.0, 3.0], [5.0, 7.0, 9.0]], delta=1e-2) def testLoad_dx(self): self._testLoad_dx('mapaligned.dx') self._testLoad_dx('mapnumeric.dx') @testing.requires_version('2.1') def testLoad_dx_skewed(self): self._testLoad_dx('mapskewed.dx') @testing.requires_version('2.5') def testLoad_dxstr(self): with open(self.datafile('mapaligned.dx'), 'rb') as handle: cmd.load_raw(handle.read(), 'dx', 'map1') extent = cmd.get_extent('map1') self.assertArrayEqual(extent, [[1.0, 2.0, 3.0], [5.0, 7.0, 9.0]], delta=1e-2) def testLoadBrick(self): cmd.load_brick self.skipTest("TODO") def testLoadCallback(self): cmd.load_callback self.skipTest("TODO") def testLoadCgo(self): cmd.load_cgo self.skipTest("TODO") def testLoadEmbedded(self): cmd.load(self.datafile("embed.p1m")) self.assertEqual(6, cmd.count_atoms()) self.assertEqual(2, cmd.count_atoms('elem O')) def testLoadMap(self): cmd.load_map self.skipTest("TODO") def testLoadModel(self): cmd.fragment('gly') m = cmd.get_model() cmd.delete('*') cmd.load_model(m, 'm1') self.assertEqual(7, cmd.count_atoms()) def testLoadObject(self): cmd.load_object self.skipTest("TODO") def testLoadRaw(self): cmd.load_raw(open(self.datafile("sampletrajectory.pdb")).read(), "pdb") self.assertEqual(115, cmd.count_atoms()) @testing.requires_version('2.3.3') def testLoadRawMMTF(self): import gzip with gzip.open(self.datafile("3njw.mmtf.gz")) as handle: cmd.load_raw(handle.read(), "mmtf") self.assertEqual(169, cmd.count_atoms()) @testing.requires_version('2.5') def testLoadRawGRO(self): cmd.load_raw(open(self.datafile("sampletrajectory.gro")).read(), "gro") self.assertEqual(115, cmd.count_atoms()) @testing.requires_version('2.4') def testLoadMMTFStr(self): # deprecated import gzip with gzip.open(self.datafile("3njw.mmtf.gz")) as handle: cmd.load(handle.read(), "m1", format="mmtfstr") self.assertEqual(169, cmd.count_atoms()) @testing.foreach( ['.pdb', '.dcd'], ['.pdb', '.crd'], ['.gro', '.xtc'], ) @testing.requires_version('1.7.3.0') def testLoadTraj(self, topext, trjext): pdbfile = self.datafile("sampletrajectory" + topext) dcdfile = self.datafile("sampletrajectory" + trjext) cmd.load(pdbfile) cmd.load_traj(dcdfile, state=0) self.assertEqual(11, cmd.count_states()) cmd.delete('*') cmd.load(pdbfile) cmd.load_traj(dcdfile, state=1, interval=2, max=3) self.assertEqual(3, cmd.count_states()) cmd.delete('*') cmd.load(pdbfile) cmd.load_traj(dcdfile, state=1, start=3, stop=5) self.assertEqual(3, cmd.count_states()) cmd.delete('*') cmd.load(pdbfile) cmd.load_traj(dcdfile, state=1, stop=9, average=3) self.assertEqual(3, cmd.count_states()) cmd.delete('*') # Changed in PyMOL 2.5: Default is now state=1 instead of state=0 @testing.requires_version('2.5') def testLoadTraj_default_state_1(self): cmd.load(self.datafile("sampletrajectory.pdb")) cmd.load_traj(self.datafile("sampletrajectory.dcd")) self.assertEqual(10, cmd.count_states()) # via ObjectMoleculeLoadTRJFile @testing.requires_version('1.7') def testLoadTraj_selection_trj(self): base = self.datafile("sampletrajectory") cmd.load(base + ".pdb") cmd.load_traj(base + ".crd", selection="backbone", format="trj", state=0) self.assertEqual(55, cmd.count_atoms('state 10')) # via PlugIOManager @testing.requires_version('2.4') def testLoadTraj_selection(self): base = self.datafile("sampletrajectory") cmd.load(base + ".gro") cmd.load_traj(base + ".xtc", selection="backbone", state=0) self.assertEqual(55, cmd.count_atoms('state 10')) @testing.requires_version('1.8.5') def testLoadCharmmCor(self): # http://www.ks.uiuc.edu/Research/vmd/plugins/molfile/corplugin.html for fmt in ['', 'cor']: cmd.load(self.datafile("charmm.crd"), format=fmt) self.assertEqual(81, cmd.count_atoms(), 'fmt: ' + fmt) cmd.delete('*') def testLoadTOP(self): ''' Data files from: http://ambermd.org/tutorials/basic/tutorial2/section6.htm ''' cmd.load(self.datafile("TRPcage.top")) cmd.load_traj(self.datafile("heat1.crd"), "TRPcage", format="trj", state=0) self.assertEqual(304, cmd.count_atoms()) self.assertEqual(10, cmd.count_states()) @testing.requires_version('1.7.5') def testLoadPSF(self): cmd.load(self.datafile("ubiquitin.psf")) self.assertEqual(26190, cmd.count_atoms()) self.assertEqual(0, cmd.count_states()) @testing.requires_version('1.7.5') def testLoadVaspCHGCAR(self): cmd.load(self.datafile("vasp.CHGCAR"), 'vasp.CHGCAR') self.assertEqual(cmd.get_type('vasp.CHGCAR'), 'object:map') extend = cmd.get_extent('vasp.CHGCAR') self.assertArrayEqual(extend, [[0.0, 0.0, 0.0], [6.5, 6.5, 7.7]], delta=1e-2) @testing.requires_version('1.7.5') def testLoadVaspOUTCAR(self): cmd.load(self.datafile("vasp.OUTCAR")) self.assertEqual(2, cmd.count_atoms()) self.assertEqual(11, cmd.count_states()) @testing.requires_version('1.7.5') def testLoadVaspPOSCAR(self): cmd.load(self.datafile("vasp.POSCAR")) self.assertEqual(2, cmd.count_atoms()) self.assertEqual(1, cmd.count_states()) @testing.requires_version('1.8.5.0') def testLoadMSMSSurface(self): cmd.load(self.datafile('surface.face')) e = cmd.get_extent('surface') self.assertArrayEqual(e, [ [28.003, 25.573, 12.883], [34.238, 31.434, 17.835]], delta=1e-3) @testing.requires_version('1.7') # broken before def testReadMmodstr(self): cmd.read_mmodstr(mmodstr, 'm1') self.assertEqual(7, cmd.count_atoms()) def testReadMolstr(self): cmd.read_molstr(molstr, 'm1') self.assertEqual(7, cmd.count_atoms()) def testReadPdbstr(self): cmd.read_pdbstr(pdbstr, 'm1') self.assertEqual(7, cmd.count_atoms()) cmd.read_pdbstr(pdbstr, 'm1') self.assertEqual(2, cmd.count_states()) def testReadSdfstr(self): sdfstr = molstr + '$$$$\n' cmd.read_sdfstr(sdfstr, 'm1') self.assertEqual(7, cmd.count_atoms()) @testing.requires_version('1.8.3.1') def testLoadSDFV3000(self): cmd.load(self.datafile("v3000.sdf")) self.assertEqual(12, cmd.count_atoms()) self.assertEqual( 1, cmd.count_atoms('formal_charge = +1')) self.assertEqual( 1, cmd.count_atoms('formal_charge = -1')) self.assertEqual( 6, cmd.count_atoms('elem C')) self.assertEqual( 6, cmd.count_atoms('elem H')) self.assertEqual( 4, cmd.count_atoms('(first elem H) extend 2')) def testReadXplorstr(self): cmd.read_xplorstr self.skipTest("TODO") def testSetSession(self): # see TestExporting.testGetSession pass def testSpace(self): cmd.space('pymol', 0.5) cmd.space('cmyk', 0.7) cmd.space('rgb') # CmdException before 2.5, now QuietException (from Shortcut) self.assertRaises((pymol.CmdException, cmd.QuietException), lambda: cmd.space('no-such-space')) pymol_data = os.environ['PYMOL_DATA'] os.environ['PYMOL_DATA'] = '/no/such/dir' pymol_path = os.environ['PYMOL_PATH'] # PyMOL 1.x os.environ['PYMOL_PATH'] = '/no/such/dir' # PyMOL 1.x try: self.assertRaises(pymol.CmdException, lambda: cmd.space('cmyk')) finally: os.environ['PYMOL_DATA'] = pymol_data os.environ['PYMOL_PATH'] = pymol_path # PyMOL 1.x @testing.requires_version('1.7.3.0') def testLoadCoords(self): import numpy cmd.fragment('gly', 'm1') coords = cmd.get_coords('m1') coords += 5.0 cmd.load_coords(coords, 'm1') self.assertTrue(numpy.allclose(coords, cmd.get_coords('m1'))) @testing.requires_version('1.7.3.0') def testLoadCoordset(self): import numpy cmd.fragment('gly', 'm1') coords = cmd.get_coordset('m1') cmd.load_coordset(coords, 'm1', state=2) self.assertEqual(2, cmd.count_states('m1')) # data manipulation with copy=0 cmd.get_coordset('m1', copy=0)[:] += 5.0 self.assertTrue(numpy.allclose(coords + 5.0, cmd.get_coords('m1'))) @testing.requires_version('1.7.7') def testLoadPDBML(self): cmd.load(self.datafile("1ubq.xml.gz")) self.assertEqual(660, cmd.count_atoms()) symmetry = cmd.get_symmetry() self.assertArrayEqual(symmetry[:6], [50.84, 42.77, 28.95, 90.0, 90.0, 90.0], delta=1e-4) self.assertEqual(symmetry[6], 'P 21 21 21') @testing.requires_version('1.7.7') def testLoadCML(self): cmd.load(self.datafile("GLY.cml")) self.assertEqual(10, cmd.count_atoms()) @testing.requires_version('1.7.7') def testLoadPDBQT(self): cmd.set('retain_order') cmd.load(self.datafile("NSC7810.pdbqt")) charges = [] n = cmd.iterate('all', 'charges.append(partial_charge)', space=locals()) self.assertEqual(n, 26) charges_expected = [0.002, 0.012, -0.024, 0.012, 0.002, 0.019, 0.052, 0.002, -0.013, 0.013, -0.013, 0.002, 0.013, -0.024, 0.052, 0.012, 0.012, 0.002, 0.002, 0.019, 0.21, -0.644, -0.644, 0.21, -0.644, -0.644] self.assertArrayEqual(charges, charges_expected, delta=1e-4) @testing.requires_version('2.6') def testLoadPLY(self): cmd.load(self.datafile("test_PHE_pentamer.ply.gz")) e = cmd.get_extent('test_PHE_pentamer') self.assertArrayEqual(e, [[-3.141,-3.036,-2.809], [15.920, 10.425, 8.680]], delta=1e-3) @testing.requires_version('1.8.4') def testLoadMMTF(self): cmd.load(self.datafile("3njw.mmtf.gz")) self.assertEqual(169, cmd.count_atoms()) self.assertEqual(36, cmd.count_atoms('ss S')) self.assertEqual(25, cmd.count_atoms('solvent')) self.assertEqual(25, cmd.count_atoms('not polymer')) symmetry = cmd.get_symmetry() self.assertArrayEqual(symmetry[:6], [19.465, 21.432, 29.523, 90.0, 90.0, 90.0], delta=1e-4) self.assertEqual(symmetry[6], 'P 21 21 21') @testing.requires_version('2.6') def testLoadMMTF_polymer(self): cmd.load(self.datafile("1x8x.mmtf.gz")) self.assertEqual(2780, cmd.count_atoms()) self.assertEqual(2544, cmd.count_atoms('polymer')) self.assertEqual(218, cmd.count_atoms('solvent')) self.assertEqual(13, cmd.count_atoms('organic')) self.assertEqual(5, cmd.count_atoms('inorganic')) @testing.requires_version('1.8.4') def testLoadMMTFEmpty(self): cmd.load(self.datafile("mmtf/empty-all0.mmtf")) self.assertEqual(cmd.count_states(), 0) cmd.delete('*') cmd.load(self.datafile("mmtf/empty-numModels1.mmtf.gz")) self.assertEqual(cmd.count_atoms(), 0) self.assertEqual(cmd.get_names(), ["empty-numModels1"]) cmd.delete('*') cmd.load(self.datafile("mmtf/empty-numChains1.mmtf.gz")) self.assertEqual(cmd.count_atoms(), 0) self.assertEqual(cmd.get_names(), ["empty-numChains1"]) cmd.delete('*') cmd.load(self.datafile("mmtf/empty-mmtfVersion99999999.mmtf")) self.assertEqual(cmd.get_names(), []) cmd.delete('*') @testing.requires_version('2.3.3') def testLoadMMTFMissingOptionalGroupTypeFields(self): cmd.load(self.datafile("mmtf/missing-optional-grouptype-fields.mmtf.gz")) self.assertEqual(cmd.count_atoms(), 17) self.assertEqual(len(cmd.get_bonds()), 7) @testing.foreach( ['', '*', True], ['', 'pdb_header', True], ['', 'x pdb_header y', True], ['', 'other', False], ['', None, False], ['other', None, False], ['pdb_header', None, True], ['x pdb_header y', None, True], ['*', None, True], ) @testing.requires_version('1.8.4') @testing.requires('incentive') def testPdbHeader(self, load_object_props_default, object_props, truth): cmd.set('load_object_props_default', load_object_props_default) cmd.load(self.datafile('1rx1.pdb'), 'm1', object_props=object_props) self.assertEqual(truth, 'pdb_header' in (cmd.get_property_list('m1') or ())) @testing.requires_version('2.4') @testing.requires( 'network' ) # doesn't use external network, but is very slow while being connected to VPN def testLoadPWG(self): content_index = b"Hello World\n" port = _get_free_port() base_url = f"http://localhost:{port}" with TemporaryDirectory() as root_dir: root_dir = Path(root_dir) index_file = root_dir / "index.html" start_pwg_file = root_dir / "start.pwg" index_file.write_bytes(content_index) pwg_content = ( f"root {root_dir}\n" f"port {port}\n" "header add Test-Key Test-Value\n" ) start_pwg_file.write_text(pwg_content) cmd.load(str(start_pwg_file)) response = requests.get(url=base_url, timeout=5) response.raise_for_status() self.assertEqual(response.headers["Test-Key"], "Test-Value") self.assertEqual(response.content, content_index) # Warning: can't call locking functions here, will dead-lock # get_version is non-locking since 1.7.4 response = requests.get(f"{base_url}/apply/pymol.cmd.get_version", timeout=5) response.raise_for_status() content = response.content.decode("ascii", errors="ignore") self.assertTrue(content, cmd.get_version()[0] in content) @testing.requires_version('2.1') def testChemCompCartnUse(self): xyz_model = (1., 2., 3.) xyz_ideal = (4., 5., 6.) xyz_short = (7., 8., 9.) for (value, xyz) in [ (0x00, xyz_ideal), (0x01, xyz_ideal), (0x02, xyz_model), (0x03, xyz_ideal), (0x04, xyz_short), (0x05, xyz_ideal), (0x06, xyz_model), (0x07, xyz_ideal), ]: cmd.set('chem_comp_cartn_use', value) cmd.load(self.datafile('chem_comp-fe.cif'), 'm1') self.assertArrayEqual(xyz, cmd.get_coords('m1').reshape(-1)) cmd.delete('*') @testing.requires_version('2.1') def testCifMissing(self): N = 7 cmd.fragment('gly', 'm1') cmd.alter('all', '(chain, segi, resv, alt) = ("?", ".", 5, "")') s = cmd.get_str('cif') self.assertTrue("'?'" in s or '"?"' in s) # chain self.assertTrue("'.'" in s or '"."' in s) # segi self.assertTrue(' ? ' in s) # e.g. pdbx_PDB_ins_code self.assertTrue(' . ' in s) # e.g. label_alt_id cmd.delete('*') cmd.set('cif_keepinmemory') cmd.load(s, 'm2', format='cifstr') self.assertEqual(['?'], cmd.get_chains()) self.assertEqual(cmd.count_atoms('segi .'), N) self.assertEqual(cmd.count_atoms('alt ""'), N) # no alt self.assertEqual(cmd.count_atoms('resi 5'), N) # no ins_code from pymol.querying import cif_get_array self.assertEqual(cif_get_array("m2", "_atom_site.type_symbol"), list('NCCOHHH')) self.assertEqual(cif_get_array("m2", "_atom_site.id", "i"), list(range(1, N + 1))) self.assertEqual(cif_get_array("m2", "_atom_site.auth_asym_id"), ['?'] * N) self.assertEqual(cif_get_array("m2", "_atom_site.label_asym_id"), ['.'] * N) self.assertEqual(cif_get_array("m2", "_atom_site.pdbx_pdb_ins_code"), [None] * N) self.assertEqual(cif_get_array("m2", "_atom_site.label_alt_id"), [None] * N) @testing.requires_version('2.4') def testCifAltAtomId(self): cmd.load(self.datafile('sia-alt-id.cif'), 'm1') self.assertEqual(cmd.count_atoms('bound_to name C1'), 3) self.assertEqual(cmd.count_atoms('(bound_to name C1) and name C3'), 0) @testing.requires_version('2.5') def testCifErrorHandling(self): with self.assertRaisesRegex(pymol.CmdException, 'Parsing CIF file failed: expected key'): cmd.load_raw('data_foo _k.a 1 2 3', 'cif', 'm1') with self.assertRaisesRegex(pymol.CmdException, 'Parsing CIF file failed: truncated loop'): cmd.load_raw('data_foo loop_ _k.a _k.b 1 2 3', 'cif', 'm2') def testLoad_cif_map(self): filename = self.datafile("cif_map.cif") cmd.load(filename, 'cif_map') field = cmd.get_volume_field('cif_map') self.assertEqual(field.shape, (12, 12, 12))