OpenGeodeWeb-Back 6.13.0rc1__tar.gz → 6.13.0rc3__tar.gz

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.
Files changed (114) hide show
  1. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/PKG-INFO +1 -1
  2. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/pyproject.toml +1 -1
  3. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/OpenGeodeWeb_Back.egg-info/PKG-INFO +1 -1
  4. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/blueprint_routes.py +51 -19
  5. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/tests/test_routes.py +86 -7
  6. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/LICENSE +0 -0
  7. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/README.md +0 -0
  8. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/requirements.txt +0 -0
  9. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/setup.cfg +0 -0
  10. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/OpenGeodeWeb_Back.egg-info/SOURCES.txt +0 -0
  11. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/OpenGeodeWeb_Back.egg-info/dependency_links.txt +0 -0
  12. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/OpenGeodeWeb_Back.egg-info/entry_points.txt +0 -0
  13. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/OpenGeodeWeb_Back.egg-info/requires.txt +0 -0
  14. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/OpenGeodeWeb_Back.egg-info/top_level.txt +0 -0
  15. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/__init__.py +0 -0
  16. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/app.py +0 -0
  17. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/app_config.py +0 -0
  18. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/geode_functions.py +0 -0
  19. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/geode_objects/__init__.py +0 -0
  20. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/geode_objects/geode_brep.py +0 -0
  21. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/geode_objects/geode_cross_section.py +0 -0
  22. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/geode_objects/geode_edged_curve2d.py +0 -0
  23. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/geode_objects/geode_edged_curve3d.py +0 -0
  24. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/geode_objects/geode_graph.py +0 -0
  25. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/geode_objects/geode_grid2d.py +0 -0
  26. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/geode_objects/geode_grid3d.py +0 -0
  27. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/geode_objects/geode_horizon_stack3d.py +0 -0
  28. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/geode_objects/geode_hybrid_solid3d.py +0 -0
  29. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/geode_objects/geode_implicit_cross_section.py +0 -0
  30. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/geode_objects/geode_implicit_structural_model.py +0 -0
  31. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/geode_objects/geode_light_regular_grid2d.py +0 -0
  32. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/geode_objects/geode_light_regular_grid3d.py +0 -0
  33. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/geode_objects/geode_mesh.py +0 -0
  34. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/geode_objects/geode_model.py +0 -0
  35. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/geode_objects/geode_object.py +0 -0
  36. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/geode_objects/geode_point_set2d.py +0 -0
  37. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/geode_objects/geode_point_set3d.py +0 -0
  38. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/geode_objects/geode_polygonal_surface2d.py +0 -0
  39. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/geode_objects/geode_polygonal_surface3d.py +0 -0
  40. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/geode_objects/geode_polyhedral_solid3d.py +0 -0
  41. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/geode_objects/geode_raster_image2d.py +0 -0
  42. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/geode_objects/geode_raster_image3d.py +0 -0
  43. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/geode_objects/geode_regular_grid2d.py +0 -0
  44. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/geode_objects/geode_regular_grid3d.py +0 -0
  45. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/geode_objects/geode_section.py +0 -0
  46. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/geode_objects/geode_solid_mesh3d.py +0 -0
  47. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/geode_objects/geode_structural_model.py +0 -0
  48. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/geode_objects/geode_surface_mesh2d.py +0 -0
  49. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/geode_objects/geode_surface_mesh3d.py +0 -0
  50. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/geode_objects/geode_tetrahedral_solid3d.py +0 -0
  51. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/geode_objects/geode_triangulated_surface2d.py +0 -0
  52. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/geode_objects/geode_triangulated_surface3d.py +0 -0
  53. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/geode_objects/geode_vertex_set.py +0 -0
  54. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/py.typed +0 -0
  55. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/create/blueprint_create.py +0 -0
  56. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/create/schemas/__init__.py +0 -0
  57. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/create/schemas/edged_curve.json +0 -0
  58. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/create/schemas/edged_curve.py +0 -0
  59. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/create/schemas/point_set.json +0 -0
  60. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/create/schemas/point_set.py +0 -0
  61. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/create/schemas/polygonal_surface.json +0 -0
  62. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/create/schemas/polygonal_surface.py +0 -0
  63. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/__init__.py +0 -0
  64. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/allowed_files.json +0 -0
  65. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/allowed_files.py +0 -0
  66. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/allowed_objects.json +0 -0
  67. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/allowed_objects.py +0 -0
  68. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/cell_attribute_names.json +0 -0
  69. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/cell_attribute_names.py +0 -0
  70. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/edge_attribute_names.json +0 -0
  71. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/edge_attribute_names.py +0 -0
  72. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/export_project.json +0 -0
  73. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/export_project.py +0 -0
  74. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/geode_object_inheritance.json +0 -0
  75. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/geode_object_inheritance.py +0 -0
  76. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/geode_objects_and_output_extensions.json +0 -0
  77. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/geode_objects_and_output_extensions.py +0 -0
  78. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/geographic_coordinate_systems.json +0 -0
  79. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/geographic_coordinate_systems.py +0 -0
  80. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/import_project.json +0 -0
  81. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/import_project.py +0 -0
  82. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/kill.json +0 -0
  83. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/kill.py +0 -0
  84. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/missing_files.json +0 -0
  85. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/missing_files.py +0 -0
  86. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/model_component_edge_attribute_names.json +0 -0
  87. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/model_component_edge_attribute_names.py +0 -0
  88. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/model_component_polygon_attribute_names.json +0 -0
  89. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/model_component_polygon_attribute_names.py +0 -0
  90. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/model_component_polyhedron_attribute_names.json +0 -0
  91. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/model_component_polyhedron_attribute_names.py +0 -0
  92. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/model_component_vertex_attribute_names.json +0 -0
  93. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/model_component_vertex_attribute_names.py +0 -0
  94. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/ping.json +0 -0
  95. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/ping.py +0 -0
  96. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/polygon_attribute_names.json +0 -0
  97. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/polygon_attribute_names.py +0 -0
  98. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/polyhedron_attribute_names.json +0 -0
  99. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/polyhedron_attribute_names.py +0 -0
  100. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/save_viewable_file.json +0 -0
  101. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/save_viewable_file.py +0 -0
  102. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/texture_coordinates.json +0 -0
  103. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/texture_coordinates.py +0 -0
  104. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/upload_file.json +0 -0
  105. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/upload_file.py +0 -0
  106. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/validate.json +0 -0
  107. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/validate.py +0 -0
  108. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/vertex_attribute_names.json +0 -0
  109. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/routes/schemas/vertex_attribute_names.py +0 -0
  110. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/test_utils.py +0 -0
  111. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/src/opengeodeweb_back/utils_functions.py +0 -0
  112. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/tests/test_create_routes.py +0 -0
  113. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/tests/test_geode_functions.py +0 -0
  114. {opengeodeweb_back-6.13.0rc1 → opengeodeweb_back-6.13.0rc3}/tests/test_utils_functions.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: OpenGeodeWeb-Back
3
- Version: 6.13.0rc1
3
+ Version: 6.13.0rc3
4
4
  Summary: OpenGeodeWeb-Back is an open source framework that proposes handy python functions and wrappers for the OpenGeode ecosystem
5
5
  Author-email: Geode-solutions <team-web@geode-solutions.com>
6
6
  Project-URL: Homepage, https://github.com/Geode-solutions/OpenGeodeWeb-Back
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "OpenGeodeWeb-Back"
7
- version = "6.13.0-rc.1"
7
+ version = "6.13.0-rc.3"
8
8
  dynamic = ["dependencies"]
9
9
  authors = [{ name = "Geode-solutions", email = "team-web@geode-solutions.com" }]
10
10
  description = "OpenGeodeWeb-Back is an open source framework that proposes handy python functions and wrappers for the OpenGeode ecosystem"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: OpenGeodeWeb-Back
3
- Version: 6.13.0rc1
3
+ Version: 6.13.0rc3
4
4
  Summary: OpenGeodeWeb-Back is an open source framework that proposes handy python functions and wrappers for the OpenGeode ecosystem
5
5
  Author-email: Geode-solutions <team-web@geode-solutions.com>
6
6
  Project-URL: Homepage, https://github.com/Geode-solutions/OpenGeodeWeb-Back
@@ -73,13 +73,26 @@ def upload_file() -> flask.Response:
73
73
  if not os.path.exists(UPLOAD_FOLDER_PATH):
74
74
  os.makedirs(UPLOAD_FOLDER_PATH, exist_ok=True)
75
75
 
76
- file = flask.request.files["file"]
77
- if file.filename is None:
78
- flask.abort(400, "Filename is required")
79
- filename = werkzeug.utils.secure_filename(os.path.basename(file.filename))
76
+ # Multipart callers (e.g. Vease) still send the file as a "file" form part;
77
+ # streaming callers PUT the raw bytes as the body with ?filename= as a query param.
78
+ if flask.request.mimetype == "multipart/form-data":
79
+ file = flask.request.files["file"]
80
+ if file.filename is None:
81
+ flask.abort(400, "Filename is required")
82
+ filename = werkzeug.utils.secure_filename(os.path.basename(file.filename))
83
+ file_path = os.path.join(UPLOAD_FOLDER_PATH, filename)
84
+ file.save(file_path)
85
+ else:
86
+ raw_filename = flask.request.args.get("filename")
87
+ if not raw_filename:
88
+ flask.abort(400, "Filename is required")
89
+ filename = werkzeug.utils.secure_filename(os.path.basename(raw_filename))
90
+ file_path = os.path.join(UPLOAD_FOLDER_PATH, filename)
91
+ chunk_size = 1024 * 1024
92
+ with open(file_path, "wb") as destination:
93
+ while chunk := flask.request.stream.read(chunk_size):
94
+ destination.write(chunk)
80
95
  print(f"{filename=}", flush=True)
81
- file_path = os.path.join(UPLOAD_FOLDER_PATH, filename)
82
- file.save(file_path)
83
96
  if filename.lower().endswith(".csv.json"):
84
97
  shutil.copyfile(
85
98
  file_path, os.path.join(UPLOAD_FOLDER_PATH, filename[:-9] + ".json")
@@ -257,23 +270,42 @@ def extract_valid_attribute_values(
257
270
  attribute_name: str,
258
271
  item_index: int,
259
272
  ) -> tuple[list[float], bool]:
260
- attribute_ids_matching_name = attribute_manager.attribute_ids_matching_name(
261
- attribute_name
262
- )
263
- if not isinstance(attribute_ids_matching_name, list):
264
- return [], False
265
- component_attribute = attribute_manager.find_generic_attribute(
266
- attribute_ids_matching_name[0]
267
- )
268
- if component_attribute is None:
273
+ attribute_ids = attribute_manager.attribute_ids_matching_name(attribute_name)
274
+ if not isinstance(attribute_ids, list):
269
275
  return [], False
270
- if not component_attribute.is_genericable():
276
+ attribute = attribute_manager.find_generic_attribute(attribute_ids[0])
277
+ if (
278
+ attribute is None
279
+ or not attribute.is_genericable()
280
+ or not attribute.properties().transferable
281
+ ):
271
282
  return [], False
283
+
284
+ nb_items = attribute.nb_items()
285
+ default_values = getattr(attribute, "default_values", None)
286
+ no_value = default_values().no_value if default_values else None
287
+ if no_value is None and (
288
+ "Point" in attribute.type() or "Vector" in attribute.type()
289
+ ):
290
+ no_value = [0.0] * nb_items
291
+
292
+ value_getter = getattr(
293
+ attribute,
294
+ "value",
295
+ lambda element_index: [
296
+ attribute.generic_item_value(element_index, i) for i in range(nb_items)
297
+ ],
298
+ )
299
+
272
300
  valid_values: list[float] = []
273
301
  has_nan = False
274
302
  for element_index in range(attribute_manager.nb_elements()):
275
- value = component_attribute.generic_item_value(element_index, item_index)
276
- if value is None or math.isnan(value):
303
+ value = attribute.generic_item_value(element_index, item_index)
304
+ if (
305
+ value is None
306
+ or math.isnan(value)
307
+ or (no_value is not None and value_getter(element_index) == no_value)
308
+ ):
277
309
  has_nan = True
278
310
  else:
279
311
  valid_values.append(value)
@@ -293,7 +325,7 @@ def attributes_metadata(
293
325
  attribute_name = attribute.name()
294
326
  if attribute_name is None:
295
327
  continue
296
- if not attribute.is_genericable():
328
+ if not attribute.is_genericable() or not attribute.properties().transferable:
297
329
  continue
298
330
  nb_items = attribute.nb_items()
299
331
  min_values, max_values = [], []
@@ -2,6 +2,7 @@
2
2
  import os
3
3
 
4
4
  # Third party imports
5
+ import opengeode as og
5
6
  from werkzeug.datastructures import FileStorage
6
7
  from flask.testing import FlaskClient
7
8
  from werkzeug.test import TestResponse
@@ -13,6 +14,7 @@ import zipfile
13
14
  from opengeodeweb_microservice.database.data import Data
14
15
  from opengeodeweb_microservice.database.connection import get_session
15
16
  from opengeodeweb_back import geode_functions, test_utils
17
+ from opengeodeweb_back.routes.blueprint_routes import extract_valid_attribute_values
16
18
  from opengeodeweb_back.geode_objects.geode_polygonal_surface3d import (
17
19
  GeodePolygonalSurface3D,
18
20
  )
@@ -79,6 +81,36 @@ def test_upload_file(client: FlaskClient, filename: str = "test.og_brep") -> Non
79
81
  assert response.status_code == 201
80
82
 
81
83
 
84
+ def test_upload_file_raw(client: FlaskClient, filename: str = "test.og_brep") -> None:
85
+ file = os.path.join(data_dir, filename)
86
+ with open(file, "rb") as opened_file:
87
+ file_bytes = opened_file.read()
88
+
89
+ raw_filename = "raw_upload_test.og_brep"
90
+ response = client.put(
91
+ f"/opengeodeweb_back/upload_file?filename={raw_filename}",
92
+ data=file_bytes,
93
+ content_type="application/octet-stream",
94
+ )
95
+ assert response.status_code == 201
96
+
97
+ uploaded_path = os.path.join(data_dir, raw_filename)
98
+ try:
99
+ with open(uploaded_path, "rb") as uploaded_file:
100
+ assert uploaded_file.read() == file_bytes
101
+ finally:
102
+ os.remove(uploaded_path)
103
+
104
+
105
+ def test_upload_file_raw_missing_filename(client: FlaskClient) -> None:
106
+ response = client.put(
107
+ f"/opengeodeweb_back/upload_file",
108
+ data=b"some raw bytes",
109
+ content_type="application/octet-stream",
110
+ )
111
+ assert response.status_code == 400
112
+
113
+
82
114
  def test_missing_files(client: FlaskClient) -> None:
83
115
  route = f"/opengeodeweb_back/missing_files"
84
116
 
@@ -495,7 +527,7 @@ def test_model_components(client: FlaskClient) -> None:
495
527
  assert isinstance(mesh_components, list)
496
528
  assert len(mesh_components) > 0
497
529
  for mesh_component in mesh_components:
498
- assert isinstance(mesh_component, object)
530
+ assert isinstance(mesh_component, dict)
499
531
  assert isinstance(mesh_component["geode_id"], str)
500
532
  assert isinstance(mesh_component["viewer_id"], int)
501
533
  assert isinstance(mesh_component["name"], str)
@@ -511,7 +543,7 @@ def test_model_components(client: FlaskClient) -> None:
511
543
  collection_components = response.get_json()["collection_components"]
512
544
  assert isinstance(collection_components, list)
513
545
  for collection_component in collection_components:
514
- assert isinstance(collection_component, object)
546
+ assert isinstance(collection_component, dict)
515
547
  assert isinstance(collection_component["geode_id"], str)
516
548
  assert isinstance(collection_component["name"], str)
517
549
  assert isinstance(collection_component["items"], list)
@@ -659,15 +691,18 @@ def _load_brep_components(client: FlaskClient) -> tuple[str, dict[str, list[str]
659
691
  response = test_save_viewable_file(client, "BRep", "cube.og_brep")
660
692
  assert response.status_code == 200
661
693
  model_id: str = response.get_json()["id"]
662
- mesh_components: list[dict] = response.get_json()["mesh_components"]
694
+ mesh_components: list[dict[str, object]] = response.get_json()["mesh_components"]
663
695
  by_type: dict[str, list[str]] = {}
664
- for mc in mesh_components:
665
- component_type = mc["type"]
666
- by_type.setdefault(component_type, []).append(mc["geode_id"])
696
+ for mesh_component in mesh_components:
697
+ component_type = mesh_component["type"]
698
+ geode_id = mesh_component["geode_id"]
699
+ assert isinstance(component_type, str)
700
+ assert isinstance(geode_id, str)
701
+ by_type.setdefault(component_type, []).append(geode_id)
667
702
  return model_id, by_type
668
703
 
669
704
 
670
- def _assert_attributes_response(response) -> None:
705
+ def _assert_attributes_response(response: TestResponse) -> None:
671
706
  assert response.status_code == 200
672
707
  attributes = response.get_json()["attributes"]
673
708
  assert isinstance(attributes, list)
@@ -744,3 +779,47 @@ def test_model_component_polyhedron_attribute_names(client: FlaskClient) -> None
744
779
  return {"id": model_id, "component_ids": block_ids}
745
780
 
746
781
  test_utils.test_route_wrong_params(client, route, get_full_data)
782
+
783
+
784
+ def test_extract_valid_attribute_values_with_sentinel_no_value() -> None:
785
+ mesh = og.TriangulatedSurface3D.create()
786
+ builder = og.TriangulatedSurfaceBuilder3D.create(mesh)
787
+ vertex_0 = builder.create_point(og.Point3D([0, 0, 0]))
788
+ vertex_1 = builder.create_point(og.Point3D([1, 0, 0]))
789
+ builder.create_triangle([vertex_0, vertex_1, vertex_0])
790
+
791
+ attribute_manager = mesh.vertex_attribute_manager()
792
+ values_config = og.AttributeValuesDouble()
793
+ values_config.no_value = -999.0
794
+ attribute_id = attribute_manager.create_attribute_variable_double(
795
+ "variable_double", values_config, og.AttributeProperties()
796
+ )
797
+ attribute = attribute_manager.find_attribute_variable_double(attribute_id)
798
+ attribute.set_value(vertex_0, -999.0)
799
+ attribute.set_value(vertex_1, 42.0)
800
+
801
+ valid_values, has_nan = extract_valid_attribute_values(
802
+ attribute_manager, "variable_double", 0
803
+ )
804
+ assert has_nan is True
805
+ assert valid_values == [42.0]
806
+
807
+
808
+ def test_extract_valid_attribute_values_with_non_transferable_attribute() -> None:
809
+ mesh = og.TriangulatedSurface3D.create()
810
+ builder = og.TriangulatedSurfaceBuilder3D.create(mesh)
811
+ vertex_0 = builder.create_point(og.Point3D([0, 0, 0]))
812
+ builder.create_triangle([vertex_0, vertex_0, vertex_0])
813
+
814
+ attribute_manager = mesh.vertex_attribute_manager()
815
+ properties = og.AttributeProperties()
816
+ properties.transferable = False
817
+ attribute_manager.create_attribute_variable_double(
818
+ "internal_attribute", og.AttributeValuesDouble(), properties
819
+ )
820
+
821
+ valid_values, has_nan = extract_valid_attribute_values(
822
+ attribute_manager, "internal_attribute", 0
823
+ )
824
+ assert has_nan is False
825
+ assert valid_values == []