Skip to content

Commit b37bb0c

Browse files
committed
Add support to PEP 563 (from __future__ import annotations)
1 parent 49bcc71 commit b37bb0c

1 file changed

Lines changed: 23 additions & 18 deletions

File tree

modules/pymol/commanding.py

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
from functools import wraps
3333
from pathlib import Path
3434
from textwrap import dedent
35-
from typing import get_args, Union, Any, get_origin
35+
from typing import get_args, Union, Any, get_origin, get_type_hints
3636
from types import UnionType
3737

3838
import re
@@ -728,40 +728,45 @@ def new_command(name, function=None, _self=cmd):
728728
if function.__doc__ is not None:
729729
function.__doc__ = dedent(function.__doc__).strip()
730730

731-
# Analysing arguments
732-
spec = inspect.getfullargspec(function)
733-
kwargs_ = {}
734-
args_ = spec.args[:]
735-
defaults = list(spec.defaults or [])
736-
737-
args2_ = args_[:]
738-
while args_ and defaults:
739-
kwargs_[args_.pop(-1)] = defaults.pop(-1)
740-
741-
funcs = {}
742-
for idx, (var, func) in enumerate(spec.annotations.items()):
743-
funcs[var] = func
731+
# Resolve strings into real class objects (PEP 563).
732+
try:
733+
resolved_hints = get_type_hints(
734+
function,
735+
globalns=sys.modules[function.__module__].__dict__
736+
)
737+
except Exception:
738+
resolved_hints = function.__annotations__
744739

740+
# Analysing arguments
741+
sign = inspect.signature(function)
742+
745743
# Inner function that will be callable every time the command is executed
746744
@wraps(function)
747745
def inner(*args, **kwargs):
748746
caller = sys._getframe(1).f_code.co_filename
749747
# It was called from command line or pml script, so parse arguments
750748
if caller == _parser_filename:
751-
kwargs = {**kwargs, **dict(zip(args2_, args))}
752749
# special _self argument
753750
kwargs.pop("_self", None)
754751
new_kwargs = {}
755-
for var, type in funcs.items():
752+
for var, param in sign.parameters.items():
756753
if var in kwargs:
757754
value = kwargs[var]
758755
# special 'quiet' argument
759756
if var == 'quiet' and isinstance(value, int):
760757
new_kwargs[var] = bool(value)
761758
else:
762-
new_kwargs[var] = _into_types(var, type, value)
759+
actual_type = resolved_hints.get(var, param.annotation)
760+
new_kwargs[var] = _into_types(var, actual_type, value)
761+
else:
762+
if param.default is sign.empty:
763+
raise RuntimeError(f"Unknow variable '{var}'.")
764+
defaults = {
765+
k: v.default for k, v in sign.parameters.items()
766+
if v.default is not sign.empty
767+
}
763768
final_kwargs = {
764-
**kwargs_,
769+
**defaults,
765770
**new_kwargs
766771
}
767772
return function(**final_kwargs)

0 commit comments

Comments
 (0)