bcf-api-xml 0.4.15__py3-none-any.whl → 0.4.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.
bcf_api_xml/__init__.py CHANGED
@@ -1,7 +1,7 @@
1
1
  from bcf_api_xml.errors import InvalidBCF # noqa: F401
2
2
  from bcf_api_xml.errors import UnsupportedBCFVersion # noqa: F401
3
- from bcf_api_xml.export import to_zip # noqa: F401
4
3
  from bcf_api_xml.export import to_xlsx # noqa: F401
4
+ from bcf_api_xml.export import to_zip # noqa: F401
5
5
  from bcf_api_xml.import_zip import to_json # noqa: F401
6
6
 
7
- __version__ = "0.4.15"
7
+ __version__ = "0.4.17"
@@ -1,5 +1,6 @@
1
1
  import base64
2
2
  import io
3
+ import string
3
4
  from datetime import datetime
4
5
 
5
6
  import requests
@@ -8,6 +9,10 @@ from dateutil import parser
8
9
  from PIL import Image
9
10
 
10
11
 
12
+ def col_to_letter(index):
13
+ return string.ascii_uppercase[index]
14
+
15
+
11
16
  HEADER_TRANSLATIONS = {
12
17
  "en": {
13
18
  "index": "Index",
@@ -15,16 +20,18 @@ HEADER_TRANSLATIONS = {
15
20
  "author": "Author",
16
21
  "assigned_to": "Assigned to",
17
22
  "title": "Title",
18
- "description": "Description of the problem",
23
+ "description": "Description",
19
24
  "due_date": "Due date",
25
+ "stage": "Stage",
20
26
  "status": "Status",
21
27
  "priority": "Priority",
22
- "tags": "Tags",
28
+ "tags": "Labels",
23
29
  "comments": "Comments",
24
30
  "viewpoint": "Image",
25
- "models": "Name of model",
31
+ "models": "Models",
26
32
  "space": "Organisation",
27
33
  "project": "Project",
34
+ "sheetname": "BCF list",
28
35
  },
29
36
  "fr": {
30
37
  "index": "N°",
@@ -32,16 +39,18 @@ HEADER_TRANSLATIONS = {
32
39
  "author": "Auteur",
33
40
  "assigned_to": "Assigné à",
34
41
  "title": "Titre",
35
- "description": "Description du problème",
42
+ "description": "Description",
36
43
  "due_date": "Date d'échéance",
44
+ "stage": "Phase",
37
45
  "status": "Statut",
38
46
  "priority": "Priorité",
39
47
  "tags": "Tags",
40
- "comments": "Commentaire du problème",
48
+ "comments": "Commentaires",
41
49
  "viewpoint": "Image",
42
- "models": "Nom du modèle",
50
+ "models": "Maquettes",
43
51
  "space": "Organisation",
44
52
  "project": "Project",
53
+ "sheetname": "Liste des BCF",
45
54
  },
46
55
  }
47
56
 
@@ -53,23 +62,41 @@ TITLE_COL_INDEX = 4
53
62
  VIEWPOINT_COL_INDEX = 5
54
63
  DESCRIPTION_COL_INDEX = 6
55
64
  DUE_DATE_COL_INDEX = 7
56
- STATUS_COL_INDEX = 8
57
- PRIORITY_COL_INDEX = 9
58
- TAGS_COL_INDEX = 10
59
- COMMENTS_COL_INDEX = 11
65
+ STAGE_COL_INDEX = 8
66
+ STATUS_COL_INDEX = 9
67
+ PRIORITY_COL_INDEX = 10
68
+ LABELS_COL_INDEX = 11
69
+ COMMENTS_COL_INDEX = 12
70
+ MODELS_COL_INDEX = 13
71
+
72
+ LAST_USED_COL_INDEX = MODELS_COL_INDEX
73
+ LAST_USED_COL_LETTER = col_to_letter(LAST_USED_COL_INDEX)
60
74
 
61
75
 
62
76
  def to_xlsx(
63
- space, project, models, topics, comments, viewpoints, company_logo_content, lang="en"
77
+ space,
78
+ project,
79
+ models,
80
+ topics,
81
+ comments,
82
+ viewpoints,
83
+ company_logo_content,
84
+ lang="en",
85
+ sheetname=None,
64
86
  ):
65
87
  """
66
88
  topics: list of topics (dict parsed from BCF-API json)
67
89
  comments: dict(topics_guid=[comment])
68
90
  viewpoints: dict(topics_guid=[viewpoint])
69
91
  """
92
+ headers = HEADER_TRANSLATIONS[lang]
93
+
70
94
  xls_file = io.BytesIO()
71
95
  with xlsxwriter.Workbook(xls_file, options={"remove_timezone": True}) as workbook:
72
- worksheet = workbook.add_worksheet()
96
+ if sheetname:
97
+ worksheet = workbook.add_worksheet(sheetname)
98
+ else:
99
+ worksheet = workbook.add_worksheet(headers["sheetname"])
73
100
 
74
101
  # Set default height for tables
75
102
  DEFAULT_CELL_HEIGHT = 220
@@ -86,27 +113,33 @@ def to_xlsx(
86
113
 
87
114
  # Set image cell width
88
115
  IMAGE_COLUMN_WIDTH = 220
89
- worksheet.set_column_pixels(VIEWPOINT_COL_INDEX, VIEWPOINT_COL_INDEX, IMAGE_COLUMN_WIDTH)
116
+ worksheet.set_column_pixels(
117
+ VIEWPOINT_COL_INDEX, VIEWPOINT_COL_INDEX, IMAGE_COLUMN_WIDTH
118
+ )
90
119
 
91
120
  header_fmt = workbook.add_format(
92
- {"align": "center", "bold": True, "bg_color": "#C0C0C0", "border": 1}
121
+ {
122
+ "valign": "vcenter",
123
+ "align": "center",
124
+ "bold": True,
125
+ "bg_color": "#C0C0C0",
126
+ "border": 1,
127
+ }
93
128
  )
94
129
  base_fmt = workbook.add_format({"valign": "top", "border": 1})
95
130
  if lang == "fr":
96
131
  date_fmt = workbook.add_format(
97
- {"valign": "top", "num_format": "dd/mm/yyyy", "border": 1}
132
+ {"align": "left", "valign": "top", "num_format": "dd/mm/yyyy", "border": 1}
98
133
  )
99
134
  else:
100
135
  date_fmt = workbook.add_format(
101
- {"valign": "top", "num_format": "yyyy-mm-dd", "border": 1}
136
+ {"align": "left", "valign": "top", "num_format": "yyyy-mm-dd", "border": 1}
102
137
  )
103
138
 
104
- comments_fmt = workbook.add_format({"valign": "top", "text_wrap": True, "border": 1})
139
+ text_wrap_fmt = workbook.add_format({"valign": "top", "text_wrap": True, "border": 1})
105
140
  header_fmt2 = workbook.add_format({"border": 1})
106
141
  base_fm_align = workbook.add_format({"align": "center", "valign": "top"})
107
142
 
108
- headers = HEADER_TRANSLATIONS[lang]
109
-
110
143
  # Company Logo followed by date, espace, space, models
111
144
  row = 0
112
145
 
@@ -152,31 +185,29 @@ def to_xlsx(
152
185
  },
153
186
  )
154
187
 
155
- worksheet.merge_range("D1:Z1", "", merge_format_gray)
188
+ worksheet.merge_range(f"D1:{LAST_USED_COL_LETTER}1", "", merge_format_gray)
156
189
  row += 1
157
190
  worksheet.set_row(row, 20)
158
- worksheet.merge_range("A2:Z2", "", merge_format_default)
191
+ worksheet.merge_range(f"A2:{LAST_USED_COL_LETTER}2", "", merge_format_default)
159
192
  row += 1
160
193
  worksheet.set_row_pixels(row, ROW_HEIGHT)
161
194
  worksheet.merge_range("A3:B3", "", merge_format_default)
162
195
  worksheet.write(row, 0, headers["project"], header_fmt)
163
- worksheet.merge_range("C3:Z3", "", merge_format_default)
196
+ worksheet.merge_range(f"C3:{LAST_USED_COL_LETTER}3", "", merge_format_default)
164
197
  worksheet.write(row, 2, project["name"], header_fmt2)
165
198
 
166
- # TODO: add spreadsheet metadata for models
167
-
168
199
  row += 1
169
200
  worksheet.set_row_pixels(row, ROW_HEIGHT)
170
201
  worksheet.merge_range("A4:B4", "", merge_format_default)
171
202
  worksheet.write(row, 0, headers["space"], header_fmt)
172
- worksheet.merge_range("C4:Z4", "", merge_format_default)
203
+ worksheet.merge_range(f"C4:{LAST_USED_COL_LETTER}4", "", merge_format_default)
173
204
  worksheet.write(row, 2, space["name"], header_fmt2)
174
205
 
175
206
  row += 1
176
207
  worksheet.set_row_pixels(row, ROW_HEIGHT)
177
208
  worksheet.merge_range("A5:B5", "", merge_format_default)
178
209
  worksheet.write(row, 0, "Date", header_fmt)
179
- worksheet.merge_range("C5:Z5", "", merge_format_default)
210
+ worksheet.merge_range(f"C5:{LAST_USED_COL_LETTER}5", "", merge_format_default)
180
211
  if lang == "fr":
181
212
  current_time = datetime.now().strftime("%d/%m/%Y, %H:%M:%S")
182
213
  else:
@@ -185,7 +216,7 @@ def to_xlsx(
185
216
 
186
217
  row += 1
187
218
  worksheet.set_row(row, 20)
188
- worksheet.merge_range("A6:Z6", "", merge_format_default)
219
+ worksheet.merge_range(f"A6:{LAST_USED_COL_LETTER}6", "", merge_format_default)
189
220
  row += 1
190
221
 
191
222
  # Set topic row height
@@ -194,18 +225,21 @@ def to_xlsx(
194
225
  # Create table header
195
226
  worksheet.write(row, INDEX_COL_INDEX, headers["index"], header_fmt)
196
227
  worksheet.write(row, CREATION_DATE_COL_INDEX, headers["creation_date"], header_fmt)
228
+ worksheet.set_column_pixels(CREATION_DATE_COL_INDEX, CREATION_DATE_COL_INDEX, 100)
197
229
  worksheet.write(row, AUTHOR_COL_INDEX, headers["author"], header_fmt)
198
230
  worksheet.write(row, ASSIGNED_TO_COL_INDEX, headers["assigned_to"], header_fmt)
199
231
  worksheet.write(row, TITLE_COL_INDEX, headers["title"], header_fmt)
200
232
  worksheet.write(row, VIEWPOINT_COL_INDEX, headers["viewpoint"], header_fmt)
201
233
  worksheet.write(row, DESCRIPTION_COL_INDEX, headers["description"], header_fmt)
202
234
  worksheet.write(row, DUE_DATE_COL_INDEX, headers["due_date"], header_fmt)
235
+ worksheet.write(row, STAGE_COL_INDEX, headers["stage"], header_fmt)
203
236
  worksheet.write(row, STATUS_COL_INDEX, headers["status"], header_fmt)
204
237
  worksheet.write(row, PRIORITY_COL_INDEX, headers["priority"], header_fmt)
205
- worksheet.write(row, TAGS_COL_INDEX, headers["tags"], header_fmt)
238
+ worksheet.write(row, LABELS_COL_INDEX, headers["tags"], header_fmt)
206
239
  worksheet.write(row, COMMENTS_COL_INDEX, headers["comments"], header_fmt)
207
- worksheet.set_column_pixels(10, 10, 100)
208
- worksheet.set_column_pixels(11, 11, 200)
240
+ worksheet.set_column_pixels(LABELS_COL_INDEX, LABELS_COL_INDEX, 100)
241
+ worksheet.set_column_pixels(COMMENTS_COL_INDEX, COMMENTS_COL_INDEX, 200)
242
+ worksheet.write(row, MODELS_COL_INDEX, headers["models"], header_fmt)
209
243
  row += 1
210
244
 
211
245
  # Sort topic by index
@@ -232,12 +266,13 @@ def to_xlsx(
232
266
  worksheet.write_datetime(row, DUE_DATE_COL_INDEX, due_date, date_fmt)
233
267
  else:
234
268
  worksheet.write(row, DUE_DATE_COL_INDEX, "", base_fmt)
269
+ worksheet.write(row, STAGE_COL_INDEX, topic.get("stage"), base_fmt)
235
270
  worksheet.write(row, STATUS_COL_INDEX, topic.get("topic_status"), base_fmt)
236
271
  worksheet.write(row, PRIORITY_COL_INDEX, topic.get("priority"), base_fmt)
237
272
 
238
- concatenated_tags = ", ".join(topic.get("labels", []))
273
+ concatenated_labels = ", ".join(topic.get("labels", []))
239
274
 
240
- worksheet.write(row, TAGS_COL_INDEX, concatenated_tags, base_fmt)
275
+ worksheet.write(row, LABELS_COL_INDEX, concatenated_labels, base_fmt)
241
276
 
242
277
  concatenated_comments = ""
243
278
 
@@ -250,7 +285,11 @@ def to_xlsx(
250
285
  concatenated_comments += (
251
286
  f"[{comment_date}] {comment['author']}: {comment['comment']}\n"
252
287
  )
253
- worksheet.write(row, COMMENTS_COL_INDEX, concatenated_comments, comments_fmt)
288
+ worksheet.write(row, COMMENTS_COL_INDEX, concatenated_comments, text_wrap_fmt)
289
+
290
+ concatenated_models = "\n".join(topic.get("models", []))
291
+
292
+ worksheet.write(row, MODELS_COL_INDEX, concatenated_models, text_wrap_fmt)
254
293
 
255
294
  if len(topic_viewpoints):
256
295
  viewpoint = topic_viewpoints[0]
@@ -287,7 +326,7 @@ def to_xlsx(
287
326
  worksheet.write(row, VIEWPOINT_COL_INDEX, "", base_fmt)
288
327
 
289
328
  row += 1
290
- worksheet.set_column("M:Z", None, None, {"hidden": True})
329
+
291
330
  worksheet.set_default_row(hide_unused_rows=True)
292
331
 
293
332
  worksheet.autofit()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: bcf-api-xml
3
- Version: 0.4.15
3
+ Version: 0.4.17
4
4
  Summary: Convert BCF-API to BCF-XML
5
5
  Home-page: https://github.com/bimdata/BCF-API-XML-translator
6
6
  License: MIT
@@ -12,6 +12,7 @@ Classifier: Programming Language :: Python :: 3
12
12
  Classifier: Programming Language :: Python :: 3.10
13
13
  Classifier: Programming Language :: Python :: 3.11
14
14
  Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
15
16
  Requires-Dist: generateDS (>=2.35.13,<3.0.0)
16
17
  Requires-Dist: lxml (>=5.3.1,<6.0.0)
17
18
  Requires-Dist: pillow (>=11.1.0,<12.0.0)
@@ -49,6 +50,8 @@ pre-commit install
49
50
  ```
50
51
 
51
52
  # Publish new version
53
+ Update version number in `pyproject.toml` and `bcf_api_xml/__init__.py` then
54
+
52
55
  ```bash
53
56
  poetry publish --build --username= --password=
54
57
  ```
@@ -3,10 +3,10 @@ bcf_api_xml/Schemas/markup.xsd,sha256=FemvIgZYcNk61FQxFHdIrcWzLvgw1t_ntOsQz15sRE
3
3
  bcf_api_xml/Schemas/project.xsd,sha256=obReOUyt8HYgnyLsnyIlA5ky9YClDNiYwUxMubHJ1dI,669
4
4
  bcf_api_xml/Schemas/version.xsd,sha256=ux0QjjSUI_70pp7MFkh5fn5zoY7plLzfmPl4pqOt-Jk,449
5
5
  bcf_api_xml/Schemas/visinfo.xsd,sha256=qxFodRHZWV_BNrzsV7T2QPDoNk2RP5tUyNwmehPG8kc,7212
6
- bcf_api_xml/__init__.py,sha256=z_vulZ7ebY_LOlOzOQt1IUj5_iVy1MxZnO4PhrEpui8,309
6
+ bcf_api_xml/__init__.py,sha256=eSOrTXYWELHFo_sculdlR6BYqWLeiDe9N4j9jhG2qRs,309
7
7
  bcf_api_xml/errors.py,sha256=krwA-Ib5R4LeeU2xzeMQ6rKXvRB-08ReQmihk8FqPsM,89
8
8
  bcf_api_xml/export/__init__.py,sha256=5jooo9c6rlALNthrCwAw8UTcx5Rir8ASyen1voo6ZRA,178
9
- bcf_api_xml/export/excel.py,sha256=h4gDgInS6Oxpc4EWP9_mleWYffeHZPU28wpTFvuVuu8,11481
9
+ bcf_api_xml/export/excel.py,sha256=eqO1GKBfMYTPtaROzICgFiUSgDHkfIlLDIhtFY6CcZU,12682
10
10
  bcf_api_xml/export/zip.py,sha256=HCSx5mx-scAlAA49WKiVV7Y7ABmT2mhUkdXyL4U2lHE,3322
11
11
  bcf_api_xml/import_zip.py,sha256=cLk5XK68My_mQDspVfl9LLS6DzLhBlh4Q9bgRaeqnSA,3107
12
12
  bcf_api_xml/models/ClippingPlane.py,sha256=sIcst3nGcaIHNl_qcXNjdSGFw3gufmh2VpOZtyo-oNE,410
@@ -23,6 +23,6 @@ bcf_api_xml/models/Visibility.py,sha256=8adXfJpceynK6W0in9C5EBEU6v6FKLcJdXG7NM3v
23
23
  bcf_api_xml/models/VisualizationInfo.py,sha256=eaq7HWJF5zMGCZunf46QZDNY7_dwVJgTLWFBDq5ElBQ,4084
24
24
  bcf_api_xml/models/XYZ.py,sha256=DZb8MBdQtbEWK62gXT8XqvdszHO9JWsUFiVX4FCkHnM,316
25
25
  bcf_api_xml/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
- bcf_api_xml-0.4.15.dist-info/METADATA,sha256=1yLVKxDi5TMH_pl4PvXApjnNv5v82BKLpqF_Wa_cfGg,1388
27
- bcf_api_xml-0.4.15.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
28
- bcf_api_xml-0.4.15.dist-info/RECORD,,
26
+ bcf_api_xml-0.4.17.dist-info/METADATA,sha256=G-a4GEKEGbRYkMFDzW0ZCRDL-FJSTQPAXPa-pKTNqUQ,1517
27
+ bcf_api_xml-0.4.17.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
28
+ bcf_api_xml-0.4.17.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 1.9.0
2
+ Generator: poetry-core 1.9.1
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any