honeybee-core 1.61.28__tar.gz → 1.61.30__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 (111) hide show
  1. {honeybee_core-1.61.28/honeybee_core.egg-info → honeybee_core-1.61.30}/PKG-INFO +1 -1
  2. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee/cli/edit.py +2 -1
  3. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee/face.py +2 -0
  4. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee/model.py +17 -4
  5. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee/room.py +24 -4
  6. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee/typing.py +25 -11
  7. {honeybee_core-1.61.28 → honeybee_core-1.61.30/honeybee_core.egg-info}/PKG-INFO +1 -1
  8. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/.github/workflows/ci.yaml +0 -0
  9. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/.github/workflows/dependency-release.yaml +0 -0
  10. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/.gitignore +0 -0
  11. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/.releaserc.json +0 -0
  12. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/CODE_OF_CONDUCT.md +0 -0
  13. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/CONTRIBUTING.md +0 -0
  14. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/LICENSE +0 -0
  15. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/MANIFEST.in +0 -0
  16. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/README.md +0 -0
  17. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/deploy.sh +0 -0
  18. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/dev-requirements.txt +0 -0
  19. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/docs/_build/.nojekyll +0 -0
  20. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/docs/_build/README.md +0 -0
  21. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/docs/_build/docs/README.md +0 -0
  22. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/docs/_static/custom.css +0 -0
  23. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/docs/_templates/layout.html +0 -0
  24. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/docs/cli/index.rst +0 -0
  25. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/docs/conf.py +0 -0
  26. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/docs/index.rst +0 -0
  27. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee/__init__.py +0 -0
  28. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee/__main__.py +0 -0
  29. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee/_base.py +0 -0
  30. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee/_basewithshade.py +0 -0
  31. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee/_lockable.py +0 -0
  32. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee/altnumber.py +0 -0
  33. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee/aperture.py +0 -0
  34. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee/boundarycondition.py +0 -0
  35. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee/checkdup.py +0 -0
  36. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee/cli/__init__.py +0 -0
  37. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee/cli/compare.py +0 -0
  38. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee/cli/create.py +0 -0
  39. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee/cli/lib.py +0 -0
  40. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee/cli/setconfig.py +0 -0
  41. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee/cli/validate.py +0 -0
  42. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee/colorobj.py +0 -0
  43. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee/config.json +0 -0
  44. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee/config.py +0 -0
  45. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee/dictutil.py +0 -0
  46. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee/door.py +0 -0
  47. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee/extensionutil.py +0 -0
  48. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee/facetype.py +0 -0
  49. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee/logutil.py +0 -0
  50. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee/orientation.py +0 -0
  51. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee/properties.py +0 -0
  52. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee/search.py +0 -0
  53. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee/shade.py +0 -0
  54. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee/shademesh.py +0 -0
  55. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee/units.py +0 -0
  56. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee/writer/__init__.py +0 -0
  57. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee/writer/aperture.py +0 -0
  58. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee/writer/door.py +0 -0
  59. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee/writer/face.py +0 -0
  60. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee/writer/model.py +0 -0
  61. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee/writer/room.py +0 -0
  62. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee/writer/shade.py +0 -0
  63. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee/writer/shademesh.py +0 -0
  64. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee_core.egg-info/SOURCES.txt +0 -0
  65. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee_core.egg-info/dependency_links.txt +0 -0
  66. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee_core.egg-info/entry_points.txt +0 -0
  67. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee_core.egg-info/requires.txt +0 -0
  68. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/honeybee_core.egg-info/top_level.txt +0 -0
  69. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/requirements.txt +0 -0
  70. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/setup.cfg +0 -0
  71. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/setup.py +0 -0
  72. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/tests/__init__.py +0 -0
  73. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/tests/aperture_test.py +0 -0
  74. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/tests/boundary_condition_test.py +0 -0
  75. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/tests/cli_compare_test.py +0 -0
  76. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/tests/cli_create_test.py +0 -0
  77. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/tests/cli_edit_test.py +0 -0
  78. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/tests/cli_validate_test.py +0 -0
  79. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/tests/colorobj_test.py +0 -0
  80. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/tests/config_test.py +0 -0
  81. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/tests/dictutil_test.py +0 -0
  82. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/tests/door_test.py +0 -0
  83. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/tests/face_test.py +0 -0
  84. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/tests/facetype_test.py +0 -0
  85. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/tests/json/ShoeBox.json +0 -0
  86. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/tests/json/bad_geometry_model.hbjson +0 -0
  87. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/tests/json/colliding_room_volumes.hbjson +0 -0
  88. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/tests/json/compare_model_1.hbjson +0 -0
  89. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/tests/json/compare_model_2.hbjson +0 -0
  90. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/tests/json/complex_polyfaces.json +0 -0
  91. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/tests/json/minor_geometry/existing_model.hbjson +0 -0
  92. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/tests/json/minor_geometry/updated_model.hbjson +0 -0
  93. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/tests/json/mismatched_area_adj.hbjson +0 -0
  94. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/tests/json/model_with_adiabatic.hbjson +0 -0
  95. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/tests/json/model_with_holes.hbjson +0 -0
  96. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/tests/json/model_without_adjacency.hbjson +0 -0
  97. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/tests/json/nonascii_face.json +0 -0
  98. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/tests/json/polygons_for_gap_boundary.json +0 -0
  99. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/tests/json/room_for_window_offset.hbjson +0 -0
  100. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/tests/json/single_family_home.hbjson +0 -0
  101. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/tests/lockable_test.py +0 -0
  102. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/tests/model_test.py +0 -0
  103. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/tests/orientation_test.py +0 -0
  104. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/tests/room_test.py +0 -0
  105. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/tests/search_test.py +0 -0
  106. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/tests/shade_test.py +0 -0
  107. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/tests/shademesh_test.py +0 -0
  108. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/tests/stl/cube_ascii.stl +0 -0
  109. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/tests/stl/cube_binary.stl +0 -0
  110. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/tests/typing_test.py +0 -0
  111. {honeybee_core-1.61.28 → honeybee_core-1.61.30}/tests/units_test.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: honeybee-core
3
- Version: 1.61.28
3
+ Version: 1.61.30
4
4
  Summary: A library to create 3D building geometry for various types of environmental simulation.
5
5
  Home-page: https://github.com/ladybug-tools/honeybee-core
6
6
  Author: Ladybug Tools
@@ -104,7 +104,8 @@ def solve_adjacency(model_file, no_merge, no_intersect, no_overwrite,
104
104
  air_boundary = not wall
105
105
  adiabatic = not surface
106
106
  parsed_model.solve_adjacency(
107
- merge_coplanar, intersect, overwrite, air_boundary, adiabatic)
107
+ merge_coplanar, intersect, overwrite,
108
+ air_boundary=air_boundary, adiabatic=adiabatic)
108
109
 
109
110
  # write the new model out to the file or stdout
110
111
  output_file.write(json.dumps(parsed_model.to_dict()))
@@ -740,6 +740,8 @@ class Face(_BaseWithShade):
740
740
  if len(joined_bounds) == 1: # can be represented with a single Face3D
741
741
  verts3d = tuple(ref_plane.xy_to_xyz(_v) for _v in joined_bounds[0])
742
742
  non_rect_geos = [Face3D(verts3d, plane=ref_plane)]
743
+ elif len(joined_bounds) == 0: # everything was invalid
744
+ non_rect_geos = []
743
745
  else: # need to separate holes from distinct Face3Ds
744
746
  bound_faces = []
745
747
  for poly in joined_bounds:
@@ -1449,7 +1449,7 @@ class Model(_Base):
1449
1449
 
1450
1450
  def solve_adjacency(
1451
1451
  self, merge_coplanar=False, intersect=False, overwrite=False,
1452
- air_boundary=False, adiabatic=False,
1452
+ remove_mismatched_sub_faces=True, air_boundary=False, adiabatic=False,
1453
1453
  tolerance=None, angle_tolerance=None):
1454
1454
  """Solve adjacency between Rooms of the Model.
1455
1455
 
@@ -1465,6 +1465,10 @@ class Model(_Base):
1465
1465
  solved. (Default: False).
1466
1466
  overwrite: Boolean to note whether existing Surface boundary
1467
1467
  conditions should be overwritten. (Default: False).
1468
+ remove_mismatched_sub_faces: Boolean to note whether any mis-matches
1469
+ in sub-faces between adjacent rooms should simply result in
1470
+ the sub-faces being removed rather than raising an
1471
+ exception. (Default: True).
1468
1472
  air_boundary: Boolean to note whether the wall adjacencies should be
1469
1473
  of the air boundary face type. (Default: False).
1470
1474
  adiabatic: Boolean to note whether the adjacencies should be
@@ -1491,11 +1495,20 @@ class Model(_Base):
1491
1495
 
1492
1496
  # solve adjacency
1493
1497
  if not overwrite: # only assign new adjacencies
1494
- adj_info = Room.solve_adjacency(self.rooms, tol)
1498
+ adj_info = Room.solve_adjacency(self.rooms, tol, remove_mismatched_sub_faces)
1495
1499
  else: # overwrite existing Surface BC
1496
1500
  adj_faces = Room.find_adjacency(self.rooms, tol)
1497
- for face_pair in adj_faces:
1498
- face_pair[0].set_adjacency(face_pair[1])
1501
+ if remove_mismatched_sub_faces:
1502
+ for face_pair in adj_faces:
1503
+ try:
1504
+ face_pair[0].set_adjacency(face_pair[1])
1505
+ except AssertionError:
1506
+ face_pair[0].remove_sub_faces()
1507
+ face_pair[1].remove_sub_faces()
1508
+ face_pair[0].set_adjacency(face_pair[1])
1509
+ else:
1510
+ for face_pair in adj_faces:
1511
+ face_pair[0].set_adjacency(face_pair[1])
1499
1512
  adj_info = {'adjacent_faces': adj_faces}
1500
1513
 
1501
1514
  # try to assign the air boundary face type
@@ -1759,10 +1759,18 @@ class Room(_BaseWithShade):
1759
1759
  nf = Face(fid, new_geo, prop_f.type, fbc)
1760
1760
  for ap in apertures:
1761
1761
  if nf.geometry.is_sub_face(ap.geometry, tol, a_tol):
1762
- nf.add_aperture(ap)
1762
+ try:
1763
+ nf.add_aperture(ap)
1764
+ except AssertionError: # probably adiabatic
1765
+ nf.boundary_condition = boundary_conditions.outdoors
1766
+ nf.add_aperture(ap)
1763
1767
  for dr in doors:
1764
1768
  if nf.geometry.is_sub_face(dr.geometry, tol, a_tol):
1765
- nf.add_door(dr)
1769
+ try:
1770
+ nf.add_door(dr)
1771
+ except AssertionError: # probably adiabatic
1772
+ nf.boundary_condition = boundary_conditions.outdoors
1773
+ nf.add_door(dr)
1766
1774
  if i == 0: # add all assigned shades to this face
1767
1775
  nf.add_indoor_shades(in_shades)
1768
1776
  nf.add_outdoor_shades(out_shades)
@@ -1943,7 +1951,7 @@ class Room(_BaseWithShade):
1943
1951
  room.coplanar_split(other_rooms, tolerance, angle_tolerance)
1944
1952
 
1945
1953
  @staticmethod
1946
- def solve_adjacency(rooms, tolerance=0.01):
1954
+ def solve_adjacency(rooms, tolerance=0.01, remove_mismatched_sub_faces=False):
1947
1955
  """Solve for adjacencies between a list of rooms.
1948
1956
 
1949
1957
  Note that this method will mutate the input rooms by setting Surface
@@ -1956,6 +1964,10 @@ class Room(_BaseWithShade):
1956
1964
  tolerance: The minimum difference between the coordinate values of two
1957
1965
  faces at which they can be considered centered adjacent. Default: 0.01,
1958
1966
  suitable for objects in meters.
1967
+ remove_mismatched_sub_faces: Boolean to note whether any mis-matches
1968
+ in sub-faces between adjacent rooms should simply result in
1969
+ the sub-faces being removed rather than raising an
1970
+ exception. (Default: False).
1959
1971
 
1960
1972
  Returns:
1961
1973
  A dictionary of information about the objects that had their adjacency set.
@@ -1989,7 +2001,15 @@ class Room(_BaseWithShade):
1989
2001
  if not isinstance(face_2.boundary_condition, Surface):
1990
2002
  if face_1.geometry.is_centered_adjacent(
1991
2003
  face_2.geometry, tolerance):
1992
- face_info = face_1.set_adjacency(face_2)
2004
+ if not remove_mismatched_sub_faces:
2005
+ face_info = face_1.set_adjacency(face_2)
2006
+ else:
2007
+ try:
2008
+ face_info = face_1.set_adjacency(face_2)
2009
+ except AssertionError:
2010
+ face_1[0].remove_sub_faces()
2011
+ face_2.remove_sub_faces()
2012
+ face_info = face_1.set_adjacency(face_2)
1993
2013
  adj_info['adjacent_faces'].append((face_1, face_2))
1994
2014
  adj_info['adjacent_apertures'].extend(
1995
2015
  face_info['adjacent_apertures'])
@@ -3,6 +3,7 @@ import re
3
3
  import os
4
4
  import math
5
5
  import uuid
6
+ import hashlib
6
7
 
7
8
  try:
8
9
  INFPOS = math.inf
@@ -170,7 +171,8 @@ def clean_string(value, input_name=''):
170
171
  """Clean a string so that it is valid for both Radiance and EnergyPlus.
171
172
 
172
173
  This will strip out spaces and special characters and raise an error if the
173
- string is empty after stripping or has more than 100 characters.
174
+ string is has more than 100 characters. If the input has no valid characters
175
+ after stripping out illegal ones, a randomly-generated UUID will be returned.
174
176
  """
175
177
  try:
176
178
  value = value.replace(' ', '_') # spaces > underscores for readability
@@ -178,8 +180,10 @@ def clean_string(value, input_name=''):
178
180
  except TypeError:
179
181
  raise TypeError('Input {} must be a text string. Got {}: {}.'.format(
180
182
  input_name, type(value), value))
181
- assert len(val) > 0, 'Input {} "{}" contains no valid characters.'.format(
182
- input_name, value)
183
+ if len(val) == 0: # generate a unique but consistent ID from the input
184
+ sha256_hash = hashlib.sha256(value.encode('utf-8'))
185
+ hash_str = str(sha256_hash.hexdigest())
186
+ return hash_str[:8] if len(hash_str) > 8 else hash_str
183
187
  assert len(val) <= 100, 'Input {} "{}" must be less than 100 characters.'.format(
184
188
  input_name, value)
185
189
  return val
@@ -188,8 +192,9 @@ def clean_string(value, input_name=''):
188
192
  def clean_rad_string(value, input_name=''):
189
193
  """Clean a string for Radiance that can be used for rad material names.
190
194
 
191
- This includes stripping out illegal characters and white spaces as well as
192
- raising an error if no legal characters are found.
195
+ This includes stripping out illegal characters and white spaces. If the input
196
+ has no valid characters after stripping out illegal ones, a randomly-generated
197
+ UUID will be returned.
193
198
  """
194
199
  try:
195
200
  value = value.replace(' ', '_') # spaces > underscores for readability
@@ -197,8 +202,10 @@ def clean_rad_string(value, input_name=''):
197
202
  except TypeError:
198
203
  raise TypeError('Input {} must be a text string. Got {}: {}.'.format(
199
204
  input_name, type(value), value))
200
- assert len(val) > 0, 'Input {} "{}" contains no valid characters.'.format(
201
- input_name, value)
205
+ if len(val) == 0: # generate a unique but consistent ID from the input
206
+ sha256_hash = hashlib.sha256(value.encode('utf-8'))
207
+ hash_str = str(sha256_hash.hexdigest())
208
+ return hash_str[:8] if len(hash_str) > 8 else hash_str
202
209
  return val
203
210
 
204
211
 
@@ -206,8 +213,9 @@ def clean_ep_string(value, input_name=''):
206
213
  """Clean a string for EnergyPlus that can be used for energy material names.
207
214
 
208
215
  This includes stripping out all illegal characters, removing trailing spaces,
209
- and rasing an error if the name is not longer than 100 characters or no legal
210
- characters found.
216
+ and rasing an error if the name is not longer than 100 characters. If the input
217
+ has no valid characters after stripping out illegal ones, a randomly-generated
218
+ UUID will be returned.
211
219
  """
212
220
  try:
213
221
  val = ''.join(i for i in value if ord(i) < 128) # strip out non-ascii
@@ -216,8 +224,10 @@ def clean_ep_string(value, input_name=''):
216
224
  raise TypeError('Input {} must be a text string. Got {}: {}.'.format(
217
225
  input_name, type(value), value))
218
226
  val = val.strip()
219
- assert len(val) > 0, 'Input {} "{}" contains no valid characters.'.format(
220
- input_name, value)
227
+ if len(val) == 0: # generate a unique but consistent ID from the input
228
+ sha256_hash = hashlib.sha256(value.encode('utf-8'))
229
+ hash_str = str(sha256_hash.hexdigest())
230
+ return hash_str[:8] if len(hash_str) > 8 else hash_str
221
231
  assert len(val) <= 100, 'Input {} "{}" must be less than 100 characters.'.format(
222
232
  input_name, value)
223
233
  return val
@@ -449,6 +459,10 @@ def clean_doe2_string(value, max_length=24):
449
459
  raise TypeError('Input must be a text string. Got {}: {}.'.format(
450
460
  type(value), value))
451
461
  val = val.strip()
462
+ if len(val) == 0: # generate a unique but consistent ID from the input
463
+ sha256_hash = hashlib.sha256(value.encode('utf-8'))
464
+ hash_str = str(sha256_hash.hexdigest())
465
+ return hash_str[:8] if len(hash_str) > 8 else hash_str
452
466
  return readable_short_name(val, max_length)
453
467
 
454
468
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: honeybee-core
3
- Version: 1.61.28
3
+ Version: 1.61.30
4
4
  Summary: A library to create 3D building geometry for various types of environmental simulation.
5
5
  Home-page: https://github.com/ladybug-tools/honeybee-core
6
6
  Author: Ladybug Tools
File without changes