Skip to content

Conversation

@pslacerda
Copy link
Contributor

A write a bunch of tests and did my best to achieve best ergonomic API.

Only optional (None) data is still failing in some cases.

image

@pslacerda pslacerda mentioned this pull request Apr 12, 2025
@JarrettSJohnson
Copy link
Member

I'll ask if we can maintain our pattern of keeping tests in testing (rather than adding tests in module).

@pslacerda
Copy link
Contributor Author

Sorry, it was my bad. I'll tackle this in a few days.

@pslacerda pslacerda force-pushed the declare_command branch 2 times, most recently from 80eb0ce to 7c9f7ff Compare May 13, 2025 15:41
@pslacerda
Copy link
Contributor Author

@JarrettSJohnson I'd like to ask, should I proceed and refactor existing commands to adhere the declare_command API?

@pslacerda
Copy link
Contributor Author

The first step is to refactor the help command to also support this API.

@JarrettSJohnson
Copy link
Member

@JarrettSJohnson I'd like to ask, should I proceed and refactor existing commands to adhere the declare_command API?

We can address that in a separate PR, if possible. Also I think some things were accidentally deleted, perhaps during the merging process? (e.g. testDeleteStates)

@pslacerda
Copy link
Contributor Author

The tip of branch were based on an old commit. It took me several hours to finish this git chore task.

Copy link
Member

@JarrettSJohnson JarrettSJohnson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally looks fine to me, I was under the impression from the original PR that this would just be for extended, custom functions rather than native ones. I'm a little hesitant to change current commands just yet. I still need to play around with this first to ensure no functional changes.

@@ -1,50 +0,0 @@
import sys
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this file intended to be removed here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Is it ok?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please keep for now since we still have code that uses this pattern.

@pslacerda
Copy link
Contributor Author

I still need to play around with this first to ensure no functional changes.

Me too. Except for the help command which I want to adjust soon, I'll take a time before any progress.

@pslacerda
Copy link
Contributor Author

If I remove the docs-on-comment feature will this be merged faster?

@JarrettSJohnson
Copy link
Member

Apologies. Give me until the weekend, and I'll come back to this review. My involvement with incentive and open-source comes in waves, and I'm still pretty deep in 3.2/3.3 work.

@pslacerda
Copy link
Contributor Author

I think this is important to get merged before 3.2 because otherwise will have a delay starting in the current incomplete feature awaiting 3.3.

@@ -1,50 +0,0 @@
import sys
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please keep for now since we still have code that uses this pattern.

break
i += 1
else:
i -= 3
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think I follow this line

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Me neither, I just placed it here because was needed. I'd need to debug to remember exactly, but seems to me that it's related to rewind the cursor i when no doc is found.


raise pymol.CmdException(f"Unsupported argument type {type}")

def parse_documentation(func):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this function probably needs its own unit test as well. The API to me is not inherently clear.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is tested integrated with declare_command on test_declare_command_arg_docs.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand, but something like this probably deserves its own test too if possible. I'll make it optional, but I will likely add it later.

@pslacerda
Copy link
Contributor Author

pslacerda commented Jul 23, 2025

Give me some days and I'll fix according to your review.

As nobody is using this yet, including me, may cmd.declare_command be renamed to cmd.new or cmd.new_command?

@JarrettSJohnson
Copy link
Member

Sure. new_command is fine. We already make use of cmd._new privately and it would be good for us not to be confused with the two.

@pslacerda1
Copy link
Contributor

Hi @JarrettSJohnson!

I lost the access to my old Github account. I'm using this new one for now. However I couldn't get open-source PyMOL working on pip editable (link) mode (pip install -e .). Can you show me how to get pytest working so I can further work on this feature?

@JarrettSJohnson
Copy link
Member

Does normal pip install . work for you?

Also, you should just be able to run a test like:

python testing/testing.py --run testing/tests/api/test_viewing.py

But if you run all tests, unittest and pytest should all just run automatically.

@pslacerda1
Copy link
Contributor

I'm on a recent Debian and installed pyqt6-dev via default repositories. No way to get PyMOL working with Qt.

Qt not available (pymol.Qt), using GLUT/Tk interface
Traceback (most recent call last):
  File "/home/peu/Desktop/pymol-open-source/venv/bin/pymol", line 8, in <module>
    sys.exit(launch())
             ^^^^^^^^
  File "/home/peu/Desktop/pymol-open-source/venv/lib/python3.11/site-packages/pymol/__init__.py", line 429, in launch
    _cmd.runpymol(None, block_input_hook)
NotImplementedError: compile with --glu

@pslacerda1
Copy link
Contributor

I'm on a recent Debian install with default apt repositories. How to fix it?

PyMOL(TM) Molecular Graphics System, Version 3.2.0a.
 Copyright (c) Schrodinger, LLC.
 All Rights Reserved.

    Created by Warren L. DeLano, Ph.D.

    PyMOL is user-supported open-source software.  Although some versions
    are freely available, PyMOL is not in the public domain.

    If PyMOL is helpful in your work or study, then please volunteer
    support for our ongoing efforts to create open and affordable scientific
    software by purchasing a PyMOL Maintenance and/or Support subscription.

    More information can be found at "http://www.pymol.org".

    Enter "help" for a list of commands.
    Enter "help <command-name>" for information on a specific command.

 Hit ESC anytime to toggle between text and graphics.

 Detected OpenGL version 4.6. Shaders available.
 Detected GLSL version 4.60.
 OpenGL graphics engine:
  GL_VENDOR:   Intel
  GL_RENDERER: Mesa Intel(R) Xe Graphics (TGL GT2)
  GL_VERSION:  4.6 (Compatibility Profile) Mesa 22.3.6
 Detected 8 CPU cores.  Enabled multithreaded rendering.
PyMOL>set fetch_path, /home/peu/.local/share/PyMOL/fetch-path
 Setting: fetch_path set to /home/peu/.local/share/PyMOL/fetch-path.

GL_ERROR : 0x0506 GenericBuffer::genBuffer failed

GL_ERROR : 0x0502 GLTextureBuffer::texture_subdata_2D failed
PyMOL>ray 628, 463, async=1
 Ray: render time: 0.00 sec. = 1273896.4 frames/hour (0.00 sec. accum.).
GL_ERROR : 0x0502 GenericBuffer::genBuffer failed

PyMOL>draw 628, 463
GL_ERROR : 0x0502 GenericBuffer::genBuffer failed

GL_ERROR : 0x0506 GenericBuffer::genBuffer failed

GL_ERROR : 0x0502 GenericBuffer::genBuffer failed

GL_ERROR : 0x0506 GenericBuffer::genBuffer failed

GL_ERROR : 0x0506 GenericBuffer::genBuffer failed

GL_ERROR : 0x0506 GenericBuffer::genBuffer failed

PyMOL>wizard appearance
GL_ERROR : 0x0506 GLTextureBuffer::texture_subdata_2D failed
QThreadStorage: entry 3 destroyed before end of thread 0x1ce23f90
QThreadStorage: entry 1 destroyed before end of thread 0x1ce23f90
QThreadStorage: entry 0 destroyed before end of thread 0x1ce23f90
image

@ye11owSub
Copy link
Contributor

Hi @pslacerda1!

I don't have a Debian machine available at the moment, but maybe one of these solutions will help you.
You can try installing pyqt as a Python library using the command pip install pyqt5 or you can install the entire project by running the command pip install '.[dev]'(this will automatically install pyside6 as one of the dependencies)

изображение

@pslacerda1
Copy link
Contributor

Hi, sorry for the slow response. I still can't fully start PyMOL open-source because I'm not seeing anything on the "canvas".

GL_ERROR : 0x0506 GenericBuffer::genBuffer failed
GL_ERROR : 0x0502 GLTextureBuffer::texture_subdata_2D failed
PyMOL>ray 628, 463, async=1
 Ray: render time: 0.00 sec. = 2007911.5 frames/hour (0.00 sec. accum.).
GL_ERROR : 0x0502 GenericBuffer::genBuffer failed
image

@JarrettSJohnson
Copy link
Member

Not sure about this, unfortunately. Does the latest Incentive version also show the same issue? Also does set use_shaders, 0 show any difference?

@pslacerda1
Copy link
Contributor

Incentive PyMOL and pymol-open-source starts like this same. However incentive continue and works while open-source fails.

 Detected OpenGL version 4.6. Shaders available.
 Detected GLSL version 4.60.
 OpenGL graphics engine:
  GL_VENDOR:   Intel
  GL_RENDERER: Mesa Intel(R) Xe Graphics (TGL GT2)
  GL_VERSION:  4.6 (Compatibility Profile) Mesa 22.3.6
 Detected 8 CPU cores.  Enabled multithreaded rendering.

@JarrettSJohnson
Copy link
Member

No changes with the use_shaders setting, and it's up to date with master? I recently pulled in some changes to keep the graphics changes similar to Incentive.

@pslacerda1
Copy link
Contributor

Yes, I'm synced to master.

@pslacerda1
Copy link
Contributor

pslacerda1 commented Oct 9, 2025

Please, provide me the hashes of your commits?

What I tried? I checkout and tried to build & run master and tag v3.1.0. Master starts without anything related to GL, v3.1.0 pop up on the screen and closes instantaneously.

@pslacerda1
Copy link
Contributor

Good and bad news: I was attempting to use the wrong Qt version. The correct is Qt5 for PyMOL 3.1 and Qt6 for PyMOL 3.2. The bad one is that I couldn't run all pytests from tests/testing/api anymore.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR introduces improvements to the @cmd.declare_command API to provide better ergonomics for command declaration and type casting. The changes focus on enhancing the command declaration system with more robust type handling and documentation parsing capabilities.

  • Replaced the previous test file for API helping functionality with comprehensive command declaration tests
  • Enhanced the declare_command decorator with improved type casting and argument handling
  • Added support for complex types including Optional, Union, Tuple, Enum, and generic types

Reviewed Changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 6 comments.

File Description
testing/tests/api/helping.py Completely removed the help API test file
testing/tests/api/commanding.py Added extensive tests for the new command declaration API with various type scenarios
modules/pymol/commanding.py Implemented enhanced type casting system and argument documentation parsing for command declarations

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.


@cmd.declare_command
def func(a: Optional[int] = None):
assert a is 10
Copy link

Copilot AI Oct 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use == for value comparison instead of is. The is operator checks for object identity, not equality, and may not work reliably for integers.

Suggested change
assert a is 10
assert a == 10

Copilot uses AI. Check for mistakes.

def _parse_list_int(value):
return list(map(int, shlex.split(value)))
elif isinstance(type, Enum):
Copy link

Copilot AI Oct 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This condition will never be true. type is a type annotation, not an instance of Enum. Use inspect.isclass(type) and issubclass(type, Enum) to check if the type is an Enum class.

Copilot uses AI. Check for mistakes.
else:
raise pymol.CmdException(f"Invalid value for enum {type.__name__}: {value}")

elif isinstance(type, builtins.type):
Copy link

Copilot AI Oct 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This condition is too broad and may incorrectly handle type annotations. Consider using more specific type checking logic or inspect.isclass() for better type validation.

Suggested change
elif isinstance(type, builtins.type):
elif inspect.isclass(type):

Copilot uses AI. Check for mistakes.
while True:
i += 1
if tokens[i].string == "def":
while tokens[i].string == "(":
Copy link

Copilot AI Oct 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will cause an infinite loop if the opening parenthesis is found, as the condition never changes. The logic should find the opening parenthesis and then break or continue processing.

Suggested change
while tokens[i].string == "(":
if tokens[i].string == "(":

Copilot uses AI. Check for mistakes.
Comment on lines +709 to +713
if tokens[i].type == tokenize.NAME and tokens[i+1].string == ":":
name = tokens[i].string
name_line = tokens[i].line
i += 1
while not (tokens[i].type == tokenize.NAME and tokens[i+1].string == ":"):
Copy link

Copilot AI Oct 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This loop may cause an IndexError when accessing tokens[i+1] if i reaches the end of the tokens list. Add bounds checking before accessing tokens[i+1].

Suggested change
if tokens[i].type == tokenize.NAME and tokens[i+1].string == ":":
name = tokens[i].string
name_line = tokens[i].line
i += 1
while not (tokens[i].type == tokenize.NAME and tokens[i+1].string == ":"):
if tokens[i].type == tokenize.NAME and (i+1 < len(tokens)) and tokens[i+1].string == ":":
name = tokens[i].string
name_line = tokens[i].line
i += 1
while not (tokens[i].type == tokenize.NAME and (i+1 < len(tokens)) and tokens[i+1].string == ":"):

Copilot uses AI. Check for mistakes.
_self.keyword[name] = [inner, 0, 0, ",", parsing.STRICT]
_self.kwhash.append(name)
_self.help_sc.append(name)
_self.keyword[name] = [inner, 0,0,',',parsing.STRICT]
Copy link

Copilot AI Oct 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Inconsistent spacing around commas. Should be [inner, 0, 0, ',', parsing.STRICT] to match Python style conventions.

Suggested change
_self.keyword[name] = [inner, 0,0,',',parsing.STRICT]
_self.keyword[name] = [inner, 0, 0, ',', parsing.STRICT]

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants