sdata 1.5.0__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.
Files changed (98) hide show
  1. sdata/__init__.py +140 -0
  2. sdata/base.py +684 -0
  3. sdata/contrib/__init__.py +0 -0
  4. sdata/contrib/piexif/__init__.py +12 -0
  5. sdata/contrib/piexif/_common.py +94 -0
  6. sdata/contrib/piexif/_dump.py +346 -0
  7. sdata/contrib/piexif/_exceptions.py +2 -0
  8. sdata/contrib/piexif/_exif.py +638 -0
  9. sdata/contrib/piexif/_insert.py +60 -0
  10. sdata/contrib/piexif/_load.py +270 -0
  11. sdata/contrib/piexif/_remove.py +56 -0
  12. sdata/contrib/piexif/_transplant.py +45 -0
  13. sdata/contrib/piexif/_webp.py +240 -0
  14. sdata/contrib/piexif/helper.py +66 -0
  15. sdata/contrib/ranger/__init__.py +8 -0
  16. sdata/contrib/ranger/collections/__init__.py +0 -0
  17. sdata/contrib/ranger/collections/rangebucketmap.py +346 -0
  18. sdata/contrib/ranger/collections/rangemap.py +396 -0
  19. sdata/contrib/ranger/collections/rangeset.py +483 -0
  20. sdata/contrib/ranger/range/__init__.py +0 -0
  21. sdata/contrib/ranger/range/cut.py +285 -0
  22. sdata/contrib/ranger/range/range.py +644 -0
  23. sdata/contrib/sobol_seq.py +394 -0
  24. sdata/contrib/sortedcontainers/LICENSE +13 -0
  25. sdata/contrib/sortedcontainers/__init__.py +74 -0
  26. sdata/contrib/sortedcontainers/sorteddict.py +789 -0
  27. sdata/contrib/sortedcontainers/sortedlist.py +2646 -0
  28. sdata/contrib/sortedcontainers/sortedset.py +733 -0
  29. sdata/contrib/sqlitedict.py +598 -0
  30. sdata/contrib/timeflake/__init__.py +40 -0
  31. sdata/contrib/timeflake/flake.py +69 -0
  32. sdata/contrib/timeflake/utils.py +47 -0
  33. sdata/deprecated/__init__.py +10 -0
  34. sdata/deprecated/data.py +1503 -0
  35. sdata/did/__init__.py +129 -0
  36. sdata/did/_http.py +67 -0
  37. sdata/did/base58btc.py +49 -0
  38. sdata/did/did_github.py +152 -0
  39. sdata/did/did_peer4.py +155 -0
  40. sdata/did/did_web.py +222 -0
  41. sdata/did/diddoc.py +75 -0
  42. sdata/did/ed25519.py +225 -0
  43. sdata/did/eddsa.py +107 -0
  44. sdata/did/errors.py +40 -0
  45. sdata/did/issue_vc.py +193 -0
  46. sdata/did/jose.py +126 -0
  47. sdata/did/keys.py +104 -0
  48. sdata/did/utils_didkey.py +161 -0
  49. sdata/did/verify_vp.py +158 -0
  50. sdata/doe.py +101 -0
  51. sdata/dtypes.py +510 -0
  52. sdata/experiments/__init__.py +331 -0
  53. sdata/experiments/blob0.py +131 -0
  54. sdata/experiments/file.py +42 -0
  55. sdata/experiments/filegroup.py +144 -0
  56. sdata/experiments/image_old.py +313 -0
  57. sdata/experiments/ks2.py +15 -0
  58. sdata/experiments/lapshear.py +8 -0
  59. sdata/experiments/material.py +7 -0
  60. sdata/experiments/parameters_deprecated.py +394 -0
  61. sdata/experiments/workbook.py +226 -0
  62. sdata/format.py +125 -0
  63. sdata/imagemeta.py +533 -0
  64. sdata/interactive.py +118 -0
  65. sdata/iolib/__init__.py +51 -0
  66. sdata/iolib/hashtree.py +264 -0
  67. sdata/iolib/json1sqlitestore.py +554 -0
  68. sdata/iolib/jsonsqlitestore.py +704 -0
  69. sdata/iolib/pud.py +242 -0
  70. sdata/iolib/reader.py +262 -0
  71. sdata/iolib/writer.py +419 -0
  72. sdata/metadata.py +882 -0
  73. sdata/parameter.py +414 -0
  74. sdata/schema.py +273 -0
  75. sdata/sclass/__init__.py +111 -0
  76. sdata/sclass/bfo_classes.py +362 -0
  77. sdata/sclass/blob.py +362 -0
  78. sdata/sclass/content.py +87 -0
  79. sdata/sclass/dataframe.py +1251 -0
  80. sdata/sclass/dataframegroup.py +187 -0
  81. sdata/sclass/dependency_graph.py +85 -0
  82. sdata/sclass/filereference.py +124 -0
  83. sdata/sclass/image.py +218 -0
  84. sdata/sclass/lazy_namespace.py +155 -0
  85. sdata/sclass/process.py +383 -0
  86. sdata/sclass/process_graph.py +221 -0
  87. sdata/sclass/zipfile.py +135 -0
  88. sdata/semantic.py +346 -0
  89. sdata/suuid.py +136 -0
  90. sdata/timestamp.py +336 -0
  91. sdata/tools.py +14 -0
  92. sdata/units.py +602 -0
  93. sdata/vocab.py +149 -0
  94. sdata-1.5.0.dist-info/METADATA +264 -0
  95. sdata-1.5.0.dist-info/RECORD +98 -0
  96. sdata-1.5.0.dist-info/WHEEL +5 -0
  97. sdata-1.5.0.dist-info/licenses/LICENSE-MIT +21 -0
  98. sdata-1.5.0.dist-info/top_level.txt +1 -0
sdata/did/verify_vp.py ADDED
@@ -0,0 +1,158 @@
1
+ # -*- coding: utf-8 -*-
2
+ """Verifikation von Verifiable Presentations (VP) und der eingebetteten VC.
3
+
4
+ Geprüft werden:
5
+
6
+ 1. die Holder-Signatur der VP,
7
+ 2. optional ``aud`` und ``nonce`` (Replay-Schutz),
8
+ 3. die Issuer-Signatur des eingebetteten VC,
9
+ 4. der Gültigkeitszeitraum des VC (``nbf``/``exp``).
10
+
11
+ Unterstützte DID-Methoden für die Schlüsselauflösung:
12
+
13
+ * **Issuer** ``did:web`` – Auflösung via HTTPS (:mod:`sdata.did.did_web`),
14
+ * **Holder** ``did:key`` – lokale Rückgewinnung des Public-JWK (kein Netzwerk).
15
+
16
+ Die Bibliotheksfunktionen werfen :class:`sdata.did.VerificationError` /
17
+ :class:`sdata.did.ResolutionError` (nie ``SystemExit``).
18
+
19
+ CLI::
20
+
21
+ python -m sdata.did.verify_vp --vp product.vp \\
22
+ --expected-aud https://verifier.example.org --expected-nonce <nonce>
23
+ """
24
+ from __future__ import annotations
25
+
26
+ import time
27
+ import logging
28
+ import argparse
29
+ from typing import Any, Dict, Optional
30
+
31
+ from . import jose
32
+ from .errors import ResolutionError, VerificationError
33
+ from .utils_didkey import pub_jwk_from_did_key
34
+ from .did_web import resolve_public_jwk_for_kid as resolve_web_kid
35
+
36
+ logger = logging.getLogger(__name__)
37
+
38
+ __all__ = [
39
+ "resolve_public_jwk_for_kid",
40
+ "verify_presentation",
41
+ "jws_header",
42
+ "jws_verify",
43
+ ]
44
+
45
+
46
+ def jws_header(compact: str) -> Dict[str, Any]:
47
+ """Dekodiere den (ungeprüften) Header eines Compact-JWS."""
48
+ return jose.decode_header(compact)
49
+
50
+
51
+ def jws_verify(compact: str, public_jwk: Dict) -> Dict[str, Any]:
52
+ """Verifiziere ein Compact-JWS gegen ``public_jwk`` und gib das Payload zurück."""
53
+ return jose.verify_compact(compact, public_jwk)
54
+
55
+
56
+ def resolve_public_jwk_for_kid(kid: str) -> Dict[str, str]:
57
+ """Löse die ``kid`` zu einem öffentlichen JWK auf (``did:web`` oder ``did:key``).
58
+
59
+ Raises:
60
+ ResolutionError: bei nicht unterstützter DID-Methode oder Auflösefehler.
61
+ """
62
+ did = kid.split("#")[0]
63
+ if did.startswith("did:web:"):
64
+ return resolve_web_kid(kid)
65
+ if did.startswith("did:key:"):
66
+ return pub_jwk_from_did_key(did)
67
+ raise ResolutionError("nicht unterstützte DID-Methode in kid: {}".format(kid))
68
+
69
+
70
+ def verify_presentation(vp_jws: str, *, expected_aud: Optional[str] = None,
71
+ expected_nonce: Optional[str] = None,
72
+ now: Optional[int] = None) -> Dict[str, Any]:
73
+ """Verifiziere eine VP samt eingebettetem VC vollständig.
74
+
75
+ Args:
76
+ vp_jws: Die Verifiable Presentation als Compact-JWS.
77
+ expected_aud: Falls gesetzt, muss ``vp.aud`` exakt übereinstimmen.
78
+ expected_nonce: Falls gesetzt, muss ``vp.nonce`` exakt übereinstimmen.
79
+ now: Referenzzeit (Unix-Sekunden) für die ``nbf``/``exp``-Prüfung;
80
+ Default ist die aktuelle Zeit. Nützlich für Tests.
81
+
82
+ Returns:
83
+ Ein Dict mit ``issuer``, ``holder``, ``credentialSubject``, ``vc`` und ``vp``.
84
+
85
+ Raises:
86
+ VerificationError: bei ungültiger Signatur, ``aud``/``nonce``-Mismatch,
87
+ fehlendem VC oder abgelaufenem/ noch nicht gültigem VC.
88
+ ResolutionError: wenn ein Schlüssel nicht aufgelöst werden kann.
89
+ """
90
+ now = int(time.time()) if now is None else int(now)
91
+
92
+ # 1) VP-Signatur (Holder)
93
+ vp_pub = resolve_public_jwk_for_kid(jws_header(vp_jws)["kid"])
94
+ vp = jws_verify(vp_jws, vp_pub)
95
+
96
+ # 2) aud / nonce
97
+ if expected_aud is not None and vp.get("aud") != expected_aud:
98
+ raise VerificationError("aud stimmt nicht überein")
99
+ if expected_nonce is not None and vp.get("nonce") != expected_nonce:
100
+ raise VerificationError("nonce stimmt nicht überein")
101
+
102
+ # 3) eingebettetes VC extrahieren & prüfen (Issuer)
103
+ creds = vp.get("vp", {}).get("verifiableCredential", [])
104
+ if not creds:
105
+ raise VerificationError("VP enthält keine verifiableCredential")
106
+ vc_jws = creds[0]
107
+ vc_pub = resolve_public_jwk_for_kid(jws_header(vc_jws)["kid"])
108
+ vc = jws_verify(vc_jws, vc_pub)
109
+
110
+ # 4) Gültigkeitszeitraum
111
+ nbf, exp = vc.get("nbf"), vc.get("exp")
112
+ if nbf is not None and now < nbf:
113
+ raise VerificationError("VC ist noch nicht gültig (nbf)")
114
+ if exp is not None and now > exp:
115
+ raise VerificationError("VC ist abgelaufen (exp)")
116
+
117
+ return {
118
+ "issuer": vc.get("iss"),
119
+ "holder": vp.get("holder"),
120
+ "credentialSubject": vc.get("vc", {}).get("credentialSubject", {}),
121
+ "vc": vc,
122
+ "vp": vp,
123
+ }
124
+
125
+
126
+ # --------------------------------------------------------------------------
127
+ # CLI
128
+ # --------------------------------------------------------------------------
129
+ def main(argv=None) -> None:
130
+ logging.basicConfig(level=logging.INFO, format="%(message)s")
131
+ ap = argparse.ArgumentParser(description="Verifiable Presentation verifizieren")
132
+ ap.add_argument("--vp", required=True)
133
+ ap.add_argument("--expected-aud")
134
+ ap.add_argument("--expected-nonce")
135
+ args = ap.parse_args(argv)
136
+
137
+ with open(args.vp, "r") as fh:
138
+ vp_jws = fh.read().strip()
139
+
140
+ try:
141
+ result = verify_presentation(
142
+ vp_jws,
143
+ expected_aud=args.expected_aud,
144
+ expected_nonce=args.expected_nonce,
145
+ )
146
+ except (VerificationError, ResolutionError) as exc:
147
+ raise SystemExit("✘ Verifikation fehlgeschlagen: {}".format(exc))
148
+
149
+ subj = result["credentialSubject"]
150
+ logger.info("✔ VP + VC verifiziert")
151
+ logger.info("Issuer: %s", result["issuer"])
152
+ logger.info("Holder: %s", result["holder"])
153
+ logger.info("GTIN: %s SN: %s", subj.get("gtin"), subj.get("serialNumber"))
154
+ logger.info("CO2: %s Recycled: %s", subj.get("co2Footprint"), subj.get("recycledContent"))
155
+
156
+
157
+ if __name__ == "__main__":
158
+ main()
sdata/doe.py ADDED
@@ -0,0 +1,101 @@
1
+ # -*-coding: utf-8-*-
2
+
3
+
4
+ import collections
5
+ import sdata
6
+ from sdata.contrib.ranger import Range
7
+ import sdata.contrib.sobol_seq
8
+ from sdata.contrib.sobol_seq import Sobol
9
+ import pandas as pd
10
+ class DOE():
11
+ """
12
+ DoE Generator
13
+
14
+ params_ranges = {"sheet_thickness": [0.8, 1.8],
15
+ "slant_depth": [10., 50.],}
16
+ doe = DOE(params_ranges)
17
+
18
+ """
19
+ def __init__(self, ranges=None, name="N.N."):
20
+ """DoE Generator
21
+
22
+ params_ranges = {"sheet_thickness": [0.8, 1.8],
23
+ "slant_depth": [10., 50.],}
24
+ doe = DOE(params_ranges)
25
+
26
+ :param ranges:
27
+ :param name:
28
+ """
29
+
30
+ self._ranges = collections.OrderedDict()
31
+ if ranges is not None:
32
+ for param_name, l in ranges.items():
33
+ r = Range.closed(float(min(l)), float(max(l)))
34
+ self._ranges[param_name] = r
35
+
36
+ def add_range(self, param_name, l):
37
+ """add range
38
+
39
+ :param param_name: str
40
+ :param range: [min, max]
41
+ :return:
42
+ """
43
+ r = Range.closed(float(min(l)), float(max(l)))
44
+ self._ranges[param_name] = r
45
+
46
+ @property
47
+ def ranges(self):
48
+ return self._ranges
49
+
50
+ @property
51
+ def dim_num(self):
52
+ return len(self._ranges)
53
+
54
+ def gen_sobol01(self, n=1):
55
+ S = Sobol()
56
+ X = S.i4_sobol_generate(dim_num=self.dim_num, n=n, skip=1)
57
+ df = pd.DataFrame(X, columns=self._ranges.keys())
58
+ df["doe_id"] = range(1, len(X)+1)
59
+ df.set_index("doe_id", inplace=True)
60
+ return df
61
+
62
+ def gen_sobol(self, n=1):
63
+ S = Sobol()
64
+ X = S.i4_sobol_generate(dim_num=self.dim_num, n=n, skip=1)
65
+ df = pd.DataFrame(X, columns=self._ranges.keys())
66
+ df["doe_id"] = range(1, len(X)+1)
67
+ df.set_index("doe_id", inplace=True)
68
+ for param_name, r in self._ranges.items():
69
+ df[param_name] *= r.length
70
+ df[param_name] += r.min
71
+ return df
72
+
73
+ def to_data(self, name, df_doe, uid=None):
74
+ """
75
+
76
+ :param df_doe: design table
77
+ :return: sdata.Data
78
+ """
79
+ data = sdata.Data(name=name, uuid=uid, table=df_doe, description="my DoE")
80
+ for parameter_name, r in self.ranges.items():
81
+ data.metadata.add(parameter_name, r, unit="?", description=f"parameter range {parameter_name}",
82
+ label=rf"${parameter_name}$")
83
+ return data
84
+
85
+ if __name__ == '__main__':
86
+ import logging
87
+ try:
88
+ from itertools import combinations
89
+ import matplotlib.pyplot as plt
90
+ def plot_doe(df, figsize=(10,10), alpha=.5, s=5, dpi=150):
91
+ dim_num = len(df.columns)
92
+ fig, axs = plt.subplots(dim_num-1, dim_num-1, figsize=figsize, dpi=dpi)
93
+ for i, j in list(combinations(range(dim_num), 2)):
94
+ xi = df.columns[i]
95
+ xj = df.columns[j]
96
+ axs[i][j-1].scatter(df.iloc[:,i], df.iloc[:,j], alpha=alpha, s=s)
97
+ axs[i][j-1].set_xlabel(xi)
98
+ axs[i][j-1].set_ylabel(xj)
99
+ fig.tight_layout()
100
+ except Exception as exp:
101
+ logging.warning(f"doe: {exp}")