Skip to content

cj_attributes

Classes to read and process the attributes of all types of CityJSON objects in a standard way for all types and all branches of the pipeline.

Classes:

Name Description
Attr

Base abstract class to store attributes.

AttrReader

Base abstract class to read attributes from CSV.

BdgAttr

Class to store the attributes of Building objects.

BdgAttrReader

Class to read attributes of Building objecys from CSV.

BdgPartAttr

Class to store the attributes of BuildingPart objects.

BdgPartAttrReader

Class to read attributes of BuildingPart objects from CSV.

BdgRoomAttr

Class to store the attributes of BuildingRoom objects.

BdgRoomAttrReader

Class to read attributes of BuildingRoom objects from CSV.

BdgStoreyAttr

Class to store the attributes of BuildingStorey objects.

BdgStoreyAttrReader

Class to read attributes of BuildingStorey objects from CSV.

BdgSubAttr

Class to store the attributes of building subdivisions.

BdgSubAttrReader

Class to read attributes of building subdivisions from CSV.

BdgUnitAttr

Class to store the attributes of BuildingUnit objects.

BdgUnitAttrReader

Class to read attributes of BuildingUnit objects from CSV.

Attr

Bases: abc.ABC

Base abstract class to store attributes.

Source code in python/src/data_pipeline/cj_helpers/cj_attributes.py
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
class Attr(ABC):
    """
    Base abstract class to store attributes.
    """

    specific_columns: tuple[str, ...] = (KEY_COLUMN,)
    key_index: int | None = 0
    key_builder_index: int | None = None

    def __init__(
        self,
        attributes: dict[str, Any],
        cj_key: str,
        icon_position: IconPosition | list[float] | None,
    ) -> None:
        self.attributes = attributes
        self.cj_key = cj_key
        if isinstance(icon_position, IconPosition):
            self.icon_position = icon_position
        elif icon_position is None or len(icon_position) == 0:
            self.icon_position = None
        else:
            self.icon_position = IconPosition.from_list(icon_position)

AttrReader

Bases: typing.Generic[cj_helpers.cj_attributes.A], abc.ABC

Base abstract class to read attributes from CSV.

Source code in python/src/data_pipeline/cj_helpers/cj_attributes.py
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
class AttrReader(Generic[A], ABC):
    """
    Base abstract class to read attributes from CSV.
    """

    attr_class: Type[A]

    def __init__(self, csv_path: Path) -> None:
        self.csv_path = csv_path
        self.specific_columns = self.attr_class.specific_columns
        self._key_to_attr: dict[str, A] = {}
        self._key_builder_counts = defaultdict(lambda: 0)
        self._read_attributes()
        self._organise_attributes()

    def _read_attributes(self) -> None:
        self.attributes_all, self.specific_values_all = csv_read_attributes(
            csv_path=self.csv_path, specific_columns=self.specific_columns
        )

    def _organise_attributes(self) -> None:
        if (
            self.attr_class.key_index is None
            and self.attr_class.key_builder_index is None
        ):
            raise RuntimeError(
                "Cannot have both `key_index` and `key_builder_index` be None."
            )

        for attributes, specific_values in zip(
            self.attributes_all, self.specific_values_all
        ):
            if self.attr_class.key_index is None:
                col_name, key_base_value = specific_values[
                    cast(int, self.attr_class.key_builder_index)
                ]
                cj_key = self._build_cj_key(col_name)
            else:
                _, cj_key = specific_values[self.attr_class.key_index]

            specific_values_map = {}
            for specific_col, col_name_value in zip(
                self.attr_class.specific_columns, specific_values
            ):
                name = COL_TO_NAME[specific_col]
                _, value = col_name_value
                specific_values_map[name] = value

            if self.attr_class.key_index is None:
                specific_values_map["cj_key"] = cj_key

            self._key_to_attr[cj_key] = self.attr_class(
                attributes=attributes, **specific_values_map
            )

    def _build_cj_key(self, col_name: str) -> str:
        count = self._key_builder_counts[col_name]
        cj_key = f"{col_name}@{count}"
        self._key_builder_counts[col_name] += 1
        return cj_key

    def get_key_to_attr(self):
        return deepcopy(self._key_to_attr)

    def get_attributes_by_cj_key(self, cj_key: str):
        try:
            return self._key_to_attr[cj_key]
        except KeyError as exc:
            raise ValueError(f"Object key '{cj_key}' does not exist.") from exc

    def __len__(self):
        return len(self._key_to_attr)

    def iterator(self):
        return iter(self._key_to_attr.items())

BdgAttr

Bases: cj_helpers.cj_attributes.Attr

Class to store the attributes of Building objects.

Source code in python/src/data_pipeline/cj_helpers/cj_attributes.py
 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
class BdgAttr(Attr):
    """
    Class to store the attributes of Building objects.
    """

    specific_columns = (
        KEY_COLUMN,
        SPACE_ID_COLUMN,
        BAG_COLUMN,
        SKIP_COLUMN,
        ICON_POSITION_COLUMN,
    )
    key_index = 0
    key_builder_index = None

    def __init__(
        self,
        attributes: dict[str, Any],
        cj_key: str,
        space_id: str,
        icon_position: IconPosition | list[float] | None,
        bag_ids: list[str],
        skip: bool,
    ) -> None:
        super().__init__(
            attributes=attributes, cj_key=cj_key, icon_position=icon_position
        )
        self.bag_ids = bag_ids
        self.skip = skip
        self.space_id = space_id

BdgAttrReader

Bases: cj_helpers.cj_attributes.AttrReader[cj_helpers.cj_attributes.BdgAttr]

Class to read attributes of Building objecys from CSV.

Source code in python/src/data_pipeline/cj_helpers/cj_attributes.py
337
338
339
340
341
342
343
344
345
class BdgAttrReader(AttrReader[BdgAttr]):
    """
    Class to read attributes of Building objecys from CSV.
    """

    attr_class = BdgAttr

    def __init__(self, csv_path: Path) -> None:
        super().__init__(csv_path)

BdgPartAttr

Bases: cj_helpers.cj_attributes.Attr

Class to store the attributes of BuildingPart objects.

Source code in python/src/data_pipeline/cj_helpers/cj_attributes.py
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
class BdgPartAttr(Attr):
    """
    Class to store the attributes of BuildingPart objects.
    """

    specific_columns = (SPACE_ID_COLUMN,)
    key_index = 0
    key_builder_index = None

    def __init__(
        self,
        attributes: dict[str, Any],
        space_id: str,
    ) -> None:
        super().__init__(attributes=attributes, cj_key=space_id, icon_position=None)
        self.space_id = space_id

BdgPartAttrReader

Bases: cj_helpers.cj_attributes.AttrReader[cj_helpers.cj_attributes.BdgPartAttr]

Class to read attributes of BuildingPart objects from CSV.

Source code in python/src/data_pipeline/cj_helpers/cj_attributes.py
359
360
361
362
363
364
365
366
367
class BdgPartAttrReader(AttrReader[BdgPartAttr]):
    """
    Class to read attributes of BuildingPart objects from CSV.
    """

    attr_class = BdgPartAttr

    def __init__(self, csv_path: Path) -> None:
        super().__init__(csv_path)

BdgRoomAttr

Bases: cj_helpers.cj_attributes.Attr

Class to store the attributes of BuildingRoom objects.

Source code in python/src/data_pipeline/cj_helpers/cj_attributes.py
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
class BdgRoomAttr(Attr):
    """
    Class to store the attributes of BuildingRoom objects.
    """

    specific_columns = (SPACE_ID_COLUMN, ICON_POSITION_COLUMN, CODE_COLUMN)
    key_index = 0
    key_builder_index = None

    def __init__(
        self,
        attributes: dict[str, Any],
        space_id: str,
        icon_position: IconPosition | list[float] | None,
        code: str,
    ) -> None:
        super().__init__(
            attributes=attributes, cj_key=space_id, icon_position=icon_position
        )
        self.space_id = space_id
        self.code = code

BdgRoomAttrReader

Bases: cj_helpers.cj_attributes.AttrReader[cj_helpers.cj_attributes.BdgRoomAttr]

Class to read attributes of BuildingRoom objects from CSV.

Source code in python/src/data_pipeline/cj_helpers/cj_attributes.py
381
382
383
384
385
386
387
388
389
class BdgRoomAttrReader(AttrReader[BdgRoomAttr]):
    """
    Class to read attributes of BuildingRoom objects from CSV.
    """

    attr_class = BdgRoomAttr

    def __init__(self, csv_path: Path) -> None:
        super().__init__(csv_path)

BdgStoreyAttr

Bases: cj_helpers.cj_attributes.Attr

Class to store the attributes of BuildingStorey objects.

Source code in python/src/data_pipeline/cj_helpers/cj_attributes.py
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
class BdgStoreyAttr(Attr):
    """
    Class to store the attributes of BuildingStorey objects.
    """

    specific_columns = (SPACE_ID_COLUMN, STOREY_LEVEL_COLUMN, STOREY_SPACE_ID_COLUMN)
    key_index = 0
    key_builder_index = None

    def __init__(
        self,
        attributes: dict[str, Any],
        space_id: str,
        storey_level: float,
        storey_space_id: str,
    ) -> None:
        super().__init__(attributes=attributes, cj_key=space_id, icon_position=None)
        self.space_id = space_id
        self.storey_level = storey_level
        self.storey_space_id = storey_space_id

BdgStoreyAttrReader

Bases: cj_helpers.cj_attributes.AttrReader[cj_helpers.cj_attributes.BdgStoreyAttr]

Class to read attributes of BuildingStorey objects from CSV.

Source code in python/src/data_pipeline/cj_helpers/cj_attributes.py
370
371
372
373
374
375
376
377
378
class BdgStoreyAttrReader(AttrReader[BdgStoreyAttr]):
    """
    Class to read attributes of BuildingStorey objects from CSV.
    """

    attr_class = BdgStoreyAttr

    def __init__(self, csv_path: Path) -> None:
        super().__init__(csv_path)

BdgSubAttr

Bases: cj_helpers.cj_attributes.Attr

Class to store the attributes of building subdivisions.

Source code in python/src/data_pipeline/cj_helpers/cj_attributes.py
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
class BdgSubAttr(Attr):
    """
    Class to store the attributes of building subdivisions.
    """

    specific_columns = (
        KEY_COLUMN,
        SPACE_ID_COLUMN,
        PARENT_KEY_COLUMN,
        SKIP_COLUMN,
        ICON_POSITION_COLUMN,
    )
    key_index = 0
    key_builder_index = None

    def __init__(
        self,
        attributes: dict[str, Any],
        cj_key: str,
        space_id: str,
        icon_position: IconPosition | list[float] | None,
        parent_cj_key: str,
        skip: bool,
    ) -> None:
        super().__init__(
            attributes=attributes, cj_key=cj_key, icon_position=icon_position
        )
        self.parent_cj_key = parent_cj_key
        self.skip = skip
        self.space_id = space_id

BdgSubAttrReader

Bases: cj_helpers.cj_attributes.AttrReader[cj_helpers.cj_attributes.BdgSubAttr]

Class to read attributes of building subdivisions from CSV.

Source code in python/src/data_pipeline/cj_helpers/cj_attributes.py
348
349
350
351
352
353
354
355
356
class BdgSubAttrReader(AttrReader[BdgSubAttr]):
    """
    Class to read attributes of building subdivisions from CSV.
    """

    attr_class = BdgSubAttr

    def __init__(self, csv_path: Path) -> None:
        super().__init__(csv_path)

BdgUnitAttr

Bases: cj_helpers.cj_attributes.Attr

Class to store the attributes of BuildingUnit objects.

Source code in python/src/data_pipeline/cj_helpers/cj_attributes.py
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
class BdgUnitAttr(Attr):
    """
    Class to store the attributes of BuildingUnit objects.
    """

    specific_columns = (
        ICON_POSITION_COLUMN,
        CODE_COLUMN,
        UNIT_GLTF_COLUMN,
        UNIT_SPACES_COLUMN,
        UNIT_STOREYS_COLUMN,
    )
    key_index = None
    key_builder_index = 0

    def __init__(
        self,
        attributes: dict[str, Any],
        cj_key: str,
        icon_position: IconPosition | list[float] | None,
        code: str,
        unit_gltf: str,
        unit_spaces: list[str],
        unit_storeys: list[str],
    ) -> None:
        super().__init__(
            attributes=attributes, cj_key=cj_key, icon_position=icon_position
        )
        self.code = code
        self.unit_gltf = None if unit_gltf == "" else unit_gltf
        self.unit_spaces = unit_spaces
        self.unit_storeys = unit_storeys

        if len(self.unit_storeys) == 0:
            unit_storeys_set: set[str] = set()
            for space in self.unit_spaces:
                space_split = space.split(".")
                if len(space.split(".")) < 3:
                    continue
                storey = ".".join(space_split[:3])
                unit_storeys_set.add(storey)
            self.unit_storeys = list(unit_storeys_set)

BdgUnitAttrReader

Bases: cj_helpers.cj_attributes.AttrReader[cj_helpers.cj_attributes.BdgUnitAttr]

Class to read attributes of BuildingUnit objects from CSV.

Source code in python/src/data_pipeline/cj_helpers/cj_attributes.py
392
393
394
395
396
397
398
399
400
class BdgUnitAttrReader(AttrReader[BdgUnitAttr]):
    """
    Class to read attributes of BuildingUnit objects from CSV.
    """

    attr_class = BdgUnitAttr

    def __init__(self, csv_path: Path) -> None:
        super().__init__(csv_path)