Skip to content

Commit

Permalink
Improve clarity of various deprecation warnings (#5774)
Browse files Browse the repository at this point in the history
A number of deprecation warnings are updated to reference the actual
method or property that is throwing the warning. In certain cases, the
`stacklevel` is adjusted such that the relevant caller is displayed in
the warning making it easier to track down for the users.

Co-authored-by: Sebastiaan Huber <mail@sphuber.net>
  • Loading branch information
danielhollas and sphuber authored May 16, 2023
1 parent 6a88cb3 commit c72a252
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 31 deletions.
8 changes: 5 additions & 3 deletions aiida/orm/entities.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ def objects(cls: EntityType) -> CollectionType: # pylint: disable=no-self-argum
:return: an object that can be used to access entities of this type
"""
warn_deprecation('This property is deprecated, use `.collection` instead.', version=3, stacklevel=2)
warn_deprecation('`objects` property is deprecated, use `collection` instead.', version=3, stacklevel=4)
return cls.collection

@classproperty
Expand All @@ -191,7 +191,9 @@ def get(cls, **kwargs):
"""
warn_deprecation(
f'This method is deprecated, use `{cls.__name__}.collection.get` instead.', version=3, stacklevel=2
f'`{cls.__name__}.get` method is deprecated, use `{cls.__name__}.collection.get` instead.',
version=3,
stacklevel=2
)
return cls.collection.get(**kwargs) # pylint: disable=no-member

Expand Down Expand Up @@ -223,7 +225,7 @@ def id(self) -> int: # pylint: disable=invalid-name
:return: the entity's id
"""
warn_deprecation('This method is deprecated, use `pk` instead.', version=3, stacklevel=2)
warn_deprecation('`id` property is deprecated, use `pk` instead.', version=3, stacklevel=2)
return self._backend_entity.id

@property
Expand Down
94 changes: 67 additions & 27 deletions aiida/orm/nodes/data/code/legacy.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,23 +102,23 @@ def hide(self):
"""
Hide the code (prevents from showing it in the verdi code list)
"""
warn_deprecation('This property is deprecated, use the `Code.is_hidden` property instead.', version=3)
warn_deprecation('`Code.hide` property is deprecated, use the `Code.is_hidden` property instead.', version=3)
self.is_hidden = True

def reveal(self):
"""
Reveal the code (allows to show it in the verdi code list)
By default, it is revealed
"""
warn_deprecation('This property is deprecated, use the `Code.is_hidden` property instead.', version=3)
warn_deprecation('`Code.reveal` property is deprecated, use the `Code.is_hidden` property instead.', version=3)
self.is_hidden = False

@property
def hidden(self):
"""
Determines whether the Code is hidden or not
"""
warn_deprecation('This property is deprecated, use the `Code.is_hidden` property instead.', version=3)
warn_deprecation('`Code.hidden` property is deprecated, use the `Code.is_hidden` property instead.', version=3)
return self.is_hidden

def set_files(self, files):
Expand Down Expand Up @@ -148,7 +148,8 @@ def __str__(self):
def get_computer_label(self):
"""Get label of this code's computer."""
warn_deprecation(
'This method is deprecated, use the `InstalledCode.computer.label` property instead.', version=3
'`Code.get_computer_label` method is deprecated, use the `InstalledCode.computer.label` property instead.',
version=3
)
return 'repository' if self.computer is None else self.computer.label

Expand All @@ -165,7 +166,7 @@ def relabel(self, new_label):
:param new_label: new code label
"""
warn_deprecation('This method is deprecated, use the `label` property instead.', version=3)
warn_deprecation('`Code.relabel` method is deprecated, use the `label` property instead.', version=3)
if self.computer is not None:
suffix = f'@{self.computer.label}'
if new_label.endswith(suffix):
Expand All @@ -178,7 +179,9 @@ def get_description(self):
:return: string description of this Code instance
"""
warn_deprecation('This method is deprecated, use the `description` property instead.', version=3)
warn_deprecation(
'`Code.get_description` method is deprecated, use the `description` property instead.', version=3
)
return f'{self.description}'

@classmethod
Expand All @@ -194,7 +197,9 @@ def get_code_helper(cls, label, machinename=None, backend=None):
from aiida.common.exceptions import MultipleObjectsError, NotExistent
from aiida.orm.querybuilder import QueryBuilder

warn_deprecation('This method is deprecated, use `aiida.orm.load_code` instead.', version=3)
warn_deprecation(
'`Code.get_code_helper` classmethod is deprecated, use `aiida.orm.load_code` instead.', version=3
)

query = QueryBuilder(backend=backend)
query.append(cls, filters={'label': label}, project='*', tag='code')
Expand Down Expand Up @@ -233,7 +238,7 @@ def get(cls, pk=None, label=None, machinename=None):
# pylint: disable=arguments-differ
from aiida.orm.utils import load_code

warn_deprecation('This method is deprecated, use `aiida.orm.load_code` instead.', version=3)
warn_deprecation('`Code.get` classmethod is deprecated, use `aiida.orm.load_code` instead.', version=3)

# first check if code pk is provided
if pk:
Expand Down Expand Up @@ -274,7 +279,9 @@ def get_from_string(cls, code_string):
"""
from aiida.common.exceptions import MultipleObjectsError, NotExistent

warn_deprecation('This method is deprecated, use `aiida.orm.load_code` instead.', version=3)
warn_deprecation(
'`Code.get_from_string` classmethod is deprecated, use `aiida.orm.load_code` instead.', version=3
)

try:
label, _, machinename = code_string.partition('@')
Expand All @@ -301,7 +308,7 @@ def list_for_plugin(cls, plugin, labels=True, backend=None):
"""
from aiida.orm.querybuilder import QueryBuilder

warn_deprecation('This method has been deprecated, there is no replacement.', version=3)
warn_deprecation('`Code.list_for_plugin` classmethod has been deprecated, there is no replacement.', version=3)

query = QueryBuilder(backend=backend)
query.append(cls, filters={'attributes.input_plugin': {'==': plugin}})
Expand Down Expand Up @@ -347,7 +354,8 @@ def validate_remote_exec_path(self):
does not exist on the remote computer.
"""
warn_deprecation(
'This method is deprecated, use the `InstalledCode.validate_filepath_executable` property instead.',
'`Code.validate_remote_exec_path` method is deprecated, use the '
'`InstalledCode.validate_filepath_executable` property instead.',
version=3
)
filepath = self.get_remote_exec_path()
Expand All @@ -374,76 +382,100 @@ def set_prepend_text(self, code):
Pass a string of code that will be put in the scheduler script before the
execution of the code.
"""
warn_deprecation('This method is deprecated, use the `prepend_text` property instead.', version=3)
warn_deprecation(
'`Code.set_prepend_text` method is deprecated, use the `prepend_text` property instead.', version=3
)
self.prepend_text = code

def get_prepend_text(self):
"""
Return the code that will be put in the scheduler script before the
execution, or an empty string if no pre-exec code was defined.
"""
warn_deprecation('This method is deprecated, use the `prepend_text` property instead.', version=3)
warn_deprecation(
'`Code.get_prepend_text` method is deprecated, use the `prepend_text` property instead.', version=3
)
return self.prepend_text

def set_input_plugin_name(self, input_plugin):
"""
Set the name of the default input plugin, to be used for the automatic
generation of a new calculation.
"""
warn_deprecation('This method is deprecated, use the `default_calc_job_plugin` property instead.', version=3)
warn_deprecation(
'`Code.set_input_plugin_name` method is deprecated, use the `default_calc_job_plugin` property instead.',
version=3
)
self.default_calc_job_plugin = input_plugin

def get_input_plugin_name(self):
"""
Return the name of the default input plugin (or None if no input plugin
was set.
"""
warn_deprecation('This method is deprecated, use the `default_calc_job_plugin` property instead.', version=3)
warn_deprecation(
'`Code.get_input_plugin_name` method is deprecated, use the `default_calc_job_plugin` property instead.',
version=3
)
return self.default_calc_job_plugin

def set_use_double_quotes(self, use_double_quotes: bool):
"""Set whether the command line invocation of this code should be escaped with double quotes.
:param use_double_quotes: True if to escape with double quotes, False otherwise.
"""
warn_deprecation('This method is deprecated, use the `use_double_quotes` property instead.', version=3)
warn_deprecation(
'`Code.set_use_double_quotes` method is deprecated, use the `use_double_quotes` property instead.',
version=3
)
self.use_double_quotes = use_double_quotes

def get_use_double_quotes(self) -> bool:
"""Return whether the command line invocation of this code should be escaped with double quotes.
:returns: True if to escape with double quotes, False otherwise which is also the default.
"""
warn_deprecation('This method is deprecated, use the `use_double_quotes` property instead.', version=3)
warn_deprecation(
'`Code.get_use_double_quotes` method is deprecated, use the `use_double_quotes` property instead.',
version=3
)
return self.use_double_quotes

def set_append_text(self, code):
"""
Pass a string of code that will be put in the scheduler script after the
execution of the code.
"""
warn_deprecation('This method is deprecated, use the `append_text` property instead.', version=3)
warn_deprecation(
'`Code.set_append_text` method is deprecated, use the `append_text` property instead.', version=3
)
self.append_text = code

def get_append_text(self):
"""
Return the postexec_code, or an empty string if no post-exec code was defined.
"""
warn_deprecation('This method is deprecated, use the `append_text` property instead.', version=3)
warn_deprecation(
'`Code.get_append_text` method is deprecated, use the `append_text` property instead.', version=3
)
return self.append_text

def set_local_executable(self, exec_name):
"""
Set the filename of the local executable.
Implicitly set the code as local.
"""
warn_deprecation('This method is deprecated, use `PortableCode`.', version=3)
warn_deprecation('`Code.set_local_executable` method is deprecated, use `PortableCode`.', version=3)

self._set_local()
self.filepath_executable = exec_name

def get_local_executable(self):
warn_deprecation('This method is deprecated, use `PortableCode.filepath_executable` instead.', version=3)
"""Return the local executable."""
warn_deprecation(
'`Code.get_local_executable` method is deprecated, use `PortableCode.filepath_executable` instead.',
version=3
)
return self.filepath_executable

def set_remote_computer_exec(self, remote_computer_exec):
Expand All @@ -457,7 +489,7 @@ def set_remote_computer_exec(self, remote_computer_exec):
from aiida import orm
from aiida.common.lang import type_check

warn_deprecation('This method is deprecated, use `InstalledCode`.', version=3)
warn_deprecation('`Code.set_remote_computer_exec` method is deprecated, use `InstalledCode`.', version=3)

if (not isinstance(remote_computer_exec, (list, tuple)) or len(remote_computer_exec) != 2):
raise ValueError(
Expand All @@ -476,14 +508,20 @@ def set_remote_computer_exec(self, remote_computer_exec):
self.base.attributes.set('remote_exec_path', remote_exec_path)

def get_remote_exec_path(self):
warn_deprecation('This method is deprecated, use `InstalledCode.filepath_executable` instead.', version=3)
"""Return the ``remote_exec_path`` attribute."""
warn_deprecation(
'`Code.get_remote_exec_path` method is deprecated, use `InstalledCode.filepath_executable` instead.',
version=3
)
if self.is_local():
raise ValueError('The code is local')
return self.base.attributes.get('remote_exec_path', '')

def get_remote_computer(self):
"""Return the remote computer associated with this code."""
warn_deprecation('This method is deprecated, use the `computer` attribute instead.', version=3)
warn_deprecation(
'`Code.get_remote_computer` method is deprecated, use the `computer` attribute instead.', version=3
)
if self.is_local():
raise ValueError('The code is local')

Expand Down Expand Up @@ -523,7 +561,9 @@ def is_local(self):
Return True if the code is 'local', False if it is 'remote' (see also documentation
of the set_local and set_remote functions).
"""
warn_deprecation('This method is deprecated, use a `PortableCode` instance and check the type.', version=3)
warn_deprecation(
'`Code.is_local` method is deprecated, use a `PortableCode` instance and check the type.', version=3
)
return self.base.attributes.get('is_local', None)

def can_run_on(self, computer):
Expand All @@ -538,7 +578,7 @@ def can_run_on(self, computer):
from aiida import orm
from aiida.common.lang import type_check

warn_deprecation('This method is deprecated, use `can_run_on_computer` instead.', version=3)
warn_deprecation('`Code.can_run_on` method is deprecated, use `can_run_on_computer` instead.', version=3)

if self.is_local():
return True
Expand All @@ -552,5 +592,5 @@ def get_execname(self):
For local codes, it is ./LOCAL_EXECUTABLE_NAME
For remote codes, it is the absolute path to the executable.
"""
warn_deprecation('This method is deprecated, use `get_executable` instead.', version=3)
warn_deprecation('`Code.get_execname` method is deprecated, use `get_executable` instead.', version=3)
return str(self.get_executable())
3 changes: 2 additions & 1 deletion aiida/orm/utils/managers.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,8 @@ def _get_node_by_link_label(self, label):
warn_deprecation(
'dereferencing nodes with links containing double underscores is deprecated, simply replace '
'the double underscores with a single dot instead. For example: \n'
'`self.inputs.some__label` can be written as `self.inputs.some.label` instead.\n',
'`node.inputs.some__label` can be written as `node.inputs.some.label` instead.\n',
stacklevel=4,
version=3
) # pylint: disable=no-member
namespaces = label.split(self._namespace_separator)
Expand Down

0 comments on commit c72a252

Please sign in to comment.