{"record":{"id":"fde1dd5df95ba1c7","repo":"apache/beam","slug":"string-functions-are-not-yet-supported-in-transform","errorCode":null,"errorMessage":"String functions are not yet supported in transform.","messagePattern":"String functions are not yet supported in transform\\.","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/dataframe/frames.py","lineNumber":4395,"sourceCode":"            [self._ungrouped_with_index],\n            proxy=proxy,\n            requires_partition_by=partitionings.Index(grouping_indexes +\n                                                      grouping_columns),\n            preserves_partition_by=partitionings.Index(grouping_indexes)))\n\n\n  @frame_base.with_docs_from(DataFrameGroupBy)\n  def transform(self, fn, *args, **kwargs):\n    \"\"\"Note that ``func`` will be called once during pipeline construction time\n    with an empty pandas object, so take care if ``func`` has a side effect.\n\n    When called with an empty pandas object, ``func`` is expected to return an\n    object of the same type as what will be returned when the pipeline is\n    processing actual data. The result should have the same type and name (for\n    a Series) or column types and names (for a DataFrame) as the actual\n    results.\"\"\"\n    if not callable(fn):\n      raise NotImplementedError(\n          \"String functions are not yet supported in transform.\")\n\n    if self._grouping_columns and not self._projection:\n      grouping_columns = self._grouping_columns\n      def fn_wrapper(x, *args, **kwargs):\n        x = x.droplevel(grouping_columns)\n        return fn(x, *args, **kwargs)\n    else:\n      fn_wrapper = fn\n\n    project = _maybe_project_func(self._projection)\n    group_keys = self._group_keys\n\n    # pandas cannot execute fn to determine the right proxy.\n    # We run user fn on a proxy here to detect the return type and generate the\n    # proxy.\n    result = fn_wrapper(project(self._ungrouped_with_index.proxy()))\n    parent_frame = self._ungrouped.args()[0].proxy()","sourceCodeStart":4377,"sourceCodeEnd":4413,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/dataframe/frames.py#L4377-L4413","documentation":"Apache Beam's DeferredGroupBy.transform() requires `fn` to be a Python callable. When a string like 'sum' or a non-callable is passed (as pandas allows in some contexts), Beam cannot build the deferred transformation and raises NotImplementedError with the 'String functions are not yet supported in transform.' message, even if the argument is simply any non-callable.","triggerScenarios":"Calling df.groupby(...).transform('some_string') or transform(anything_not_callable) on a Beam deferred DataFrame; string aggregation-style names accepted by pandas GroupBy.transform are not supported here.","commonSituations":"Porting existing pandas pipeline code to Beam where transform was invoked with a string function name; confusing GroupBy.transform with GroupBy.agg, which does accept string aggregation names.","solutions":["Pass a callable, e.g. df.groupby('k').transform(lambda s: s - s.mean()) instead of a string.","If a string aggregation is what you need, use groupby(...).agg(...) which supports string aggregation names via _handle_agg_function.","Check the argument is callable before calling: isinstance(fn, collections.abc.Callable)."],"exampleFix":"# before\ndf.groupby('k').transform('mean')\n# after\ndf.groupby('k').transform(lambda s: s.mean())","handlingStrategy":"type-guard","validationCode":"import collections.abc\nif not isinstance(fn, collections.abc.Callable):\n    raise TypeError('transform requires a callable, got %r' % (fn,))","typeGuard":"def is_callable_fn(fn) -> bool:\n    return isinstance(fn, collections.abc.Callable)","tryCatchPattern":"try:\n    out = beam_df.groupby('k').transform(fn)\nexcept NotImplementedError as e:\n    if 'not yet supported in transform' in str(e):\n        out = beam_df.groupby('k').agg(fn if callable(fn) else lambda s: getattr(s, fn)())","preventionTips":["Always pass lambdas or named functions to Beam transform, never string names.","Use agg for string aggregations; reserve transform for callables.","Add a unit test exercising each transform call at pipeline-construction time."],"tags":["apache-beam","dataframe","not-implemented","callable-required"],"backgroundTag":"method-not-implemented","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}