howso-engine 65.0.2__tar.gz → 65.0.3__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 (112) hide show
  1. {howso_engine-65.0.2/howso_engine.egg-info → howso_engine-65.0.3}/PKG-INFO +1 -1
  2. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/utilities/feature_attributes/abstract_data.py +71 -16
  3. {howso_engine-65.0.2 → howso_engine-65.0.3/howso_engine.egg-info}/PKG-INFO +1 -1
  4. {howso_engine-65.0.2 → howso_engine-65.0.3}/.coveragerc +0 -0
  5. {howso_engine-65.0.2 → howso_engine-65.0.3}/.flake8 +0 -0
  6. {howso_engine-65.0.2 → howso_engine-65.0.3}/.github/CODEOWNERS +0 -0
  7. {howso_engine-65.0.2 → howso_engine-65.0.3}/.github/templates/version_summary.md +0 -0
  8. {howso_engine-65.0.2 → howso_engine-65.0.3}/.github/workflows/build-pr.yml +0 -0
  9. {howso_engine-65.0.2 → howso_engine-65.0.3}/.github/workflows/build-release.yml +0 -0
  10. {howso_engine-65.0.2 → howso_engine-65.0.3}/.github/workflows/build.yml +0 -0
  11. {howso_engine-65.0.2 → howso_engine-65.0.3}/.github/workflows/rebuild-requirements.yml +0 -0
  12. {howso_engine-65.0.2 → howso_engine-65.0.3}/.github/workflows/version-update.yml +0 -0
  13. {howso_engine-65.0.2 → howso_engine-65.0.3}/.gitignore +0 -0
  14. {howso_engine-65.0.2 → howso_engine-65.0.3}/.gitmodules +0 -0
  15. {howso_engine-65.0.2 → howso_engine-65.0.3}/.pylintrc +0 -0
  16. {howso_engine-65.0.2 → howso_engine-65.0.3}/CONTRIBUTING.md +0 -0
  17. {howso_engine-65.0.2 → howso_engine-65.0.3}/LICENSE-3RD-PARTY.txt +0 -0
  18. {howso_engine-65.0.2 → howso_engine-65.0.3}/LICENSE.txt +0 -0
  19. {howso_engine-65.0.2 → howso_engine-65.0.3}/MANIFEST.in +0 -0
  20. {howso_engine-65.0.2 → howso_engine-65.0.3}/Makefile +0 -0
  21. {howso_engine-65.0.2 → howso_engine-65.0.3}/README.md +0 -0
  22. {howso_engine-65.0.2 → howso_engine-65.0.3}/bin/build.sh +0 -0
  23. {howso_engine-65.0.2 → howso_engine-65.0.3}/config/latest-mt-debug-howso.yml +0 -0
  24. {howso_engine-65.0.2 → howso_engine-65.0.3}/config/latest-mt-howso.yml +0 -0
  25. {howso_engine-65.0.2 → howso_engine-65.0.3}/config/latest-mt-noavx-traces-howso.yml +0 -0
  26. {howso_engine-65.0.2 → howso_engine-65.0.3}/config/latest-mt-traces-howso.yml +0 -0
  27. {howso_engine-65.0.2 → howso_engine-65.0.3}/config/latest-st-debug-howso.yml +0 -0
  28. {howso_engine-65.0.2 → howso_engine-65.0.3}/config/latest-st-howso.yml +0 -0
  29. {howso_engine-65.0.2 → howso_engine-65.0.3}/config/latest-st-traces-howso.yml +0 -0
  30. {howso_engine-65.0.2 → howso_engine-65.0.3}/config/powershell/Download-Tzdata.ps1 +0 -0
  31. {howso_engine-65.0.2 → howso_engine-65.0.3}/config/powershell/Helper-Functions.ps1 +0 -0
  32. {howso_engine-65.0.2 → howso_engine-65.0.3}/hatch.toml +0 -0
  33. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/__main__.py +0 -0
  34. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/client/__init__.py +0 -0
  35. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/client/api.py +0 -0
  36. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/client/base.py +0 -0
  37. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/client/cache.py +0 -0
  38. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/client/client.py +0 -0
  39. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/client/configuration.py +0 -0
  40. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/client/exceptions.py +0 -0
  41. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/client/feature_flags.py +0 -0
  42. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/client/pandas/__init__.py +0 -0
  43. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/client/pandas/client.py +0 -0
  44. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/client/protocols.py +0 -0
  45. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/client/schemas/__init__.py +0 -0
  46. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/client/schemas/aggregate_reaction.py +0 -0
  47. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/client/schemas/base.py +0 -0
  48. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/client/schemas/group_reaction.py +0 -0
  49. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/client/schemas/project.py +0 -0
  50. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/client/schemas/reaction.py +0 -0
  51. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/client/schemas/session.py +0 -0
  52. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/client/schemas/trainee.py +0 -0
  53. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/client/schemas/version.py +0 -0
  54. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/client/typing.py +0 -0
  55. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/direct/__init__.py +0 -0
  56. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/direct/_utilities.py +0 -0
  57. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/direct/client.py +0 -0
  58. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/direct/schemas/__init__.py +0 -0
  59. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/direct/schemas/trainee.py +0 -0
  60. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/engine/__init__.py +0 -0
  61. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/engine/client.py +0 -0
  62. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/engine/project.py +0 -0
  63. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/engine/session.py +0 -0
  64. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/engine/trainee.py +0 -0
  65. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/howso-engine/howso.caml +0 -0
  66. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/howso-engine/migrations/migrations.caml +0 -0
  67. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/howso-engine/version.json +0 -0
  68. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/scikit/__init__.py +0 -0
  69. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/scikit/scikit.py +0 -0
  70. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/utilities/__init__.py +0 -0
  71. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/utilities/decorators.py +0 -0
  72. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/utilities/fanout_features.py +0 -0
  73. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/utilities/feature_attributes/__init__.py +0 -0
  74. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/utilities/feature_attributes/base.py +0 -0
  75. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/utilities/feature_attributes/infer_feature_attributes.py +0 -0
  76. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/utilities/feature_attributes/pandas.py +0 -0
  77. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/utilities/feature_attributes/protocols.py +0 -0
  78. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/utilities/feature_attributes/relational.py +0 -0
  79. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/utilities/feature_attributes/serializers.py +0 -0
  80. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/utilities/feature_attributes/suggestions.py +0 -0
  81. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/utilities/feature_attributes/time_series.py +0 -0
  82. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/utilities/feature_attributes/warnings.py +0 -0
  83. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/utilities/features.py +0 -0
  84. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/utilities/installation_verification.py +0 -0
  85. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/utilities/internals.py +0 -0
  86. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/utilities/json_wrapper.py +0 -0
  87. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/utilities/locale.py +0 -0
  88. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/utilities/monitors.py +0 -0
  89. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/utilities/posix.py +0 -0
  90. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/utilities/random.py +0 -0
  91. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/utilities/reaction.py +0 -0
  92. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/utilities/testing.py +0 -0
  93. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/utilities/tokenizing.py +0 -0
  94. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso/utilities/utilities.py +0 -0
  95. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso_engine.egg-info/SOURCES.txt +0 -0
  96. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso_engine.egg-info/dependency_links.txt +0 -0
  97. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso_engine.egg-info/entry_points.txt +0 -0
  98. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso_engine.egg-info/requires.txt +0 -0
  99. {howso_engine-65.0.2 → howso_engine-65.0.3}/howso_engine.egg-info/top_level.txt +0 -0
  100. {howso_engine-65.0.2 → howso_engine-65.0.3}/pyproject.toml +0 -0
  101. {howso_engine-65.0.2 → howso_engine-65.0.3}/pyrightconfig.json +0 -0
  102. {howso_engine-65.0.2 → howso_engine-65.0.3}/requirements-3.11-dev.txt +0 -0
  103. {howso_engine-65.0.2 → howso_engine-65.0.3}/requirements-3.11.txt +0 -0
  104. {howso_engine-65.0.2 → howso_engine-65.0.3}/requirements-3.12-dev.txt +0 -0
  105. {howso_engine-65.0.2 → howso_engine-65.0.3}/requirements-3.12.txt +0 -0
  106. {howso_engine-65.0.2 → howso_engine-65.0.3}/requirements-3.13-dev.txt +0 -0
  107. {howso_engine-65.0.2 → howso_engine-65.0.3}/requirements-3.13.txt +0 -0
  108. {howso_engine-65.0.2 → howso_engine-65.0.3}/requirements-3.14-dev.txt +0 -0
  109. {howso_engine-65.0.2 → howso_engine-65.0.3}/requirements-3.14.txt +0 -0
  110. {howso_engine-65.0.2 → howso_engine-65.0.3}/ruff.toml +0 -0
  111. {howso_engine-65.0.2 → howso_engine-65.0.3}/setup.cfg +0 -0
  112. {howso_engine-65.0.2 → howso_engine-65.0.3}/version.json +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: howso-engine
3
- Version: 65.0.2
3
+ Version: 65.0.3
4
4
  Summary: The Howso Engine™ is a natively and fully explainable ML engine, serving as an alternative to black box AI neural networks.
5
5
  Author: Howso Incorporated
6
6
  Author-email: support@howso.com
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from collections.abc import Collection, Iterable, Mapping
4
+ from contextlib import suppress
4
5
  import datetime
5
6
  from datetime import time, timedelta
6
7
  import decimal
@@ -148,21 +149,55 @@ class InferFeatureAttributesAbstractData(InferFeatureAttributesBase):
148
149
 
149
150
  return any([c['column_names'] == [feature_name] for c in uniques])
150
151
 
152
+ def _get_column_dtype(self, feature_name: str) -> t.Any:
153
+ """
154
+ Return a feature's dtype, coercing a string representation to a real dtype.
155
+
156
+ Some ADCs report dtypes as their string representation. Parse those
157
+ with Pandas rather than NumPy: NumPy has no concept of a time zone, so
158
+ `np.dtype` rejects strings like "datetime64[ns, UTC]" outright. A dtype
159
+ left as a string makes every `DatetimeTZDtype` and `tz` check below
160
+ read as though the column were tz-naive, which both misclassifies a
161
+ tz-aware column whose first value falls at midnight as date-only and
162
+ drops the "%z" from its inferred format.
163
+ """
164
+ dtype = self.data.get_column_dtype(feature_name)
165
+ if isinstance(dtype, str):
166
+ # Not every string names a dtype Pandas recognizes; leave those as-is.
167
+ with suppress(TypeError):
168
+ dtype = pd.api.types.pandas_dtype(dtype)
169
+ return dtype
170
+
171
+ def _is_datetime_date_only(self, feature_name: str, max_rows: int = 1000) -> bool:
172
+ """
173
+ Return whether every sampled value of a datetime feature falls at midnight.
174
+
175
+ A date-only column deserialized into a datetime dtype carries
176
+ a midnight time component on every row. Deciding that from a single
177
+ value misreads any column that merely starts at midnight -- hourly
178
+ telemetry beginning at 00:00, for instance -- and silently discards its
179
+ time component. Scanning stops at the first value that proves the
180
+ column carries a time, so the common case costs one chunk at most.
181
+ """
182
+ seen = 0
183
+ for chunk in self.data.yield_chunk(maintain_natural_order=True):
184
+ column = pd.to_datetime(chunk[feature_name], errors="coerce").dropna()
185
+ if column.empty:
186
+ continue
187
+ if (column != column.dt.normalize()).any():
188
+ return False
189
+ seen += len(column)
190
+ if seen >= max_rows:
191
+ break
192
+ # No non-null values observed: nothing indicates a time component.
193
+ return True
194
+
151
195
  def _get_feature_type(self, feature_name: str # noqa: C901
152
196
  ) -> tuple[FeatureType | None, dict | None]:
153
197
  # Import this here to avoid circular import
154
198
  from howso.client.exceptions import HowsoError
155
199
 
156
- dtype = self.data.get_column_dtype(feature_name)
157
-
158
- # Some ADCs will return the string representation of the dtype.
159
- # Convert to NumPy DType so that we can access attributes like 'itemsize.'
160
- if isinstance(dtype, str):
161
- try:
162
- dtype = np.dtype(dtype)
163
- except Exception:
164
- # If there is a problem, leave as-is
165
- pass
200
+ dtype = self._get_column_dtype(feature_name)
166
201
  try:
167
202
  if is_float_dtype(dtype):
168
203
  typing_info = {}
@@ -191,20 +226,40 @@ class InferFeatureAttributesAbstractData(InferFeatureAttributesBase):
191
226
  return FeatureType.DATE, {}
192
227
  # datetime64[Y/M/D] only supported by Pandas > 3.0; need more checks for date-only columns
193
228
  first_non_null = self._get_first_non_null(feature_name)
194
- if isinstance(first_non_null, datetime.date) and not isinstance(first_non_null, pd.Timestamp):
195
- # Timestamp objects are instances of datetime.date/time, but only return 'DATE' here if
196
- # it's *not* a Timestamp as there may be tzinfo we should inspect.
229
+ if (isinstance(first_non_null, datetime.date)
230
+ and not isinstance(first_non_null, datetime.datetime)):
231
+ # `datetime.datetime` subclasses `datetime.date` (and
232
+ # `pd.Timestamp` subclasses `datetime.datetime`), so only a
233
+ # value that is a date and not a datetime is strictly
234
+ # date-only. Excluding just `pd.Timestamp` here let the
235
+ # plain `datetime.datetime` objects that several connectors
236
+ # return be misread as dates. Datetimes fall through so
237
+ # their time and tzinfo are inspected below.
197
238
  return FeatureType.DATE, {}
198
- # Date-only Timestamp objects in Pandas will have a default time of midnight
199
- if (isinstance(first_non_null, pd.Timestamp)
239
+ # Date-only Timestamp objects in Pandas will have a default time of
240
+ # midnight. Confirm that holds across the column rather than for
241
+ # just this one value, so a timed column that happens to start at
242
+ # midnight is not demoted to a date.
243
+ if (isinstance(first_non_null, datetime.datetime)
200
244
  and first_non_null.time() == datetime.time(0, 0, 0)
201
245
  and (not hasattr(dtype, "tz") or not dtype.tz)
246
+ and self._is_datetime_date_only(feature_name)
202
247
  ):
248
+ # `datetime.datetime` rather than `pd.Timestamp`: several
249
+ # connectors hand back plain datetimes, and testing only
250
+ # for Timestamp let a genuine date-only column from
251
+ # those sources fall through as a datetime.
203
252
  return FeatureType.DATE, {}
204
253
  if isinstance(dtype, pd.DatetimeTZDtype):
205
254
  # If using a named time zone capture it, otherwise
206
255
  # rely on the offset in the iso8601 format
207
256
  tz_name = getattr(dtype.tz, 'key', None) or getattr(dtype.tz, 'zone', None)
257
+ if tz_name is None and dtype.tz is datetime.timezone.utc:
258
+ # Parsing a dtype *string* yields stdlib UTC, which
259
+ # exposes neither `key` nor `zone` the way `zoneinfo`
260
+ # and `pytz` zones do. It is still a named zone, unlike
261
+ # the fixed offsets that deliberately fall through here.
262
+ tz_name = 'UTC'
208
263
  if tz_name:
209
264
  typing_info['timezone'] = tz_name
210
265
  return FeatureType.DATETIME, typing_info
@@ -660,7 +715,7 @@ class InferFeatureAttributesAbstractData(InferFeatureAttributesBase):
660
715
  'type': 'nominal',
661
716
  }
662
717
 
663
- dtype = self.data.get_column_dtype(feature_name)
718
+ dtype = self._get_column_dtype(feature_name)
664
719
  # Pandas datetime64 columns will be deserialized to ISO8601
665
720
  dt_format = ISO_8601_FORMAT
666
721
  if isinstance(dtype, pd.DatetimeTZDtype):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: howso-engine
3
- Version: 65.0.2
3
+ Version: 65.0.3
4
4
  Summary: The Howso Engine™ is a natively and fully explainable ML engine, serving as an alternative to black box AI neural networks.
5
5
  Author: Howso Incorporated
6
6
  Author-email: support@howso.com
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes