python-materialsdb 0.3.0__py3-none-any.whl → 0.3.2__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.
- materialsdb/cache.py +69 -16
- materialsdb/gui/listener.py +15 -4
- materialsdb/ifc/material_builder.py +54 -24
- materialsdb/serialiser.py +27 -12
- {python_materialsdb-0.3.0.dist-info → python_materialsdb-0.3.2.dist-info}/METADATA +1 -1
- {python_materialsdb-0.3.0.dist-info → python_materialsdb-0.3.2.dist-info}/RECORD +10 -10
- {python_materialsdb-0.3.0.dist-info → python_materialsdb-0.3.2.dist-info}/WHEEL +0 -0
- {python_materialsdb-0.3.0.dist-info → python_materialsdb-0.3.2.dist-info}/entry_points.txt +0 -0
- {python_materialsdb-0.3.0.dist-info → python_materialsdb-0.3.2.dist-info}/licenses/LICENSE.md +0 -0
- {python_materialsdb-0.3.0.dist-info → python_materialsdb-0.3.2.dist-info}/top_level.txt +0 -0
materialsdb/cache.py
CHANGED
|
@@ -2,6 +2,7 @@ import os
|
|
|
2
2
|
import pathlib
|
|
3
3
|
import urllib.request
|
|
4
4
|
from collections import namedtuple
|
|
5
|
+
from concurrent.futures import FIRST_COMPLETED, ThreadPoolExecutor, wait
|
|
5
6
|
|
|
6
7
|
from lxml import etree
|
|
7
8
|
|
|
@@ -85,25 +86,77 @@ def _plan_index(index):
|
|
|
85
86
|
return _IndexPlan(index, new_index, unchanged, todos)
|
|
86
87
|
|
|
87
88
|
|
|
88
|
-
def update_producers_data(url_list=MATERIALSDBINDEXURLLIST, on_progress=None):
|
|
89
|
-
"""
|
|
90
|
-
|
|
91
|
-
|
|
89
|
+
def update_producers_data(url_list=MATERIALSDBINDEXURLLIST, on_progress=None, max_workers: int = 8):
|
|
90
|
+
"""Update the cached producer files from the index URLs.
|
|
91
|
+
|
|
92
|
+
Downloads run on a bounded thread pool (max_workers). on_progress(done,
|
|
93
|
+
total, name) is called once per completed download from the calling
|
|
94
|
+
thread with a monotonic running total; returning a truthy value stops
|
|
95
|
+
NEW submissions (queued jobs are abandoned, in-flight ones finish but
|
|
96
|
+
no longer count toward the partial Report). A download error stops the
|
|
97
|
+
run and the first exception is re-raised after the pool drains.
|
|
98
|
+
"""
|
|
92
99
|
plans = [_plan_index(index) for index in url_list]
|
|
93
|
-
|
|
94
|
-
|
|
100
|
+
jobs = [
|
|
101
|
+
(plan, company, cached_producer, producer_path)
|
|
102
|
+
for plan in plans
|
|
103
|
+
for (company, cached_producer, producer_path) in plan.todos
|
|
104
|
+
]
|
|
105
|
+
total = len(jobs)
|
|
106
|
+
workers = max(1, min(int(max_workers), total or 1))
|
|
107
|
+
|
|
108
|
+
existing: list = []
|
|
109
|
+
updated: list = []
|
|
110
|
+
deleted: list = []
|
|
95
111
|
done = 0
|
|
112
|
+
cancel_requested = False
|
|
113
|
+
failure = None
|
|
114
|
+
|
|
115
|
+
def _download(job):
|
|
116
|
+
_, company, cached_producer, producer_path = job
|
|
117
|
+
deleted_path = None
|
|
118
|
+
if cached_producer is not None:
|
|
119
|
+
deleted_path = get_producers_dir() / pathlib.Path(cached_producer.get("href")).name
|
|
120
|
+
deleted_path.unlink(True)
|
|
121
|
+
urllib.request.urlretrieve(company.get("href"), producer_path)
|
|
122
|
+
return deleted_path
|
|
123
|
+
|
|
124
|
+
pool = ThreadPoolExecutor(max_workers=workers)
|
|
125
|
+
pending = list(jobs) # pops from the FRONT, submission order preserved
|
|
126
|
+
futures: dict = {}
|
|
127
|
+
try:
|
|
128
|
+
while futures or pending:
|
|
129
|
+
while pending and len(futures) < workers:
|
|
130
|
+
job = pending.pop(0)
|
|
131
|
+
futures[pool.submit(_download, job)] = job
|
|
132
|
+
if not futures:
|
|
133
|
+
break
|
|
134
|
+
ready, _ = wait(set(futures), return_when=FIRST_COMPLETED)
|
|
135
|
+
for future in ready:
|
|
136
|
+
job = futures.pop(future)
|
|
137
|
+
try:
|
|
138
|
+
deleted_path = future.result()
|
|
139
|
+
except Exception as err: # noqa: BLE001 - re-raised below, caller decides
|
|
140
|
+
if failure is None:
|
|
141
|
+
failure = err
|
|
142
|
+
break
|
|
143
|
+
if deleted_path is not None:
|
|
144
|
+
deleted.append(deleted_path)
|
|
145
|
+
updated.append(job[3])
|
|
146
|
+
done += 1
|
|
147
|
+
if on_progress is not None and on_progress(done, total, pathlib.Path(job[3]).name):
|
|
148
|
+
cancel_requested = True
|
|
149
|
+
break
|
|
150
|
+
if cancel_requested or failure is not None:
|
|
151
|
+
break
|
|
152
|
+
finally:
|
|
153
|
+
pool.shutdown(wait=True, cancel_futures=True)
|
|
154
|
+
|
|
155
|
+
if failure is not None:
|
|
156
|
+
raise failure
|
|
157
|
+
if cancel_requested:
|
|
158
|
+
return Report(existing, updated, deleted)
|
|
96
159
|
for plan in plans:
|
|
97
|
-
for company, cached_producer, producer_path in plan.todos:
|
|
98
|
-
if cached_producer is not None:
|
|
99
|
-
cached_path = get_producers_dir() / pathlib.Path(cached_producer.get("href")).name
|
|
100
|
-
deleted.append(cached_path)
|
|
101
|
-
cached_path.unlink(True)
|
|
102
|
-
urllib.request.urlretrieve(company.get("href"), producer_path)
|
|
103
|
-
updated.append(producer_path)
|
|
104
|
-
done += 1
|
|
105
|
-
if on_progress is not None and on_progress(done, total, pathlib.Path(company.get("href")).name):
|
|
106
|
-
return Report(existing, updated, deleted)
|
|
107
160
|
if plan.todos:
|
|
108
161
|
plan.new_index.write(str(get_cached_index_path(plan.index)))
|
|
109
162
|
existing.extend(plan.unchanged)
|
materialsdb/gui/listener.py
CHANGED
|
@@ -5,7 +5,7 @@ MaterialBuilder would create (one entry per IfcMaterial); the Bonsai add-on
|
|
|
5
5
|
maps the payload onto its open file without importing this library."""
|
|
6
6
|
|
|
7
7
|
from materialsdb import config, utils
|
|
8
|
-
from materialsdb.ifc.material_builder import PSETS, get_value
|
|
8
|
+
from materialsdb.ifc.material_builder import PSETS, get_value, style_for
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
def _resolved_psets(layer, country) -> dict:
|
|
@@ -50,6 +50,10 @@ def build_add_materials_payload(store_, items, country=None, lang=None):
|
|
|
50
50
|
description = str(utils.get_material_description(material, lang))
|
|
51
51
|
category = str(getattr(material.information, "group", "") or "")
|
|
52
52
|
color = getattr(material.information, "color", None)
|
|
53
|
+
color = int(color) if color else None
|
|
54
|
+
# Resolve the surface style server-side: the add-on runs in Blender's
|
|
55
|
+
# interpreter without access to the materialsdb colour scheme.
|
|
56
|
+
style_name, style_rgb = style_for(color, category)
|
|
53
57
|
entries = []
|
|
54
58
|
for layer in utils.get_material_layers(material):
|
|
55
59
|
if wanted is not None and str(layer.id) not in wanted:
|
|
@@ -63,7 +67,9 @@ def build_add_materials_payload(store_, items, country=None, lang=None):
|
|
|
63
67
|
"name": name,
|
|
64
68
|
"description": description,
|
|
65
69
|
"category": category,
|
|
66
|
-
"color":
|
|
70
|
+
"color": color,
|
|
71
|
+
"style_name": style_name,
|
|
72
|
+
"style_color": [round(component, 6) for component in style_rgb],
|
|
67
73
|
"identity": {
|
|
68
74
|
"material_id": material_id,
|
|
69
75
|
"company_id": str(summary.company_id or ""),
|
|
@@ -120,6 +126,9 @@ def build_add_construction_payload(store_, body, country=None, lang=None):
|
|
|
120
126
|
problems.append(f"unknown material id: {layer.material_id}")
|
|
121
127
|
continue
|
|
122
128
|
color = getattr(material.information, "color", None)
|
|
129
|
+
color = int(color) if color else None
|
|
130
|
+
category = str(getattr(material.information, "group", "") or "")
|
|
131
|
+
style_name, style_rgb = style_for(color, category)
|
|
123
132
|
layers.append(
|
|
124
133
|
{
|
|
125
134
|
"material_id": layer.material_id,
|
|
@@ -128,8 +137,10 @@ def build_add_construction_payload(store_, body, country=None, lang=None):
|
|
|
128
137
|
"source_id": layer.material_id,
|
|
129
138
|
"name": str(utils.get_material_name(material, lang)),
|
|
130
139
|
"description": str(utils.get_material_description(material, lang)),
|
|
131
|
-
"category":
|
|
132
|
-
"color":
|
|
140
|
+
"category": category,
|
|
141
|
+
"color": color,
|
|
142
|
+
"style_name": style_name,
|
|
143
|
+
"style_color": [round(component, 6) for component in style_rgb],
|
|
133
144
|
"identity": {
|
|
134
145
|
"material_id": layer.material_id,
|
|
135
146
|
"company_id": str(summary.company_id or ""),
|
|
@@ -2,12 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
4
|
from pathlib import Path
|
|
5
|
+
from typing import TypedDict
|
|
5
6
|
|
|
6
7
|
from materialsdb import config, utils
|
|
7
8
|
|
|
8
9
|
MATERIALSDB_PSET = "materialsdb"
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
|
|
12
|
+
class CategoryStyle(TypedDict):
|
|
13
|
+
"""One palette entry. `hatch` is reserved for future pattern support."""
|
|
14
|
+
|
|
15
|
+
hatch: str
|
|
16
|
+
color: tuple[int, int, int]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
CATEGORIES: dict[str, CategoryStyle] = {
|
|
11
20
|
"Others": {"hatch": "", "color": (255, 255, 255)},
|
|
12
21
|
"Water_Proof": {"hatch": "", "color": (255, 255, 255)},
|
|
13
22
|
"Vapour_Proof": {"hatch": "", "color": (0, 0, 0)},
|
|
@@ -27,6 +36,29 @@ CATEGORIES = {
|
|
|
27
36
|
"Soil": {"hatch": "", "color": (142, 84, 52)},
|
|
28
37
|
}
|
|
29
38
|
|
|
39
|
+
# Named colour schemes: a category -> palette. Only the default ships today;
|
|
40
|
+
# more schemes (and a GUI selector) are planned.
|
|
41
|
+
SCHEMES: dict[str, dict[str, CategoryStyle]] = {"Lesosai": CATEGORIES}
|
|
42
|
+
DEFAULT_SCHEME = "Lesosai"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _rgb_int_components(color: int) -> tuple[float, float, float]:
|
|
46
|
+
"""Decimal 0xRRGGBB -> normalised (r, g, b) in 0..1 (IfcColourRgb units)."""
|
|
47
|
+
return (((color >> 16) & 255) / 255, ((color >> 8) & 255) / 255, (color & 255) / 255)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def style_for(color, category, scheme=None):
|
|
51
|
+
"""Resolve a material's (IfcSurfaceStyle.Name, (r, g, b) in 0..1).
|
|
52
|
+
|
|
53
|
+
The producer colour wins when present; otherwise the category colour from
|
|
54
|
+
the scheme (default 'Lesosai' = CATEGORIES). Unknown categories fall back
|
|
55
|
+
to 'Others'."""
|
|
56
|
+
if color:
|
|
57
|
+
return f"color {int(color)}", _rgb_int_components(int(color))
|
|
58
|
+
palette = SCHEMES.get(scheme or DEFAULT_SCHEME, CATEGORIES)
|
|
59
|
+
category = category if category in palette else "Others"
|
|
60
|
+
return f"category {category}", tuple(component / 255 for component in palette[category]["color"])
|
|
61
|
+
|
|
30
62
|
|
|
31
63
|
def clean_psets(psets):
|
|
32
64
|
new_dict = {}
|
|
@@ -71,6 +103,7 @@ class MaterialBuilder:
|
|
|
71
103
|
name = utils.get_material_name(material, self.lang)
|
|
72
104
|
description = utils.get_material_description(material, self.lang)
|
|
73
105
|
category = str(material.information.group or "")
|
|
106
|
+
color = material.information.color
|
|
74
107
|
if not with_layers:
|
|
75
108
|
# reuse an already-present material instead of duplicating it;
|
|
76
109
|
# its identity pset is already in place
|
|
@@ -79,15 +112,9 @@ class MaterialBuilder:
|
|
|
79
112
|
return [existing]
|
|
80
113
|
ifc_material = self.file.createIfcMaterial(name, str(description), str(category))
|
|
81
114
|
self._create_identity_pset(ifc_material, material, company_id, company, verxml)
|
|
115
|
+
self._add_style_chain(color, category)
|
|
82
116
|
return [ifc_material]
|
|
83
|
-
color
|
|
84
|
-
surface_style = self.get_surface_style(color, category)
|
|
85
|
-
styled_item = self.file.createIfcStyledItem(Styles=[surface_style])
|
|
86
|
-
self.file.createIfcStyledRepresentation(
|
|
87
|
-
ContextOfItems=self._get_context(),
|
|
88
|
-
RepresentationIdentifier="Body",
|
|
89
|
-
Items=[styled_item],
|
|
90
|
-
)
|
|
117
|
+
self._add_style_chain(color, category)
|
|
91
118
|
created = []
|
|
92
119
|
wanted = {str(g) for g in layer_ids} if layer_ids is not None else None
|
|
93
120
|
for layer in utils.get_material_layers(material):
|
|
@@ -191,29 +218,32 @@ class MaterialBuilder:
|
|
|
191
218
|
Material=ifc_material,
|
|
192
219
|
)
|
|
193
220
|
|
|
194
|
-
def
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
221
|
+
def _add_style_chain(self, color, category, scheme=None):
|
|
222
|
+
"""Create the floating styled chain MaterialBuilder uses for a
|
|
223
|
+
material's colour (shared style + one styled item per build)."""
|
|
224
|
+
surface_style = self.get_surface_style(color, category, scheme=scheme)
|
|
225
|
+
styled_item = self.file.createIfcStyledItem(Styles=[surface_style])
|
|
226
|
+
self.file.createIfcStyledRepresentation(
|
|
227
|
+
ContextOfItems=self._get_context(),
|
|
228
|
+
RepresentationIdentifier="Body",
|
|
229
|
+
Items=[styled_item],
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
def get_surface_style(self, color, category, scheme=None):
|
|
233
|
+
name, rgb = style_for(color, category, scheme=scheme)
|
|
201
234
|
if name in self._styles and self._styles[name] in self.file:
|
|
202
235
|
return self._styles[name]
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
SurfaceColour=self.file.createIfcColourRgb(None, *CATEGORIES[category]["color"]),
|
|
208
|
-
)
|
|
209
|
-
surface_style = self.file.createIfcSurfaceStyle(Name=name, Side="BOTH", Styles=[style])
|
|
236
|
+
shading = self.file.createIfcSurfaceStyleShading(
|
|
237
|
+
SurfaceColour=self.file.createIfcColourRgb(None, *rgb),
|
|
238
|
+
)
|
|
239
|
+
surface_style = self.file.createIfcSurfaceStyle(Name=name, Side="BOTH", Styles=[shading])
|
|
210
240
|
self._styles[name] = surface_style
|
|
211
241
|
return surface_style
|
|
212
242
|
|
|
213
243
|
def color_xml_to_ifc(self, color: int):
|
|
214
244
|
"""Color definition in xml is obscur. We assume that it is a decimal color.
|
|
215
245
|
See: https://stackoverflow.com/a/2262152/4098083"""
|
|
216
|
-
return self.file.createIfcColourRgb(
|
|
246
|
+
return self.file.createIfcColourRgb(None, *_rgb_int_components(int(color)))
|
|
217
247
|
|
|
218
248
|
|
|
219
249
|
def _materials_of(pset):
|
materialsdb/serialiser.py
CHANGED
|
@@ -25,9 +25,31 @@ def get_xml_schema() -> str:
|
|
|
25
25
|
return str(Path(__file__).parent / "schema/materialsdb103.xsd")
|
|
26
26
|
|
|
27
27
|
|
|
28
|
+
@cache
|
|
29
|
+
def cached_type_hints(cls) -> dict:
|
|
30
|
+
return typing.get_type_hints(cls)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@cache
|
|
34
|
+
def _tag_local_name(tag: str) -> str:
|
|
35
|
+
m = re.search("{.*}(.*)", tag)
|
|
36
|
+
return m.group(1) if m else tag
|
|
37
|
+
|
|
38
|
+
|
|
28
39
|
def get_element_name(element: objectify.ObjectifiedElement) -> str:
|
|
29
|
-
|
|
30
|
-
|
|
40
|
+
return _tag_local_name(element.tag)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@cache
|
|
44
|
+
def _is_optional(type_hint):
|
|
45
|
+
return typing.get_origin(type_hint) is typing.Union and typing.get_args(type_hint)[1] is type(None)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@cache
|
|
49
|
+
def _strip_optional(type_hint):
|
|
50
|
+
if _is_optional(type_hint):
|
|
51
|
+
return typing.get_args(type_hint)[0]
|
|
52
|
+
return type_hint
|
|
31
53
|
|
|
32
54
|
|
|
33
55
|
def create_element_maker():
|
|
@@ -49,11 +71,6 @@ def get_valid_root(tree: objectify.ObjectifiedElement) -> objectify.ObjectifiedE
|
|
|
49
71
|
return root
|
|
50
72
|
|
|
51
73
|
|
|
52
|
-
@cache
|
|
53
|
-
def cached_type_hints(cls) -> dict:
|
|
54
|
-
return typing.get_type_hints(cls)
|
|
55
|
-
|
|
56
|
-
|
|
57
74
|
class XmlDeserialiser:
|
|
58
75
|
def __init__(self):
|
|
59
76
|
self.schema = etree.XMLSchema(file=get_xml_schema())
|
|
@@ -93,7 +110,7 @@ class XmlDeserialiser:
|
|
|
93
110
|
value = element.get(attrib)
|
|
94
111
|
if value is None:
|
|
95
112
|
continue
|
|
96
|
-
base_class =
|
|
113
|
+
base_class = _strip_optional(type_hints[attrib])
|
|
97
114
|
|
|
98
115
|
kwargs[attrib] = base_class(value)
|
|
99
116
|
for child_name in getattr(element_class, "xml_elements", ()):
|
|
@@ -127,12 +144,10 @@ class XmlDeserialiser:
|
|
|
127
144
|
return instance
|
|
128
145
|
|
|
129
146
|
def strip_optional(self, type_hint):
|
|
130
|
-
|
|
131
|
-
return typing.get_args(type_hint)[0]
|
|
132
|
-
return type_hint
|
|
147
|
+
return _strip_optional(type_hint)
|
|
133
148
|
|
|
134
149
|
def is_optional(self, type_hint):
|
|
135
|
-
return
|
|
150
|
+
return _is_optional(type_hint)
|
|
136
151
|
|
|
137
152
|
def cls_name(self, name: str) -> str:
|
|
138
153
|
return name if name[0].isupper() else name.title()
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
materialsdb/__init__.py,sha256=lml7ffWFF3-0MD-Z7YbPZNireUpDO7tR9B3KNamrI0k,127
|
|
2
|
-
materialsdb/cache.py,sha256=
|
|
2
|
+
materialsdb/cache.py,sha256=wPCksig6hidUssjRx_KaPk9V5ZeWbHfbs0Qt2XTuLPk,6594
|
|
3
3
|
materialsdb/classes.py,sha256=WdXNiCqFcevgWrqDZKLR8HPio3BwcmOJ1NyVGArQ0hw,21549
|
|
4
4
|
materialsdb/config.py,sha256=Tp14G_Y_XEkYshwrp4gd9XjGb5e_mO-hxYOevCTVnmI,1291
|
|
5
5
|
materialsdb/construction.py,sha256=29H5gt3EX0LFNJ7ftE0Ob7huQgyZzx3ygW7nNcUSo5s,17817
|
|
6
6
|
materialsdb/query.py,sha256=h9kP3Zc41l4h9bcxjwp-UUb8ezsG0A3ZkraJjaQZVVI,620
|
|
7
|
-
materialsdb/serialiser.py,sha256=
|
|
7
|
+
materialsdb/serialiser.py,sha256=J6bUc7eKYD569TrOWVAK5ZDeb7cdD2YbF0nD6jf3iPY,7263
|
|
8
8
|
materialsdb/store.py,sha256=_Iu425X7-sYE7A2vvQVrR1R6ju2R63m_BK43c9y3mhM,11000
|
|
9
9
|
materialsdb/summary.py,sha256=vl6LhVIfN4KHN-KZxU6oVBYut0FPA3E_baGp_fegnBU,2558
|
|
10
10
|
materialsdb/utils.py,sha256=2xGwr6b4NgOtjT5lxpFVN9jnOSlDsmZPnelSGEs5MDs,3068
|
|
11
11
|
materialsdb/gui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
12
|
materialsdb/gui/__main__.py,sha256=Rha9z_Lxmf2mnCfLUV8s8ZqMRankDhtRrype1v5cm48,1405
|
|
13
13
|
materialsdb/gui/discovery.py,sha256=au_X0ULkIxjAMV1EWgVAs1aLcl902wi4Kzw6y7M26Ag,792
|
|
14
|
-
materialsdb/gui/listener.py,sha256=
|
|
14
|
+
materialsdb/gui/listener.py,sha256=tfHjQyvu-YkTfXpFUoKwZZQzfm9y6Jo87LCOZkXbJOk,7107
|
|
15
15
|
materialsdb/gui/server.py,sha256=yMYy_EDPp5Y7kiQiRDc4rGJ_xbSda3RiycWs3CZyN5w,33553
|
|
16
16
|
materialsdb/gui/static/app-constructions.js,sha256=59oO_oo9li6SJacA1XYQHVG3rx37MJG7ySaM8Mpn5s4,31343
|
|
17
17
|
materialsdb/gui/static/app.js,sha256=eDb53OkMhslgp5vVghaDZstSK_ooenu0cGumjaMZcOY,22707
|
|
@@ -19,15 +19,15 @@ materialsdb/gui/static/constructions.html,sha256=kozoWdVHWrKTiB08kcchXLMuL6jijGE
|
|
|
19
19
|
materialsdb/gui/static/index.html,sha256=4pXwmXLIwUIosa7wVBRzVbeuLf_WzlRUs5dxwZsSeNU,3208
|
|
20
20
|
materialsdb/gui/static/picker-core.js,sha256=bK8308VJcrTgEZECblELwtrU3QW1VZHuqtM3pBPTaIg,4145
|
|
21
21
|
materialsdb/ifc/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
22
|
-
materialsdb/ifc/material_builder.py,sha256=
|
|
22
|
+
materialsdb/ifc/material_builder.py,sha256=PGpznk02_wHcCH4o0jC6jRDoDmugA5kqJO6XL6wL2UY,13523
|
|
23
23
|
materialsdb/ifc/material_psets.json,sha256=lQ0zQgBq3xnxyYItkmu7BzB5KE9ysFof-rrHawb5T-M,10897
|
|
24
24
|
materialsdb/ifc/project_library.py,sha256=hOvirB73ZiTYiP6rOu6eN1dU2ZXFRgSOGpQrH2DY4RM,6324
|
|
25
25
|
materialsdb/schema/MaterialsDBIndex100.xsd,sha256=oK81n2b3_82Mt5G31yEm9vwkMjUmNyM6jglt_zpUQZc,2199
|
|
26
26
|
materialsdb/schema/materialsdb102.xsd,sha256=IaC6E_B3N1VaU9lhrl6ZGwi8m2rk2p7HTEZKN_Yj2AY,32880
|
|
27
27
|
materialsdb/schema/materialsdb103.xsd,sha256=iX7Q1ejWEN_ZSuRVCX40zjYt5UraY3f_JxBzqZUFu7Q,37762
|
|
28
|
-
python_materialsdb-0.3.
|
|
29
|
-
python_materialsdb-0.3.
|
|
30
|
-
python_materialsdb-0.3.
|
|
31
|
-
python_materialsdb-0.3.
|
|
32
|
-
python_materialsdb-0.3.
|
|
33
|
-
python_materialsdb-0.3.
|
|
28
|
+
python_materialsdb-0.3.2.dist-info/licenses/LICENSE.md,sha256=M7wm1EmMGDtwPRdg7kW4d00h1uAXjKOT3HFScYQMeiE,34916
|
|
29
|
+
python_materialsdb-0.3.2.dist-info/METADATA,sha256=EWVnNfW1XA8YsScGmrwWkLBqKVkvy8dGAvZgX0pk7cw,7673
|
|
30
|
+
python_materialsdb-0.3.2.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
31
|
+
python_materialsdb-0.3.2.dist-info/entry_points.txt,sha256=7bCySVv6oV9hiva7Fn5Dm9oboPRIC6DU6DRlsjCLO6k,66
|
|
32
|
+
python_materialsdb-0.3.2.dist-info/top_level.txt,sha256=5ZHbF8Oj1W24bifG65Fl3hCaivZpkO6EyOHHaRavZxE,12
|
|
33
|
+
python_materialsdb-0.3.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
{python_materialsdb-0.3.0.dist-info → python_materialsdb-0.3.2.dist-info}/licenses/LICENSE.md
RENAMED
|
File without changes
|
|
File without changes
|