Forum Discussion

michael_muell's avatar
michael_muell
New Member
1 year ago
Solved

UDF Connection to Lakehouse does not work

Hi all, 

 

I'm trying to get a UDF to work that creates a file in the lakehouse. I saw that there is a sample that almost achieves what I want. Unfortunately it does not work when I connect my lakehouse. I get the following error: 

Running another sample snippet connecting with a warehouse item works perfectly fine. It seems to be some problem specifically with the lakehouse connection.

 

Can anyone help?  

{
"functionName": "write_csv_file_in_lakehouse",
"invocationId": "00000000-0000-0000-0000-000000000000",
"status": "Failed",
"errors": [
{
"errorCode": "WorkloadException",
"subErrorCode": "NotFound",
"message": "User data function: 'write_csv_file_in_lakehouse' invocation failed."
}
]
}

The connection to the datasource is setup: 

 


This is the code I'm running: 

import datetime
import fabric.functions as fn
import logging

udf = fn.UserDataFunctions()

import pandas as pd
import datetime
# Select 'Manage connections' and add a connection to a Lakehouse.
#Replace the alias "<My Lakehouse alias>" with your connection alias.
@udf.connection(argName="myLakehouse", alias="dateiupload")
@udf.function()
def write_csv_file_in_lakehouse(myLakehouse: fn.FabricLakehouseClient, employees: list)-> str:

    logging.info('test')
    '''
    Description: Write employee data to lakehouse as timestamped CSV file using pandas.
   
    Args:
        myLakehouse (fn.FabricLakehouseClient): Fabric lakehouse connection.
        employees (list): List of employee records as [ID, Name, DeptID] arrays.
   
    Returns:
        str: Confirmation message with filename and viewing instructions.
       
    Example:
        employees = [[1,"John Smith", 31], [2,"Kayla Jones", 33]]
        Creates "Employees1672531200.csv" in lakehouse
    '''
   
    csvFileName = "Employees" + str(round(datetime.datetime.now().timestamp())) + ".csv"
       
    # Convert the data to a DataFrame
    df = pd.DataFrame(employees, columns=['ID','EmpName', 'DepID'])
    # Write the DataFrame to a CSV file
    csv_string = df.to_csv(index=False)
       
    # Upload the CSV file to the Lakehouse
    connection = myLakehouse.connectToFiles()
    csvFile = connection.get_file_client(csvFileName)  
   
    csvFile.upload_data(csv_string, overwrite=True)

    csvFile.close()
    connection.close()
    return f"File {csvFileName} was written to the Lakehouse. Open the Lakehouse in https://app.fabric.microsoft.com to view the files"
  • Hi michael_muell ,

    Please use the below code:

    import pandas as pd

    import datetime

    import fabric.functions as fn

    import logging

     

    udf = fn.UserDataFunctions()

     

    @udf.connection(argName="myLakehouse", alias="LH123")

    @udf.function()

    def write_csv_file_in_lakehouse(myLakehouse: fn.FabricLakehouseClient, employees: list) -> str:

        """

        Writes employee data to Lakehouse Files as a CSV.

        """

       

        logging.info("Starting CSV file write to Lakehouse")

     

        # Create timestamped filename

        csvFileName = "Employees_" + str(round(datetime.datetime.now().timestamp())) + ".csv"

       

        # Create DataFrame and CSV string

        df = pd.DataFrame(employees, columns=["ID", "EmpName", "DepID"])

        csv_string = df.to_csv(index=False)

        csv_bytes = csv_string.encode("utf-8")  # Convert string to bytes

     

        # Connect to Lakehouse Files and upload

        connection = myLakehouse.connectToFiles()

        file_client = connection.get_file_client(csvFileName)

        file_client.upload_data(csv_bytes, overwrite=True)

     

        # Close connections

        file_client.close()

        connection.close()

     

        return f"File '{csvFileName}' was uploaded successfully."

     

    Add Pandas library as shown below:

     

    To test this I have created pipeline and it worked for me:

     

    File got created in Lakehouse as shown below:

     

     

    Thank you.

     

7 Replies

  • v-venuppu's avatar
    v-venuppu
    Community Support

    Hi michael_muell ,

    Please use the below code:

    import pandas as pd

    import datetime

    import fabric.functions as fn

    import logging

     

    udf = fn.UserDataFunctions()

     

    @udf.connection(argName="myLakehouse", alias="LH123")

    @udf.function()

    def write_csv_file_in_lakehouse(myLakehouse: fn.FabricLakehouseClient, employees: list) -> str:

        """

        Writes employee data to Lakehouse Files as a CSV.

        """

       

        logging.info("Starting CSV file write to Lakehouse")

     

        # Create timestamped filename

        csvFileName = "Employees_" + str(round(datetime.datetime.now().timestamp())) + ".csv"

       

        # Create DataFrame and CSV string

        df = pd.DataFrame(employees, columns=["ID", "EmpName", "DepID"])

        csv_string = df.to_csv(index=False)

        csv_bytes = csv_string.encode("utf-8")  # Convert string to bytes

     

        # Connect to Lakehouse Files and upload

        connection = myLakehouse.connectToFiles()

        file_client = connection.get_file_client(csvFileName)

        file_client.upload_data(csv_bytes, overwrite=True)

     

        # Close connections

        file_client.close()

        connection.close()

     

        return f"File '{csvFileName}' was uploaded successfully."

     

    Add Pandas library as shown below:

     

    To test this I have created pipeline and it worked for me:

     

    File got created in Lakehouse as shown below:

     

     

    Thank you.

     

    • jasonhuang5750's avatar
      jasonhuang5750
      New Member

      Hi same issue here and I used your code - did not work. 

      I am testing Microsoft Fabric User Data Functions in Develop mode and keep getting the following error even when using the official/default-style sample code for writing a CSV file to a Lakehouse.

      The error happens at function registration time on this line:

      ```python
      @udf.function()
      ```

      It happens before the function is executed and before the UI test input is submitted.

      **Code used**

      We are using this code exactly, only changing the Lakehouse alias to our environment:

      ```python
      import datetime
      import logging

      import fabric.functions as fn
      import pandas as pd


      udf = fn.UserDataFunctions()


      @udf.connection(argName="myLakehouse", alias="dltranslyticalpoc")
      @udf.function()
      def write_csv_file_in_lakehouse(
      myLakehouse: fn.FabricLakehouseClient,
      employees: list,
      ) -> str:
      """
      Writes employee data to Lakehouse Files as a CSV.
      """
      logging.info("Starting CSV file write to Lakehouse")

      csv_file_name = (
      "Employees_" + str(round(datetime.datetime.now().timestamp())) + ".csv"
      )

      df = pd.DataFrame(employees, columns=["ID", "EmpName", "DepID"])
      csv_string = df.to_csv(index=False)
      csv_bytes = csv_string.encode("utf-8")

      connection = myLakehouse.connectToFiles()
      file_client = connection.get_file_client(csv_file_name)
      file_client.upload_data(csv_bytes, overwrite=True)

      file_client.close()
      connection.close()

      return f"File '{csv_file_name}' was uploaded successfully."
      ```

      We also tried our original Fabric UDF code using a Lakehouse connection and request context:

      ```python
      import fabric.functions as fn

      udf = fn.UserDataFunctions()


      @udf.connection(argName="retailLakehouse", alias="dltranslyticalpoc")
      @udf.context(argName="requestContext")
      @udf.function()
      def submitReplenishment(
      retailLakehouse: fn.FabricLakehouseClient,
      requestContext: fn.UserDataFunctionContext,
      requestId: int,
      storeKey: int,
      productKey: int,
      actionType: str = "Replenish stock",
      priority: str = "High",
      triggerValue: int = 0,
      thresholdValue: int = 10,
      suggestedQuantity: int = 0,
      comment: str = "",
      ) -> str:
      return "OK"
      ```

      Both versions fail with the same error.

      **Error**

      ```text
      AttributeError: 'str' object has no attribute '__name__'
      ```

      Traceback excerpt:

      ```text
      File ~/.local/lib/python3.12/site-packages/fabric/internal/decorators/configure_fabric_function_builder.py:97,
      in configure_fabric_function_builder.<locals>.decorator(func)
      fb = udf._validate_type(user_func)
      udf._function_builders.append(fb)
      _build_spec(user_func, udfParams, functions_metadata, func.__annotations__)

      File ~/.local/lib/python3.12/site-packages/fabric/internal/decorators/configure_fabric_function_builder.py:195,
      in _build_spec(user_func, udfParams, functions_metadata, func_annotations)
      multipart_req, binary_res, multipart_req_model = get_multipart_content(user_func.__name__, udfParams)

      File ~/.local/lib/python3.12/site-packages/fabric/internal/utils/spec_utils.py:18,
      in get_multipart_content.<locals>.<lambda>(param)
      lambda param: param.annotation.__name__ == "DataFrame"
      or param.annotation.__name__ == "Series",

      AttributeError: 'str' object has no attribute '__name__'
      ```

      **What we expected**

      The function should register successfully in Fabric UDF Develop mode, then allow us to test it with a list parameter such as:

      ```json
      [[12345, "chris", 10]]
      ```

      **What actually happens**

      The function fails during decoration/registration at `@udf.function()`. The error occurs before the local test UI or Lakehouse write logic is reached.

      **Question**

      Is this a known issue with the Fabric UDF Python SDK, especially on Python 3.12, where function annotations may be interpreted as strings?

      The traceback suggests Fabric is doing this internally:

      ```python
      param.annotation.__name__
      ```

      but at least one annotation appears to be a string, so the SDK raises:

      ```text
      'str' object has no attribute '__name__'
      ```

      Has anyone else hit this with the official/default Lakehouse CSV sample? Is there a required package version, runtime setting, notebook reset step, or workaround to force annotations to be evaluated as actual Python types rather than strings? 

      Please also note alias connections and dependencies are all set up

      Any guidance would be appreciated.

  • v-venuppu's avatar
    v-venuppu
    Community Support

    Hi michael_muell ,

    Thank you for reaching out to Microsoft Fabric Community.

    The issue is likely caused by a mismatch in the Lakehouse connection alias or trying to upload string data using the wrong method. Make sure your UDF connection alias (dateiupload) matches exactly what’s set in the UDF UI. Also, replace upload_data with upload_text since you're uploading a CSV string, not binary data. Here's the fix:
    csvFile.upload_text(csv_string, overwrite=True)

     

    Here's a documentation for your reference:
    fabric.functions.FabricLakehouseClient class | Microsoft Learn

     

    Thank you.

     

    • michael_muell's avatar
      michael_muell
      New Member

      Hi v-venuppu 
      Thanks for the reply. I triple checked and the alias is exactly matching. 
      Also the code change did not help. The problem is the connection to the lakehouse. 

       

      Any other suggestions?

      Best regards 
      Michael

       

      • usmanFawad's avatar
        usmanFawad
        New Member

        If you are working in production environment or a corporate setup, usually all the communication between fabric items is set to be private. In that case with having all correct setup you still face proxy 400 error. If this is the case then you have to consult with Admins to whitelist or allow comunication between UDF and lakehouse.

  • This is how it works:
    Python (Pandas ) -- > Apache Spark ( Data Lake ) --> Delta Lake ( Data Lakehouse ) 

      # Convert the data to a DataFrame
        df = pd.DataFrame(employees, columns=['ID','EmpName''DepID'])
    # Covert DataFrame to Data Lake
    sdf = spark.createDataFrame(df)
    or 
    sdf = spark.read.csv("Employees_" + str(round(datetime.datetime.now().timestamp())) + ".csv",header = True)

     

    # Writing a DataFrame to Delta format
    sdf.write.format("delta").option("overwrite").saveAsTable("DimEmployees")

     

    You are missing Spark Dataframe ( Data Lake ).