-
-
Notifications
You must be signed in to change notification settings - Fork 1
File Formats and Import Export
This page lists every file format MoleditPy can open, import, save, or export, grounded in ui/io_logic.py (IOManager), ui/export_logic.py (ExportManager), and ui/string_importers.py (StringImporterManager). "2D" means the format populates the 2D editor canvas; "3D" means it populates/reads the 3D viewer only.
The recommended, default save format (File ▸ Save Project / Ctrl+S, Save Project As... / Ctrl+Shift+S).
- Written by
IOManager.save_project_as/save_as_jsonas UTF-8 JSON (json.dump(..., indent=2, ensure_ascii=False)), with an internal"format": "PME Project"marker and"version"field. -
create_json_data()(StateManager) serializes the full editing session — the exact contents depend onStateManager, but per the app's own README/manual this includes: the 2D drawing (atoms, bonds, positions, charges, radicals, stereo), the generated/loaded 3D structure, chiral-label state, and — because plugins can hookregister_save_handler/register_load_handler— any plugin's own persisted state (e.g. PMEFF's geometry overrides, the Metadata Saver plugin's debug fields) gets written into the same file. - On load (
Open Project.../Ctrl+O, orFile ▸ Open Project...),load_json_data()checks the"format"marker (rejects anything else with "This file is not a valid PME Project format.") and warns — but still attempts to load — if"version"isn't"1.0". - Corrupt/foreign JSON, a missing file, or a data-shape mismatch each surface a specific dialog (
Invalid Format/Project Load Errorwith the underlyingjson.JSONDecodeError/KeyError/etc. message) rather than a generic failure. - After loading, the 3D camera is reset to isometric and the view is re-fit on a short
QTimerdelay.
- Written by
Export ▸ PME Raw Format...(save_raw_data) viapickle.dump(get_current_state(), f); loaded viaOpen Project File(auto-detected by extension) or explicitly viaload_raw_data. -
Security note (from the project README): this format uses Python's
pickle, which can execute arbitrary code when deserialized. Only open.pmerawfiles you created yourself — for anything you intend to share, use.pmeprjinstead. This is a documented, deliberate risk of the legacy format, not a bug. - Load failures are caught explicitly for
pickle.UnpicklingError,EOFError, andImportError(a.pmerawreferencing a class that no longer exists) and reported as "Invalid project file format."
File ▸ Import ▸ MOL/SDF File... (load_mol_file):
-
.molfiles are read as text, thenfix_mol_block()patches the counts line to guarantee a validV2000tag if the line doesn't already declareV2000/V3000(defends against hand-edited or nonstandard MOL files with a malformed counts line). -
.sdffiles useChem.SDMolSupplier(file_path, removeHs=False)and take only the first molecule in the file — there is no multi-molecule SDF browser in the main app (some plugins, e.g. OpenBabel Conversion Tool, add multi-molecule support). - Both paths parse with
sanitize=True/RDKit defaults andChem.Kekulize(); if the file has no conformer, 2D coordinates are computed (AllChem.Compute2DCoords). Stereochemistry (wedge/dash, E/Z) is reassigned and re-wedged from the parsed 3D/2D geometry (AssignStereochemistry+WedgeMolBonds) — stereochemistry is preserved even though 2D coordinates may be recalculated. - The imported structure is placed to the right of whatever is already on the canvas (offset by 80 px past the rightmost existing atom) rather than overwriting it — MOL/SDF import is additive, not a replace.
- Any read/parse failure (
Chem.MolFromMolBlock/SDMolSupplierreturningNone, or anyOSError/ValueError/RuntimeError/AttributeError/KeyError) surfaces as a "MOL Import Error" dialog with the underlying message.
File ▸ Export ▸ 2D Formats ▸ MOL File... (save_as_mol): writes state_manager.data.to_mol_block() (the current 2D structure) as a .mol file, stamping the header comment line with MoleditPy Ver. {VERSION} 2D in place of RDKit's default header if present.
File ▸ Import ▸ SMILES... / InChI... (string_importers.py): a QInputDialog text prompt feeds Chem.MolFromSmiles/Chem.MolFromInchi. On success, 2D coordinates are computed, the molecule is Kekulized, stereo is reassigned/rewedged, and it is added to the 2D canvas the same way MOL import is (offset to the right of existing content, or centered in the viewport if the canvas is empty). An empty or unparseable string reports "Invalid SMILES"/"Invalid InChI" on the status bar rather than throwing. There is no SMILES/InChI export in the main app itself — the Molecular Analysis window displays a computed SMILES/InChI string for the current molecule (read-only, copyable), but there's no dedicated "export as SMILES" file action; the PubChem plugins and MCP Server plugin add SMILES round-tripping capability on top.
File ▸ Import ▸ 3D XYZ (3D View Only)... (load_xyz_for_3d_viewing → _mol_from_xyz_lines):
- Parses a standard headed XYZ (
Natoms line, title/comment line, thenNrows) or falls back to a headerless/irregular file (any line that isn't a valid atom-count integer causes the whole file to be treated as bare atom rows with comment lines stripped). - Robust to malformed rows: if the declared atom count exceeds the rows actually present, it loads what's there and warns rather than refusing the file; ghost/label columns like
XX : x y zare tolerated by taking the first three float-parseable tokens as coordinates regardless of extra separator tokens. - Any atom symbol not in RDKit's valid element table, or a symbol containing
:, or one of the recognized dummy tokens (DUMMY_XYZ_SYMBOLS) is loaded as a wildcard*(ghost atom), with the original text preserved in anxyz_original_symbolRDKit property for round-tripping. -
Bond determination and charge prompting: unless
skip_chemistry_checksis enabled in Settings or the file contains any ghost/dummy atoms (which always skip chemistry), the app first tries RDKit'srdDetermineBonds.DetermineBondsat charge 0; if that fails (or "Always ask for charge" is enabled in Settings), a modal "Import XYZ Charge" dialog prompts for the total molecular charge (default0), with a "Skip chemistry" button that instead falls back to pure distance-based bond estimation (covalent-radius sum,0.5×–1.2×/1.3×tolerance window depending on whether either atom is H, nearest-pairs-first with a one-bond-per-H cap) and no sanitization at all. - Loading enters "3D Viewer Mode": the 2D editor is cleared, the molecule is shown only in the 3D view, and
is_xyz_derivedis set (used elsewhere to gate/adjust some 2D-oriented features). - If any atom row had a non-standard leading column, the status bar reports how many rows were affected.
File ▸ Export ▸ 3D Formats ▸ XYZ File... (save_as_xyz): writes a standard headed XYZ with the comment/title line set to chrg = {charge} mult = {multiplicity} | Generated by MoleditPy Ver. {VERSION}, where charge comes from the _xyz_charge property if the molecule was itself XYZ-derived, else RDKit's computed formal charge; multiplicity is NumRadicalElectrons() + 1. Coordinates are written at 8 decimal places, symbol left-padded to 5 chars.
File ▸ Import ▸ 3D MOL/SDF (3D View Only)... (load_mol_file_for_3d_viewing): reads a MOL (with the same fix_mol_block counts-line patch) or the first molecule of an SDF, generating a conformer via AllChem.EmbedMolecule if the file has none. Also clears the 2D editor and enters 3D-viewer-only mode; is_xyz_derived is explicitly False for this path (unlike the XYZ import) since a MOL/SDF file has real bond-order/stereo data, not distance-estimated bonds.
File ▸ Export ▸ 3D Formats ▸ MOL File... (save_3d_as_mol): writes Chem.MolToMolBlock(current_mol, includeStereo=True) for the currently-displayed 3D structure, with the same MoleditPy Ver. {VERSION} 3D header stamp as the 2D MOL export.
File ▸ Export ▸ 2D Formats ▸ PNG Image... (export_2d_png): asks Yes/No/Cancel for a transparent background, temporarily hides every non-atom/non-bond scene item (labels, template previews, etc.), computes the tight bounding box of visible atoms/bonds with a 20 px margin on each side, renders via QPainter/QImage (Format_ARGB32_Premultiplied), then restores visibility/background afterward (in a finally block, so a mid-export exception still restores the canvas).
File ▸ Export ▸ 2D Formats ▸ SVG Image... (export_2d_svg): same background-choice/bounding-box/restore logic as PNG, but renders through QSvgGenerator at the screen's logical DPI (falls back to 96 if logicalDpiX() isn't available), titled "MoleditPy Molecule".
File ▸ Export ▸ 3D Formats ▸ PNG Image... (export_3d_png): same transparency prompt, then plotter.screenshot(path, transparent_background=...) — a straight PyVista/VTK render-to-file of the current 3D view exactly as displayed (camera angle, style, lighting).
File ▸ Export ▸ 3D Formats ▸ STL File... (export_stl): walks every actor in the PyVista renderer, extracts its underlying mesh (mapper.dataset/.input, or GetInput()/GetInputAsDataSet() for raw VTK actors), merges them into one PolyData, and writes a binary STL with no color information — appropriate for slicers/3D printing.
export_color_stl (reachable in-code but not currently wired to a menu item in the reviewed source — the export menu exposes the two-file colored path below instead): same mesh-merge logic as plain STL, but stamps each mesh's actor color into point_data (red/green/blue, diffuse_red/green/blue, and a combined colors array) before saving, for tools that read vertex-color STL extensions.
File ▸ Export ▸ 3D Formats ▸ OBJ/MTL (with colors)... (export_obj_mtl): produces a companion pair of files — name.obj and name.mtl (same basename, .mtl derived via os.path.splitext so a .OBJ-cased path can't collide with itself). Each PyVista actor becomes one o object_N block with its own usemtl material_N_<actor> material (ambient 0.2, diffuse = the actor's RGB, specular 0.5, shininess 32, illum model 2). Where an actor carries per-vertex color data (e.g. a single merged-atom glyph mesh where each atom has a different applied color — see the Atom/Bond Colorizer plugins), the mesh is further split into per-unique-color sub-meshes (extract_points) so each color group gets its own material in the OBJ, rather than collapsing to one averaged color.
The formats above are everything the main app itself reads/writes. Several official plugins extend this considerably — see Official Plugins for the full catalogue, but notably:
- OpenBabel Conversion Tool — imports many additional chemical formats via OpenBabel, with multi-molecule (multi-frame) support.
- Paste from ChemDraw — pastes structures directly from the ChemDraw clipboard format.
- Animated XYZ Giffer — opens multi-frame/trajectory XYZ files and exports GIF animations.
- Blender Export / Blender Export Pro / POV-Ray Export — export the 3D scene as a Blender Python script or POV-Ray scene file for external rendering.
-
CIF Viewer — opens
.cifcrystal structure files (visualization only; see its dedicated page). -
Cube File Viewer / Cube File Viewer Advanced / Mapped Cube Viewer / Orbital Comparator — open Gaussian
.cubevolumetric-data files. -
Gaussian FCHK Loader / Gaussian Freq Analyzer / Gaussian MO Analyzer — open Gaussian
.fchk/.fch/.fckfiles. -
ORCA Result Analyzer / ORCA Freq Analyzer — open ORCA
.outoutput files. -
Encrypted Project — adds a password-protected
.pmeencsave/load format (AES-128). - DECIMER Image Importer — imports structures from PNG/JPG images via deep-learning OCSR.
- User Manual — walkthrough of the File menu in context
- Command-Line Options — opening a file directly from the command line
- Official Plugins — every plugin that adds an additional format