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

Add python version for content graph #3339

Merged
merged 117 commits into from
Sep 5, 2023
Merged
Show file tree
Hide file tree
Changes from 102 commits
Commits
Show all changes
117 commits
Select commit Hold shift + click to select a range
a48daef
[graph] - add python versions to scripts/integrations
GuyAfik Jul 19, 2023
ed4dbaf
add env var
GuyAfik Jul 19, 2023
d89946d
change version to string
GuyAfik Jul 19, 2023
d40dec4
pre-commit
GuyAfik Jul 19, 2023
e351398
revert _get_python_version_from_image_client testing
GuyAfik Jul 19, 2023
6aa9bb6
use image_env
GuyAfik Jul 19, 2023
a9aef2e
Merge branch 'master' of github.com:demisto/demisto-sdk into add_pyth…
GuyAfik Jul 31, 2023
9c13ffb
remove env var
GuyAfik Jul 31, 2023
7c7b37f
update
GuyAfik Jul 31, 2023
15b6033
finish
GuyAfik Jul 31, 2023
e0cbaa4
implement pydantic object for docker file info
GuyAfik Aug 2, 2023
c787c72
handle none values python_version
GuyAfik Aug 2, 2023
7f689d6
do not calculate python version for deprecated scripts/integrations
GuyAfik Aug 2, 2023
3386341
lru cache
GuyAfik Aug 2, 2023
8229a5b
remove lru
GuyAfik Aug 2, 2023
99446ec
fix type
GuyAfik Aug 2, 2023
dfd36d3
make type abstract
GuyAfik Aug 2, 2023
7204873
fix
GuyAfik Aug 2, 2023
3d594b0
fix
GuyAfik Aug 6, 2023
d8d1d2f
Merge branch 'master' of github.com:demisto/demisto-sdk into add_pyth…
GuyAfik Aug 9, 2023
8a27a51
docker file fixes
GuyAfik Aug 9, 2023
5a5af20
implement the validator for DockerImageTagMetadata
GuyAfik Aug 10, 2023
72a8ca5
use get_remote_file_from_api func
GuyAfik Aug 10, 2023
6e520e8
use class method instead of constructor
GuyAfik Aug 10, 2023
887eb06
mock python version
GuyAfik Aug 10, 2023
0d7b6cc
Merge branch 'master' of github.com:demisto/demisto-sdk into add_pyth…
GuyAfik Aug 10, 2023
cbd998b
remove mocks
GuyAfik Aug 10, 2023
3309d67
pre-commit
GuyAfik Aug 10, 2023
47642dc
fix tests
GuyAfik Aug 10, 2023
85a77ec
do not run python_version in upload / unify
GuyAfik Aug 13, 2023
44312dc
do not add python version as a property
GuyAfik Aug 13, 2023
e19eab9
fix issues
GuyAfik Aug 13, 2023
56e7f4e
remove irrelevant changes
GuyAfik Aug 13, 2023
111dc54
pre-commit
GuyAfik Aug 13, 2023
4616e68
pre-commit
GuyAfik Aug 13, 2023
bd84c02
update pre-commit
GuyAfik Aug 13, 2023
64ae081
update
GuyAfik Aug 13, 2023
188e015
save str and not Version
GuyAfik Aug 13, 2023
1cea912
fix pre-commit tests
GuyAfik Aug 13, 2023
5089e8a
add docker image to mocks
GuyAfik Aug 13, 2023
89ccd78
fix bugs
GuyAfik Aug 13, 2023
2bb650b
fixes
GuyAfik Aug 13, 2023
f686966
mock github request to get docker metadata
GuyAfik Aug 13, 2023
1b1d07d
mock in setup
GuyAfik Aug 13, 2023
9925df3
remove irrelvant mock
GuyAfik Aug 13, 2023
93309ca
black
GuyAfik Aug 13, 2023
13eb418
fix test_create_content_graph_relationships
GuyAfik Aug 13, 2023
fc2aabf
add uts
GuyAfik Aug 14, 2023
2ff0034
add ut
GuyAfik Aug 14, 2023
ae1efda
update tools
GuyAfik Aug 14, 2023
8bab6e6
pre-commit
GuyAfik Aug 14, 2023
b99ccb4
add logs for debugging
GuyAfik Aug 15, 2023
f4555a6
fix issue with singelton
GuyAfik Aug 15, 2023
a720fc3
some cr fixes
GuyAfik Aug 15, 2023
fdb89de
revert some changes
GuyAfik Aug 15, 2023
7016661
use regex to extract tag and docker folder
GuyAfik Aug 15, 2023
5103884
run-time-error to valueError
GuyAfik Aug 15, 2023
69d4b2d
add abstract class to pydnatic singelton
GuyAfik Aug 15, 2023
e29afd5
update native image
GuyAfik Aug 15, 2023
1ebab18
native image uts fixes
GuyAfik Aug 15, 2023
4cf1109
pre-commit
GuyAfik Aug 15, 2023
ea89e63
fix failing uts
GuyAfik Aug 15, 2023
38d5166
typo
GuyAfik Aug 15, 2023
b26e6ab
fix lint ut
GuyAfik Aug 15, 2023
0dab86b
extract full python version and not only major/minor
GuyAfik Aug 15, 2023
f3ec105
try to fix ut
GuyAfik Aug 15, 2023
e3d5cf6
pre-commit
GuyAfik Aug 15, 2023
ad60264
try to fix the ut
GuyAfik Aug 15, 2023
6dbda18
fix ut and update singelton file
GuyAfik Aug 15, 2023
2bda236
use parse_file instead of parse_obj
GuyAfik Aug 15, 2023
7b120d1
Merge branch 'master' of github.com:demisto/demisto-sdk into add_pyth…
GuyAfik Aug 16, 2023
f7b17fc
validate if dockerfiles metadata file was retrieved
GuyAfik Aug 16, 2023
bd9bb9e
add repo hostname
GuyAfik Aug 16, 2023
ddba1da
update
GuyAfik Aug 16, 2023
087296e
add dockerfiles-info to allowed repos
GuyAfik Aug 17, 2023
73a953a
add another test case docker helper get python ver
GuyAfik Aug 17, 2023
bede7c3
add comment
GuyAfik Aug 17, 2023
4d0c694
Merge branch 'master' of github.com:demisto/demisto-sdk into add_pyth…
GuyAfik Aug 17, 2023
be474b1
changelog
GuyAfik Aug 17, 2023
39125a0
info to debug
GuyAfik Aug 17, 2023
17c3f30
remove irrelevant code
GuyAfik Aug 17, 2023
8510379
pre-commit
GuyAfik Aug 17, 2023
c1365a4
docstrings
GuyAfik Aug 17, 2023
454e527
review fixes
GuyAfik Aug 20, 2023
b4e5fd6
update
GuyAfik Aug 20, 2023
87adbfe
fixes
GuyAfik Aug 20, 2023
e8db7f6
implement lazy field decorator
GuyAfik Aug 21, 2023
bd58922
pre-commit
GuyAfik Aug 21, 2023
cd15a02
update lazy field implementation
GuyAfik Aug 21, 2023
2603ae7
add ut
GuyAfik Aug 21, 2023
17799b4
update failed ut
GuyAfik Aug 22, 2023
997cc9a
update
GuyAfik Aug 22, 2023
14d4cae
update uts
GuyAfik Aug 22, 2023
36e83e8
update ut
GuyAfik Aug 22, 2023
7a74f3e
update ut
GuyAfik Aug 22, 2023
050cae5
update
GuyAfik Aug 22, 2023
2f997c4
side effect
GuyAfik Aug 22, 2023
3061b11
Merge branch 'master' of github.com:demisto/demisto-sdk into add_pyth…
GuyAfik Aug 22, 2023
5dab8b5
try to fix uts
GuyAfik Aug 22, 2023
98f7a73
remove irrelvant code
GuyAfik Aug 22, 2023
c8bdf74
final cr fixes
GuyAfik Aug 22, 2023
c7f9f02
final cr
GuyAfik Aug 22, 2023
6a191d2
cr fixes
GuyAfik Aug 27, 2023
274dbe2
pre-commit
GuyAfik Aug 27, 2023
c5545aa
cr fixes
GuyAfik Aug 27, 2023
785fe43
cr fixes
GuyAfik Aug 27, 2023
a730333
cr fixes
GuyAfik Aug 28, 2023
7048b6a
Merge branch 'master' of github.com:demisto/demisto-sdk into add_pyth…
GuyAfik Aug 28, 2023
5e991fb
pre-commit
GuyAfik Aug 28, 2023
1f06db7
Merge branch 'master' of github.com:demisto/demisto-sdk into add_pyth…
GuyAfik Aug 29, 2023
544f3ec
Merge branch 'master' of github.com:demisto/demisto-sdk into add_pyth…
GuyAfik Aug 30, 2023
259a866
Merge branch 'master' of github.com:demisto/demisto-sdk into add_pyth…
GuyAfik Aug 30, 2023
dad6554
Merge branch 'master' of github.com:demisto/demisto-sdk into add_pyth…
GuyAfik Aug 31, 2023
507d94a
Merge branch 'master' of github.com:demisto/demisto-sdk into add_pyth…
GuyAfik Sep 5, 2023
2f3df4c
changelog
GuyAfik Sep 5, 2023
b762077
Merge branch 'master' of github.com:demisto/demisto-sdk into add_pyth…
GuyAfik Sep 5, 2023
c7c6a1e
Merge branch 'master' of github.com:demisto/demisto-sdk into add_pyth…
GuyAfik Sep 5, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* Added a period at the end of lines produced by the **generate-docs** command that state the tested version of the product.
* Update `RN112` validation's docs reference link.
* Fixed an issue in calculating content graph hash when creating or updating it.
* The content graph will now include the **python_version** field that each script/integration uses.
* Calling **graph create** or **graph update** now run the commands with default arguments, instead of showing the command help.
* Removed the use of chunks when calculating content relationships.

Expand Down
1 change: 1 addition & 0 deletions demisto_sdk/commands/common/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -1845,5 +1845,6 @@ class ParameterType(Enum):
FORMATTING_SCRIPT = "indicator-format"

ENV_SDK_WORKING_OFFLINE = "DEMISTO_SDK_OFFLINE_ENV"
DOCKERFILES_INFO_REPO = "demisto/dockerfiles-info"

TEST_COVERAGE_DEFAULT_URL = "https://storage.googleapis.com/marketplace-dist-dev/code-coverage-reports/coverage-min.json"
83 changes: 66 additions & 17 deletions demisto_sdk/commands/common/docker_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@
from demisto_sdk.commands.common.constants import (
DEFAULT_PYTHON2_VERSION,
DEFAULT_PYTHON_VERSION,
DOCKERFILES_INFO_REPO,
TYPE_PWSH,
TYPE_PYTHON,
TYPE_PYTHON2,
TYPE_PYTHON3,
)
from demisto_sdk.commands.common.docker_images_metadata import DockerImagesMetadata
from demisto_sdk.commands.common.logger import logger

DOCKER_CLIENT = None
Expand All @@ -36,7 +38,9 @@
)
)

PYTHON_IMAGE_REGEX = re.compile(r"[\d\w]+/python3?:(?P<python_version>[23]\.\d+)")
DEMISTO_PYTHON_BASE_IMAGE_REGEX = re.compile(
r"[\d\w]+/python3?:(?P<python_version>[23]\.\d+(\.\d+)?)"
)

TEST_REQUIREMENTS_DIR = Path(__file__).parent.parent / "lint" / "resources"

Expand Down Expand Up @@ -286,8 +290,12 @@ def pull_or_create_test_image(
The test image name and errors to create it if any
"""
errors = ""
if not python_version and container_type != TYPE_PWSH:
python_version = get_python_version(base_image).major
if (
not python_version
GuyAfik marked this conversation as resolved.
Show resolved Hide resolved
and container_type != TYPE_PWSH
and (version := get_python_version(base_image))
):
python_version = version.major
python3_requirements = get_pip_requirements_from_file(
TEST_REQUIREMENTS_DIR / "python3_requirements" / "dev-requirements.txt"
)
Expand Down Expand Up @@ -400,6 +408,14 @@ def get_docker():
return MountableDocker() if CAN_MOUNT_FILES else DockerBase()


def _get_python_version_from_tag_by_regex(image: str) -> Optional[Version]:

if match := DEMISTO_PYTHON_BASE_IMAGE_REGEX.match(image):
return Version(match.group("python_version"))

return None


def _get_docker_hub_token(repo: str) -> str:
auth = None

Expand Down Expand Up @@ -467,25 +483,49 @@ def _get_python_version_from_env(env: List[str]) -> Version:


@functools.lru_cache
def get_python_version(image: Optional[str]) -> Version:
log_prompt = f"Get python version from image {image}"
logger.debug(f"{log_prompt} - Start")
if not image or "pwsh" in image or "powershell" in image:
def get_python_version(image: Optional[str]):
GuyAfik marked this conversation as resolved.
Show resolved Hide resolved
"""
Get the python version of a docker image if exist.

Args:
image (str): the docker image

Returns:
Version: Python version X.Y (3.7, 3.6, ..)
"""
logger.debug(f"Get python version from image {image=}")

if not image:
# When no docker_image is specified, we use the default python version which is Python 2.7.18
logger.debug(
f"No docker image specified or a powershell image, using default python version: {DEFAULT_PYTHON2_VERSION}"
GuyAfik marked this conversation as resolved.
Show resolved Hide resolved
)
return Version(DEFAULT_PYTHON2_VERSION)
if match := PYTHON_IMAGE_REGEX.match(image):
return Version(match.group("python_version"))

if "pwsh" in image or "powershell" in image:
logger.debug(
f"The {image=} is a powershell image, does not have python version"
)
return None

if python_version := DockerImagesMetadata.get_instance().python_version(image):
return python_version
logger.debug(
f"Could not get python version for {image=} from {DOCKERFILES_INFO_REPO} repo"
)

if python_version := _get_python_version_from_tag_by_regex(image):
return python_version
logger.debug(f"Could not get python version for {image=} from regex")

try:
return _get_python_version_from_image_client(image)
logger.debug(f"get python version for {image=} from dockerhub api")
return _get_python_version_from_dockerhub_api(image)
except Exception:
logger.debug(
"Could not get the python version from client. Trying with API",
exc_info=True,
f"Getting python version from {image=} by pulling its image and query its env"
)
return _get_python_version_from_dockerhub_api(image)
return _get_python_version_from_image_client(image)


def _get_python_version_from_image_client(image: str) -> Version:
Expand All @@ -499,15 +539,24 @@ def _get_python_version_from_image_client(image: str) -> Version:
"""
try:
image_model = DockerBase.pull_image(image)
env = image_model.attrs["Config"]["Env"]
logger.debug(f"Got {env=} from {image=}")
return _get_python_version_from_env(env)
image_env = image_model.attrs["Config"]["Env"]
logger.debug(f"Got {image_env=} from {image=}")
return _get_python_version_from_env(image_env)
except Exception:
logger.exception(f"Failed detecting Python version for {image=}")
raise


def _get_python_version_from_dockerhub_api(image: str):
def _get_python_version_from_dockerhub_api(image: str) -> Version:
"""
Get python version for a docker image from the dockerhub api

Args:
image (str): the docker image.

Returns:
Version: Python version X.Y (3.7, 3.6, ..)
"""
if ":" not in image:
repo = image
tag = "latest"
Expand Down
101 changes: 101 additions & 0 deletions demisto_sdk/commands/common/docker_images_metadata.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import re
from enum import Enum
from typing import Dict, Optional

from packaging.version import Version
from pydantic import BaseModel

from demisto_sdk.commands.common.constants import (
DOCKERFILES_INFO_REPO,
)
from demisto_sdk.commands.common.git_content_config import GitContentConfig
from demisto_sdk.commands.common.logger import logger
from demisto_sdk.commands.common.singleton import PydanticSingleton
from demisto_sdk.commands.common.tools import get_remote_file_from_api

DOCKER_IMAGES_METADATA_NAME = "docker_images_metadata.json"

# regex to extract docker-images that are specific to content / dockerfiles
DOCKER_IMAGE_REGEX = r"^demisto/([^\s:]+):(\d+(\.\d+)*)$"
GuyAfik marked this conversation as resolved.
Show resolved Hide resolved


class DockerImageTagMetadata(BaseModel):
python_version: Optional[str]


class DockerImagesMetadata(PydanticSingleton, BaseModel):
docker_images: Dict[str, Dict[str, DockerImageTagMetadata]]
GuyAfik marked this conversation as resolved.
Show resolved Hide resolved

class MetadataValues(str, Enum):
PYTHON_VERSION = "python_version"

@classmethod
def get_instance_from(cls, *args, **kwargs):
return cls.__from_github(*args, **kwargs)

@classmethod
def __from_github(
cls, file_name: str = DOCKER_IMAGES_METADATA_NAME, tag: str = "master"
):
"""
Get the docker_images_metadata.json from the dockerfiles-info repo and load it to a pydnatic object.

Args:
file_name (str): the file path for the docker_images_metadata.json
tag (str): branch/commit to get a specific docker_images_metadata.json

"""
logger.debug(
f"Trying to load the {DOCKER_IMAGES_METADATA_NAME} from {DOCKERFILES_INFO_REPO}"
)
dockerfiles_metadata = get_remote_file_from_api(
file_name,
tag=tag,
git_content_config=GitContentConfig(repo_name=DOCKERFILES_INFO_REPO),
encoding="utf-8-sig",
)
if not dockerfiles_metadata:
logger.error(
f"Could not retrieve the {DOCKER_IMAGES_METADATA_NAME} from {DOCKERFILES_INFO_REPO} repo"
)
dockerfiles_metadata = {"docker_images": {}}

return cls.parse_obj(dockerfiles_metadata)

def __get_metadata_value(
self, docker_image: str, docker_metadata_key: str
) -> Optional[str]:
"""
Get the content of the requested key in the metadata

Args:
docker_image (str): the docker image from the script/integration yml
docker_metadata_key (str): the key in the DockerImageTagMetadata class
"""
try:
# if we were not able to load the file
if not self.docker_images:
return None
match = re.match(DOCKER_IMAGE_REGEX, docker_image)
docker_name, tag = match.group(1), match.group(2) # type: ignore[union-attr]
docker_image_metadata = (self.docker_images.get(docker_name) or {}).get(tag)
return getattr(docker_image_metadata, docker_metadata_key)
except (AttributeError, ValueError, TypeError) as err:
logger.debug(
f"Could not get {docker_metadata_key} for {docker_image=} because {err=} occurred"
)
return None

def python_version(self, docker_image: str) -> Optional[Version]:
"""
Get the python version of a docker image.
"""
if python_version := self.__get_metadata_value(
docker_image, self.MetadataValues.PYTHON_VERSION
):
logger.debug(
f"successfully got {python_version=} for {docker_image=} from {DOCKER_IMAGES_METADATA_NAME}"
)
return Version(python_version)

return None
2 changes: 2 additions & 0 deletions demisto_sdk/commands/common/git_content_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
# dirs
import requests

from demisto_sdk.commands.common.constants import DOCKERFILES_INFO_REPO
from demisto_sdk.commands.common.git_util import GitUtil
from demisto_sdk.commands.common.handlers import DEFAULT_JSON_HANDLER as json

Expand Down Expand Up @@ -67,6 +68,7 @@ class GitContentConfig:
(GITHUB_USER_CONTENT, OFFICIAL_CONTENT_REPO_NAME),
(GITHUB, OFFICIAL_CONTENT_REPO_NAME),
(CODE_PAN_RUN, OFFICIAL_CONTENT_PROJECT_ID),
(GITHUB_USER_CONTENT, DOCKERFILES_INFO_REPO),
}

CREDENTIALS = GitCredentials()
Expand Down
65 changes: 23 additions & 42 deletions demisto_sdk/commands/common/native_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,8 @@

from demisto_sdk.commands.common.constants import NATIVE_IMAGE_FILE_NAME
from demisto_sdk.commands.common.logger import logger
from demisto_sdk.commands.common.singleton import Singleton
from demisto_sdk.commands.common.tools import (
extract_docker_image_from_text,
get_dict_from_file,
)
from demisto_sdk.commands.common.singleton import PydanticSingleton
from demisto_sdk.commands.common.tools import extract_docker_image_from_text


class NativeImage(BaseModel):
Expand All @@ -26,19 +23,23 @@ def _extract_native_image_version_for_server(native_image: str) -> str:
return native_image.replace("native:", "")


class NativeImageConfig(Singleton, BaseModel):
class NativeImageConfig(PydanticSingleton, BaseModel):
native_images: Dict[str, NativeImage]
ignored_content_items: List[IgnoredContentItem]
flags_versions_mapping: Dict[str, str] = {}
docker_images_to_native_images_mapping: Dict[str, List] = {}

def __init__(
self, native_image_config_file_path: str = f"Tests/{NATIVE_IMAGE_FILE_NAME}"
@classmethod
def get_instance_from(cls, *args, **kwargs):
return cls.from_path(*args, **kwargs)

@classmethod
def from_path(
cls, native_image_config_file_path: str = f"Tests/{NATIVE_IMAGE_FILE_NAME}"
GuyAfik marked this conversation as resolved.
Show resolved Hide resolved
):
super().__init__(**self.load(native_image_config_file_path))
self.docker_images_to_native_images_mapping = (
self.__docker_images_to_native_images_support()
)
native_image_config = cls.parse_file(native_image_config_file_path)
native_image_config.__docker_images_to_native_images_support()
return native_image_config

def __docker_images_to_native_images_support(self):
"""
Expand All @@ -53,29 +54,18 @@ def __docker_images_to_native_images_support(self):
chromium docker image is supported in both 8.1.0, 8.2.0 native images
while tesseract is only supported in 8.1.0
"""
docker_images_to_native_images_mapping: Dict = {}

for native_image_name, native_image_obj in self.native_images.items():
for supported_docker_image in native_image_obj.supported_docker_images:
if supported_docker_image not in docker_images_to_native_images_mapping:
docker_images_to_native_images_mapping[supported_docker_image] = []
docker_images_to_native_images_mapping[supported_docker_image].append(
native_image_name
)

return docker_images_to_native_images_mapping

@staticmethod
def load(
native_image_config_file_path: str = f"Tests/{NATIVE_IMAGE_FILE_NAME}",
) -> Dict:
"""
Load the native image configuration file
"""
native_image_config_content, _ = get_dict_from_file(
native_image_config_file_path
)
return native_image_config_content
if (
supported_docker_image
not in self.docker_images_to_native_images_mapping
):
self.docker_images_to_native_images_mapping[
supported_docker_image
] = []
self.docker_images_to_native_images_mapping[
supported_docker_image
].append(native_image_name)

def get_native_image_reference(self, native_image) -> Optional[str]:
"""
Expand Down Expand Up @@ -182,12 +172,3 @@ def get_supported_native_image_versions(
)
return native_images
return []


def file_to_native_image_config(
native_image_config_file_path: str = f"Tests/{NATIVE_IMAGE_FILE_NAME}",
) -> NativeImageConfig:
"""
Converts the native image file to NativeImageConfig object.
"""
return NativeImageConfig(native_image_config_file_path)
21 changes: 17 additions & 4 deletions demisto_sdk/commands/common/singleton.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
class Singleton:
from abc import abstractmethod


class PydanticSingleton:
_instance = None
GuyAfik marked this conversation as resolved.
Show resolved Hide resolved

def __new__(cls, *args, **kwargs):
if not isinstance(cls._instance, cls):
cls._instance = super().__new__(cls)
@classmethod
def get_instance(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = cls.get_instance_from(*args, **kwargs)
return cls._instance

@classmethod
@abstractmethod
def get_instance_from(cls, *args, **kwargs):
"""
GuyAfik marked this conversation as resolved.
Show resolved Hide resolved
Pydantic objects should be initialized with class methods and not from the class constructor.
Each Singleton that is based on pydantic should implement this abstract method.
"""
pass