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

Capture caller frame of napari.run() when starting the console. #18

Merged
merged 11 commits into from
Sep 19, 2024

Conversation

Carreau
Copy link
Contributor

@Carreau Carreau commented Mar 7, 2022

Should fix napari/napari#4098
Replaces napari/napari#4140, and see discussion there as well
Needs napari/napari#4212

Copy link
Contributor

@alisterburt alisterburt left a comment

Choose a reason for hiding this comment

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

napari/napari#4212 has merged now, should we merge this too @Carreau? Changes look good to me, although there are a few strange extra blank lines :)

@psobolewskiPhD

This comment was marked as outdated.

@codecov
Copy link

codecov bot commented Dec 21, 2022

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 90.38%. Comparing base (29b68a3) to head (94e8cbc).
Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main      #18      +/-   ##
==========================================
+ Coverage   87.60%   90.38%   +2.78%     
==========================================
  Files           4        4              
  Lines         121      156      +35     
==========================================
+ Hits          106      141      +35     
  Misses         15       15              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@psobolewskiPhD
Copy link
Member

I installed this PR branch and napari main. No more errors, but I must be missing something, because, I made a script:

import napari
a = 3
b = 4
viewer = napari.Viewer()
c = 5
napari.run()

I was expecting c to be available in the napari console, but it's not.
🤔

@Carreau
Copy link
Contributor Author

Carreau commented Dec 21, 2022 via email

@psobolewskiPhD
Copy link
Member

Ah, I assumed it would be stuff after the viewer.
But checking again, a and b arn't available either.
☹️

@Carreau
Copy link
Contributor Author

Carreau commented Dec 22, 2022

Yeah, I forgot to push...

@Carreau
Copy link
Contributor Author

Carreau commented Dec 22, 2022

Or technically I pushed, but did not commit, so it pushed nothing.

@brisvag
Copy link
Contributor

brisvag commented Dec 22, 2022

I was expecting c to be available in the napari console, but it's not.

that would be great too, but probably more complicated cause it requires back and forth communication?

@psobolewskiPhD
Copy link
Member

Or technically I pushed, but did not commit, so it pushed nothing.

Ah! I'm so pleased it wasn't me screwing something up again! 😊
Anyhow, refreshing the branch and it works perfectly:

a
Out[1]: 3

b
Out[2]: 4

c
Out[3]: 5

Copy link
Contributor

@Czaki Czaki left a comment

Choose a reason for hiding this comment

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

I have mixed feelings. It is really nice in the context of scripts or notebooks.

But for example, PartSeg allow opening napari viewer from the view menu. And with this PR the context of this method is pushed:

https://github.com/4DNucleome/PartSeg/blob/3f8f3bc56e1fa055f65d428b1d9e6d776af8ae37/package/PartSeg/common_gui/main_window.py#L230-L235

I do not feel that it is proper behavior.

@@ -55,6 +58,14 @@ def str_to_rgb(arg):
asyncio.set_event_loop_policy(WindowsSelectorEventLoopPolicy())


def _not_napari(n: int, frame: FrameType):
# in-n-out is used in napari for dependency injection.
for pref in ["napari", "in_n_out"]:
Copy link
Contributor

Choose a reason for hiding this comment

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

What with modules named napari-something?

Copy link
Member

Choose a reason for hiding this comment

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

should we change these to

Suggested change
for pref in ["napari", "in_n_out"]:
for pref in ["napari.", "in_n_out."]:

then?

@psobolewskiPhD
Copy link
Member

@Czaki can you elaborate what is the issue with your PartSeg use case?
Does it maybe make sense to have the console disabled in that case?

@Czaki
Copy link
Contributor

Czaki commented Jan 13, 2023

@Czaki can you elaborate what is the issue with your PartSeg use case?

exporting internal application variables to the console. (It could be easily workaround - for a person like me who understands napari internals)

Does it maybe make sense to have the console disabled in that case?

I use it regularly in the context of debugging and development. And some person uses it to perform actions not possible by GUI (ex layer scale).

@psobolewskiPhD
Copy link
Member

Gotcha. Makes sense. Maybe we need an argument to not do this when launching napari?
Even from a script someone may not want the variables passed?

@jni
Copy link
Member

jni commented Feb 23, 2023

Can we try to push this over the line? Todos:

  • check my suggestion on the prefixes
  • figure out solution for libraries that use napari as an internal tool; two half-baked suggestions:
    • add a "max_depth=1" kwarg for the frame, so that this only works for scripts (depth=0) and a single function (depth=1), but is easily configurable if we find that doesn't cover everything. (Not sure whether this works in IPython?)
    • add a "blacklist" of modules where we don't do this, including partseg

For point 2, I wouldn't mind leaving it to a later PR, as this is already extremely useful.

@Czaki
Copy link
Contributor

Czaki commented Feb 23, 2023

I like option 1.

I'm not the favorite of option 2. It should be rather information in the documentation that will inform about this and suggest ways to workaround it. (maybe such variable _not_incude_in_napari_console=True).

Czaki added a commit to napari/napari that referenced this pull request Jun 15, 2023
# Description
Currently, if
[`update_console`](https://github.com/napari/napari/blob/7117d22e4baa740864762454911dc5ed09764ccc/napari/viewer.py#L88)
is called on viewer object before the console is instantiated the
function does nothing. With this PR instead references to the requested
variables are added to a `console_backlog` list attribute on qt_viewer.
If and when console is instantiated these variables are pushed.

Unsure if [this related
PR](napari/napari-console#18) is moving forward
and whether it would solve this case.

## Type of change

- [x] Enhancment

# References
Closes #4098

# How has this been tested?
- [x] Ran unit tests for `napari/_qt`. There were some errors but looked
unrelated to my changes.
- [x] Added unit test based on existing `test_update_console`

## Final checklist:
- [x] My PR is the minimum possible work for the desired functionality
- [x] I have commented my code, particularly in hard-to-understand areas
- [x] I have made corresponding changes to the documentation
- [x] I have added tests that prove my fix is effective or that my
feature works

---------

Co-authored-by: Peter Sobolewski <[email protected]>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Grzegorz Bokota <[email protected]>
Co-authored-by: Juan Nunez-Iglesias <[email protected]>
Czaki added a commit to napari/napari that referenced this pull request Jun 19, 2023
Currently, if
[`update_console`](https://github.com/napari/napari/blob/7117d22e4baa740864762454911dc5ed09764ccc/napari/viewer.py#L88)
is called on viewer object before the console is instantiated the
function does nothing. With this PR instead references to the requested
variables are added to a `console_backlog` list attribute on qt_viewer.
If and when console is instantiated these variables are pushed.

Unsure if [this related
PR](napari/napari-console#18) is moving forward
and whether it would solve this case.

- [x] Enhancment

Closes #4098

- [x] Ran unit tests for `napari/_qt`. There were some errors but looked
unrelated to my changes.
- [x] Added unit test based on existing `test_update_console`

- [x] My PR is the minimum possible work for the desired functionality
- [x] I have commented my code, particularly in hard-to-understand areas
- [x] I have made corresponding changes to the documentation
- [x] I have added tests that prove my fix is effective or that my
feature works

---------

Co-authored-by: Peter Sobolewski <[email protected]>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Grzegorz Bokota <[email protected]>
Co-authored-by: Juan Nunez-Iglesias <[email protected]>
Czaki added a commit to napari/napari that referenced this pull request Jun 21, 2023
Currently, if
[`update_console`](https://github.com/napari/napari/blob/7117d22e4baa740864762454911dc5ed09764ccc/napari/viewer.py#L88)
is called on viewer object before the console is instantiated the
function does nothing. With this PR instead references to the requested
variables are added to a `console_backlog` list attribute on qt_viewer.
If and when console is instantiated these variables are pushed.

Unsure if [this related
PR](napari/napari-console#18) is moving forward
and whether it would solve this case.

- [x] Enhancment

Closes #4098

- [x] Ran unit tests for `napari/_qt`. There were some errors but looked
unrelated to my changes.
- [x] Added unit test based on existing `test_update_console`

- [x] My PR is the minimum possible work for the desired functionality
- [x] I have commented my code, particularly in hard-to-understand areas
- [x] I have made corresponding changes to the documentation
- [x] I have added tests that prove my fix is effective or that my
feature works

---------

Co-authored-by: Peter Sobolewski <[email protected]>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Grzegorz Bokota <[email protected]>
Co-authored-by: Juan Nunez-Iglesias <[email protected]>
Czaki added a commit to napari/napari that referenced this pull request Jun 21, 2023
Currently, if
[`update_console`](https://github.com/napari/napari/blob/7117d22e4baa740864762454911dc5ed09764ccc/napari/viewer.py#L88)
is called on viewer object before the console is instantiated the
function does nothing. With this PR instead references to the requested
variables are added to a `console_backlog` list attribute on qt_viewer.
If and when console is instantiated these variables are pushed.

Unsure if [this related
PR](napari/napari-console#18) is moving forward
and whether it would solve this case.

- [x] Enhancment

Closes #4098

- [x] Ran unit tests for `napari/_qt`. There were some errors but looked
unrelated to my changes.
- [x] Added unit test based on existing `test_update_console`

- [x] My PR is the minimum possible work for the desired functionality
- [x] I have commented my code, particularly in hard-to-understand areas
- [x] I have made corresponding changes to the documentation
- [x] I have added tests that prove my fix is effective or that my
feature works

---------

Co-authored-by: Peter Sobolewski <[email protected]>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Grzegorz Bokota <[email protected]>
Co-authored-by: Juan Nunez-Iglesias <[email protected]>
Czaki added a commit to napari/napari that referenced this pull request Jun 21, 2023
Currently, if
[`update_console`](https://github.com/napari/napari/blob/7117d22e4baa740864762454911dc5ed09764ccc/napari/viewer.py#L88)
is called on viewer object before the console is instantiated the
function does nothing. With this PR instead references to the requested
variables are added to a `console_backlog` list attribute on qt_viewer.
If and when console is instantiated these variables are pushed.

Unsure if [this related
PR](napari/napari-console#18) is moving forward
and whether it would solve this case.

- [x] Enhancment

Closes #4098

- [x] Ran unit tests for `napari/_qt`. There were some errors but looked
unrelated to my changes.
- [x] Added unit test based on existing `test_update_console`

- [x] My PR is the minimum possible work for the desired functionality
- [x] I have commented my code, particularly in hard-to-understand areas
- [x] I have made corresponding changes to the documentation
- [x] I have added tests that prove my fix is effective or that my
feature works

---------

Co-authored-by: Peter Sobolewski <[email protected]>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Grzegorz Bokota <[email protected]>
Co-authored-by: Juan Nunez-Iglesias <[email protected]>
@jni
Copy link
Member

jni commented Oct 16, 2023

If you yourself are happy with your proposal can you dismiss your review and we can merge? 😃

@Czaki Czaki dismissed their stale review October 16, 2023 08:01

implemented

@Czaki
Copy link
Contributor

Czaki commented Oct 16, 2023

@jni I have added tests and updated the readme. Could you check it?

@jni
Copy link
Member

jni commented Oct 16, 2023

Well the tests seem unhappy... 😅

@Czaki
Copy link
Contributor

Czaki commented Oct 16, 2023

Well the tests seem unhappy... 😅

I forget that there is a global state in the console, so names in tests cannot collide.

@jni
Copy link
Member

jni commented Oct 16, 2023

I updated the README message to include a usage example.

Comment on lines +53 to +56
If you want to disable this behavior (for example, because you are embedding
napari and the console within some larger application), you can add
`NAPARI_EMBED=1` to your environment variables before instantiating the
console.
Copy link
Contributor

Choose a reason for hiding this comment

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

This is not true. I implement it as global module-level variable, not an environment variable. Should I change it?

Copy link
Member

Choose a reason for hiding this comment

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

Oh! Sorry. I did read that and thought you misspoke. 😅 I think I prefer this way because it's easier to describe and quite a common way to change functionality. Otherwise you have to make sure that the global is accessible in the correct frame, which is not something people are used to thinking about, I think? 🤷

Copy link
Contributor

Choose a reason for hiding this comment

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

yes, but environment variable is global per process, and module level variable is in module.

If someone would like first spawn PartSeg and then napari, If I use an environment variable, then it will prevent variable propagation in follow-up napari start.

If using module-level variable it impacts only possible console spawn when open console from napari embedded here. But will not impact napari spawned from the top-level script.

Comment on lines +163 to +166
Predicates that return Wether we are in napari by looking
at:
1) the frames modules names:
2) the min_depth
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
Predicates that return Wether we are in napari by looking
at:
1) the frames modules names:
2) the min_depth
Determines whether we are in napari by looking at:
1) the frames modules names:
2) the min_depth

@jni
Copy link
Member

jni commented Oct 18, 2023

The only dodgy one is action_manager at the bottom, dunno what's going on there...

(from me at #18 (comment))

@Carreau it looks like that was added by you in napari/napari#2677 without any discussion. I see now in the PR description your comment, "I also inject action_manager in the qtconsole context, so one does not have to import it everytime", but in general I think the action manager is not really a user-facing object, even though it is convenient for people developing specific things. Was that for debugging and can it be removed? (This would be for 0.5.0 or later in any case...)

@Carreau
Copy link
Contributor Author

Carreau commented Nov 6, 2023

I see now in the PR description your comment, "I also inject action_manager in the qtconsole context, so one does not have to import it everytime",

I belive this was done before we had the shortcut editor so we needed a way to edit shortcuts is a relatively friendly way.

@jni
Copy link
Member

jni commented Dec 16, 2023

Well, I suggest that we merge this and fix the action_manager injection in another PR.

@jni
Copy link
Member

jni commented Dec 16, 2023

(It would be cool to simul-release this improvement with 0.4.19!)

@Carreau Carreau closed this Sep 16, 2024
@jni jni reopened this Sep 18, 2024
@jni jni merged commit 2148590 into napari:main Sep 19, 2024
9 checks passed
@jni
Copy link
Member

jni commented Sep 19, 2024

Shit, I should have tested this again before merging 😅

Right now when I run python examples/add_labels.py, I see the viewer, np, napari, and some IPython stuff:

In [1]: locals()
Out[1]: 
{'__name__': '__main__',
 '__doc__': 'Automatically created module for IPython interactive environment',
 '__package__': None,
 '__loader__': None,
 '__spec__': None,
 '__builtin__': <module 'builtins' (built-in)>,
 '__builtins__': <module 'builtins' (built-in)>,
 '_ih': ['', 'locals()'],
 '_oh': {},
 '_dh': [PosixPath('/Users/jni/projects/napari')],
 'In': ['', 'locals()'],
 'Out': {},
 'get_ipython': <bound method InteractiveShell.get_ipython of <ipykernel.inprocess.ipkernel.InProcessInteractiveShell object at 0x301fd1310>>,
 'exit': <IPython.core.autocall.ZMQExitAutocall at 0x3030068d0>,
 'quit': <IPython.core.autocall.ZMQExitAutocall at 0x3030068d0>,
 'open': <function io.open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)>,
 '_': '',
 '__': '',
 '___': '',
 'viewer': Viewer(camera=Camera(center=(0.0, np.float64(101.0), np.float64(141.5)), zoom=np.float64(1.7528169014084505), angles=(0.0, 0.0, 90.0), perspective=0.0, mouse_pan=True, mouse_zoom=True), cursor=Cursor(position=(1.0, 1.0), scaled=True, style=<CursorStyle.STANDARD: 'standard'>, size=np.float64(10.0)), dims=Dims(ndim=2, ndisplay=2, order=(0, 1), axis_labels=('0', '1'), rollable=(True, True), range=(RangeTuple(start=np.float64(0.0), stop=np.float64(202.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(283.0), step=np.float64(1.0))), margin_left=(0.0, 0.0), margin_right=(0.0, 0.0), point=(np.float64(101.0), np.float64(141.0)), last_used=0), grid=GridCanvas(stride=1, shape=(-1, -1), enabled=False), layers=[<Image layer 'coins' at 0x1750fa190>, <Labels layer 'segmentation' at 0x1750f9a50>], help='use <7> for transform, use <1> for activate the label eraser, use <2> for activate the paint brush, use <3> for activate the polygon tool, use <4> for activate the fill bucket, use <5> for pick mode', status='Ready', tooltip=Tooltip(visible=False, text=''), theme='dark', title='napari', mouse_over_canvas=False, mouse_move_callbacks=[], mouse_drag_callbacks=[], mouse_double_click_callbacks=[], mouse_wheel_callbacks=[<function dims_scroll at 0x1647e4040>], _persisted_mouse_event={}, _mouse_drag_gen={}, _mouse_wheel_gen={}, _keymap={}),
 'napari': <module 'napari' from '/Users/jni/projects/napari/napari/__init__.py'>,
 'action_manager': <napari.utils.action_manager.ActionManager at 0x15e051910>,
 'np': <module 'numpy' from '/Users/jni/micromamba/envs/all/lib/python3.11/site-packages/numpy/__init__.py'>,
 '_i': '',
 '_ii': '',
 '_iii': '',
 '_i1': 'locals()'}

I wonder if this commit broke things?

5339095

@jni
Copy link
Member

jni commented Sep 19, 2024

Indeed changing this:

if c.frame.f_globals.get("__name__", "") != "__main__" and "NAPARI_EMBED" not in c.frame.f_globals:

to

if "NAPARI_EMBED" not in c.frame.f_globals:

fixes it again. I'll make a PR, since I don't think the first part is necessary (?) @Czaki

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.

update_console example is broken
6 participants