LoopStructural 1.6.15__py3-none-any.whl → 1.6.17__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.
Potentially problematic release.
This version of LoopStructural might be problematic. Click here for more details.
- LoopStructural/__init__.py +31 -12
- LoopStructural/interpolators/_geological_interpolator.py +7 -2
- LoopStructural/modelling/core/fault_topology.py +234 -0
- LoopStructural/modelling/core/geological_model.py +119 -119
- LoopStructural/modelling/core/stratigraphic_column.py +500 -0
- LoopStructural/modelling/features/builders/_fault_builder.py +1 -0
- LoopStructural/modelling/features/fault/_fault_segment.py +1 -1
- LoopStructural/utils/__init__.py +1 -0
- LoopStructural/utils/_surface.py +6 -1
- LoopStructural/utils/observer.py +150 -0
- LoopStructural/version.py +1 -1
- {loopstructural-1.6.15.dist-info → loopstructural-1.6.17.dist-info}/METADATA +1 -1
- {loopstructural-1.6.15.dist-info → loopstructural-1.6.17.dist-info}/RECORD +16 -13
- {loopstructural-1.6.15.dist-info → loopstructural-1.6.17.dist-info}/WHEEL +0 -0
- {loopstructural-1.6.15.dist-info → loopstructural-1.6.17.dist-info}/licenses/LICENSE +0 -0
- {loopstructural-1.6.15.dist-info → loopstructural-1.6.17.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Callable
|
|
4
|
+
from contextlib import contextmanager
|
|
5
|
+
from typing import Any, Generic, Protocol, TypeAlias, TypeVar, runtime_checkable
|
|
6
|
+
import threading
|
|
7
|
+
import weakref
|
|
8
|
+
|
|
9
|
+
__all__ = ["Observer", "Observable", "Disposable"]
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@runtime_checkable
|
|
13
|
+
class Observer(Protocol):
|
|
14
|
+
"""Objects implementing an *update* method can subscribe."""
|
|
15
|
+
|
|
16
|
+
def update(self, observable: "Observable", event: str, *args: Any, **kwargs: Any) -> None:
|
|
17
|
+
"""Receive a notification."""
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
Callback: TypeAlias = Callable[["Observable", str, Any], None]
|
|
21
|
+
T = TypeVar("T", bound="Observable")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class Disposable:
|
|
25
|
+
"""A small helper that detaches an observer when disposed."""
|
|
26
|
+
|
|
27
|
+
__slots__ = ("_detach",)
|
|
28
|
+
|
|
29
|
+
def __init__(self, detach: Callable[[], None]):
|
|
30
|
+
self._detach = detach
|
|
31
|
+
|
|
32
|
+
def dispose(self) -> None:
|
|
33
|
+
"""Detach the associated observer immediately."""
|
|
34
|
+
|
|
35
|
+
self._detach()
|
|
36
|
+
|
|
37
|
+
# Allow use as a context‑manager for temporary subscriptions
|
|
38
|
+
def __enter__(self) -> "Disposable":
|
|
39
|
+
return self
|
|
40
|
+
|
|
41
|
+
def __exit__(self, exc_type, exc, tb):
|
|
42
|
+
self.dispose()
|
|
43
|
+
return False # do not swallow exceptions
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class Observable(Generic[T]):
|
|
47
|
+
"""Base‑class that provides Observer pattern plumbing."""
|
|
48
|
+
|
|
49
|
+
#: Internal storage: mapping *event* → WeakSet[Callback]
|
|
50
|
+
_observers: dict[str, weakref.WeakSet[Callback]]
|
|
51
|
+
_any_observers: weakref.WeakSet[Callback]
|
|
52
|
+
|
|
53
|
+
def __init__(self) -> None:
|
|
54
|
+
self._lock = threading.RLock()
|
|
55
|
+
self._observers = {}
|
|
56
|
+
self._any_observers = weakref.WeakSet()
|
|
57
|
+
self._frozen = 0
|
|
58
|
+
self._pending: list[tuple[str, tuple[Any, ...], dict[str, Any]]] = []
|
|
59
|
+
|
|
60
|
+
# ‑‑‑ subscription api --------------------------------------------------
|
|
61
|
+
def attach(self, listener: Observer | Callback, event: str | None = None) -> Disposable:
|
|
62
|
+
"""Register *listener* for *event* (all events if *event* is None).
|
|
63
|
+
|
|
64
|
+
Returns a :class:`Disposable` so the caller can easily detach again.
|
|
65
|
+
"""
|
|
66
|
+
callback: Callback = (
|
|
67
|
+
listener.update # type: ignore[attr‑defined]
|
|
68
|
+
if isinstance(listener, Observer) # type: ignore[misc]
|
|
69
|
+
else listener # already a callable
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
with self._lock:
|
|
73
|
+
if event is None:
|
|
74
|
+
self._any_observers.add(callback)
|
|
75
|
+
else:
|
|
76
|
+
self._observers.setdefault(event, weakref.WeakSet()).add(callback)
|
|
77
|
+
|
|
78
|
+
return Disposable(lambda: self.detach(listener, event))
|
|
79
|
+
|
|
80
|
+
def detach(self, listener: Observer | Callback, event: str | None = None) -> None:
|
|
81
|
+
"""Unregister a previously attached *listener*."""
|
|
82
|
+
|
|
83
|
+
callback: Callback = (
|
|
84
|
+
listener.update # type: ignore[attr‑defined]
|
|
85
|
+
if isinstance(listener, Observer) # type: ignore[misc]
|
|
86
|
+
else listener
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
with self._lock:
|
|
90
|
+
if event is None:
|
|
91
|
+
self._any_observers.discard(callback)
|
|
92
|
+
for s in self._observers.values():
|
|
93
|
+
s.discard(callback)
|
|
94
|
+
else:
|
|
95
|
+
self._observers.get(event, weakref.WeakSet()).discard(callback)
|
|
96
|
+
def __getstate__(self):
|
|
97
|
+
state = self.__dict__.copy()
|
|
98
|
+
state.pop('_lock', None) # RLock cannot be pickled
|
|
99
|
+
state.pop('_observers', None) # WeakSet cannot be pickled
|
|
100
|
+
state.pop('_any_observers', None)
|
|
101
|
+
return state
|
|
102
|
+
def __setstate__(self, state):
|
|
103
|
+
self.__dict__.update(state)
|
|
104
|
+
self._lock = threading.RLock()
|
|
105
|
+
self._observers = {}
|
|
106
|
+
self._any_observers = weakref.WeakSet()
|
|
107
|
+
self._frozen = 0
|
|
108
|
+
# ‑‑‑ notification api --------------------------------------------------
|
|
109
|
+
def notify(self: T, event: str, *args: Any, **kwargs: Any) -> None:
|
|
110
|
+
"""Notify observers that *event* happened."""
|
|
111
|
+
|
|
112
|
+
with self._lock:
|
|
113
|
+
if self._frozen:
|
|
114
|
+
# defer until freeze_notifications() exits
|
|
115
|
+
self._pending.append((event, args, kwargs))
|
|
116
|
+
return
|
|
117
|
+
|
|
118
|
+
observers = list(self._any_observers)
|
|
119
|
+
observers.extend(self._observers.get(event, ()))
|
|
120
|
+
|
|
121
|
+
# Call outside lock — prevent deadlocks if observers trigger other
|
|
122
|
+
# notifications.
|
|
123
|
+
for cb in observers:
|
|
124
|
+
try:
|
|
125
|
+
cb(self, event, *args, **kwargs)
|
|
126
|
+
except Exception: # pragma: no cover
|
|
127
|
+
# Optionally log; never allow an observer error to break flow.
|
|
128
|
+
import logging
|
|
129
|
+
|
|
130
|
+
logging.getLogger(__name__).exception(
|
|
131
|
+
"Unhandled error in observer %s for event %s", cb, event
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
# ‑‑‑ batching ----------------------------------------------------------
|
|
135
|
+
@contextmanager
|
|
136
|
+
def freeze_notifications(self):
|
|
137
|
+
"""Context manager that batches notifications until exit."""
|
|
138
|
+
|
|
139
|
+
with self._lock:
|
|
140
|
+
self._frozen += 1
|
|
141
|
+
try:
|
|
142
|
+
yield self
|
|
143
|
+
finally:
|
|
144
|
+
with self._lock:
|
|
145
|
+
self._frozen -= 1
|
|
146
|
+
if self._frozen == 0 and self._pending:
|
|
147
|
+
pending = self._pending[:]
|
|
148
|
+
self._pending.clear()
|
|
149
|
+
for event, args, kw in pending: # type: ignore[has‑type]
|
|
150
|
+
self.notify(event, *args, **kw)
|
LoopStructural/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "1.6.
|
|
1
|
+
__version__ = "1.6.17"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
LoopStructural/__init__.py,sha256=
|
|
2
|
-
LoopStructural/version.py,sha256=
|
|
1
|
+
LoopStructural/__init__.py,sha256=ZS5J2TI2OuhRE0o3EXmPbbjrvh1-Vy9RFwL7Hc1YBow,2079
|
|
2
|
+
LoopStructural/version.py,sha256=RFX1x9AQ2Z9aP2gCXAUVtaLq0UOmist-rpJN8M8jz9I,23
|
|
3
3
|
LoopStructural/datasets/__init__.py,sha256=ylb7fzJU_DyQ73LlwQos7VamqkDSGITbbnoKg7KAOmE,677
|
|
4
4
|
LoopStructural/datasets/_base.py,sha256=FB_D5ybBYHoaNbycdkpZcRffzjrrL1xp9X0k-pyob9Y,7618
|
|
5
5
|
LoopStructural/datasets/_example_models.py,sha256=Zg33IeUyh4C-lC0DRMLqCDP2IrX8L-gNV1WxJwBGjzM,113
|
|
@@ -45,7 +45,7 @@ LoopStructural/interpolators/_constant_norm.py,sha256=gGaDGDoEzfnL4b6386YwInCxIA
|
|
|
45
45
|
LoopStructural/interpolators/_discrete_fold_interpolator.py,sha256=eDe0R1lcQ0AuMcv7zlpu5c-soCv7AybIqQAuN2vFE3M,6542
|
|
46
46
|
LoopStructural/interpolators/_discrete_interpolator.py,sha256=bPGJ1CrvLmz3m86JkXAiw7WbfbGEeGXR5cklDX54PQU,26083
|
|
47
47
|
LoopStructural/interpolators/_finite_difference_interpolator.py,sha256=qc7zpqJka16I7yv-GigjQxF0hWRRHyWpHm8dHersy_8,18712
|
|
48
|
-
LoopStructural/interpolators/_geological_interpolator.py,sha256=
|
|
48
|
+
LoopStructural/interpolators/_geological_interpolator.py,sha256=74tQUImZ9axkXUrWygl6vqspY3bsoHf_d3twVB30rho,11430
|
|
49
49
|
LoopStructural/interpolators/_interpolator_builder.py,sha256=Z8bhmco5aSQX19A8It2SB_rG61wnlyshWfp3ivm8rU0,4586
|
|
50
50
|
LoopStructural/interpolators/_interpolator_factory.py,sha256=fbjebXSe5IgTol1tnBlnsw9gD426v-TGkX3gquIg7LI,2782
|
|
51
51
|
LoopStructural/interpolators/_interpolatortype.py,sha256=q8U9JGyFpO2FBA9XsMI5ojv3TV1LYqyvYHzLAbHcj9A,593
|
|
@@ -71,7 +71,9 @@ LoopStructural/interpolators/supports/_face_table.py,sha256=Hyj4Io63NkPRN8ab9uDH
|
|
|
71
71
|
LoopStructural/interpolators/supports/_support_factory.py,sha256=XNAxnr-JS3KEhdsoZeJ-VaLTJwlvxgBuRMCqYrCDW18,1485
|
|
72
72
|
LoopStructural/modelling/__init__.py,sha256=a-bq2gDhyUlcky5l9kl_IP3ExMdohkgYjQz2V8madQE,902
|
|
73
73
|
LoopStructural/modelling/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
74
|
-
LoopStructural/modelling/core/
|
|
74
|
+
LoopStructural/modelling/core/fault_topology.py,sha256=bChp5dnfc-4GJRENWxB14mEW_13uBMh5ZYRKbLdjweE,11195
|
|
75
|
+
LoopStructural/modelling/core/geological_model.py,sha256=23ZQF2Xvs-PeRdrxt-IqrkVaMDWud_JjW00ok2tKs2k,65850
|
|
76
|
+
LoopStructural/modelling/core/stratigraphic_column.py,sha256=GB93W607LY3d_NE75lzwBWrV34YhHN_troCXWuUMBk8,18070
|
|
75
77
|
LoopStructural/modelling/features/__init__.py,sha256=Vf-qd5EDBtJ1DpuXXyCcw2-wf6LWPRW5wzxDEO3vOc8,939
|
|
76
78
|
LoopStructural/modelling/features/_analytical_feature.py,sha256=U_g86LgQhYY2359rdsDqpvziYwqrWkc5EdvhJARiUWo,3597
|
|
77
79
|
LoopStructural/modelling/features/_base_geological_feature.py,sha256=kGyrbb8nNzfi-M8WSrVMEQYKtxThdcBxaji5HKXtAqw,13483
|
|
@@ -84,14 +86,14 @@ LoopStructural/modelling/features/_structural_frame.py,sha256=e3QmNHLwuZc5PX3rLa
|
|
|
84
86
|
LoopStructural/modelling/features/_unconformity_feature.py,sha256=2Bx0BI38YLdcNvDWuP9E1pKFN4orEUq9aC8b5xG1UVk,2362
|
|
85
87
|
LoopStructural/modelling/features/builders/__init__.py,sha256=Gqld1C-PcaXfJ8vpkWMDCmehmd3hZNYQk1knPtl59Bk,266
|
|
86
88
|
LoopStructural/modelling/features/builders/_base_builder.py,sha256=N3txGC98V08A8-k2TLdoIWgWLfblZ91kaTvciPq_QVM,3750
|
|
87
|
-
LoopStructural/modelling/features/builders/_fault_builder.py,sha256=
|
|
89
|
+
LoopStructural/modelling/features/builders/_fault_builder.py,sha256=_DZ0Hy_-jjm2fFU-5lY60zGisixdUWbAjsOQzMFKigY,25359
|
|
88
90
|
LoopStructural/modelling/features/builders/_folded_feature_builder.py,sha256=1_0BVTzcvmFl6K3_lX-jF0tiMFPmS8j6vPeSLn9MbrE,6607
|
|
89
91
|
LoopStructural/modelling/features/builders/_geological_feature_builder.py,sha256=tQJJol1U5wH6V0Rw3OgigCFPssv8uOPQ5jdwdLFg3cc,22015
|
|
90
92
|
LoopStructural/modelling/features/builders/_structural_frame_builder.py,sha256=ms3-fuFpDEarjzYU5W499TquOIlTwHPUibVxIypfmWY,8019
|
|
91
93
|
LoopStructural/modelling/features/fault/__init__.py,sha256=4u0KfYzmoO-ddFGo9qd9ov0gBoLqBiPAUsaw5zhEOAQ,189
|
|
92
94
|
LoopStructural/modelling/features/fault/_fault_function.py,sha256=QEPh2jIvgD68hEJc5SM5xuMzZw-93V1me1ZbK9G2TB0,12655
|
|
93
95
|
LoopStructural/modelling/features/fault/_fault_function_feature.py,sha256=4m0jVNx7ewrVI0pECI1wNciv8Cy8FzhZrYDjKJ_e2GU,2558
|
|
94
|
-
LoopStructural/modelling/features/fault/_fault_segment.py,sha256=
|
|
96
|
+
LoopStructural/modelling/features/fault/_fault_segment.py,sha256=BEIVAY_-iQYYuoyIj1doq_cDLgmMpY0PDYBiuBXOjN8,18309
|
|
95
97
|
LoopStructural/modelling/features/fold/__init__.py,sha256=pOv20yQvshZozvmO_YFw2E7Prp9DExlm855N-0SnxbQ,175
|
|
96
98
|
LoopStructural/modelling/features/fold/_fold.py,sha256=bPnnLUSiF4uoMRg8aHoOSTPRgaM0JyLoRQPu5_A-J3w,5448
|
|
97
99
|
LoopStructural/modelling/features/fold/_fold_rotation_angle_feature.py,sha256=CXLbFRQ3CrTMAcHmfdbKcmSvvLs9_6TLe0Wqi1pK2tg,892
|
|
@@ -114,8 +116,8 @@ LoopStructural/modelling/intrusions/intrusion_builder.py,sha256=PtNLDreUZTGodMwt
|
|
|
114
116
|
LoopStructural/modelling/intrusions/intrusion_feature.py,sha256=ESjtikHFJQzUnowbYiY7UZ_kYdV2QHobQoRJ2far9Vc,15489
|
|
115
117
|
LoopStructural/modelling/intrusions/intrusion_frame_builder.py,sha256=YEJv2GURAL8bW6J1KscM69ZVx9yoKVQKF_gXbjB513I,40150
|
|
116
118
|
LoopStructural/modelling/intrusions/intrusion_support_functions.py,sha256=wodakheMD62WJyoKnyX8UO-C1pje0I-5kHQEoDqShzo,13951
|
|
117
|
-
LoopStructural/utils/__init__.py,sha256=
|
|
118
|
-
LoopStructural/utils/_surface.py,sha256=
|
|
119
|
+
LoopStructural/utils/__init__.py,sha256=n-3PGnV-KEy4LOJkHZ6nlnoDyKDlfG6rJhXM0OgFYm0,1004
|
|
120
|
+
LoopStructural/utils/_surface.py,sha256=M0ZYujrqu-pWz-Y8iAhZsgoDxvI5YZG4GyhtBHdbCfk,6389
|
|
119
121
|
LoopStructural/utils/_transformation.py,sha256=peuLPH3BJ5DxnPbOuNKcqK4eXhAXdbT540L1OIsO3v0,5404
|
|
120
122
|
LoopStructural/utils/colours.py,sha256=-KRf1MXKx4L8TXnwyiunmKAX4tfy0qG68fRadyfn_bM,1163
|
|
121
123
|
LoopStructural/utils/config.py,sha256=ITGOtZTo2_QBwXkG_0AFANfE90J9siCXLzxypVmg9QA,414
|
|
@@ -127,12 +129,13 @@ LoopStructural/utils/json_encoder.py,sha256=5YNouf1TlhjEqOYgthd07MRXc0JLgxern-ny
|
|
|
127
129
|
LoopStructural/utils/linalg.py,sha256=tBXyu6NXcG2AcPuzUMnkVI4ncZWtE_MPHGj2PLXRwfY,123
|
|
128
130
|
LoopStructural/utils/logging.py,sha256=dIUWEsS2lT4G1dsf4ZYXknTR7eQkrgvGA4b_E0vMIRU,2402
|
|
129
131
|
LoopStructural/utils/maths.py,sha256=KaLj9RHsxdaSkEHm4t0JEzykhiuETAV14KpjL6lknWY,10374
|
|
132
|
+
LoopStructural/utils/observer.py,sha256=BjoL2-DydNWF1QDfFNd7TQIlRbKus_JNBfqX2ZFDAek,5327
|
|
130
133
|
LoopStructural/utils/regions.py,sha256=SjCC40GI7_n03G4mlcmvyrBgJFbxnvB3leBzXWco37o,3891
|
|
131
134
|
LoopStructural/utils/typing.py,sha256=29uVSTZdzXXH-jdlaYyBWZ1gQ2-nlZ2-XoVgG_PXNFY,157
|
|
132
135
|
LoopStructural/utils/utils.py,sha256=2Z4zVE6G752-SPmM29zebk82bROJxEwi_YiiJjcVED4,2438
|
|
133
136
|
LoopStructural/visualisation/__init__.py,sha256=5BDgKor8-ae6DrS7IZybJ3Wq_pTnCchxuY4EgzA7v1M,318
|
|
134
|
-
loopstructural-1.6.
|
|
135
|
-
loopstructural-1.6.
|
|
136
|
-
loopstructural-1.6.
|
|
137
|
-
loopstructural-1.6.
|
|
138
|
-
loopstructural-1.6.
|
|
137
|
+
loopstructural-1.6.17.dist-info/licenses/LICENSE,sha256=ZqGeNFOgmYevj7Ld7Q-kR4lAxWXuBRUdUmPC6XM_py8,1071
|
|
138
|
+
loopstructural-1.6.17.dist-info/METADATA,sha256=Io5NikqqA3SupAKqkEtWRytgor6JPn9c5nV8L0FzQLw,6453
|
|
139
|
+
loopstructural-1.6.17.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
140
|
+
loopstructural-1.6.17.dist-info/top_level.txt,sha256=QtQErKzYHfg6ddxTQ1NyaTxXBVM6qAqrM_vxEPyXZLg,15
|
|
141
|
+
loopstructural-1.6.17.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|