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

Let PyGMT functions support tab autocompletion #1203

Open
seisman opened this issue Apr 11, 2021 · 11 comments
Open

Let PyGMT functions support tab autocompletion #1203

seisman opened this issue Apr 11, 2021 · 11 comments
Labels
enhancement Improving an existing feature

Comments

@seisman
Copy link
Member

seisman commented Apr 11, 2021

Jupyter and most modern text editors support tab autocompletion, which is useful for typing long function and parameter names. However, currently, most PyGMT functions don't support tab autocompletion, since we use the alias system (use_alias), *args, and **kwargs. The only way I know to enable tab autocompletion is using normal Python parameters instead of relying on the **kwargs and use_alias decorator (see #262 for the original issue).

The solution seems straightforward. For example, for the pygmt.info() function, the current function is defined as:

@fmt_docstring
@use_alias(
    C="per_column",
    I="spacing",
    T="nearest_multiple",
    V="verbose",
    a="aspatial",
    f="coltypes",
    r="registration",
)
@kwargs_to_strings(I="sequence")
def info(table, **kwargs):

To make it support tab autocompletion, we just need to change the def info() part:

@fmt_docstring
@use_alias(
    C="per_column",
    I="spacing",
    T="nearest_multiple",
    V="verbose",
    a="aspatial",
    f="coltypes",
    r="registration",
)
@kwargs_to_strings(I="sequence")
def info(
    table,
    per_column=False,
    spacing=None,
    nearest_multiple=None,
    verbose=None,
    aspatial=None,
    coltypes=None,
    registration=None,
    **kwargs
):

Since all parameters are defined as normal Python parameters, tab autocompletion should work. The new function definition still keeps the **kwargs parameter, so that single-letter options are still supported (but we are likely to disallow single-letter options in future releases, see #262). Thus, this would be backward compatible, and is the first step to address #262.

The screenshots below show how the autocompletion work after applying the changes in PR #1202:

Current pygmt.info() Updated pygmt.info()
image image
image image

Please give #1202 a try and leave your thoughts.

@seisman seisman added the question Further information is requested label Apr 11, 2021
@weiji14
Copy link
Member

weiji14 commented Apr 11, 2021

Nice idea, but just wondering if there's a way to modify the @use_alias decorator to insert the keyword arguments directly (instead of duplicating work for each PyGMT module)?

@seisman
Copy link
Member Author

seisman commented Apr 11, 2021

but just wondering if there's a way to modify the @use_alias decorator to insert the keyword arguments directly (instead of duplicating work for each PyGMT module)?

Here is a quick script to list the parameters:

import pygmt
from inspect import getmembers, isfunction

for module in (pygmt, pygmt.Figure):
    for funcname in getmembers(module, isfunction):
        func = getattr(module, funcname[0])
        if hasattr(func, "aliases"):
            print(f"{funcname[0]}:")
            for arg, alias in func.aliases.items():
                print(f"    {alias}=None,")
            print("")

The output looks like this. We still need to manually copy the output parameter list into each function.

blockmean:
    spacing=None,
    region=None,
    verbose=None,
    aspatial=None,
    coltypes=None,
    registration=None,

blockmedian:
    spacing=None,
    region=None,
    verbose=None,
    aspatial=None,
    coltypes=None,
    registration=None,

grd2cpt:
    transparency=None,
    cmap=None,
    background=None,
    color_model=None,
    nlevels=None,
    truncate=None,
    output=None,
    reverse=None,
    limit=None,
    overrule_bg=None,
    no_bg=None,
    log=None,
    region=None,
    series=None,
    verbose=None,
    categorical=None,
    cyclic=None,
    continuous=None,

@seisman seisman changed the title Let PyGMT functions support tab completion Let PyGMT functions support tab autocompletion Apr 11, 2021
@seisman
Copy link
Member Author

seisman commented Apr 11, 2021

All functions are manually updated in #1202, so they should all support auto-completion now. The only exception is pygmt.config(), which needs more work.

@weiji14
Copy link
Member

weiji14 commented Apr 11, 2021

Thanks, but what I meant was to recode the @use_alias decorator to inject the keyword parameters into the functions directly. See e.g. https://code.activestate.com/recipes/577382-keyword-argument-injection-with-python-decorators/. I haven't tested it, but I think it involves adding the keyword arguments to the __dict__ attribute of the function.

@seisman
Copy link
Member Author

seisman commented Apr 12, 2021

Actually, I'm trying to fully get rid of the use_alias decorator.

@weiji14
Copy link
Member

weiji14 commented Apr 12, 2021

Actually, I'm trying to fully get rid of the use_alias decorator.

Yes, I understand that we're working towards resolving #262. There are a lot of line changes made in 998a123, much of which appears to be similar/duplicating that of the @use_alias decorator. And this is why I suggested #1203 (comment) to provide a central location tying the aliases/keyword-arguments to the function as an alternative interim solution (instead of introducing such a large diff).

Perhaps we need more discussion and ideas on the best way to proceed on this long-term issue. My argument is that this would be something for v0.5.0, and until we have an automated solution to sync upstream GMT module parameters and documentation (c.f. #895) with PyGMT, there is no way I feel comfortable with disabling single-character parameters in #262 because it would be limiting the utility of PyGMT (albeit one that is undocumented).

@seisman
Copy link
Member Author

seisman commented Apr 12, 2021

we have an automated solution to sync upstream GMT module parameters and documentation (c.f. #895) with PyGMT.

It seems an impossible task to me.

there is no way I feel comfortable with disabling single-character parameters in #262 because it would be limiting the utility of PyGMT (albeit one that is undocumented).

I agree. We probably won't be able to disable single-letter parameters until v1.0.0.

@seisman seisman added enhancement Improving an existing feature and removed question Further information is requested labels Apr 12, 2021
@willschlitzer
Copy link
Contributor

there is no way I feel comfortable with disabling single-character parameters in #262 because it would be limiting the utility of PyGMT (albeit one that is undocumented).

I agree. We probably won't be able to disable single-letter parameters until v1.0.0.

What is the push to disable single letter parameters, even at v1.0.0? I'm not a fan of single-letter parameters and think we should maximize our use of PyGMT parameter names, but does it cost us anything to remove that capability?

@willschlitzer
Copy link
Contributor

@GenericMappingTools/pygmt-maintainers Should I add the available parameters to the function itself (instead of just the @use_alias decorator) in the #1249 (histogram) in line with the proposed changes that @seisman made in #1202?

@maxrjones
Copy link
Member

maxrjones commented May 20, 2021

there is no way I feel comfortable with disabling single-character parameters in #262 because it would be limiting the utility of PyGMT (albeit one that is undocumented).

I agree. We probably won't be able to disable single-letter parameters until v1.0.0.

What is the push to disable single letter parameters, even at v1.0.0? I'm not a fan of single-letter parameters and think we should maximize our use of PyGMT parameter names, but does it cost us anything to remove that capability?

Good question. I am also curious about this. The main limitation that I see to disallowing the use of single-letter parameters is that it would prevent people from using 'cutting-edge' GMT functionality. Each GMT release tends to offer several new single-character options (see https://docs.generic-mapping-tools.org/dev/changes.html), so removing PyGMT support for single-character options would make it so that users would need to wait for a PyGMT release with new aliases for the options. The impact of this is limited by PyGMT's relatively quick release cycle compared to GMT's and the (assumption here) minority of users that build GMT from source or upgrade to the latest GMT version right away, but I think it is still worth considering.

@seisman
Copy link
Member Author

seisman commented May 20, 2021

The main limitation that I see to disallowing the use of single-letter parameters is that it would prevent people from using 'cutting-edge' GMT functionality.

I agree. Actually what I meant is to disallow single-letter parameters if they already have aliases. For example, currently, the blockmean function doesn't have an alias for -A, so users can still pass A="a" when calling blockmean. After we add an alias (e.g., field), users can either use A="a" or field="a". I think we should disallow A="a" syntax and raise a warning so that users know that it's recommended to change A="a" to field="a".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Improving an existing feature
Projects
None yet
Development

No branches or pull requests

4 participants