Skip to content

Commit

Permalink
Added docs links to error messages (#281)
Browse files Browse the repository at this point in the history
* added exceptions with docs links

* copy fix

* fixed indentation

* updated crucial error messages

* added library not installed exception, fixed linting

* fixed library constructor missing input and format

* fix to library not installed error

* added getting help link

* changed the help message

* changed get help message

* renamed exceptions

* fixed formatting, changed imported class in tests

* fixes

* fixed orded params

* added os styles dispatch

* fixed dict merging

* fixed parsing inputs for librarynotinstalled exception
  • Loading branch information
jakubczakon authored Oct 12, 2020
1 parent f783833 commit 230f823
Show file tree
Hide file tree
Showing 6 changed files with 219 additions and 39 deletions.
18 changes: 10 additions & 8 deletions neptune/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@
import os
import threading

from neptune import envs
from neptune import constants
from neptune.exceptions import MissingProjectQualifiedName, Uninitialized, InvalidNeptuneBackend
from neptune import envs
from neptune.exceptions import NeptuneMissingProjectQualifiedNameException, NeptuneUninitializedException, \
InvalidNeptuneBackend
from neptune.internal.backends.hosted_neptune_backend import HostedNeptuneBackend
from neptune.internal.backends.offline_backend import OfflineBackend
from neptune.projects import Project
Expand Down Expand Up @@ -112,8 +113,9 @@ def init(project_qualified_name=None, api_token=None, proxies=None, backend=None
:class:`~neptune.projects.Project` object that is used to create or list experiments, notebooks, etc.
Raises:
`MissingApiToken`: When ``api_token`` is None and ``NEPTUNE_API_TOKEN`` environment variable was not set.
`MissingProjectQualifiedName`: When ``project_qualified_name`` is None
`NeptuneMissingApiTokenException`: When ``api_token`` is None
and ``NEPTUNE_API_TOKEN`` environment variable was not set.
`NeptuneMissingProjectQualifiedNameException`: When ``project_qualified_name`` is None
and ``NEPTUNE_PROJECT`` environment variable was not set.
`InvalidApiKey`: When given ``api_token`` is malformed.
`Unauthorized`: When given ``api_token`` is invalid.
Expand Down Expand Up @@ -153,7 +155,7 @@ def init(project_qualified_name=None, api_token=None, proxies=None, backend=None
session = Session(backend=backend)

if project_qualified_name is None:
raise MissingProjectQualifiedName()
raise NeptuneMissingProjectQualifiedNameException()

project = session.get_project(project_qualified_name)

Expand All @@ -176,7 +178,7 @@ def set_project(project_qualified_name):
:class:`~neptune.projects.Project` object that is used to create or list experiments, notebooks, etc.
Raises:
`MissingApiToken`: When library was not initialized previously by ``init`` call and
`NeptuneMissingApiTokenException`: When library was not initialized previously by ``init`` call and
``NEPTUNE_API_TOKEN`` environment variable is not set.
Examples:
Expand Down Expand Up @@ -223,7 +225,7 @@ def create_experiment(name=None,
# pylint: disable=global-statement
global project
if project is None:
raise Uninitialized()
raise NeptuneUninitializedException()

return project.create_experiment(
name=name,
Expand All @@ -249,7 +251,7 @@ def get_experiment():
# pylint: disable=global-statement
global project
if project is None:
raise Uninitialized()
raise NeptuneUninitializedException()

# pylint: disable=protected-access
return project._get_current_experiment()
Expand Down
224 changes: 201 additions & 23 deletions neptune/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,75 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
import platform

from neptune import envs

UNIX_STYLES = {'h1': '\033[95m',
'h2': '\033[94m',
'python': '\033[96m',
'bash': '\033[95m',
'warning': '\033[93m',
'correct': '\033[92m',
'fail': '\033[91m',
'bold': '\033[1m',
'underline': '\033[4m',
'end': '\033[0m'}

WINDOWS_STYLES = {'h1': '',
'h2': '',
'python': '',
'bash': '',
'warning': '',
'correct': '',
'fail': '',
'bold': '',
'underline': '',
'end': ''}

EMPTY_STYLES = {'h1': '',
'h2': '',
'python': '',
'bash': '',
'warning': '',
'correct': '',
'fail': '',
'bold': '',
'underline': '',
'end': ''}

if platform.system() in ['Linux', 'Darwin']:
STYLES = UNIX_STYLES
elif platform.system() == 'Windows':
STYLES = WINDOWS_STYLES
else:
STYLES = EMPTY_STYLES


class NeptuneException(Exception):
pass


class Uninitialized(NeptuneException):
class NeptuneUninitializedException(NeptuneException):
def __init__(self):
super(Uninitialized, self).__init__(
"You must initialize neptune-client first. "
"For more information, please visit: https://github.com/neptune-ai/neptune-client#initialize-neptune")
message = """
{h1}
----NeptuneUninitializedException---------------------------------------------------------------------------------------
{end}
You must initialize neptune-client before you create an experiment.
Looks like you forgot to add:
{python}neptune.init(project_qualified_name='WORKSPACE_NAME/PROJECT_NAME', api_token='YOUR_API_TOKEN'){end}
before you ran:
{python}neptune.create_experiment(){end}
You may also want to check the following docs pages:
- https://docs.neptune.ai/getting-started/quick-starts/log_first_experiment.html
{correct}Need help?{end}-> https://docs.neptune.ai/getting-started/getting-help.html
""".format(**STYLES)
super(NeptuneUninitializedException, self).__init__(message)


class FileNotFound(NeptuneException):
Expand Down Expand Up @@ -59,9 +116,24 @@ def __init__(self):
super(NoChannelValue, self).__init__('No channel value provided.')


class LibraryNotInstalled(NeptuneException):
class NeptuneLibraryNotInstalledException(NeptuneException):
def __init__(self, library):
super(LibraryNotInstalled, self).__init__("Library {} is not installed".format(library))
message = """
{h1}
----NeptuneLibraryNotInstalledException---------------------------------------------------------------------------------
{end}
Looks like library {library} wasn't installed.
To install run:
{bash}pip install {library}{end}
You may also want to check the following docs pages:
- https://docs.neptune.ai/getting-started/installation/index.html
{correct}Need help?{end}-> https://docs.neptune.ai/getting-started/getting-help.html
"""
inputs = dict(list({'library': library}.items()) + list(STYLES.items()))
super(NeptuneLibraryNotInstalledException, self).__init__(message.format(**inputs))


class InvalidChannelValue(NeptuneException):
Expand All @@ -71,32 +143,135 @@ def __init__(self, expected_type, actual_type):
expected=expected_type, actual=actual_type))


class NoExperimentContext(NeptuneException):
class NeptuneNoExperimentContextException(NeptuneException):
def __init__(self):
super(NoExperimentContext, self).__init__('Unable to find current active experiment')
message = """
{h1}
----NeptuneNoExperimentContextException---------------------------------------------------------------------------------
{end}
Neptune couldn't find an active experiment.
Looks like you forgot to run:
{python}neptune.create_experiment(){end}
You may also want to check the following docs pages:
- https://docs.neptune.ai/getting-started/quick-starts/log_first_experiment.html
class MissingApiToken(NeptuneException):
def __init__(self):
super(MissingApiToken, self).__init__('Missing API token. Use "{}" environment '
'variable or pass it as an argument to neptune.init. '
'Open this link to get your API token '
'https://ui.neptune.ai/get_my_api_token'
.format(envs.API_TOKEN_ENV_NAME))
{correct}Need help?{end}-> https://docs.neptune.ai/getting-started/getting-help.html
"""
super(NeptuneNoExperimentContextException, self).__init__(message.format(**STYLES))


class MissingProjectQualifiedName(NeptuneException):
class NeptuneMissingApiTokenException(NeptuneException):
def __init__(self):
super(MissingProjectQualifiedName, self).__init__('Missing project qualified name. Use "{}" environment '
'variable or pass it as an argument'
.format(envs.PROJECT_ENV_NAME))
message = """
{h1}
----NeptuneMissingApiTokenException-------------------------------------------------------------------------------------
{end}
Neptune client couldn't find your API token.
Learn how to get it in this docs page:
https://docs.neptune.ai/security-and-privacy/api-tokens/how-to-find-and-set-neptune-api-token.html
There are two options to add it:
- specify it in your code
- set an environment variable in your operating system.
{h2}CODE{end}
Pass the token to {bold}neptune.init(){end} via {bold}api_token{end} argument:
{python}neptune.init(project_qualified_name='WORKSPACE_NAME/PROJECT_NAME', api_token='YOUR_API_TOKEN'){end}
{h2}ENVIRONMENT VARIABLE{end} {correct}(Recommended option){end}
or export or set an environment variable depending on your operating system:
{correct}Linux/Unix{end}
In your terminal run:
{bash}export {env_api_token}=YOUR_API_TOKEN{end}
{correct}Windows{end}
In your CMD run:
{bash}set {env_api_token}=YOUR_API_TOKEN{end}
and skip the {bold}api_token{end} argument of {bold}neptune.init(){end}:
{python}neptune.init(project_qualified_name='WORKSPACE_NAME/PROJECT_NAME'){end}
You may also want to check the following docs pages:
- https://docs.neptune.ai/security-and-privacy/api-tokens/how-to-find-and-set-neptune-api-token.html
- https://docs.neptune.ai/getting-started/quick-starts/log_first_experiment.html
{correct}Need help?{end}-> https://docs.neptune.ai/getting-started/getting-help.html
"""
inputs = dict(list({'env_api_token': envs.API_TOKEN_ENV_NAME}.items()) + list(STYLES.items()))
super(NeptuneMissingApiTokenException, self).__init__(message.format(**inputs))


class NeptuneMissingProjectQualifiedNameException(NeptuneException):
def __init__(self):
message = """
{h1}
----NeptuneMissingProjectQualifiedNameException-------------------------------------------------------------------------
{end}
Neptune client couldn't find your project name.
There are two options two add it:
- specify it in your code
- set an environment variable in your operating system.
{h2}CODE{end}
Pass it to {bold}neptune.init(){end} via {bold}project_qualified_name{end} argument:
{python}neptune.init(project_qualified_name='WORKSPACE_NAME/PROJECT_NAME', api_token='YOUR_API_TOKEN'){end}
{h2}ENVIRONMENT VARIABLE{end}
or export or set an environment variable depending on your operating system:
{correct}Linux/Unix{end}
In your terminal run:
{bash}export {env_project}=WORKSPACE_NAME/PROJECT_NAME{end}
{correct}Windows{end}
In your CMD run:
{bash}set {env_project}=WORKSPACE_NAME/PROJECT_NAME{end}
class IncorrectProjectQualifiedName(NeptuneException):
and skip the {bold}project_qualified_name{end} argument of {bold}neptune.init(){end}:
{python}neptune.init(api_token='YOUR_API_TOKEN'){end}
You may also want to check the following docs pages:
- https://docs.neptune.ai/workspace-project-and-user-management/index.html
- https://docs.neptune.ai/getting-started/quick-starts/log_first_experiment.html
{correct}Need help?{end}-> https://docs.neptune.ai/getting-started/getting-help.html
"""
inputs = dict(list({'env_project': envs.PROJECT_ENV_NAME}.items()) + list(STYLES.items()))
super(NeptuneMissingProjectQualifiedNameException, self).__init__(message.format(**inputs))


class NeptuneIncorrectProjectQualifiedNameException(NeptuneException):
def __init__(self, project_qualified_name):
super(IncorrectProjectQualifiedName, self).__init__('Incorrect project qualified name "{}". '
'Should be in format "namespace/project_name".'
.format(project_qualified_name))
message = """
{h1}
----NeptuneIncorrectProjectQualifiedNameException-----------------------------------------------------------------------
{end}
Project qualified name {fail}"{project_qualified_name}"{end} you specified was incorrect.
The correct project qualified name should look like this {correct}WORKSPACE/PROJECT_NAME{end}.
It has two parts:
- {correct}WORKSPACE{end}: which can be your username or your organization name
- {correct}PROJECT_NAME{end}: which is the actual project name you chose
For example, a project {correct}neptune-ai/credit-default-prediction{end} parts are:
- {correct}neptune-ai{end}: {underline}WORKSPACE{end} our company organization name
- {correct}credit-default-prediction{end}: {underline}PROJECT_NAME{end} a project name
The URL to this project looks like this: https://ui.neptune.ai/neptune-ai/credit-default-prediction
You may also want to check the following docs pages:
- https://docs.neptune.ai/workspace-project-and-user-management/index.html
- https://docs.neptune.ai/getting-started/quick-starts/log_first_experiment.html
{correct}Need help?{end}-> https://docs.neptune.ai/getting-started/getting-help.html
"""
inputs = dict(list({'project_qualified_name': project_qualified_name}.items()) + list(STYLES.items()))
super(NeptuneIncorrectProjectQualifiedNameException, self).__init__(message.format(**inputs))


class InvalidNeptuneBackend(NeptuneException):
Expand All @@ -107,16 +282,19 @@ def __init__(self, provided_backend_name):
'e.g. using {}=offline allows you to run your code without logging anything to Neptune'
.format(envs.BACKEND, provided_backend_name, envs.BACKEND))


class DeprecatedApiToken(NeptuneException):
def __init__(self, app_url):
super(DeprecatedApiToken, self).__init__(
"Your API token is deprecated. Please visit {} to get a new one.".format(app_url))


class CannotResolveHostname(NeptuneException):
def __init__(self, host):
super(CannotResolveHostname, self).__init__(
"Cannot resolve hostname {}. Please contact Neptune support.".format(host))


class UnsupportedClientVersion(NeptuneException):
def __init__(self, version, minVersion, maxVersion):
super(UnsupportedClientVersion, self).__init__(
Expand Down
4 changes: 2 additions & 2 deletions neptune/internal/backends/credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

from neptune import envs
from neptune.api_exceptions import InvalidApiKey
from neptune.exceptions import MissingApiToken
from neptune.exceptions import NeptuneMissingApiTokenException

_logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -66,7 +66,7 @@ def __init__(self, api_token=None):

self._api_token = api_token
if self.api_token is None:
raise MissingApiToken()
raise NeptuneMissingApiTokenException()

token_dict = self._api_token_to_dict(self.api_token)
self._token_origin_address = token_dict['api_address']
Expand Down
4 changes: 2 additions & 2 deletions neptune/projects.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
import six

from neptune.envs import NOTEBOOK_ID_ENV_NAME, NOTEBOOK_PATH_ENV_NAME
from neptune.exceptions import NoExperimentContext
from neptune.exceptions import NeptuneNoExperimentContextException
from neptune.experiments import Experiment
from neptune.internal.abort import DefaultAbortImpl
from neptune.internal.notebooks.notebooks import create_checkpoint
Expand Down Expand Up @@ -609,7 +609,7 @@ def _get_current_experiment(self):
if self._experiments_stack:
return self._experiments_stack[-1]
else:
raise NoExperimentContext()
raise NeptuneNoExperimentContextException()

def _push_new_experiment(self, new_experiment):
with self.__lock:
Expand Down
4 changes: 2 additions & 2 deletions neptune/sessions.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

from neptune.api_exceptions import ProjectNotFound
from neptune.internal.backends.hosted_neptune_backend import HostedNeptuneBackend
from neptune.exceptions import IncorrectProjectQualifiedName
from neptune.exceptions import NeptuneIncorrectProjectQualifiedNameException
from neptune.patterns import PROJECT_QUALIFIED_NAME_PATTERN
from neptune.projects import Project

Expand Down Expand Up @@ -165,7 +165,7 @@ def get_project(self, project_qualified_name):
raise ProjectNotFound(project_qualified_name)

if not re.match(PROJECT_QUALIFIED_NAME_PATTERN, project_qualified_name):
raise IncorrectProjectQualifiedName(project_qualified_name)
raise NeptuneIncorrectProjectQualifiedNameException(project_qualified_name)

return self._backend.get_project(project_qualified_name)

Expand Down
Loading

0 comments on commit 230f823

Please sign in to comment.