Use sentinel everywhere (#84041)

* Use sentinel everywhere

Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
pull/84043/head
Abhijeet Kasurde 2 months ago committed by GitHub
parent 9abc651cd6
commit b3c4154e86
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -17,6 +17,7 @@ from collections.abc import Mapping, Sequence
from jinja2.nativetypes import NativeEnvironment from jinja2.nativetypes import NativeEnvironment
from ansible.errors import AnsibleOptionsError, AnsibleError, AnsibleRequiredOptionError from ansible.errors import AnsibleOptionsError, AnsibleError, AnsibleRequiredOptionError
from ansible.module_utils.common.sentinel import Sentinel
from ansible.module_utils.common.text.converters import to_text, to_bytes, to_native from ansible.module_utils.common.text.converters import to_text, to_bytes, to_native
from ansible.module_utils.common.yaml import yaml_load from ansible.module_utils.common.yaml import yaml_load
from ansible.module_utils.six import string_types from ansible.module_utils.six import string_types
@ -232,15 +233,13 @@ def find_ini_config_file(warnings=None):
# Note: In this case, warnings does nothing # Note: In this case, warnings does nothing
warnings = set() warnings = set()
# A value that can never be a valid path so that we can tell if ANSIBLE_CONFIG was set later
# We can't use None because we could set path to None.
SENTINEL = object
potential_paths = [] potential_paths = []
# A value that can never be a valid path so that we can tell if ANSIBLE_CONFIG was set later
# We can't use None because we could set path to None.
# Environment setting # Environment setting
path_from_env = os.getenv("ANSIBLE_CONFIG", SENTINEL) path_from_env = os.getenv("ANSIBLE_CONFIG", Sentinel)
if path_from_env is not SENTINEL: if path_from_env is not Sentinel:
path_from_env = unfrackpath(path_from_env, follow=False) path_from_env = unfrackpath(path_from_env, follow=False)
if os.path.isdir(to_bytes(path_from_env)): if os.path.isdir(to_bytes(path_from_env)):
path_from_env = os.path.join(path_from_env, "ansible.cfg") path_from_env = os.path.join(path_from_env, "ansible.cfg")

@ -126,13 +126,13 @@ from ansible.galaxy.dependency_resolution.dataclasses import (
from ansible.galaxy.dependency_resolution.versioning import meets_requirements from ansible.galaxy.dependency_resolution.versioning import meets_requirements
from ansible.plugins.loader import get_all_plugin_loaders from ansible.plugins.loader import get_all_plugin_loaders
from ansible.module_utils.common.file import S_IRWU_RG_RO, S_IRWXU_RXG_RXO, S_IXANY from ansible.module_utils.common.file import S_IRWU_RG_RO, S_IRWXU_RXG_RXO, S_IXANY
from ansible.module_utils.common.sentinel import Sentinel
from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text
from ansible.module_utils.common.collections import is_sequence from ansible.module_utils.common.collections import is_sequence
from ansible.module_utils.common.yaml import yaml_dump from ansible.module_utils.common.yaml import yaml_dump
from ansible.utils.collection_loader import AnsibleCollectionRef from ansible.utils.collection_loader import AnsibleCollectionRef
from ansible.utils.display import Display from ansible.utils.display import Display
from ansible.utils.hashing import secure_hash, secure_hash_s from ansible.utils.hashing import secure_hash, secure_hash_s
from ansible.utils.sentinel import Sentinel
display = Display() display = Display()

@ -33,10 +33,10 @@ from ansible.module_utils.common.text.converters import to_bytes, to_native, to_
from ansible.module_utils.api import retry_with_delays_and_condition from ansible.module_utils.api import retry_with_delays_and_condition
from ansible.module_utils.api import generate_jittered_backoff from ansible.module_utils.api import generate_jittered_backoff
from ansible.module_utils.common.process import get_bin_path from ansible.module_utils.common.process import get_bin_path
from ansible.module_utils.common.sentinel import Sentinel
from ansible.module_utils.common.yaml import yaml_load from ansible.module_utils.common.yaml import yaml_load
from ansible.module_utils.urls import open_url from ansible.module_utils.urls import open_url
from ansible.utils.display import Display from ansible.utils.display import Display
from ansible.utils.sentinel import Sentinel
import yaml import yaml

@ -30,6 +30,7 @@ from urllib.error import HTTPError
from ansible import constants as C from ansible import constants as C
from ansible.galaxy.api import GalaxyError from ansible.galaxy.api import GalaxyError
from ansible.galaxy.user_agent import user_agent from ansible.galaxy.user_agent import user_agent
from ansible.module_utils.common.sentinel import Sentinel as NoTokenSentinel
from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text
from ansible.module_utils.common.yaml import yaml_dump, yaml_load from ansible.module_utils.common.yaml import yaml_dump, yaml_load
from ansible.module_utils.urls import open_url from ansible.module_utils.urls import open_url
@ -38,12 +39,6 @@ from ansible.utils.display import Display
display = Display() display = Display()
class NoTokenSentinel(object):
""" Represents an ansible.cfg server with not token defined (will ignore cmdline and GALAXY_TOKEN_PATH. """
def __new__(cls, *args, **kwargs):
return cls
class KeycloakToken(object): class KeycloakToken(object):
'''A token granted by a Keycloak server. '''A token granted by a Keycloak server.

@ -0,0 +1,66 @@
# Copyright (c) 2019 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import annotations
class Sentinel:
"""
Object which can be used to mark whether an entry as being special
A sentinel value demarcates a value or marks an entry as having a special meaning. In C, the
Null byte is used as a sentinel for the end of a string. In Python, None is often used as
a Sentinel in optional parameters to mean that the parameter was not set by the user.
You should use None as a Sentinel value any Python code where None is not a valid entry. If
None is a valid entry, though, then you need to create a different value, which is the purpose
of this class.
Example of using Sentinel as a default parameter value::
def confirm_big_red_button(tristate=Sentinel):
if tristate is Sentinel:
print('You must explicitly press the big red button to blow up the base')
elif tristate is True:
print('Countdown to destruction activated')
elif tristate is False:
print('Countdown stopped')
elif tristate is None:
print('Waiting for more input')
Example of using Sentinel to tell whether a dict which has a default value has been changed::
values = {'one': Sentinel, 'two': Sentinel}
defaults = {'one': 1, 'two': 2}
# [.. Other code which does things including setting a new value for 'one' ..]
values['one'] = None
# [..]
print('You made changes to:')
for key, value in values.items():
if value is Sentinel:
continue
print('%s: %s' % (key, value)
"""
def __new__(cls):
"""
Return the cls itself. This makes both equality and identity True for comparing the class
to an instance of the class, preventing common usage errors.
Preferred usage::
a = Sentinel
if a is Sentinel:
print('Sentinel value')
However, these are True as well, eliminating common usage errors::
if Sentinel is Sentinel():
print('Sentinel value')
if Sentinel == Sentinel():
print('Sentinel value')
"""
return cls

@ -239,7 +239,7 @@ from grp import getgrnam, getgrgid
from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.common.text.converters import to_bytes, to_native from ansible.module_utils.common.text.converters import to_bytes, to_native
from ansible.module_utils.common.sentinel import Sentinel
# There will only be a single AnsibleModule object per module # There will only be a single AnsibleModule object per module
module = None module = None
@ -257,11 +257,6 @@ class ParameterError(AnsibleModuleError):
pass pass
class Sentinel(object):
def __new__(cls, *args, **kwargs):
return cls
def _ansible_excepthook(exc_type, exc_value, tb): def _ansible_excepthook(exc_type, exc_value, tb):
# Using an exception allows us to catch it if the calling code knows it can recover # Using an exception allows us to catch it if the calling code knows it can recover
if issubclass(exc_type, AnsibleModuleError): if issubclass(exc_type, AnsibleModuleError):

@ -20,12 +20,12 @@ from __future__ import annotations
import ansible.constants as C import ansible.constants as C
from ansible.errors import AnsibleParserError, AnsibleError, AnsibleAssertionError from ansible.errors import AnsibleParserError, AnsibleError, AnsibleAssertionError
from ansible.module_utils.six import string_types from ansible.module_utils.six import string_types
from ansible.module_utils.common.sentinel import Sentinel
from ansible.module_utils.common.text.converters import to_text from ansible.module_utils.common.text.converters import to_text
from ansible.parsing.splitter import parse_kv, split_args from ansible.parsing.splitter import parse_kv, split_args
from ansible.plugins.loader import module_loader, action_loader from ansible.plugins.loader import module_loader, action_loader
from ansible.template import Templar from ansible.template import Templar
from ansible.utils.fqcn import add_internal_fqcns from ansible.utils.fqcn import add_internal_fqcns
from ansible.utils.sentinel import Sentinel
# modules formated for user msg # modules formated for user msg

@ -17,7 +17,7 @@
from __future__ import annotations from __future__ import annotations
from ansible.utils.sentinel import Sentinel from ansible.module_utils.common.sentinel import Sentinel
_CONTAINERS = frozenset(('list', 'dict', 'set')) _CONTAINERS = frozenset(('list', 'dict', 'set'))

@ -19,13 +19,13 @@ from ansible import context
from ansible.errors import AnsibleError, AnsibleParserError, AnsibleUndefinedVariable, AnsibleAssertionError from ansible.errors import AnsibleError, AnsibleParserError, AnsibleUndefinedVariable, AnsibleAssertionError
from ansible.module_utils.six import string_types from ansible.module_utils.six import string_types
from ansible.module_utils.parsing.convert_bool import boolean from ansible.module_utils.parsing.convert_bool import boolean
from ansible.module_utils.common.sentinel import Sentinel
from ansible.module_utils.common.text.converters import to_text from ansible.module_utils.common.text.converters import to_text
from ansible.parsing.dataloader import DataLoader from ansible.parsing.dataloader import DataLoader
from ansible.playbook.attribute import Attribute, FieldAttribute, ConnectionFieldAttribute, NonInheritableFieldAttribute from ansible.playbook.attribute import Attribute, FieldAttribute, ConnectionFieldAttribute, NonInheritableFieldAttribute
from ansible.plugins.loader import module_loader, action_loader from ansible.plugins.loader import module_loader, action_loader
from ansible.utils.collection_loader._collection_finder import _get_collection_metadata, AnsibleCollectionRef from ansible.utils.collection_loader._collection_finder import _get_collection_metadata, AnsibleCollectionRef
from ansible.utils.display import Display from ansible.utils.display import Display
from ansible.utils.sentinel import Sentinel
from ansible.utils.vars import combine_vars, isidentifier, get_unique_id from ansible.utils.vars import combine_vars, isidentifier, get_unique_id
display = Display() display = Display()

@ -19,6 +19,7 @@ from __future__ import annotations
import ansible.constants as C import ansible.constants as C
from ansible.errors import AnsibleParserError from ansible.errors import AnsibleParserError
from ansible.module_utils.common.sentinel import Sentinel
from ansible.playbook.attribute import NonInheritableFieldAttribute from ansible.playbook.attribute import NonInheritableFieldAttribute
from ansible.playbook.base import Base from ansible.playbook.base import Base
from ansible.playbook.conditional import Conditional from ansible.playbook.conditional import Conditional
@ -28,7 +29,6 @@ from ansible.playbook.helpers import load_list_of_tasks
from ansible.playbook.notifiable import Notifiable from ansible.playbook.notifiable import Notifiable
from ansible.playbook.role import Role from ansible.playbook.role import Role
from ansible.playbook.taggable import Taggable from ansible.playbook.taggable import Taggable
from ansible.utils.sentinel import Sentinel
class Block(Base, Conditional, CollectionSearch, Taggable, Notifiable, Delegatable): class Block(Base, Conditional, CollectionSearch, Taggable, Notifiable, Delegatable):

@ -24,6 +24,7 @@ from types import MappingProxyType
from ansible import constants as C from ansible import constants as C
from ansible.errors import AnsibleError, AnsibleParserError, AnsibleAssertionError from ansible.errors import AnsibleError, AnsibleParserError, AnsibleAssertionError
from ansible.module_utils.common.sentinel import Sentinel
from ansible.module_utils.common.text.converters import to_text from ansible.module_utils.common.text.converters import to_text
from ansible.module_utils.six import binary_type, text_type from ansible.module_utils.six import binary_type, text_type
from ansible.playbook.attribute import FieldAttribute from ansible.playbook.attribute import FieldAttribute
@ -37,7 +38,6 @@ from ansible.playbook.taggable import Taggable
from ansible.plugins.loader import add_all_plugin_dirs from ansible.plugins.loader import add_all_plugin_dirs
from ansible.utils.collection_loader import AnsibleCollectionConfig from ansible.utils.collection_loader import AnsibleCollectionConfig
from ansible.utils.path import is_subpath from ansible.utils.path import is_subpath
from ansible.utils.sentinel import Sentinel
from ansible.utils.vars import combine_vars from ansible.utils.vars import combine_vars
__all__ = ['Role', 'hash_params'] __all__ = ['Role', 'hash_params']

@ -19,9 +19,9 @@ from __future__ import annotations
from ansible.errors import AnsibleError from ansible.errors import AnsibleError
from ansible.module_utils.six import string_types from ansible.module_utils.six import string_types
from ansible.module_utils.common.sentinel import Sentinel
from ansible.playbook.attribute import FieldAttribute from ansible.playbook.attribute import FieldAttribute
from ansible.template import Templar from ansible.template import Templar
from ansible.utils.sentinel import Sentinel
def _flatten_tags(tags: list) -> list: def _flatten_tags(tags: list) -> list:

@ -19,6 +19,7 @@ from __future__ import annotations
from ansible import constants as C from ansible import constants as C
from ansible.errors import AnsibleError, AnsibleParserError, AnsibleUndefinedVariable, AnsibleAssertionError from ansible.errors import AnsibleError, AnsibleParserError, AnsibleUndefinedVariable, AnsibleAssertionError
from ansible.module_utils.common.sentinel import Sentinel
from ansible.module_utils.common.text.converters import to_native from ansible.module_utils.common.text.converters import to_native
from ansible.module_utils.six import string_types from ansible.module_utils.six import string_types
from ansible.parsing.mod_args import ModuleArgsParser from ansible.parsing.mod_args import ModuleArgsParser
@ -36,7 +37,7 @@ from ansible.playbook.role import Role
from ansible.playbook.taggable import Taggable from ansible.playbook.taggable import Taggable
from ansible.utils.collection_loader import AnsibleCollectionConfig from ansible.utils.collection_loader import AnsibleCollectionConfig
from ansible.utils.display import Display from ansible.utils.display import Display
from ansible.utils.sentinel import Sentinel
from ansible.utils.vars import isidentifier from ansible.utils.vars import isidentifier
__all__ = ['Task'] __all__ = ['Task']

@ -19,10 +19,10 @@ from __future__ import annotations
import ansible.constants as C import ansible.constants as C
from ansible.errors import AnsibleParserError from ansible.errors import AnsibleParserError
from ansible.module_utils.common.sentinel import Sentinel
from ansible.playbook.block import Block from ansible.playbook.block import Block
from ansible.playbook.task import Task from ansible.playbook.task import Task
from ansible.utils.display import Display from ansible.utils.display import Display
from ansible.utils.sentinel import Sentinel
__all__ = ['TaskInclude'] __all__ = ['TaskInclude']

@ -84,10 +84,10 @@ import ansible.plugins.loader as plugin_loader
from ansible import constants as C from ansible import constants as C
from ansible.errors import AnsibleError, AnsibleLookupError, AnsibleOptionsError from ansible.errors import AnsibleError, AnsibleLookupError, AnsibleOptionsError
from ansible.module_utils.common.sentinel import Sentinel
from ansible.module_utils.common.text.converters import to_native from ansible.module_utils.common.text.converters import to_native
from ansible.module_utils.six import string_types from ansible.module_utils.six import string_types
from ansible.plugins.lookup import LookupBase from ansible.plugins.lookup import LookupBase
from ansible.utils.sentinel import Sentinel
class MissingSetting(AnsibleOptionsError): class MissingSetting(AnsibleOptionsError):

@ -41,6 +41,7 @@ from ansible.executor.process.worker import WorkerProcess
from ansible.executor.task_result import TaskResult from ansible.executor.task_result import TaskResult
from ansible.executor.task_queue_manager import CallbackSend, DisplaySend, PromptSend from ansible.executor.task_queue_manager import CallbackSend, DisplaySend, PromptSend
from ansible.module_utils.six import string_types from ansible.module_utils.six import string_types
from ansible.module_utils.common.sentinel import Sentinel
from ansible.module_utils.common.text.converters import to_text from ansible.module_utils.common.text.converters import to_text
from ansible.module_utils.connection import Connection, ConnectionError from ansible.module_utils.connection import Connection, ConnectionError
from ansible.playbook.conditional import Conditional from ansible.playbook.conditional import Conditional
@ -53,7 +54,6 @@ from ansible.template import Templar
from ansible.utils.display import Display from ansible.utils.display import Display
from ansible.utils.fqcn import add_internal_fqcns from ansible.utils.fqcn import add_internal_fqcns
from ansible.utils.unsafe_proxy import wrap_var from ansible.utils.unsafe_proxy import wrap_var
from ansible.utils.sentinel import Sentinel
from ansible.utils.vars import combine_vars from ansible.utils.vars import combine_vars
from ansible.vars.clean import strip_internal_keys, module_response_deepcopy from ansible.vars.clean import strip_internal_keys, module_response_deepcopy

@ -1,66 +1,8 @@
# Copyright (c) 2019 Ansible Project # -*- coding: utf-8 -*-
# Copyright: Contributors to the Ansible project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import annotations from __future__ import annotations
# For Backward compatibility
class Sentinel: from ansible.module_utils.common.sentinel import Sentinel # pylint: disable=unused-import
"""
Object which can be used to mark whether an entry as being special
A sentinel value demarcates a value or marks an entry as having a special meaning. In C, the
Null byte is used as a sentinel for the end of a string. In Python, None is often used as
a Sentinel in optional parameters to mean that the parameter was not set by the user.
You should use None as a Sentinel value any Python code where None is not a valid entry. If
None is a valid entry, though, then you need to create a different value, which is the purpose
of this class.
Example of using Sentinel as a default parameter value::
def confirm_big_red_button(tristate=Sentinel):
if tristate is Sentinel:
print('You must explicitly press the big red button to blow up the base')
elif tristate is True:
print('Countdown to destruction activated')
elif tristate is False:
print('Countdown stopped')
elif tristate is None:
print('Waiting for more input')
Example of using Sentinel to tell whether a dict which has a default value has been changed::
values = {'one': Sentinel, 'two': Sentinel}
defaults = {'one': 1, 'two': 2}
# [.. Other code which does things including setting a new value for 'one' ..]
values['one'] = None
# [..]
print('You made changes to:')
for key, value in values.items():
if value is Sentinel:
continue
print('%s: %s' % (key, value)
"""
def __new__(cls):
"""
Return the cls itself. This makes both equality and identity True for comparing the class
to an instance of the class, preventing common usage errors.
Preferred usage::
a = Sentinel
if a is Sentinel:
print('Sentinel value')
However, these are True as well, eliminating common usage errors::
if Sentinel is Sentinel():
print('Sentinel value')
if Sentinel == Sentinel():
print('Sentinel value')
"""
return cls

@ -22,13 +22,13 @@ from ansible.cli.galaxy import GalaxyCLI
from ansible.config import manager from ansible.config import manager
from ansible.errors import AnsibleError from ansible.errors import AnsibleError
from ansible.galaxy import api, collection, token from ansible.galaxy import api, collection, token
from ansible.module_utils.common.sentinel import Sentinel
from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text
from ansible.module_utils.common.file import S_IRWU_RG_RO from ansible.module_utils.common.file import S_IRWU_RG_RO
import builtins import builtins
from ansible.utils import context_objects as co from ansible.utils import context_objects as co
from ansible.utils.display import Display from ansible.utils.display import Display
from ansible.utils.hashing import secure_hash_s from ansible.utils.hashing import secure_hash_s
from ansible.utils.sentinel import Sentinel
@pytest.fixture(autouse='function') @pytest.fixture(autouse='function')

@ -7,9 +7,9 @@ from __future__ import annotations
import pytest import pytest
from ansible.errors import AnsibleParserError from ansible.errors import AnsibleParserError
from ansible.module_utils.common.sentinel import Sentinel
from ansible.parsing.mod_args import ModuleArgsParser from ansible.parsing.mod_args import ModuleArgsParser
from ansible.plugins.loader import init_plugin_loader from ansible.plugins.loader import init_plugin_loader
from ansible.utils.sentinel import Sentinel
class TestModArgsDwim: class TestModArgsDwim:

Loading…
Cancel
Save