python-sdk-remote 0.0.188b3517__tar.gz → 0.0.190b3356__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {python_sdk_remote-0.0.188b3517 → python_sdk_remote-0.0.190b3356}/PKG-INFO +1 -1
- {python_sdk_remote-0.0.188b3517 → python_sdk_remote-0.0.190b3356}/python_sdk_remote/src/__init__.py +2 -2
- python_sdk_remote-0.0.190b3356/python_sdk_remote/src/dot_env_files.py +80 -0
- python_sdk_remote-0.0.190b3356/python_sdk_remote/src/environment.py +21 -0
- python_sdk_remote-0.0.190b3356/python_sdk_remote/src/environment_variable_exception.py +2 -0
- python_sdk_remote-0.0.190b3356/python_sdk_remote/src/filesystem.py +15 -0
- python_sdk_remote-0.0.190b3356/python_sdk_remote/src/masking.py +8 -0
- python_sdk_remote-0.0.190b3356/python_sdk_remote/src/our_environment_variable.py +96 -0
- python_sdk_remote-0.0.188b3517/python_sdk_remote/src/environment_variable_exception.py → python_sdk_remote-0.0.190b3356/python_sdk_remote/src/our_environment_variable_exception.py +5 -1
- python_sdk_remote-0.0.190b3356/python_sdk_remote/src/personal_repo.py +31 -0
- {python_sdk_remote-0.0.188b3517 → python_sdk_remote-0.0.190b3356}/python_sdk_remote/src/unified_json.py +6 -2
- python_sdk_remote-0.0.190b3356/python_sdk_remote/src/username.py +11 -0
- {python_sdk_remote-0.0.188b3517 → python_sdk_remote-0.0.190b3356}/python_sdk_remote/src/utilities.py +28 -127
- {python_sdk_remote-0.0.188b3517 → python_sdk_remote-0.0.190b3356}/python_sdk_remote.egg-info/PKG-INFO +1 -1
- {python_sdk_remote-0.0.188b3517 → python_sdk_remote-0.0.190b3356}/python_sdk_remote.egg-info/SOURCES.txt +8 -0
- {python_sdk_remote-0.0.188b3517 → python_sdk_remote-0.0.190b3356}/setup.py +1 -1
- {python_sdk_remote-0.0.188b3517 → python_sdk_remote-0.0.190b3356}/README.md +0 -0
- {python_sdk_remote-0.0.188b3517 → python_sdk_remote-0.0.190b3356}/pyproject.toml +0 -0
- {python_sdk_remote-0.0.188b3517 → python_sdk_remote-0.0.190b3356}/python_sdk_remote/src/constants.py +0 -0
- {python_sdk_remote-0.0.188b3517 → python_sdk_remote-0.0.190b3356}/python_sdk_remote/src/constants_src_mini_logger_and_logger.py +0 -0
- {python_sdk_remote-0.0.188b3517 → python_sdk_remote-0.0.190b3356}/python_sdk_remote/src/datetime_range.py +0 -0
- {python_sdk_remote-0.0.188b3517 → python_sdk_remote-0.0.190b3356}/python_sdk_remote/src/filename.py +0 -0
- {python_sdk_remote-0.0.188b3517 → python_sdk_remote-0.0.190b3356}/python_sdk_remote/src/generic_crud.py +0 -0
- {python_sdk_remote-0.0.188b3517 → python_sdk_remote-0.0.190b3356}/python_sdk_remote/src/http_response.py +0 -0
- {python_sdk_remote-0.0.188b3517 → python_sdk_remote-0.0.190b3356}/python_sdk_remote/src/is_test_data.py +0 -0
- {python_sdk_remote-0.0.188b3517 → python_sdk_remote-0.0.190b3356}/python_sdk_remote/src/item.py +0 -0
- {python_sdk_remote-0.0.188b3517 → python_sdk_remote-0.0.190b3356}/python_sdk_remote/src/mini_logger.py +0 -0
- {python_sdk_remote-0.0.188b3517 → python_sdk_remote-0.0.190b3356}/python_sdk_remote/src/our_obfuscation.py +0 -0
- {python_sdk_remote-0.0.188b3517 → python_sdk_remote-0.0.190b3356}/python_sdk_remote/src/our_object.py +0 -0
- {python_sdk_remote-0.0.188b3517 → python_sdk_remote-0.0.190b3356}/python_sdk_remote/src/our_objects.py +0 -0
- {python_sdk_remote-0.0.188b3517 → python_sdk_remote-0.0.190b3356}/python_sdk_remote/src/our_objects_local.py +0 -0
- {python_sdk_remote-0.0.188b3517 → python_sdk_remote-0.0.190b3356}/python_sdk_remote/src/our_objects_remote.py +0 -0
- {python_sdk_remote-0.0.188b3517 → python_sdk_remote-0.0.190b3356}/python_sdk_remote/src/our_request.py +0 -0
- {python_sdk_remote-0.0.188b3517 → python_sdk_remote-0.0.190b3356}/python_sdk_remote/src/our_request_old.py +0 -0
- {python_sdk_remote-0.0.188b3517 → python_sdk_remote-0.0.190b3356}/python_sdk_remote/src/valid_json_versions.py +0 -0
- {python_sdk_remote-0.0.188b3517 → python_sdk_remote-0.0.190b3356}/python_sdk_remote/src/validate_environment.py +0 -0
- {python_sdk_remote-0.0.188b3517 → python_sdk_remote-0.0.190b3356}/python_sdk_remote/src/version.py +0 -0
- {python_sdk_remote-0.0.188b3517 → python_sdk_remote-0.0.190b3356}/python_sdk_remote.egg-info/dependency_links.txt +0 -0
- {python_sdk_remote-0.0.188b3517 → python_sdk_remote-0.0.190b3356}/python_sdk_remote.egg-info/requires.txt +0 -0
- {python_sdk_remote-0.0.188b3517 → python_sdk_remote-0.0.190b3356}/python_sdk_remote.egg-info/top_level.txt +0 -0
- {python_sdk_remote-0.0.188b3517 → python_sdk_remote-0.0.190b3356}/setup.cfg +0 -0
{python_sdk_remote-0.0.188b3517 → python_sdk_remote-0.0.190b3356}/python_sdk_remote/src/__init__.py
RENAMED
|
@@ -10,7 +10,7 @@ from .utilities import (
|
|
|
10
10
|
get_environment_name,
|
|
11
11
|
get_brand_name,
|
|
12
12
|
our_get_env,
|
|
13
|
-
|
|
13
|
+
OurEnvironmentVariableException,
|
|
14
14
|
our_set_env,
|
|
15
15
|
our_delete_env,
|
|
16
16
|
to_dict,
|
|
@@ -83,7 +83,7 @@ __all__ = [
|
|
|
83
83
|
'get_environment_name',
|
|
84
84
|
'get_brand_name',
|
|
85
85
|
'our_get_env',
|
|
86
|
-
'
|
|
86
|
+
'OurEnvironmentVariableException',
|
|
87
87
|
'our_set_env',
|
|
88
88
|
'our_delete_env',
|
|
89
89
|
'to_dict',
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
from dotenv import dotenv_values
|
|
5
|
+
|
|
6
|
+
from .filesystem import _find_nearest_file
|
|
7
|
+
from .masking import _mask
|
|
8
|
+
from .mini_logger import MiniLogger as logger
|
|
9
|
+
from .personal_repo import PERSONAL_REPO_DOT_ENV_DIRECTORY, get_personal_repo_path
|
|
10
|
+
|
|
11
|
+
DOT_ENV_FILENAME = ".env"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def get_dot_env_file_value(dot_env_filename: str, key: str) -> Optional[str]:
|
|
15
|
+
"""The value of key in a .env file, None when the file or the key is missing"""
|
|
16
|
+
if not os.path.isfile(dot_env_filename):
|
|
17
|
+
return None
|
|
18
|
+
return dotenv_values(dot_env_filename).get(key)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def get_our_dot_env_filenames(start_directory: Optional[str] = None, environment_name: Optional[str] = None,
|
|
22
|
+
personal_repo_path: Optional[str] = None) -> list:
|
|
23
|
+
"""The .env files our_get_env() looks in, in this order: the project's .env.<ENVIRONMENT_NAME> and .env (the nearest
|
|
24
|
+
ones from the current directory up), then the personal repo's .config/circlez.ai/.env.<ENVIRONMENT_NAME> and
|
|
25
|
+
.config/circlez.ai/.env"""
|
|
26
|
+
# Not get_environment_name(), which calls our_get_env()
|
|
27
|
+
environment_name = environment_name or os.environ.get("ENVIRONMENT_NAME")
|
|
28
|
+
dot_env_basenames = ([f"{DOT_ENV_FILENAME}.{environment_name}"] if environment_name else []) + [DOT_ENV_FILENAME]
|
|
29
|
+
dot_env_filenames = []
|
|
30
|
+
for dot_env_basename in dot_env_basenames:
|
|
31
|
+
dot_env_filename = _find_nearest_file(dot_env_basename, start_directory)
|
|
32
|
+
if dot_env_filename:
|
|
33
|
+
dot_env_filenames.append(dot_env_filename)
|
|
34
|
+
personal_repo_path = personal_repo_path or get_personal_repo_path()
|
|
35
|
+
if personal_repo_path:
|
|
36
|
+
for dot_env_basename in dot_env_basenames:
|
|
37
|
+
dot_env_filename = os.path.join(personal_repo_path, PERSONAL_REPO_DOT_ENV_DIRECTORY, dot_env_basename)
|
|
38
|
+
if os.path.isfile(dot_env_filename) and dot_env_filename not in dot_env_filenames:
|
|
39
|
+
dot_env_filenames.append(dot_env_filename)
|
|
40
|
+
return dot_env_filenames
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _get_env_or_dot_env(key: str) -> Optional[str]:
|
|
44
|
+
"""The environment variable, otherwise its value in the .env files of get_our_dot_env_filenames(), which is then
|
|
45
|
+
set in the environment so the next lookup does not read the files again"""
|
|
46
|
+
env_var = os.getenv(key)
|
|
47
|
+
if env_var is not None:
|
|
48
|
+
return env_var
|
|
49
|
+
for dot_env_filename in get_our_dot_env_filenames():
|
|
50
|
+
dot_env_value = get_dot_env_file_value(dot_env_filename, key)
|
|
51
|
+
if dot_env_value:
|
|
52
|
+
os.environ[key] = dot_env_value
|
|
53
|
+
logger.info(f"our_get_env() found {key}={_mask(dot_env_value)} in {dot_env_filename}")
|
|
54
|
+
return dot_env_value
|
|
55
|
+
return None
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
# TODO shall we rename the function _file_ to _key_value_file_
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def add_to_file_if_not_existed(file: str, key: str, value: Optional[str]) -> None:
|
|
62
|
+
logger.start(object={"file": file, "key": key, "value": value})
|
|
63
|
+
if not os.path.exists(file):
|
|
64
|
+
with open(file, "w") as f:
|
|
65
|
+
f.write(f"{key}={value}\n")
|
|
66
|
+
else:
|
|
67
|
+
with open(file, "r") as f:
|
|
68
|
+
lines = f.readlines()
|
|
69
|
+
if f"{key}=" not in lines:
|
|
70
|
+
with open(file, "a") as f:
|
|
71
|
+
f.write(f"{key}={value}\n")
|
|
72
|
+
logger.end()
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def update_dot_env_example(key: str, value: Optional[str]):
|
|
76
|
+
# Avoid recursion by checking environment directly
|
|
77
|
+
env_name = os.getenv("ENVIRONMENT_NAME", "").lower()
|
|
78
|
+
if env_name == "play1":
|
|
79
|
+
return
|
|
80
|
+
add_to_file_if_not_existed(file=".env.example", key=key, value=value)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from url_remote.environment_name_enum import EnvironmentName
|
|
4
|
+
|
|
5
|
+
from .our_environment_variable import our_get_env
|
|
6
|
+
from .version import PACKAGE_VERSION
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def get_environment_name(raise_if_not_found: bool = True,
|
|
10
|
+
raise_if_empty: bool = False) -> Optional[str]:
|
|
11
|
+
environment_name = our_get_env("ENVIRONMENT_NAME",
|
|
12
|
+
raise_if_not_found=raise_if_not_found,
|
|
13
|
+
raise_if_empty=raise_if_empty)
|
|
14
|
+
try:
|
|
15
|
+
EnvironmentName(environment_name) # if invalid, raises ValueError: x is not a valid EnvironmentName
|
|
16
|
+
except ValueError:
|
|
17
|
+
# Shows the current PACKAGE_VERSION for debugging
|
|
18
|
+
raise Exception(f"python-sdk-remote {PACKAGE_VERSION} get_environment_name(): Invalid EnvironmentName: "
|
|
19
|
+
f"{environment_name} either misspelling or you need the environment in a few places such as "
|
|
20
|
+
"url-remote-python-package environment_name_enum.py ...")
|
|
21
|
+
return environment_name
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def _find_nearest_file(filename: str, start_directory: Optional[str] = None) -> Optional[str]:
|
|
6
|
+
"""The nearest filename from start_directory (default: the current directory) up, as python-dotenv finds .env"""
|
|
7
|
+
directory = os.path.abspath(start_directory or os.getcwd())
|
|
8
|
+
while True:
|
|
9
|
+
candidate = os.path.join(directory, filename)
|
|
10
|
+
if os.path.isfile(candidate):
|
|
11
|
+
return candidate
|
|
12
|
+
parent_directory = os.path.dirname(directory)
|
|
13
|
+
if parent_directory == directory:
|
|
14
|
+
return None
|
|
15
|
+
directory = parent_directory
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
from .dot_env_files import _get_env_or_dot_env, update_dot_env_example
|
|
5
|
+
from .masking import _mask
|
|
6
|
+
from .mini_logger import MiniLogger as logger
|
|
7
|
+
from .our_environment_variable_exception import OurEnvironmentVariableException
|
|
8
|
+
|
|
9
|
+
# TODO If running in a lower environment(i.e. local1, play1) if key do not exit in Personal Repo relevant
|
|
10
|
+
# .env.{environment_} or value diffrent update Personal Repo (create new and comment the old record)
|
|
11
|
+
# TODO If running in a lower environment(i.e. local1, play1) update .env.example with the key without the value
|
|
12
|
+
# TODO If running in a lower environment(i.e. local1, play1) and the key do not exist look for it in the Team Member
|
|
13
|
+
# Personal Repo and copy both the key and value to the repo .env.{environment_name} file
|
|
14
|
+
# TODO move all our_*_env() to our_env.py
|
|
15
|
+
# TODO shall we rename optional_prefix to prefix?
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def our_get_env(key: str, default: Optional[str] = None, raise_if_not_found: bool = True,
|
|
19
|
+
raise_if_empty: bool = False, optional_prefix: Optional[str] = None) -> Optional[str]:
|
|
20
|
+
"""
|
|
21
|
+
Get environment variable with optional prefix fallback.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
key: Environment variable name
|
|
25
|
+
default: Default value if not found
|
|
26
|
+
raise_if_not_found: Raise exception if variable not found and no default
|
|
27
|
+
raise_if_empty: Raise exception if variable is empty
|
|
28
|
+
optional_prefix: Try with this prefix first, then without it
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
Environment variable value
|
|
32
|
+
"""
|
|
33
|
+
logger.start(object={"key": key, "default": default,
|
|
34
|
+
"raise_if_not_found": raise_if_not_found,
|
|
35
|
+
"raise_if_empty": raise_if_empty,
|
|
36
|
+
"optional_prefix": optional_prefix})
|
|
37
|
+
|
|
38
|
+
# A key missing in the environment is looked for in the project's .env.<ENVIRONMENT_NAME> and .env, then in the
|
|
39
|
+
# personal repo's .config/circlez.ai/.env.<ENVIRONMENT_NAME> and .env (as PowerShell Get-OurEnvironmentVariable and
|
|
40
|
+
# TypeScript ourGetEnv)
|
|
41
|
+
# Try with prefix first if provided
|
|
42
|
+
if optional_prefix:
|
|
43
|
+
prefixed_key = f"{optional_prefix}_{key}"
|
|
44
|
+
env_var = _get_env_or_dot_env(prefixed_key)
|
|
45
|
+
if env_var is not None:
|
|
46
|
+
logger.end(object={"env_var": _mask(env_var), "used_prefix": True})
|
|
47
|
+
return env_var.strip('"\'') if isinstance(env_var, str) else env_var
|
|
48
|
+
|
|
49
|
+
# Try without prefix
|
|
50
|
+
env_var = _get_env_or_dot_env(key)
|
|
51
|
+
if env_var is None:
|
|
52
|
+
env_var = default
|
|
53
|
+
|
|
54
|
+
if ((raise_if_not_found and key not in os.environ and default is None)
|
|
55
|
+
or (raise_if_empty and not env_var and not default)):
|
|
56
|
+
raise OurEnvironmentVariableException(f"Environment variable {key} not found - please check your .env file") # noqa: E501
|
|
57
|
+
|
|
58
|
+
# Strip quotes from env_var if present
|
|
59
|
+
if env_var and isinstance(env_var, str):
|
|
60
|
+
env_var = env_var.strip('"\'')
|
|
61
|
+
|
|
62
|
+
update_dot_env_example(key, value=default)
|
|
63
|
+
logger.end(object={"env_var": _mask(env_var)})
|
|
64
|
+
return env_var
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def our_set_env(key: str, value: str) -> None:
|
|
68
|
+
"""
|
|
69
|
+
Set an environment variable, routed through the logger so the system can
|
|
70
|
+
track which repos/tests write which env vars (cf. our_get_env).
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
key: Environment variable name
|
|
74
|
+
value: Value to set
|
|
75
|
+
"""
|
|
76
|
+
logger.start(object={"key": key, "value": value})
|
|
77
|
+
os.environ[key] = value
|
|
78
|
+
logger.end(object={"key": key})
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def our_delete_env(key: str, raise_if_not_found: bool = False) -> None:
|
|
82
|
+
"""
|
|
83
|
+
Delete an environment variable if present, routed through the logger
|
|
84
|
+
(cf. our_get_env / our_set_env).
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
key: Environment variable name
|
|
88
|
+
raise_if_not_found: Raise if the variable is not set
|
|
89
|
+
"""
|
|
90
|
+
logger.start(object={"key": key,
|
|
91
|
+
"raise_if_not_found": raise_if_not_found})
|
|
92
|
+
if key in os.environ:
|
|
93
|
+
del os.environ[key]
|
|
94
|
+
elif raise_if_not_found:
|
|
95
|
+
raise OurEnvironmentVariableException(f"Environment variable {key} not found") # noqa: E501
|
|
96
|
+
logger.end(object={"key": key})
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
class
|
|
1
|
+
class OurEnvironmentVariableException(Exception):
|
|
2
2
|
"""Raised when a required environment variable is missing or empty.
|
|
3
3
|
|
|
4
4
|
A specific exception (rather than a generic Exception) so callers can catch
|
|
5
5
|
exactly this case; shared by our_get_env / our_delete_env for consistency.
|
|
6
6
|
"""
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# Backward compatibility: the name before the Our prefix
|
|
10
|
+
EnvironmentVariableException = OurEnvironmentVariableException
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
from .username import _get_username_from_full_name
|
|
5
|
+
|
|
6
|
+
PERSONAL_REPO_DIRECTORY_SUFFIX = "-circlez.ai"
|
|
7
|
+
# The directory of the .env files in the personal repo
|
|
8
|
+
PERSONAL_REPO_DOT_ENV_DIRECTORY = os.path.join(".config", "circlez.ai")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def get_personal_repo_path() -> Optional[str]:
|
|
12
|
+
"""The personal repo (i.e. /repos/circlez/tal-circlez.ai), as PowerShell Get-PersonalRepoDirectory:
|
|
13
|
+
PERSONAL_REPO_PATH when set, otherwise <REPOS_ORGANIZATION_BASE>/<username>-circlez.ai with the username from
|
|
14
|
+
FULL_NAME, otherwise the only *-circlez.ai directory in REPOS_ORGANIZATION_BASE. None when it cannot be found"""
|
|
15
|
+
personal_repo_path = os.environ.get("PERSONAL_REPO_PATH")
|
|
16
|
+
if personal_repo_path:
|
|
17
|
+
return personal_repo_path
|
|
18
|
+
repos_organization_base = os.environ.get("REPOS_ORGANIZATION_BASE")
|
|
19
|
+
if not repos_organization_base or not os.path.isdir(repos_organization_base):
|
|
20
|
+
return None
|
|
21
|
+
full_name = os.environ.get("FULL_NAME")
|
|
22
|
+
username = _get_username_from_full_name(full_name) if full_name else None
|
|
23
|
+
if username:
|
|
24
|
+
personal_repo_path = os.path.join(repos_organization_base, username + PERSONAL_REPO_DIRECTORY_SUFFIX)
|
|
25
|
+
if os.path.isdir(personal_repo_path):
|
|
26
|
+
return personal_repo_path
|
|
27
|
+
personal_repo_paths = [os.path.join(repos_organization_base, directory)
|
|
28
|
+
for directory in os.listdir(repos_organization_base)
|
|
29
|
+
if directory.endswith(PERSONAL_REPO_DIRECTORY_SUFFIX)
|
|
30
|
+
and os.path.isdir(os.path.join(repos_organization_base, directory))]
|
|
31
|
+
return personal_repo_paths[0] if len(personal_repo_paths) == 1 else None
|
|
@@ -5,9 +5,8 @@ from .valid_json_versions import valid_json_versions
|
|
|
5
5
|
# Alias validate_json
|
|
6
6
|
class UnifiedJson:
|
|
7
7
|
def __init__(self, data: dict, json_version: str):
|
|
8
|
-
# TODO Move this code to UnifiedJson.is_valid_json() method and call it
|
|
9
8
|
# TODO Write function/method both in TypeScript and Python to validate JSON i.e. to make sure there is version field in the upper level (Like in AWS JSON)
|
|
10
|
-
if
|
|
9
|
+
if not self.is_valid_json(json_version):
|
|
11
10
|
raise Exception(
|
|
12
11
|
f"version {json_version} is not in valid_json_versions {valid_json_versions}, "
|
|
13
12
|
f"please make sure you run sql2code."
|
|
@@ -15,6 +14,11 @@ class UnifiedJson:
|
|
|
15
14
|
self.json_version = json_version
|
|
16
15
|
self.data = data
|
|
17
16
|
|
|
17
|
+
@staticmethod
|
|
18
|
+
def is_valid_json(json_version: str) -> bool:
|
|
19
|
+
is_valid_json_result = json_version in valid_json_versions
|
|
20
|
+
return is_valid_json_result
|
|
21
|
+
|
|
18
22
|
def get_unified_json(self):
|
|
19
23
|
get_unified_json_result = {"version": self.json_version, "data": self.data}
|
|
20
24
|
return get_unified_json_result
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def _get_username_from_full_name(full_name: str) -> Optional[str]:
|
|
5
|
+
# Same as PowerShell User.psm1 Get-OurUsername
|
|
6
|
+
if full_name == "Tal Rosenberger":
|
|
7
|
+
return "tal"
|
|
8
|
+
name_parts = full_name.split()
|
|
9
|
+
if len(name_parts) != 2:
|
|
10
|
+
return None
|
|
11
|
+
return f"{name_parts[0]}.{name_parts[1][0]}".lower()
|
{python_sdk_remote-0.0.188b3517 → python_sdk_remote-0.0.190b3356}/python_sdk_remote/src/utilities.py
RENAMED
|
@@ -17,7 +17,18 @@ from .version import PACKAGE_VERSION
|
|
|
17
17
|
|
|
18
18
|
from .mini_logger import MiniLogger as logger
|
|
19
19
|
|
|
20
|
-
from .
|
|
20
|
+
from .our_environment_variable_exception import EnvironmentVariableException, OurEnvironmentVariableException # noqa: F401
|
|
21
|
+
# Split out of this file, imported here so utilities.<name> keeps working
|
|
22
|
+
from .dot_env_files import ( # noqa: F401
|
|
23
|
+
DOT_ENV_FILENAME, _get_env_or_dot_env, add_to_file_if_not_existed, get_dot_env_file_value,
|
|
24
|
+
get_our_dot_env_filenames, update_dot_env_example)
|
|
25
|
+
from .environment import get_environment_name # noqa: F401
|
|
26
|
+
from .filesystem import _find_nearest_file # noqa: F401
|
|
27
|
+
from .masking import _mask # noqa: F401
|
|
28
|
+
from .our_environment_variable import our_delete_env, our_get_env, our_set_env # noqa: F401
|
|
29
|
+
from .personal_repo import ( # noqa: F401
|
|
30
|
+
PERSONAL_REPO_DIRECTORY_SUFFIX, PERSONAL_REPO_DOT_ENV_DIRECTORY, get_personal_repo_path)
|
|
31
|
+
from .username import _get_username_from_full_name # noqa: F401
|
|
21
32
|
|
|
22
33
|
load_dotenv()
|
|
23
34
|
# Load environment variables from .env file
|
|
@@ -127,31 +138,33 @@ def is_valid_time_range(time_range: tuple) -> bool:
|
|
|
127
138
|
|
|
128
139
|
|
|
129
140
|
# Enhanced URL validation with support for both str and URL types
|
|
141
|
+
|
|
142
|
+
|
|
130
143
|
def validate_url(url: Union[str, object]) -> bool:
|
|
131
144
|
"""
|
|
132
145
|
Validate URL format.
|
|
133
|
-
|
|
146
|
+
|
|
134
147
|
Args:
|
|
135
148
|
url: URL string or URL object to validate
|
|
136
|
-
|
|
149
|
+
|
|
137
150
|
Returns:
|
|
138
151
|
bool: True if URL is valid, False otherwise
|
|
139
152
|
"""
|
|
140
153
|
logger.start(object={"url": url, "url_type": type(url).__name__})
|
|
141
|
-
|
|
154
|
+
|
|
142
155
|
# Handle URL object (if using yarl or similar library)
|
|
143
156
|
if hasattr(url, 'scheme') and hasattr(url, 'host'):
|
|
144
157
|
is_valid_url = bool(url.scheme and url.host)
|
|
145
158
|
logger.end(object={"is_valid_url": is_valid_url, "source": "url_object"})
|
|
146
159
|
return is_valid_url
|
|
147
|
-
|
|
160
|
+
|
|
148
161
|
# Handle string URL
|
|
149
162
|
if url is not None and url != "":
|
|
150
163
|
parsed_url = urlparse(str(url))
|
|
151
164
|
is_valid_url = bool(parsed_url.scheme and parsed_url.netloc)
|
|
152
165
|
else:
|
|
153
166
|
is_valid_url = True # Empty URL is considered valid (optional field)
|
|
154
|
-
|
|
167
|
+
|
|
155
168
|
logger.end(object={"is_valid_url": is_valid_url, "source": "string_parsing"})
|
|
156
169
|
return is_valid_url
|
|
157
170
|
|
|
@@ -306,110 +319,6 @@ def is_datetime_in_datetime_range(check_datetime: datetime, datetime_range: Tupl
|
|
|
306
319
|
return is_datetime_in_datetime_range_result
|
|
307
320
|
|
|
308
321
|
|
|
309
|
-
# TODO shall we rename the function _file_ to _key_value_file_
|
|
310
|
-
def add_to_file_if_not_existed(file: str, key: str, value: Optional[str]) -> None:
|
|
311
|
-
logger.start(object={"file": file, "key": key, "value": value})
|
|
312
|
-
if not os.path.exists(file):
|
|
313
|
-
with open(file, "w") as f:
|
|
314
|
-
f.write(f"{key}={value}\n")
|
|
315
|
-
else:
|
|
316
|
-
with open(file, "r") as f:
|
|
317
|
-
lines = f.readlines()
|
|
318
|
-
if f"{key}=" not in lines:
|
|
319
|
-
with open(file, "a") as f:
|
|
320
|
-
f.write(f"{key}={value}\n")
|
|
321
|
-
logger.end()
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
def update_dot_env_example(key: str, value: Optional[str]):
|
|
325
|
-
# Avoid recursion by checking environment directly
|
|
326
|
-
env_name = os.getenv("ENVIRONMENT_NAME", "").lower()
|
|
327
|
-
if env_name == "play1":
|
|
328
|
-
return
|
|
329
|
-
add_to_file_if_not_existed(file=".env.example", key=key, value=value)
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
# TODO If running in a lower environment(i.e. local1, play1) if key do not exit in Personal Repo relevant .env.{environment_} or value diffrent update Personal Repo (create new and comment the old record)
|
|
333
|
-
# TODO If running in a lower environment(i.e. local1, play1) update .env.example with the key without the value
|
|
334
|
-
# TODO If running in a lower environment(i.e. local1, play1) and the key do not exist look for it in the Team Member Personal Repo and copy both the key and value to the repo .env.{environment_name} file
|
|
335
|
-
# TODO move all our_*_env() to our_env.py
|
|
336
|
-
# TODO shall we rename optional_prefix to prefix?
|
|
337
|
-
def our_get_env(key: str, default: Optional[str] = None, raise_if_not_found: bool = True,
|
|
338
|
-
raise_if_empty: bool = False, optional_prefix: Optional[str] = None) -> Optional[str]:
|
|
339
|
-
"""
|
|
340
|
-
Get environment variable with optional prefix fallback.
|
|
341
|
-
|
|
342
|
-
Args:
|
|
343
|
-
key: Environment variable name
|
|
344
|
-
default: Default value if not found
|
|
345
|
-
raise_if_not_found: Raise exception if variable not found and no default
|
|
346
|
-
raise_if_empty: Raise exception if variable is empty
|
|
347
|
-
optional_prefix: Try with this prefix first, then without it
|
|
348
|
-
|
|
349
|
-
Returns:
|
|
350
|
-
Environment variable value
|
|
351
|
-
"""
|
|
352
|
-
logger.start(object={"key": key, "default": default,
|
|
353
|
-
"raise_if_not_found": raise_if_not_found,
|
|
354
|
-
"raise_if_empty": raise_if_empty,
|
|
355
|
-
"optional_prefix": optional_prefix})
|
|
356
|
-
|
|
357
|
-
# Try with prefix first if provided
|
|
358
|
-
if optional_prefix:
|
|
359
|
-
prefixed_key = f"{optional_prefix}_{key}"
|
|
360
|
-
env_var = os.getenv(prefixed_key)
|
|
361
|
-
if env_var is not None:
|
|
362
|
-
logger.end(object={"env_var": env_var, "used_prefix": True})
|
|
363
|
-
return env_var.strip('"\'') if isinstance(env_var, str) else env_var
|
|
364
|
-
|
|
365
|
-
# Try without prefix
|
|
366
|
-
env_var = os.getenv(key, default)
|
|
367
|
-
|
|
368
|
-
if ((raise_if_not_found and key not in os.environ and default is None)
|
|
369
|
-
or (raise_if_empty and not env_var and not default)):
|
|
370
|
-
raise EnvironmentVariableException(f"Environment variable {key} not found - please check your .env file") # noqa: E501
|
|
371
|
-
|
|
372
|
-
# Strip quotes from env_var if present
|
|
373
|
-
if env_var and isinstance(env_var, str):
|
|
374
|
-
env_var = env_var.strip('"\'')
|
|
375
|
-
|
|
376
|
-
update_dot_env_example(key, value=default)
|
|
377
|
-
logger.end(object={"env_var": env_var})
|
|
378
|
-
return env_var
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
def our_set_env(key: str, value: str) -> None:
|
|
382
|
-
"""
|
|
383
|
-
Set an environment variable, routed through the logger so the system can
|
|
384
|
-
track which repos/tests write which env vars (cf. our_get_env).
|
|
385
|
-
|
|
386
|
-
Args:
|
|
387
|
-
key: Environment variable name
|
|
388
|
-
value: Value to set
|
|
389
|
-
"""
|
|
390
|
-
logger.start(object={"key": key, "value": value})
|
|
391
|
-
os.environ[key] = value
|
|
392
|
-
logger.end(object={"key": key})
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
def our_delete_env(key: str, raise_if_not_found: bool = False) -> None:
|
|
396
|
-
"""
|
|
397
|
-
Delete an environment variable if present, routed through the logger
|
|
398
|
-
(cf. our_get_env / our_set_env).
|
|
399
|
-
|
|
400
|
-
Args:
|
|
401
|
-
key: Environment variable name
|
|
402
|
-
raise_if_not_found: Raise if the variable is not set
|
|
403
|
-
"""
|
|
404
|
-
logger.start(object={"key": key,
|
|
405
|
-
"raise_if_not_found": raise_if_not_found})
|
|
406
|
-
if key in os.environ:
|
|
407
|
-
del os.environ[key]
|
|
408
|
-
elif raise_if_not_found:
|
|
409
|
-
raise EnvironmentVariableException(f"Environment variable {key} not found") # noqa: E501
|
|
410
|
-
logger.end(object={"key": key})
|
|
411
|
-
|
|
412
|
-
|
|
413
322
|
def get_brand_name(raise_if_not_found: bool = True,
|
|
414
323
|
raise_if_empty: bool = False) -> Optional[str]:
|
|
415
324
|
get_brand_name_result = our_get_env("BRAND_NAME",
|
|
@@ -418,19 +327,6 @@ def get_brand_name(raise_if_not_found: bool = True,
|
|
|
418
327
|
return get_brand_name_result
|
|
419
328
|
|
|
420
329
|
|
|
421
|
-
def get_environment_name(raise_if_not_found: bool = True,
|
|
422
|
-
raise_if_empty: bool = False) -> Optional[str]:
|
|
423
|
-
environment_name = our_get_env("ENVIRONMENT_NAME",
|
|
424
|
-
raise_if_not_found=raise_if_not_found,
|
|
425
|
-
raise_if_empty=raise_if_empty)
|
|
426
|
-
try:
|
|
427
|
-
EnvironmentName(environment_name) # if invalid, raises ValueError: x is not a valid EnvironmentName
|
|
428
|
-
except ValueError:
|
|
429
|
-
# Shows the current PACKAGE_VERSION for debugging
|
|
430
|
-
raise Exception(f"python-sdk-remote {PACKAGE_VERSION} get_environment_name(): Invalid EnvironmentName: {environment_name} either misspelling or you need the environment in a few places such as url-remote-python-package environment_name_enum.py ...")
|
|
431
|
-
return environment_name
|
|
432
|
-
|
|
433
|
-
|
|
434
330
|
def get_product_user_identifier(raise_if_not_found: bool = True,
|
|
435
331
|
raise_if_empty: bool = False) -> Optional[str]:
|
|
436
332
|
get_product_user_identifier_result = our_get_env("PRODUCT_USER_IDENTIFIER",
|
|
@@ -443,7 +339,7 @@ def get_product_user_password(raise_if_not_found: bool = True,
|
|
|
443
339
|
raise_if_empty: bool = False) -> Optional[str]:
|
|
444
340
|
"""
|
|
445
341
|
Get product user password from environment variables.
|
|
446
|
-
|
|
342
|
+
|
|
447
343
|
Note: PRODUCT_USER_PASSWORD is preferred over PRODUCT_PASSWORD (deprecated).
|
|
448
344
|
This function maintains backward compatibility.
|
|
449
345
|
"""
|
|
@@ -461,6 +357,8 @@ def get_product_user_password(raise_if_not_found: bool = True,
|
|
|
461
357
|
|
|
462
358
|
|
|
463
359
|
# Database-specific functions - Consider moving to database package when it's created
|
|
360
|
+
|
|
361
|
+
|
|
464
362
|
def get_sql_hostname(raise_if_not_found: bool = True,
|
|
465
363
|
raise_if_empty: bool = False) -> Optional[str]:
|
|
466
364
|
get_sql_hostname_result = our_get_env("RDS_HOSTNAME",
|
|
@@ -481,6 +379,8 @@ def get_sql_password(raise_if_empty: bool = False) -> Optional[str]:
|
|
|
481
379
|
|
|
482
380
|
|
|
483
381
|
# Dialog-specific function - Consider moving to dialog repo when it's created
|
|
382
|
+
|
|
383
|
+
|
|
484
384
|
def get_dialog_jwt_secret_key() -> Optional[str]:
|
|
485
385
|
get_dialog_jwt_secret_key_result = our_get_env("DIALOG_JWT_SECRET_KEY", raise_if_empty=True)
|
|
486
386
|
return get_dialog_jwt_secret_key_result
|
|
@@ -507,13 +407,13 @@ def decode_jwt(token: str, key: str) -> dict:
|
|
|
507
407
|
def obfuscate_log_dict(log_dict: dict) -> dict:
|
|
508
408
|
"""
|
|
509
409
|
Obfuscate sensitive keys in log dictionaries for security.
|
|
510
|
-
|
|
410
|
+
|
|
511
411
|
Obfuscates keys containing:
|
|
512
412
|
- password, secret, token, jwt
|
|
513
413
|
- email (with variations like e-mail, e_mail)
|
|
514
414
|
- phone, name (first/last/nick/user etc.)
|
|
515
415
|
- address, ssn
|
|
516
|
-
|
|
416
|
+
|
|
517
417
|
In play1 environment, returns original dict for debugging purposes.
|
|
518
418
|
"""
|
|
519
419
|
environment_name = get_environment_name()
|
|
@@ -533,6 +433,7 @@ def obfuscate_log_dict(log_dict: dict) -> dict:
|
|
|
533
433
|
|
|
534
434
|
# Tests for the following functions are implemented in utilities_test.py
|
|
535
435
|
|
|
436
|
+
|
|
536
437
|
def remove_digits(text: str) -> str:
|
|
537
438
|
remove_digits_result = ''.join(i for i in text if not i.isdigit())
|
|
538
439
|
return remove_digits_result
|
|
@@ -588,7 +489,7 @@ def validate_arguments(args: dict) -> None:
|
|
|
588
489
|
def reformat_time_string(input_str: str) -> str:
|
|
589
490
|
"""
|
|
590
491
|
Reformat time string from compact format to HH:MM:SS:MS format.
|
|
591
|
-
|
|
492
|
+
|
|
592
493
|
Example:
|
|
593
494
|
"1234" -> "12:34:00:00"
|
|
594
495
|
"123456" -> "12:34:56:00"
|
|
@@ -10,13 +10,19 @@ python_sdk_remote/src/__init__.py
|
|
|
10
10
|
python_sdk_remote/src/constants.py
|
|
11
11
|
python_sdk_remote/src/constants_src_mini_logger_and_logger.py
|
|
12
12
|
python_sdk_remote/src/datetime_range.py
|
|
13
|
+
python_sdk_remote/src/dot_env_files.py
|
|
14
|
+
python_sdk_remote/src/environment.py
|
|
13
15
|
python_sdk_remote/src/environment_variable_exception.py
|
|
14
16
|
python_sdk_remote/src/filename.py
|
|
17
|
+
python_sdk_remote/src/filesystem.py
|
|
15
18
|
python_sdk_remote/src/generic_crud.py
|
|
16
19
|
python_sdk_remote/src/http_response.py
|
|
17
20
|
python_sdk_remote/src/is_test_data.py
|
|
18
21
|
python_sdk_remote/src/item.py
|
|
22
|
+
python_sdk_remote/src/masking.py
|
|
19
23
|
python_sdk_remote/src/mini_logger.py
|
|
24
|
+
python_sdk_remote/src/our_environment_variable.py
|
|
25
|
+
python_sdk_remote/src/our_environment_variable_exception.py
|
|
20
26
|
python_sdk_remote/src/our_obfuscation.py
|
|
21
27
|
python_sdk_remote/src/our_object.py
|
|
22
28
|
python_sdk_remote/src/our_objects.py
|
|
@@ -24,7 +30,9 @@ python_sdk_remote/src/our_objects_local.py
|
|
|
24
30
|
python_sdk_remote/src/our_objects_remote.py
|
|
25
31
|
python_sdk_remote/src/our_request.py
|
|
26
32
|
python_sdk_remote/src/our_request_old.py
|
|
33
|
+
python_sdk_remote/src/personal_repo.py
|
|
27
34
|
python_sdk_remote/src/unified_json.py
|
|
35
|
+
python_sdk_remote/src/username.py
|
|
28
36
|
python_sdk_remote/src/utilities.py
|
|
29
37
|
python_sdk_remote/src/valid_json_versions.py
|
|
30
38
|
python_sdk_remote/src/validate_environment.py
|
|
@@ -10,7 +10,7 @@ setuptools.setup(
|
|
|
10
10
|
# Every feature branch needs its own free beta: PyPI never accepts a version twice, and
|
|
11
11
|
# dev's literal is always one that has already been published. b3517 is this branch's
|
|
12
12
|
# Jira id. GA stays a [pub] commit on dev.
|
|
13
|
-
version='0.0.
|
|
13
|
+
version='0.0.190b3356', # https://pypi.org/project/python-sdk-remote#history
|
|
14
14
|
author="Circles",
|
|
15
15
|
author_email="info@circlez.ai",
|
|
16
16
|
description="PyPI Package for Circles Python SDK Local Python",
|
|
File without changes
|
|
File without changes
|
{python_sdk_remote-0.0.188b3517 → python_sdk_remote-0.0.190b3356}/python_sdk_remote/src/constants.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_sdk_remote-0.0.188b3517 → python_sdk_remote-0.0.190b3356}/python_sdk_remote/src/filename.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_sdk_remote-0.0.188b3517 → python_sdk_remote-0.0.190b3356}/python_sdk_remote/src/item.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_sdk_remote-0.0.188b3517 → python_sdk_remote-0.0.190b3356}/python_sdk_remote/src/version.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|