logs-py 4.0.7__py3-none-any.whl
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.
- LOGS/Auxiliary/CheckClassName.py +1075 -0
- LOGS/Auxiliary/Constants.py +99 -0
- LOGS/Auxiliary/CustomEntityClassGenerator.py +254 -0
- LOGS/Auxiliary/CustomFieldClassGenerator.py +115 -0
- LOGS/Auxiliary/CustomFieldValueTypeChecker.py +168 -0
- LOGS/Auxiliary/CustomSectionClassGenerator.py +113 -0
- LOGS/Auxiliary/CustomTypeClassGenerator.py +147 -0
- LOGS/Auxiliary/DateTimeConverter.py +66 -0
- LOGS/Auxiliary/Decorators.py +109 -0
- LOGS/Auxiliary/Exceptions.py +341 -0
- LOGS/Auxiliary/LOGSErrorResponse.py +89 -0
- LOGS/Auxiliary/MinimalModelGenerator.py +236 -0
- LOGS/Auxiliary/ParameterHelper.py +56 -0
- LOGS/Auxiliary/ReplaceMessage.py +13 -0
- LOGS/Auxiliary/Tools.py +432 -0
- LOGS/Auxiliary/__init__.py +15 -0
- LOGS/Converter/Conversion.py +248 -0
- LOGS/Converter/Converter.py +96 -0
- LOGS/Converter/ConverterParameter.py +88 -0
- LOGS/Converter/DateTimeRange.py +58 -0
- LOGS/Converter/ExportParameters.py +89 -0
- LOGS/Converter/__init__.py +13 -0
- LOGS/Entities/Attachment.py +84 -0
- LOGS/Entities/AttachmentMinimal.py +8 -0
- LOGS/Entities/AttachmentRequestParameter.py +42 -0
- LOGS/Entities/Attachments.py +53 -0
- LOGS/Entities/AutoloadFileInfo.py +12 -0
- LOGS/Entities/AutoloadStatusError.py +7 -0
- LOGS/Entities/AxisNaming.py +33 -0
- LOGS/Entities/AxisZoom.py +33 -0
- LOGS/Entities/Bridge.py +165 -0
- LOGS/Entities/BridgeClientInfo.py +93 -0
- LOGS/Entities/BridgeMinimal.py +8 -0
- LOGS/Entities/BridgeRequestParameter.py +49 -0
- LOGS/Entities/BridgeType.py +7 -0
- LOGS/Entities/Bridges.py +12 -0
- LOGS/Entities/CustomField.py +243 -0
- LOGS/Entities/CustomFieldMinimal.py +8 -0
- LOGS/Entities/CustomFieldModels.py +111 -0
- LOGS/Entities/CustomFieldRequestParameter.py +69 -0
- LOGS/Entities/CustomFieldSearchQuery.py +40 -0
- LOGS/Entities/CustomFields.py +12 -0
- LOGS/Entities/CustomType.py +212 -0
- LOGS/Entities/CustomTypeMinimal.py +8 -0
- LOGS/Entities/CustomTypeRequestParameter.py +60 -0
- LOGS/Entities/CustomTypeSection.py +63 -0
- LOGS/Entities/CustomTypes.py +12 -0
- LOGS/Entities/DataFormat.py +97 -0
- LOGS/Entities/DataFormatInstrument.py +18 -0
- LOGS/Entities/DataFormatInstrumentMinimal.py +8 -0
- LOGS/Entities/DataFormatInstrumentRequestParameter.py +17 -0
- LOGS/Entities/DataFormatInstruments.py +16 -0
- LOGS/Entities/DataFormatMinimal.py +18 -0
- LOGS/Entities/DataFormatRequestParameter.py +21 -0
- LOGS/Entities/DataFormats.py +12 -0
- LOGS/Entities/DataSource.py +218 -0
- LOGS/Entities/DataSourceConnectionStatus.py +12 -0
- LOGS/Entities/DataSourceMinimal.py +8 -0
- LOGS/Entities/DataSourceRequestParameter.py +57 -0
- LOGS/Entities/DataSourceStatus.py +108 -0
- LOGS/Entities/DataSourceStatusIterator.py +16 -0
- LOGS/Entities/DataSourceStatusRequestParameter.py +31 -0
- LOGS/Entities/DataSources.py +12 -0
- LOGS/Entities/Dataset.py +439 -0
- LOGS/Entities/DatasetBase.py +196 -0
- LOGS/Entities/DatasetCreator.py +148 -0
- LOGS/Entities/DatasetInfo.py +147 -0
- LOGS/Entities/DatasetMatchTypes.py +157 -0
- LOGS/Entities/DatasetMatching.py +196 -0
- LOGS/Entities/DatasetMinimal.py +8 -0
- LOGS/Entities/DatasetModels.py +33 -0
- LOGS/Entities/DatasetRequestParameter.py +92 -0
- LOGS/Entities/DatasetTemplate.py +23 -0
- LOGS/Entities/DatasetUploadParameter.py +14 -0
- LOGS/Entities/Datasets.py +142 -0
- LOGS/Entities/Datatrack.py +179 -0
- LOGS/Entities/DatatrackFormattedTable.py +25 -0
- LOGS/Entities/DatatrackGeneric.py +34 -0
- LOGS/Entities/DatatrackImage.py +25 -0
- LOGS/Entities/DatatrackNumericArray.py +30 -0
- LOGS/Entities/DatatrackNumericMatrix.py +98 -0
- LOGS/Entities/Entities.py +71 -0
- LOGS/Entities/EntitiesRequestParameter.py +18 -0
- LOGS/Entities/EntityOriginWriteModelWithId.py +15 -0
- LOGS/Entities/FileEntry.py +138 -0
- LOGS/Entities/FileExcludePattern.py +8 -0
- LOGS/Entities/FormatMetaData.py +56 -0
- LOGS/Entities/FormattedTable/DatatypeFormattedTable.py +135 -0
- LOGS/Entities/FormattedTable/DatatypeFormattedTableCell.py +108 -0
- LOGS/Entities/FormattedTable/DatatypeFormattedTableSettings.py +11 -0
- LOGS/Entities/FormattedTable/__init__.py +9 -0
- LOGS/Entities/HierarchyLeaf.py +15 -0
- LOGS/Entities/HierarchyNode.py +40 -0
- LOGS/Entities/ILiteraryTypedEntity.py +19 -0
- LOGS/Entities/InventoryItem.py +102 -0
- LOGS/Entities/InventoryItemMinimal.py +25 -0
- LOGS/Entities/InventoryItemRequestParameter.py +58 -0
- LOGS/Entities/InventoryItems.py +12 -0
- LOGS/Entities/LabNotebook.py +33 -0
- LOGS/Entities/LabNotebookEntries.py +16 -0
- LOGS/Entities/LabNotebookEntry.py +106 -0
- LOGS/Entities/LabNotebookEntryContent/BasicAttribute.py +15 -0
- LOGS/Entities/LabNotebookEntryContent/EntityAttribute.py +85 -0
- LOGS/Entities/LabNotebookEntryContent/EntryContentBlockquote.py +13 -0
- LOGS/Entities/LabNotebookEntryContent/EntryContentBulletList.py +17 -0
- LOGS/Entities/LabNotebookEntryContent/EntryContentCallout.py +40 -0
- LOGS/Entities/LabNotebookEntryContent/EntryContentContentPlaceholderNode.py +31 -0
- LOGS/Entities/LabNotebookEntryContent/EntryContentConverter.py +207 -0
- LOGS/Entities/LabNotebookEntryContent/EntryContentDocument.py +8 -0
- LOGS/Entities/LabNotebookEntryContent/EntryContentEntity.py +13 -0
- LOGS/Entities/LabNotebookEntryContent/EntryContentEntityMention.py +31 -0
- LOGS/Entities/LabNotebookEntryContent/EntryContentHeading.py +33 -0
- LOGS/Entities/LabNotebookEntryContent/EntryContentHorizontalRule.py +12 -0
- LOGS/Entities/LabNotebookEntryContent/EntryContentItem.py +37 -0
- LOGS/Entities/LabNotebookEntryContent/EntryContentListItem.py +49 -0
- LOGS/Entities/LabNotebookEntryContent/EntryContentOrderedList.py +31 -0
- LOGS/Entities/LabNotebookEntryContent/EntryContentParagraph.py +13 -0
- LOGS/Entities/LabNotebookEntryContent/EntryContentTable.py +17 -0
- LOGS/Entities/LabNotebookEntryContent/EntryContentTableCell.py +40 -0
- LOGS/Entities/LabNotebookEntryContent/EntryContentTableRow.py +8 -0
- LOGS/Entities/LabNotebookEntryContent/EntryContentTaskList.py +17 -0
- LOGS/Entities/LabNotebookEntryContent/EntryContentTaskListItem.py +31 -0
- LOGS/Entities/LabNotebookEntryContent/EntryContentText.py +33 -0
- LOGS/Entities/LabNotebookEntryContent/IEntryContentWithAttribute.py +23 -0
- LOGS/Entities/LabNotebookEntryContent/IEntryContentWithContent.py +38 -0
- LOGS/Entities/LabNotebookEntryContent/IEntryContentWithTextAttribute.py +16 -0
- LOGS/Entities/LabNotebookEntryContent/TextAttribute.py +46 -0
- LOGS/Entities/LabNotebookEntryContent/TextMarkAtributes.py +64 -0
- LOGS/Entities/LabNotebookEntryContent/TextMarkConverter.py +45 -0
- LOGS/Entities/LabNotebookEntryContent/TextMarks.py +71 -0
- LOGS/Entities/LabNotebookEntryContent/__init__.py +34 -0
- LOGS/Entities/LabNotebookEntryMinimal.py +8 -0
- LOGS/Entities/LabNotebookEntryRequestParameter.py +59 -0
- LOGS/Entities/LabNotebookExperiment.py +58 -0
- LOGS/Entities/LabNotebookExperimentMinimal.py +8 -0
- LOGS/Entities/LabNotebookExperimentRequestParameter.py +52 -0
- LOGS/Entities/LabNotebookExperiments.py +16 -0
- LOGS/Entities/LabNotebookMinimal.py +8 -0
- LOGS/Entities/LabNotebookModels.py +14 -0
- LOGS/Entities/LabNotebookRequestParameter.py +42 -0
- LOGS/Entities/LabNotebookTemplate.py +42 -0
- LOGS/Entities/LabNotebookTemplateMinimal.py +8 -0
- LOGS/Entities/LabNotebookTemplateRequestParameter.py +38 -0
- LOGS/Entities/LabNotebookTemplates.py +16 -0
- LOGS/Entities/LabNotebooks.py +12 -0
- LOGS/Entities/Method.py +66 -0
- LOGS/Entities/MethodMinimal.py +8 -0
- LOGS/Entities/MethodRequestParameter.py +16 -0
- LOGS/Entities/Methods.py +12 -0
- LOGS/Entities/Origin.py +53 -0
- LOGS/Entities/OriginMinimal.py +8 -0
- LOGS/Entities/OriginRequestParameter.py +28 -0
- LOGS/Entities/Origins.py +12 -0
- LOGS/Entities/ParserLog.py +49 -0
- LOGS/Entities/Permission.py +9 -0
- LOGS/Entities/Person.py +145 -0
- LOGS/Entities/PersonCategory.py +12 -0
- LOGS/Entities/PersonMinimal.py +8 -0
- LOGS/Entities/PersonRequestParameter.py +58 -0
- LOGS/Entities/Persons.py +12 -0
- LOGS/Entities/Project.py +52 -0
- LOGS/Entities/ProjectMinimal.py +8 -0
- LOGS/Entities/ProjectPersonPermission.py +102 -0
- LOGS/Entities/ProjectRequestParameter.py +58 -0
- LOGS/Entities/Projects.py +12 -0
- LOGS/Entities/Role.py +94 -0
- LOGS/Entities/RoleMinimal.py +8 -0
- LOGS/Entities/RoleRequestParameter.py +40 -0
- LOGS/Entities/Roles.py +12 -0
- LOGS/Entities/RunState.py +9 -0
- LOGS/Entities/Sample.py +53 -0
- LOGS/Entities/SampleMinimal.py +8 -0
- LOGS/Entities/SampleRequestParameter.py +54 -0
- LOGS/Entities/Samples.py +12 -0
- LOGS/Entities/SharedContent.py +87 -0
- LOGS/Entities/SharedContentMinimal.py +8 -0
- LOGS/Entities/SharedContentRequestParameter.py +38 -0
- LOGS/Entities/SharedContents.py +12 -0
- LOGS/Entities/Signature.py +60 -0
- LOGS/Entities/Track.py +93 -0
- LOGS/Entities/TrackData.py +20 -0
- LOGS/Entities/TrackImage.py +21 -0
- LOGS/Entities/TrackImageData.py +20 -0
- LOGS/Entities/TrackMatrix.py +28 -0
- LOGS/Entities/TrackMatrixData.py +22 -0
- LOGS/Entities/TrackSettings.py +55 -0
- LOGS/Entities/TrackTable.py +21 -0
- LOGS/Entities/TrackTableData.py +22 -0
- LOGS/Entities/TrackXY.py +40 -0
- LOGS/Entities/TrackXYComplex.py +51 -0
- LOGS/Entities/TrackXYComplexData.py +50 -0
- LOGS/Entities/TrackXYData.py +31 -0
- LOGS/Entities/Vendor.py +40 -0
- LOGS/Entities/VendorMinimal.py +8 -0
- LOGS/Entities/VendorRequestParameter.py +17 -0
- LOGS/Entities/Vendors.py +12 -0
- LOGS/Entities/__init__.py +118 -0
- LOGS/Entity/ConnectedEntity.py +170 -0
- LOGS/Entity/Entity.py +203 -0
- LOGS/Entity/EntityConnector.py +70 -0
- LOGS/Entity/EntityIterator.py +263 -0
- LOGS/Entity/EntityMinimal.py +141 -0
- LOGS/Entity/EntityMinimalWithIntId.py +36 -0
- LOGS/Entity/EntityMinimalWithStrId.py +36 -0
- LOGS/Entity/EntityMinimalWithType.py +47 -0
- LOGS/Entity/EntityRequestParameter.py +104 -0
- LOGS/Entity/EntitySortBy.py +69 -0
- LOGS/Entity/EntityWithIntId.py +26 -0
- LOGS/Entity/EntityWithStrId.py +26 -0
- LOGS/Entity/IGenericEntityOrderBy.py +55 -0
- LOGS/Entity/IdIterator.py +207 -0
- LOGS/Entity/SerializableContent.py +834 -0
- LOGS/Entity/__init__.py +23 -0
- LOGS/Interfaces/ICustomFieldValue.py +92 -0
- LOGS/Interfaces/ICustomSectionValue.py +161 -0
- LOGS/Interfaces/ICustomTypeValue.py +152 -0
- LOGS/Interfaces/ICustomValue.py +28 -0
- LOGS/Interfaces/IEntityInterface.py +7 -0
- LOGS/Interfaces/IEntryRecord.py +57 -0
- LOGS/Interfaces/IHierarchicalEntity.py +41 -0
- LOGS/Interfaces/IHierarchyType.py +63 -0
- LOGS/Interfaces/ILockableEntity.py +52 -0
- LOGS/Interfaces/IModificationRecord.py +56 -0
- LOGS/Interfaces/INamedEntity.py +25 -0
- LOGS/Interfaces/IOwnedEntity.py +27 -0
- LOGS/Interfaces/IPaginationRequest.py +11 -0
- LOGS/Interfaces/IPermissionedEntity.py +72 -0
- LOGS/Interfaces/IProjectBased.py +27 -0
- LOGS/Interfaces/ISessionedEntity.py +59 -0
- LOGS/Interfaces/ISignableEntity.py +49 -0
- LOGS/Interfaces/ISoftDeletable.py +28 -0
- LOGS/Interfaces/ITypedEntity.py +129 -0
- LOGS/Interfaces/IUniqueEntity.py +61 -0
- LOGS/Interfaces/IVersionedEntity.py +39 -0
- LOGS/Interfaces/__init__.py +7 -0
- LOGS/LOGS.py +1436 -0
- LOGS/LOGSConnection.py +647 -0
- LOGS/LOGSOptions.py +11 -0
- LOGS/Parameters/Color.py +92 -0
- LOGS/Parameters/ParameterBase.py +55 -0
- LOGS/Parameters/ParameterConverter.py +24 -0
- LOGS/Parameters/ParameterElement.py +99 -0
- LOGS/Parameters/ParameterList.py +52 -0
- LOGS/Parameters/ParameterTable.py +64 -0
- LOGS/Parameters/__init__.py +13 -0
- LOGS/ServerMetaData.py +120 -0
- LOGS/__init__.py +12 -0
- logs_py-4.0.7.dist-info/METADATA +51 -0
- logs_py-4.0.7.dist-info/RECORD +251 -0
- logs_py-4.0.7.dist-info/WHEEL +5 -0
- logs_py-4.0.7.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import regex as re
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class ParameterHelper:
|
|
5
|
+
floatRe = re.compile(r"^[\d\.\-\+e]+$")
|
|
6
|
+
intRe = re.compile(r"^\d+$")
|
|
7
|
+
splitRe = re.compile(r"[ \t,]+")
|
|
8
|
+
quotation = re.compile(r"^'(.*)'$")
|
|
9
|
+
|
|
10
|
+
def __init__(self, parameters):
|
|
11
|
+
if not isinstance(parameters, dict):
|
|
12
|
+
raise Exception("Parameter argument must be of type dict")
|
|
13
|
+
self.parameters = parameters
|
|
14
|
+
|
|
15
|
+
@classmethod
|
|
16
|
+
def isNumeric(cls, value):
|
|
17
|
+
vtype = "str"
|
|
18
|
+
if cls.floatRe.match(str(value)):
|
|
19
|
+
if cls.intRe.match(str(value)):
|
|
20
|
+
try:
|
|
21
|
+
value = int(value)
|
|
22
|
+
vtype = "int"
|
|
23
|
+
except:
|
|
24
|
+
pass
|
|
25
|
+
else:
|
|
26
|
+
try:
|
|
27
|
+
value = float(value)
|
|
28
|
+
vtype = "float"
|
|
29
|
+
except:
|
|
30
|
+
pass
|
|
31
|
+
return value, vtype
|
|
32
|
+
|
|
33
|
+
@classmethod
|
|
34
|
+
def removeUnit(cls, value):
|
|
35
|
+
if value == None:
|
|
36
|
+
return "-"
|
|
37
|
+
if not isinstance(value, str):
|
|
38
|
+
return value
|
|
39
|
+
v = cls.splitRe.split(value)
|
|
40
|
+
v, _ = cls.isNumeric(v[0])
|
|
41
|
+
return v
|
|
42
|
+
|
|
43
|
+
def get(self, key, removeUnit=False):
|
|
44
|
+
if key in self.parameters:
|
|
45
|
+
if isinstance(self.parameters[key], list):
|
|
46
|
+
return self.parameters[key]
|
|
47
|
+
|
|
48
|
+
value = self.parameters[key]
|
|
49
|
+
if isinstance(value, str):
|
|
50
|
+
match = self.quotation.match(value)
|
|
51
|
+
if match:
|
|
52
|
+
value = match.group(1)
|
|
53
|
+
if removeUnit:
|
|
54
|
+
value = self.removeUnit(value)
|
|
55
|
+
return value
|
|
56
|
+
return None
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from typing import List, Optional, Union
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class ReplaceMessage:
|
|
5
|
+
def __init__(self, message: str = "", path: Optional[List[Union[str, int]]] = None):
|
|
6
|
+
self.message = message
|
|
7
|
+
self.path = path if path else []
|
|
8
|
+
|
|
9
|
+
def __str__(self):
|
|
10
|
+
return self.message
|
|
11
|
+
|
|
12
|
+
def unshiftPath(self, pathEntry: Union[str, int]):
|
|
13
|
+
self.path.insert(0, pathEntry)
|
LOGS/Auxiliary/Tools.py
ADDED
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
import dataclasses
|
|
2
|
+
import os
|
|
3
|
+
import random
|
|
4
|
+
import string
|
|
5
|
+
import sys
|
|
6
|
+
from datetime import datetime, time, timezone
|
|
7
|
+
from enum import Enum
|
|
8
|
+
from typing import Any, Callable, Dict, List, Optional, Set, Type, TypeVar, Union, cast
|
|
9
|
+
from unicodedata import normalize
|
|
10
|
+
from uuid import UUID
|
|
11
|
+
|
|
12
|
+
from regex import Regex
|
|
13
|
+
|
|
14
|
+
from LOGS.Auxiliary.DateTimeConverter import DateTimeConverter
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class Unbuffered(object):
|
|
18
|
+
def __init__(self, stream):
|
|
19
|
+
self.stream = stream
|
|
20
|
+
|
|
21
|
+
def write(self, data):
|
|
22
|
+
self.stream.write(data)
|
|
23
|
+
self.stream.flush()
|
|
24
|
+
|
|
25
|
+
def writelines(self, data):
|
|
26
|
+
self.stream.writelines(data)
|
|
27
|
+
self.stream.flush()
|
|
28
|
+
|
|
29
|
+
def __getattr__(self, attr):
|
|
30
|
+
return getattr(self.stream, attr)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
_T = TypeVar("_T")
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class UnbufferedStdout(Unbuffered):
|
|
37
|
+
def __init__(self):
|
|
38
|
+
super().__init__(sys.stdout)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class Tools:
|
|
42
|
+
messageStrMaxLength = 25
|
|
43
|
+
__byteUnits = ["", "K", "M", "G", "T", "P", "E", "Z"]
|
|
44
|
+
|
|
45
|
+
@classmethod
|
|
46
|
+
def ObjectToString(cls, obj: Any) -> str:
|
|
47
|
+
name = getattr(obj, "name") if hasattr(obj, "name") else None
|
|
48
|
+
id = getattr(obj, "id") if hasattr(obj, "id") else None
|
|
49
|
+
i = " id:'%s'" % id if id is not None else ""
|
|
50
|
+
n = " name:'%s'" % name if name is not None else ""
|
|
51
|
+
return "<%s%s%s>" % (type(obj).__name__, i, n)
|
|
52
|
+
|
|
53
|
+
@classmethod
|
|
54
|
+
def unbufferStdout(cls):
|
|
55
|
+
unbuffered = UnbufferedStdout()
|
|
56
|
+
sys.stdout = cast(Any, unbuffered)
|
|
57
|
+
|
|
58
|
+
@classmethod
|
|
59
|
+
def getHumanReadableSize(cls, size, suffix="B"):
|
|
60
|
+
for unit in cls.__byteUnits:
|
|
61
|
+
if abs(size) < 1024.0:
|
|
62
|
+
return "%3.1f%s%s" % (size, unit, suffix)
|
|
63
|
+
size /= 1024.0
|
|
64
|
+
return "%.1f%s%s" % (size, "Yi", suffix)
|
|
65
|
+
|
|
66
|
+
@classmethod
|
|
67
|
+
def osPathSeparators(cls):
|
|
68
|
+
seps = []
|
|
69
|
+
for sep in os.path.sep, os.path.altsep:
|
|
70
|
+
if sep:
|
|
71
|
+
seps.append(sep)
|
|
72
|
+
return seps
|
|
73
|
+
|
|
74
|
+
@classmethod
|
|
75
|
+
def sanitizeFileName(cls, fileName: Optional[str], defaultName: str = "Unknown"):
|
|
76
|
+
if not fileName:
|
|
77
|
+
fileName = defaultName
|
|
78
|
+
# Sort out unicode characters
|
|
79
|
+
valid_filename = (
|
|
80
|
+
normalize("NFKD", fileName).encode("ascii", "ignore").decode("ascii")
|
|
81
|
+
)
|
|
82
|
+
# Replace path separators with underscores
|
|
83
|
+
for sep in cls.osPathSeparators():
|
|
84
|
+
valid_filename = valid_filename.replace(sep, "_")
|
|
85
|
+
# Ensure only valid characters
|
|
86
|
+
valid_chars = "-_.() {0}{1}".format(string.ascii_letters, string.digits)
|
|
87
|
+
valid_filename = "".join(ch for ch in valid_filename if ch in valid_chars)
|
|
88
|
+
# Ensure at least one letter or number to ignore names such as '..'
|
|
89
|
+
valid_chars = "{0}{1}".format(string.ascii_letters, string.digits)
|
|
90
|
+
test_filename = "".join(ch for ch in fileName if ch in valid_chars)
|
|
91
|
+
if len(test_filename) == 0:
|
|
92
|
+
# Replace empty file name or file path part with the following
|
|
93
|
+
valid_filename = defaultName
|
|
94
|
+
if valid_filename[0] not in string.ascii_letters:
|
|
95
|
+
valid_filename = "_" + valid_filename
|
|
96
|
+
return valid_filename
|
|
97
|
+
|
|
98
|
+
@classmethod
|
|
99
|
+
def timeToString(cls, dt: Optional[time]) -> str:
|
|
100
|
+
if dt is None:
|
|
101
|
+
return ""
|
|
102
|
+
return dt.strftime("%H:%M:%S") + f".{dt.microsecond:03d}"
|
|
103
|
+
|
|
104
|
+
@classmethod
|
|
105
|
+
def datetimeToUTCString(cls, dt: Optional[datetime]) -> str:
|
|
106
|
+
if dt is None:
|
|
107
|
+
return ""
|
|
108
|
+
dt = dt.astimezone(
|
|
109
|
+
timezone.utc
|
|
110
|
+
) # we convert all datetimes to UTC for the LOGS server
|
|
111
|
+
return dt.strftime("%Y-%m-%dT%H:%M:%S.%fZ")
|
|
112
|
+
|
|
113
|
+
@classmethod
|
|
114
|
+
def eclipsesJoin(cls, separator: str, items: List, maxCount: int = 3):
|
|
115
|
+
if len(items) > maxCount:
|
|
116
|
+
items = items[:maxCount]
|
|
117
|
+
return separator.join(items) + "..."
|
|
118
|
+
|
|
119
|
+
return separator.join(items)
|
|
120
|
+
|
|
121
|
+
@classmethod
|
|
122
|
+
def wordToPlural(cls, word: str):
|
|
123
|
+
if word[-1] == "y":
|
|
124
|
+
return word[:-1] + "ies"
|
|
125
|
+
|
|
126
|
+
return word + "s"
|
|
127
|
+
|
|
128
|
+
@classmethod
|
|
129
|
+
def plural(cls, word: str, count: Union[int, list, set]):
|
|
130
|
+
if isinstance(count, (list, set)):
|
|
131
|
+
count = len(count)
|
|
132
|
+
|
|
133
|
+
if count == 1:
|
|
134
|
+
return word
|
|
135
|
+
|
|
136
|
+
return cls.wordToPlural(word)
|
|
137
|
+
|
|
138
|
+
@classmethod
|
|
139
|
+
def numberPlural(cls, word: str, count: Union[int, List]):
|
|
140
|
+
if isinstance(count, list):
|
|
141
|
+
count = len(count)
|
|
142
|
+
|
|
143
|
+
if count < 1:
|
|
144
|
+
return "no %s" % cls.wordToPlural(word)
|
|
145
|
+
|
|
146
|
+
if count < 2:
|
|
147
|
+
return "%d %s" % (count, word)
|
|
148
|
+
|
|
149
|
+
return "%d %s" % (count, cls.wordToPlural(word))
|
|
150
|
+
|
|
151
|
+
@classmethod
|
|
152
|
+
def getTypeFromTypeEntry(cls, item: dict, types: list):
|
|
153
|
+
if isinstance(item, dict) and "type" in item:
|
|
154
|
+
type = item["type"]
|
|
155
|
+
for t in types:
|
|
156
|
+
if t._type == type:
|
|
157
|
+
return t
|
|
158
|
+
return None
|
|
159
|
+
else:
|
|
160
|
+
return None
|
|
161
|
+
|
|
162
|
+
_uidRegex = Regex(
|
|
163
|
+
r"^[0-9a-f]{8}\-?[0-9a-f]{4}\-?[0-9a-f]{4}\-?[0-9a-f]{4}\-?[0-9a-f]{12}$"
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
@classmethod
|
|
167
|
+
def uuidConverter(cls, value):
|
|
168
|
+
if isinstance(value, UUID):
|
|
169
|
+
return value
|
|
170
|
+
else:
|
|
171
|
+
v = str(value)
|
|
172
|
+
if not cls._uidRegex.match(v):
|
|
173
|
+
raise Exception(
|
|
174
|
+
"The provided uid %a does not fit the format 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'"
|
|
175
|
+
)
|
|
176
|
+
return UUID(v)
|
|
177
|
+
|
|
178
|
+
@classmethod
|
|
179
|
+
def dataClassConverterGenerator(cls, dataClassType: type) -> Callable:
|
|
180
|
+
|
|
181
|
+
if dataclasses.is_dataclass(dataClassType):
|
|
182
|
+
|
|
183
|
+
def converter(value):
|
|
184
|
+
if isinstance(value, dataClassType):
|
|
185
|
+
return value
|
|
186
|
+
if isinstance(value, dict):
|
|
187
|
+
fieldTypes = set(f.name for f in dataclasses.fields(dataClassType))
|
|
188
|
+
fieldValues = {k: v for k, v in value.items() if k in fieldTypes}
|
|
189
|
+
|
|
190
|
+
return dataClassType(**fieldValues)
|
|
191
|
+
raise Exception(f"Cannot convert to type {dataClassType.__name__}")
|
|
192
|
+
|
|
193
|
+
return converter
|
|
194
|
+
|
|
195
|
+
return lambda value: None
|
|
196
|
+
|
|
197
|
+
@classmethod
|
|
198
|
+
def checkAndConvert(
|
|
199
|
+
cls,
|
|
200
|
+
value: Any,
|
|
201
|
+
fieldType: Union[Type[_T], str],
|
|
202
|
+
fieldName: Optional[str] = None,
|
|
203
|
+
converter: Optional[Callable[[Any], _T]] = None,
|
|
204
|
+
allowNone=False,
|
|
205
|
+
initOnNone=False,
|
|
206
|
+
) -> _T:
|
|
207
|
+
if isinstance(fieldType, list):
|
|
208
|
+
fieldType = cast(Any, cls.getTypeFromTypeEntry(value, fieldType))
|
|
209
|
+
|
|
210
|
+
if not fieldType:
|
|
211
|
+
return value
|
|
212
|
+
|
|
213
|
+
if not isinstance(fieldType, type) and converter is None:
|
|
214
|
+
raise Exception(
|
|
215
|
+
f"Manual field type '{fieldType}' cannot be used without a converter definition."
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
if not converter:
|
|
219
|
+
if isinstance(fieldType, type) and isinstance(value, fieldType):
|
|
220
|
+
return value
|
|
221
|
+
|
|
222
|
+
if issubclass(cast(Type[_T], fieldType), Enum):
|
|
223
|
+
if allowNone and value == None:
|
|
224
|
+
return cast(Any, None)
|
|
225
|
+
|
|
226
|
+
try:
|
|
227
|
+
enum = cast(Any, fieldType)
|
|
228
|
+
return enum(value)
|
|
229
|
+
except ValueError:
|
|
230
|
+
raise Exception(
|
|
231
|
+
"Field %a cannot be converted to enum type %a. (Got invalid value %a)"
|
|
232
|
+
% (
|
|
233
|
+
fieldName,
|
|
234
|
+
cast(type, fieldType).__name__,
|
|
235
|
+
cls.truncString(str(value)),
|
|
236
|
+
)
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
if cast(type, fieldType).__name__ == datetime.__name__:
|
|
240
|
+
converter = cast(Callable, DateTimeConverter.convertDateTime)
|
|
241
|
+
elif cast(type, fieldType).__name__ == time.__name__:
|
|
242
|
+
converter = cast(Callable, DateTimeConverter.convertTime)
|
|
243
|
+
elif cast(type, fieldType).__name__ == UUID.__name__:
|
|
244
|
+
converter = cast(Callable, cls.uuidConverter)
|
|
245
|
+
elif dataclasses.is_dataclass(fieldType):
|
|
246
|
+
converter = cls.dataClassConverterGenerator(fieldType)
|
|
247
|
+
else:
|
|
248
|
+
converter = cast(Callable, fieldType)
|
|
249
|
+
|
|
250
|
+
if fieldName == None:
|
|
251
|
+
fieldName = "field"
|
|
252
|
+
fieldName = cast(str, fieldName)
|
|
253
|
+
|
|
254
|
+
if value == None:
|
|
255
|
+
if initOnNone and hasattr(fieldType, "__init__"):
|
|
256
|
+
return cast(Callable, fieldType)()
|
|
257
|
+
if allowNone:
|
|
258
|
+
return cast(Any, None)
|
|
259
|
+
else:
|
|
260
|
+
raise Exception("Field %a cannot be 'None'." % (fieldName))
|
|
261
|
+
|
|
262
|
+
typeName = (
|
|
263
|
+
cast(type, fieldType).__name__
|
|
264
|
+
if isinstance(fieldType, type)
|
|
265
|
+
else str(fieldType)
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
# print(f"{fieldName}({fieldType}) = {value}")
|
|
269
|
+
try:
|
|
270
|
+
value = converter(value)
|
|
271
|
+
except:
|
|
272
|
+
raise Exception(
|
|
273
|
+
"Field %a cannot be converted to type %a. (Got value %a of type %a)"
|
|
274
|
+
% (
|
|
275
|
+
fieldName,
|
|
276
|
+
typeName,
|
|
277
|
+
cls.truncString(str(value)),
|
|
278
|
+
type(value).__name__,
|
|
279
|
+
)
|
|
280
|
+
)
|
|
281
|
+
|
|
282
|
+
# print(f"{fieldName}({fieldType}) => {value}")
|
|
283
|
+
|
|
284
|
+
if value == None:
|
|
285
|
+
if allowNone:
|
|
286
|
+
return cast(Any, None)
|
|
287
|
+
else:
|
|
288
|
+
raise Exception("%s cannot be 'None'." % (fieldName))
|
|
289
|
+
|
|
290
|
+
return value
|
|
291
|
+
|
|
292
|
+
@classmethod
|
|
293
|
+
def checkListAndConvert(
|
|
294
|
+
cls,
|
|
295
|
+
value: Any,
|
|
296
|
+
fieldType: Union[Type[_T], str],
|
|
297
|
+
fieldName: Optional[str] = None,
|
|
298
|
+
converter: Optional[Callable[[Any], _T]] = None,
|
|
299
|
+
allowNone: bool = False,
|
|
300
|
+
singleToList: bool = False,
|
|
301
|
+
length: int = -1,
|
|
302
|
+
) -> List[_T]:
|
|
303
|
+
if fieldName == None:
|
|
304
|
+
fieldName = "field"
|
|
305
|
+
fieldName = cast(str, fieldName)
|
|
306
|
+
|
|
307
|
+
if value == None:
|
|
308
|
+
value = []
|
|
309
|
+
|
|
310
|
+
if singleToList:
|
|
311
|
+
if not isinstance(value, (list, tuple)):
|
|
312
|
+
value = [value]
|
|
313
|
+
|
|
314
|
+
typeName = (
|
|
315
|
+
cast(type, fieldType).__name__
|
|
316
|
+
if isinstance(fieldType, type)
|
|
317
|
+
else str(fieldType)
|
|
318
|
+
)
|
|
319
|
+
if not isinstance(value, (list, tuple)):
|
|
320
|
+
raise Exception(
|
|
321
|
+
"%s must be of type 'list[%s]'. (Got type %a)"
|
|
322
|
+
% (fieldName, typeName, type(value).__name__)
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
if length >= 0 and len(value) != length:
|
|
326
|
+
raise Exception(
|
|
327
|
+
"%s must have length %d. (Got length %a)"
|
|
328
|
+
% (fieldName, length, len(value))
|
|
329
|
+
)
|
|
330
|
+
|
|
331
|
+
return [
|
|
332
|
+
cls.checkAndConvert(
|
|
333
|
+
f,
|
|
334
|
+
fieldType=fieldType,
|
|
335
|
+
fieldName="%s[%d]" % (fieldName, i),
|
|
336
|
+
converter=converter,
|
|
337
|
+
allowNone=allowNone,
|
|
338
|
+
)
|
|
339
|
+
for i, f in enumerate(value)
|
|
340
|
+
]
|
|
341
|
+
|
|
342
|
+
@staticmethod
|
|
343
|
+
def checkDirectory(dir):
|
|
344
|
+
if not os.path.isdir(dir):
|
|
345
|
+
return "could not find directory '%s'" % dir
|
|
346
|
+
|
|
347
|
+
list_of_entries = []
|
|
348
|
+
try:
|
|
349
|
+
with os.scandir(dir) as entries:
|
|
350
|
+
for entry in entries:
|
|
351
|
+
list_of_entries.append(entry.name)
|
|
352
|
+
except PermissionError:
|
|
353
|
+
return "permission denied for directory '%s' on server" % dir
|
|
354
|
+
except:
|
|
355
|
+
return "could not access directory '%s'" % dir
|
|
356
|
+
|
|
357
|
+
return False
|
|
358
|
+
|
|
359
|
+
@staticmethod
|
|
360
|
+
def convertToNativeNewline(text: str):
|
|
361
|
+
return text.replace("\n", os.linesep)
|
|
362
|
+
|
|
363
|
+
@staticmethod
|
|
364
|
+
def namedSwitchConverter(switchList: List[str]) -> Dict[str, bool]:
|
|
365
|
+
result = {}
|
|
366
|
+
for s in switchList:
|
|
367
|
+
result[s] = True
|
|
368
|
+
|
|
369
|
+
return result
|
|
370
|
+
|
|
371
|
+
@staticmethod
|
|
372
|
+
def stringToId(s: str):
|
|
373
|
+
if not isinstance(s, str):
|
|
374
|
+
s = str(s)
|
|
375
|
+
return "".join([c if c.isalpha() or c.isdigit() else "_" for c in s]).rstrip()
|
|
376
|
+
|
|
377
|
+
@classmethod
|
|
378
|
+
def truncString(cls, text: str, length: int = 30) -> str:
|
|
379
|
+
return "%s%s" % (text[:length], "..." if len(text) > length else "")
|
|
380
|
+
|
|
381
|
+
@classmethod
|
|
382
|
+
def checkSubFieldAndConvert(
|
|
383
|
+
cls,
|
|
384
|
+
value: dict,
|
|
385
|
+
fieldType: Union[Type[_T], str],
|
|
386
|
+
fieldName: Union[str, None],
|
|
387
|
+
subFieldName: str,
|
|
388
|
+
allowNone=False,
|
|
389
|
+
):
|
|
390
|
+
name = f"{fieldName}.{subFieldName}" if fieldName else None
|
|
391
|
+
v = value.get(subFieldName, None) if isinstance(value, dict) else None
|
|
392
|
+
return Tools.checkAndConvert(v, fieldType, name, allowNone=allowNone)
|
|
393
|
+
|
|
394
|
+
@classmethod
|
|
395
|
+
def resolveKeyConflictWithPrefix(
|
|
396
|
+
cls,
|
|
397
|
+
name: str,
|
|
398
|
+
prefix: str,
|
|
399
|
+
lookup: Union[Dict, Set],
|
|
400
|
+
separator="_",
|
|
401
|
+
startIndex=1,
|
|
402
|
+
) -> str:
|
|
403
|
+
originalName = name
|
|
404
|
+
index = startIndex
|
|
405
|
+
while name in lookup or prefix + name in lookup:
|
|
406
|
+
name = f"{originalName}{separator}{index}"
|
|
407
|
+
index += 1
|
|
408
|
+
return name
|
|
409
|
+
|
|
410
|
+
@classmethod
|
|
411
|
+
def resolveKeyConflict(
|
|
412
|
+
cls, name: str, lookup: Union[Dict, Set], separator="_", startIndex=1
|
|
413
|
+
) -> str:
|
|
414
|
+
originalName = name
|
|
415
|
+
index = startIndex
|
|
416
|
+
while name in lookup:
|
|
417
|
+
name = f"{originalName}{separator}{index}"
|
|
418
|
+
index += 1
|
|
419
|
+
return name
|
|
420
|
+
|
|
421
|
+
@classmethod
|
|
422
|
+
def generateRandomString(cls, len=10):
|
|
423
|
+
return "".join(map(lambda r: chr(random.randint(65, 90)), range(len)))
|
|
424
|
+
|
|
425
|
+
@classmethod
|
|
426
|
+
def gerundVerb(cls, verb: str):
|
|
427
|
+
if verb.endswith("ing"):
|
|
428
|
+
return verb
|
|
429
|
+
elif verb.endswith("e"):
|
|
430
|
+
verb = verb[:-1]
|
|
431
|
+
|
|
432
|
+
return verb + "ing"
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This Module is written for the LOGS Repository.
|
|
3
|
+
|
|
4
|
+
It's objects can be used to access the LOGS public API
|
|
5
|
+
programatically via python scripts.
|
|
6
|
+
...
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from .Constants import *
|
|
10
|
+
from .DateTimeConverter import *
|
|
11
|
+
from .Decorators import *
|
|
12
|
+
from .Exceptions import *
|
|
13
|
+
from .MinimalModelGenerator import *
|
|
14
|
+
from .ReplaceMessage import *
|
|
15
|
+
from .Tools import *
|