Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add mechanism to reload Cpython modules and mark graph dirty #11714

Merged
merged 17 commits into from
Jun 3, 2021

Conversation

mjkkirschner
Copy link
Member

@mjkkirschner mjkkirschner commented May 27, 2021

Purpose

https://jira.autodesk.com/browse/DYN-3514
https://jira.autodesk.com/browse/DYN-2941

Update:

To help dynamo users who write their own python modules in cpython deal with the difference in module import/reload between cpython and ironPython- this PR adds a button to Reset CPython. What it does is to reload python modules that are backed by a .py file and are not named __main__ and a few other checks inspired by autoreload
https://ipython.org/ipython-doc/3/config/extensions/autoreload.html

The implementation is a subset of what autoreload does:

  • modules that have .py files are reloaded - modules that are reloaded, are logged to the console:
    ie:
2021-05-28 22:18:42Z : Python Script: considering reload_test3
2021-05-28 22:18:42Z : Python Script: reloading reload_test3
2021-05-28 22:18:42Z : Python Script: failed to reload reload_test3 spec not found for the module 'reload_test3'
2021-05-28 22:18:42Z : Python Script: considering importlib._bootstrap
2021-05-28 22:18:42Z : Python Script: considering importlib._bootstrap_external
2021-05-28 22:18:42Z : Python Script: considering importlib
2021-05-28 22:18:42Z : Python Script: considering importlib.machinery
2021-05-28 22:18:42Z : Python Script: considering importlib.abc
2021-05-28 22:18:42Z : Python Script: considering contextlib
2021-05-28 22:18:42Z : Python Script: considering importlib.util
2021-05-28 22:18:42Z : Python Script: considering pprint

Currently, after the modules are reloaded, the Dynamo engine is reset and all nodes are marked dirty - this is very likely overkill. I think we would be safe simply marking the nodes dirty in topological order or disabling execution, marking all nodes dirty, and then re-enabling execution.
The goal is to have the DS GC collect the old objects created with out dated modules, the easiest way to do this is to rerun the graph.

also:

  • I had to change the use of python thread macros and lock code we started using in this PR: Tests for CPython3 Engine as well as for IronPython. #10631 - I think it was a bit confused (passing a pointer from the GIL mutex to a macro that expected a pointer to a different mutex).

  • I ended up using static internal events to avoid having any references on DSCPython or PythonNet in DynamoCore/DynamoCoreWPF - I guess I could also use interfaces and a singleton or something. Feedback welcome there.

  • Modified the style for flatButton so that its center aligned @Jingyi-Wen fyi. (that affects the group add stye button)

Screen Shot 2021-06-01 at 4 30 19 PM

Screen Shot 2021-06-01 at 3 53 08 PM

Screen Shot 2021-06-02 at 1 29 02 PM

TODO:

Declarations

Check these if you believe they are true

  • The codebase is in a better state after this PR
  • Is documented according to the standards
  • The level of testing this PR includes is appropriate
  • User facing strings, if any, are extracted into *.resx files
  • All tests pass using the self-service CI.
  • Snapshot of UI changes, if any.
  • Changes to the API follow Semantic Versioning and are documented in the API Changes document.
  • This PR modifies some build requirements and the readme is updated

raise event from button
handle event in cpython engine
fix python thread macros - no need for double lock.
mixing thread state and gil state.
shutdown when requested
fix tests.
@Jingyi-Wen
Copy link

@mjkkirschner The location of the restart button makes sense! For the button style, could we not have the outline?
In HIG, the default state of the flat button is without outline (so should look the same as the "Add style" button).

@mjkkirschner
Copy link
Member Author

@mjkkirschner The location of the restart button makes sense! For the button style, could we not have the outline?
In HIG, the default state of the flat button is without outline (so should look the same as the "Add style" button).

Hey @Jingyi-Wen yep it looks just like the Add Style button - I used the same style, I was just hovering over it when I took the screenshot.

@Jingyi-Wen
Copy link

@mjkkirschner The location of the restart button makes sense! For the button style, could we not have the outline?
In HIG, the default state of the flat button is without outline (so should look the same as the "Add style" button).

Hey @Jingyi-Wen yep it looks just like the Add Style button - I used the same style, I was just hovering over it when I took the screenshot.

Got it. Looks good then!

resx for add style
resx for restart
resx for tooltip on restart button
logging re enabled
add failing test
modify tests to use different module names to avoid moving on disk error - missing mod spec
remove extra python
change tooltips and button text
update tests
fix bug with engine name
@mjkkirschner mjkkirschner changed the title WIP add a restart cpython engine button to python prefs add a reset cpython button to python prefs Jun 1, 2021
@mjkkirschner mjkkirschner changed the title add a reset cpython button to python prefs add mechanism to reload Cpython modules and mark graph dirty Jun 1, 2021
@@ -119,125 +119,6 @@ public partial class DynamoModel : IDynamoModel, IDisposable, IEngineControllerM

#endregion

#region events
Copy link
Member Author

@mjkkirschner mjkkirschner Jun 1, 2021

Choose a reason for hiding this comment

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

moved all DynamoModel events to DynamoModelEvents.cs file.

@@ -2390,4 +2390,13 @@ Uninstall the following packages: {0}?</value>
<data name="PreferencesViewEnableNodeAutoCompleteTooltipText" xml:space="preserve">
<value>Learn more about Node Autocomplete feature.</value>
</data>
<data name="AddStyleButton" xml:space="preserve">
<value>Add Style</value>
Copy link
Member Author

Choose a reason for hiding this comment

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

this was missing a resx property.

@mjkkirschner mjkkirschner requested review from pinzart90 and sm6srw June 1, 2021 20:37
@mjkkirschner mjkkirschner added PTAL Please Take A Look 👀 and removed WIP labels Jun 1, 2021
if (CurrentWorkspace is HomeWorkspaceModel hmwsm)
{
RequestPythonReset?.Invoke(pythonEngine);
ResetEngine(true);
Copy link
Member Author

Choose a reason for hiding this comment

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

I think this is probably overkill, but this function is only triggered manually for now.

Copy link
Contributor

Choose a reason for hiding this comment

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

by manually you mean via new button in preferences ?
When/if we move to something more reactive/automated....we will probably want to reset only the nodes that are affected by the .py reloads right ?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, that would be the ideal - BUT identifying those nodes without creating a circular reference is kind of a pain - we can use reflection or string matching if necessary.

Copy link
Contributor

Choose a reason for hiding this comment

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

so by re executing all the nodes we are also taking care (refreshing) of potentially dangling objects that might still reference the old python files right ?

Copy link
Member Author

Choose a reason for hiding this comment

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

yes

<value>Reset CPython</value>
</data>
<data name="ResetCPythonButtonToolTip" xml:space="preserve">
<value>Resets CPython environment by reloading modules.</value>
Copy link
Contributor

Choose a reason for hiding this comment

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

does this need to be more descriptive ?
all modules ? or some ? do we need to be specific I wonder ...

Copy link
Member Author

Choose a reason for hiding this comment

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

thanks @pinzart90 - I was thinking to leave it a bit intentionally vague at this point so we can adjust it easily, but we could specify modules that have file attributes?

Copy link
Contributor

Choose a reason for hiding this comment

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

not sure....maybe vague here and more specific in some dynamoDS wiki ?

Copy link
Member Author

@mjkkirschner mjkkirschner Jun 3, 2021

Choose a reason for hiding this comment

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


IntPtr gs = PythonEngine.AcquireLock();
try
{
Copy link
Contributor

Choose a reason for hiding this comment

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

this lock stuff is not needed anymore ?

Copy link
Member Author

Choose a reason for hiding this comment

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

nope, I believe this is the same as using Py.GIL() - see the description and threading wiki that says as much.

fix issue with static logger reference
import importlib.util
import os
def getInfoFile(module):
if not hasattr(module, '__file__') or module.__file__ is None:
Copy link
Contributor

Choose a reason for hiding this comment

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

maybe add comments to all these filters/conditions so that we know what the intention was (in case something goes wrong)

Copy link
Member Author

Choose a reason for hiding this comment

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

good idea, will add some comments

Copy link
Contributor

Choose a reason for hiding this comment

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

where did you find documentation for these module attributes ?

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe we should add a comment (like in the importlib.reload documentation)
Reloading sys, __main__, builtins and other key modules is not recommended
https://docs.python.org/3.4/library/importlib.html#importlib.reload

Copy link
Member Author

Choose a reason for hiding this comment

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

will do - these attributes (and this function) were modified from the autoreload.py script which is why I added attribution to this library in the license and about boxes.

return py_filename


for modname,mod in sys.modules.copy().items():
Copy link
Contributor

Choose a reason for hiding this comment

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

any idea why we need to make the copy() call ?

Copy link
Member Author

Choose a reason for hiding this comment

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

yes because iterating over sys.modules and reloading modules directly modifies the keys in this dictionary during iteration.

Making a copy avoids modifying the dictionary we're iterating over.

update comments in reload snippet
@mjkkirschner
Copy link
Member Author

@pinzart90 PTAL - I've added comments, please check if they are adequate. When this is merged, I will update the wiki with specifics and note that the change has been merged.

@mjkkirschner
Copy link
Member Author

@pinzart90 this passed on the parallel job here:
https://master-5.jenkins.autodesk.com/job/Dynamo/job/DynamoSelfServe/job/pullRequestValidation/2562/
and serial one here:
https://master-15.jenkins.autodesk.com/view/DYN/job/DYN-DevCI_Self_Service/797/

though there were some flaky test failures we've seen before that occurred on the previous parallel run. I'm going to merge this, but if we see them get more frequent we can revert.
FYI @QilongTang @jasonstratton

@mjkkirschner mjkkirschner merged commit 38b57f9 into DynamoDS:master Jun 3, 2021
@mjkkirschner mjkkirschner deleted the pythonResetManual branch June 3, 2021 20:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
PTAL Please Take A Look 👀
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants