File: global_attribute_manager.py

package info (click to toggle)
python-loompy 3.0.7%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 3,272 kB
  • sloc: python: 3,152; sh: 63; makefile: 16
file content (118 lines) | stat: -rw-r--r-- 3,917 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
from typing import Dict, List, Iterable, Tuple, Any, Iterator
import scipy.sparse as sparse
import numpy as np
import loompy
import warnings
with warnings.catch_warnings():
	warnings.simplefilter("ignore")
	import h5py
from .utils import compare_loom_spec_version


class GlobalAttributeManager(object):
	def __init__(self, f: h5py.File) -> None:
		setattr(self, "!f", f)
		storage: Dict[str, str] = {}
		setattr(self, "!storage", storage)
		if "attrs" not in self.f:
			for key, val in f.attrs.items():
				materialized = loompy.materialize_attr_values(val)
				self.__dict__["storage"][key] = materialized
		else:
			for key, val in f["attrs"].items():
				materialized = loompy.materialize_attr_values(val[()])
				self.__dict__["storage"][key] = materialized

	def keys(self) -> List[str]:
		return list(self.__dict__["storage"].keys())

	def items(self) -> Iterable[Tuple[str, sparse.coo_matrix]]:
		for key in self.keys():
			yield (key, self[key])

	def __len__(self) -> int:
		return len(self.keys())

	def __contains__(self, name: str) -> bool:
		return name in self.keys()

	def __iter__(self) -> Iterator[str]:
		for key in self.keys():
			yield key

	def __getitem__(self, thing: Any) -> np.ndarray:
		return self.__getattr__(thing)

	def __getattr__(self, name: str) -> np.ndarray:
		try:
			return self.__dict__["storage"][name]
		except KeyError:
			if self.f is not None:
				if loompy.compare_loom_spec_version(self.f, "3.0.0") < 0:
					if name in self.f.attrs:
						val = self.f.attrs[name]
					else:
						raise AttributeError(f"File has no global attribute '{name}'")
				else:
					if name in self.f["attrs"]:
						val = self.f["attrs"][name]
					else:
						raise AttributeError(f"File has no global attribute '{name}'")
				materialized = loompy.materialize_attr_values(val)
				self.__dict__["storage"][name] = materialized
				return materialized

	def __setitem__(self, name: str, val: Any) -> None:
		return self.__setattr__(name, val)

	def __setattr__(self, name: str, val: Any) -> None:
		if name.startswith("!"):
			super(GlobalAttributeManager, self).__setattr__(name[1:], val)
		elif "/" in name:
			raise KeyError("Attribute name cannot contain slash (/)")
		else:
			if self.f is not None:
				if loompy.compare_loom_spec_version(self.f, "3.0.0") < 0 and "attrs" not in self.f["/"]:
					normalized = loompy.normalize_attr_values(val, False)
					self.f.attrs[name] = normalized
					self.f.flush()
					val = self.f.attrs[name]
					# Read it back in to ensure it's synced and normalized
					normalized = loompy.materialize_attr_values(val)
					self.__dict__["storage"][name] = normalized
				else:
					normalized = loompy.normalize_attr_values(val, True)
					if name in self.f["attrs"]:
						del self.f["attrs"][name]
					if not np.isscalar(normalized) and normalized.dtype == np.object_:
						self.ds._file.create_dataset("attrs/" + name, data=normalized, dtype=h5py.special_dtype(vlen=str))
					else:
						self.f["attrs"][name] = normalized
					self.f.flush()
					val = self.f["attrs"][name][()]
					# Read it back in to ensure it's synced and normalized
					normalized = loompy.materialize_attr_values(val)
					self.__dict__["storage"][name] = normalized

	def __delattr__(self, name: str) -> None:
		if name.startswith("!"):
			super(GlobalAttributeManager, self).__delattr__(name[1:])
		else:
			if self.f is not None:
				if loompy.compare_loom_spec_version(self.f, "3.0.0") < 0:
					if name in self.f.attrs:
						del self.f.attrs[name]
				else:
					if name in self.f["attrs"]:
						del self.f["attrs"][name]
			del self.__dict__["storage"][name]

	def get(self, name: str, default: Any = None) -> np.ndarray:
		"""
		Return the value for a named attribute if it exists, else default.
		If default is not given, it defaults to None, so that this method never raises a KeyError.
		"""
		if name in self:
			return self[name]
		else:
			return default