Skip to content

Conversation

gitgud5000
Copy link

Pull Request Description

This PR resolves an issue in Featuretools where using distributed>=2024.8.2 causes a crash due to an incorrect instantiation of Future without passing a client instance.

๐Ÿ”ง Bug Description

As reported by @BohdanBilonoh, the latest Featuretools release fails when used with Dask versions >=2024.8.2. The issue occurs due to the following line in calculate_feature_matrix.py:

https://github.com/kedro-org/kedro-plugins/blob/552b973a256c0f4a9f96e36feb70f4fc15fb371b/kedro-datasets/kedro_datasets/tensorflow/tensorflow_model_dataset.py#L168-L172

num_scattered_workers = len(
client.who_has([Future(es_token)]).get(es_token, []),
)

The above code leads to an AttributeError because Dask's API now requires Future to be explicitly associated with a client instance.

Fix Implementation

Updating the Future instantiation to include the client resolves the issue:

num_scattered_workers = len(
    client.who_has([Future(es_token, client=client)]).get(es_token, []),
)

Testing & Verification

  • Successfully tested fix with featuretools==1.31.0 and distributed==2025.2.0.
  • Verified Featuretools runs successfully with the modified code.
  • No breaking changes introduced.

References & Related Issues

  • Issue: #2733

  • Related Dask Function: [distributed.client.py#L322](https://github.com/dask/distributed/blob/7ab72493b6df194bf6cb86ec1c4ac7c27cf1b3a1/distributed/client.py#L322)

Error

View log output
โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Traceback (most recent call last) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ in <module>:4                                                                                    โ”‚
โ”‚                                                                                                  โ”‚
โ”‚   1 FEATURE_ONLY = True                                                                         โ”‚
โ”‚   2 FEATURE_ONLY = False                                                                        โ”‚
โ”‚    3 # columns_to_ignore = ["ID_UEN"]                                                            โ”‚
โ”‚ โฑ  4 out = ft.dfs(                                                                               โ”‚
โ”‚   5 โ”‚   entityset=es,                                                                           โ”‚
โ”‚   6 โ”‚   cutoff_time=cutoff_times,                                                               โ”‚
โ”‚   7 โ”‚   cutoff_time_in_index=True,                                                              โ”‚
โ”‚                                                                                                  โ”‚
โ”‚ /anaconda/envs/fraude_mp_env/lib/python3.12/site-packages/featuretools/utils/entry_point.py:39   โ”‚
โ”‚ in function_wrapper                                                                              โ”‚
โ”‚                                                                                                  โ”‚
โ”‚   36 โ”‚   โ”‚   โ”‚   โ”‚   # send error                                                                โ”‚
โ”‚   37 โ”‚   โ”‚   โ”‚   โ”‚   for ep in entry_points:                                                     โ”‚
โ”‚   38 โ”‚   โ”‚   โ”‚   โ”‚   โ”‚   ep.on_error(error=e, runtime=runtime)                                   โ”‚
โ”‚ โฑ 39 โ”‚   โ”‚   โ”‚   โ”‚   raise e                                                                     โ”‚
โ”‚   40 โ”‚   โ”‚   โ”‚                                                                                   โ”‚
โ”‚   41 โ”‚   โ”‚   โ”‚   # send return value                                                             โ”‚
โ”‚   42 โ”‚   โ”‚   โ”‚   for ep in entry_points:                                                         โ”‚
โ”‚                                                                                                  โ”‚
โ”‚ /anaconda/envs/fraude_mp_env/lib/python3.12/site-packages/featuretools/utils/entry_point.py:32   โ”‚
โ”‚ in function_wrapper                                                                              โ”‚
โ”‚                                                                                                  โ”‚
โ”‚   29 โ”‚   โ”‚   โ”‚   try:                                                                            โ”‚
โ”‚   30 โ”‚   โ”‚   โ”‚   โ”‚   # call function                                                             โ”‚
โ”‚   31 โ”‚   โ”‚   โ”‚   โ”‚   start = time.time()                                                         โ”‚
โ”‚ โฑ 32 โ”‚   โ”‚   โ”‚   โ”‚   return_value = func(*args, **kwargs)                                        โ”‚
โ”‚   33 โ”‚   โ”‚   โ”‚   โ”‚   runtime = time.time() - start                                               โ”‚
โ”‚   34 โ”‚   โ”‚   โ”‚   except Exception as e:                                                          โ”‚
โ”‚   35 โ”‚   โ”‚   โ”‚   โ”‚   runtime = time.time() - start                                               โ”‚
โ”‚                                                                                                  โ”‚
โ”‚ /anaconda/envs/fraude_mp_env/lib/python3.12/site-packages/featuretools/synthesis/dfs.py:283 in   โ”‚
โ”‚ dfs                                                                                              โ”‚
โ”‚                                                                                                  โ”‚
โ”‚   280 โ”‚   โ”‚   features != []                                                                     โ”‚
โ”‚   281 โ”‚   ), "No features can be generated from the specified primitives. Please make sure the   โ”‚
โ”‚   282 โ”‚                                                                                          โ”‚
โ”‚ โฑ 283 โ”‚   feature_matrix = calculate_feature_matrix(                                             โ”‚
โ”‚   284 โ”‚   โ”‚   features,                                                                          โ”‚
โ”‚   285 โ”‚   โ”‚   entityset=entityset,                                                               โ”‚
โ”‚   286 โ”‚   โ”‚   cutoff_time=cutoff_time,                                                           โ”‚
โ”‚                                                                                                  โ”‚
โ”‚ /anaconda/envs/fraude_mp_env/lib/python3.12/site-packages/featuretools/computational_backends/ca โ”‚
โ”‚ lculate_feature_matrix.py:298 in calculate_feature_matrix                                        โ”‚
โ”‚                                                                                                  โ”‚
โ”‚   295 โ”‚                                                                                          โ”‚
โ”‚   296 โ”‚   with make_tqdm_iterator(**tqdm_options) as progress_bar:                               โ”‚
โ”‚   297 โ”‚   โ”‚   if n_jobs != 1 or dask_kwargs is not None:                                         โ”‚
โ”‚ โฑ 298 โ”‚   โ”‚   โ”‚   feature_matrix = parallel_calculate_chunks(                                    โ”‚
โ”‚   299 โ”‚   โ”‚   โ”‚   โ”‚   cutoff_time=cutoff_time_to_pass,                                           โ”‚
โ”‚   300 โ”‚   โ”‚   โ”‚   โ”‚   chunk_size=chunk_size,                                                     โ”‚
โ”‚   301 โ”‚   โ”‚   โ”‚   โ”‚   feature_set=feature_set,                                                   โ”‚
โ”‚                                                                                                  โ”‚
โ”‚ /anaconda/envs/fraude_mp_env/lib/python3.12/site-packages/featuretools/computational_backends/ca โ”‚
โ”‚ lculate_feature_matrix.py:747 in parallel_calculate_chunks                                       โ”‚
โ”‚                                                                                                  โ”‚
โ”‚   744 โ”‚   โ”‚   _saved_features = client.scatter(pickled_feats)                                    โ”‚
โ”‚   745 โ”‚   โ”‚   client.replicate([_es, _saved_features])                                           โ”‚
โ”‚   746 โ”‚   โ”‚   num_scattered_workers = len(                                                       โ”‚
โ”‚ โฑ 747 โ”‚   โ”‚   โ”‚   client.who_has([Future(es_token)]).get(es_token, []),                          โ”‚
โ”‚   748 โ”‚   โ”‚   )                                                                                  โ”‚
โ”‚   749 โ”‚   โ”‚   num_workers = len(client.scheduler_info()["workers"].values())                     โ”‚
โ”‚   750                                                                                            โ”‚
โ”‚                                                                                                  โ”‚
โ”‚ /anaconda/envs/fraude_mp_env/lib/python3.12/site-packages/distributed/client.py:4203 in who_has  โ”‚
โ”‚                                                                                                  โ”‚
โ”‚   4200 โ”‚   โ”‚   Client.nthreads                                                                   โ”‚
โ”‚   4201 โ”‚   โ”‚   """                                                                               โ”‚
โ”‚   4202 โ”‚   โ”‚   if futures is not None:                                                           โ”‚
โ”‚ โฑ 4203 โ”‚   โ”‚   โ”‚   futures = self.futures_of(futures)                                            โ”‚
โ”‚   4204 โ”‚   โ”‚   โ”‚   keys = list({f.key for f in futures})                                         โ”‚
โ”‚   4205 โ”‚   โ”‚   else:                                                                             โ”‚
โ”‚   4206 โ”‚   โ”‚   โ”‚   keys = None                                                                   โ”‚
โ”‚                                                                                                  โ”‚
โ”‚ /anaconda/envs/fraude_mp_env/lib/python3.12/site-packages/distributed/client.py:4912 in          โ”‚
โ”‚ futures_of                                                                                       โ”‚
โ”‚                                                                                                  โ”‚
โ”‚   4909 โ”‚   โ”‚   futures : tuple                                                                   โ”‚
โ”‚   4910 โ”‚   โ”‚   โ”‚   The futures                                                                   โ”‚
โ”‚   4911 โ”‚   โ”‚   """                                                                               โ”‚
โ”‚ โฑ 4912 โ”‚   โ”‚   return futures_of(futures, client=self)                                           โ”‚
โ”‚   4913 โ”‚                                                                                         โ”‚
โ”‚   4914 โ”‚   @classmethod                                                                          โ”‚
โ”‚   4915 โ”‚   def _expand_key(cls, k):                                                              โ”‚
โ”‚                                                                                                  โ”‚
โ”‚ /anaconda/envs/fraude_mp_env/lib/python3.12/site-packages/distributed/client.py:6132 in          โ”‚
โ”‚ futures_of                                                                                       โ”‚
โ”‚                                                                                                  โ”‚
โ”‚   6129 โ”‚   if client is not None:                                                                โ”‚
โ”‚   6130 โ”‚   โ”‚   cancelled_errors = defaultdict(list)                                              โ”‚
โ”‚   6131 โ”‚   โ”‚   for f in futures:                                                                 โ”‚
โ”‚ โฑ 6132 โ”‚   โ”‚   โ”‚   if not f.cancelled():                                                         โ”‚
โ”‚   6133 โ”‚   โ”‚   โ”‚   โ”‚   continue                                                                  โ”‚
โ”‚   6134 โ”‚   โ”‚   โ”‚   exception = f._state.exception                                                โ”‚
โ”‚   6135 โ”‚   โ”‚   โ”‚   assert isinstance(exception, FutureCancelledError)                            โ”‚
โ”‚                                                                                                  โ”‚
โ”‚ /anaconda/envs/fraude_mp_env/lib/python3.12/site-packages/distributed/client.py:520 in cancelled โ”‚
โ”‚                                                                                                  โ”‚
โ”‚   517 โ”‚   โ”‚   bool                                                                              โ”‚
โ”‚   518 โ”‚   โ”‚   โ”‚   True if the future was 'cancelled', otherwise False                           โ”‚
โ”‚   519 โ”‚   โ”‚   """                                                                               โ”‚
โ”‚ โฑ  520 โ”‚   โ”‚   return self._state.status == "cancelled"                                          โ”‚
โ”‚   521 โ”‚                                                                                         โ”‚
โ”‚   522 โ”‚   async def _traceback(self):                                                           โ”‚
โ”‚   523 โ”‚   โ”‚   await self._state.wait()                                                          โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
AttributeError: 'NoneType' object has no attribute 'status'

After creating the pull request: in order to pass the release_notes_updated check you will need to update the "Future Release" section of docs/source/release_notes.rst to include this pull request.

@CLAassistant
Copy link

CLAassistant commented Feb 28, 2025

CLA assistant check
All committers have signed the CLA.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants