【问题标题】:unittest: NameError: name 'dbutils' is not definedunittest:NameError:名称'dbutils'未定义
【发布时间】:2022-04-05 20:37:39
【问题描述】:

如何在不从 .ipynb 文件中导入所有内容的情况下对 Databricks .ipynb 中的 python 文件进行单元测试?

例如,我尝试在我的桌面上使用 VS Code 中的 unittest,我从我的 Azure Databricks 实例中克隆了 .ipynb 文件。

一旦我在本地运行它,我就有一个简单的单元测试来读取 CSV。

问题是,当我尝试从我正在测试的文件 (csv_to_parquet) 加载 --single 函数时,测试会尝试加载整个文件,其中包含本地不可用的项目。具体来说,NameError: name 'dbutils' is not defined

在这个单元测试中我没有使用 dbutils。它只是在尝试加载 csv_to_parquet.py 文件时读取。 我如何告诉单元测试完全忽略它?

从我要测试的文件中导入的唯一函数是:

def readAndShowCSV(sFilePath = 'users.csv/users' ):
  csvFile = spark.read.csv(mountPoint+loadPath+'/' + sFilePath, header=True, inferSchema=True)
  csvFile.show(5)

  return csvFile

那么为什么要调用 Dbutils 呢?

import unittest
import pandas as pd
from csv_to_parquet import readAndShowCSV

# Inherits from unittest.TestCase
# Gives us access to testing capibilities 
class TestParquet(unittest.TestCase):

    def test_readAndShowCSV(self): 

        # Function lives in csv_to_parquet.py
        csvFile = readAndShowCSV() 


# Will run all of our tests
if __name__ == '__main__':
    unittest.main()

【问题讨论】:

    标签: python unit-testing python-unittest databricks


    【解决方案1】:

    我相信 "from [class] import [function]" 只会导入一个函数,但事实并非如此。它导入整个类。

    类中的一个功能是使用 dbutils。

    用户simon_dmorais推荐:

    我会考虑使用 databricks-connect 来执行此操作(它会很慢 用于单元测试)。或从该模块中删除所有 dbutils 引用(或 它导入的子模块)。

    【讨论】:

      【解决方案2】:

      对于无数据块环境中的单元测试,您可以模拟 dbutils。这是一个例子:https://github.com/jugi92/dbutilsMock

      from typing import Dict
      from unittest.mock import MagicMock
      
      class DbutilsMock():
          """Simple Mock for dbutils functions that can be used whenever dbutils is not available, e.g. for unittesting databricks notebooks locally
          
          Use in the following way:
          Before your test initiate the dbutils Mock:
          ```
          from dbutilsmock import DbutilsMock
          dbutils = DbutilsMock(
              widgets_dict={
                  "input_path": "/test/asd",
                  "out_path": "/out/test"
              },
              secrets_dict={
                  "my_scope": {
                      "my_key": "the_real_secret"
                  }
              }
          )
          ```
          Then in your test code the following code should work:
          ```
          >>>dbutils.widgets.text(name="widget_name", defaultValue="defaultWidgetValue", label="WidgetLabel")
          >>>dbutils.widgets.get("input_path")
          '/test/asd'
          >>>dbutils.secrets.get("my_scope", "my_key")
          'the_real_secret'
          ```
          """
          widgets = MagicMock()
          secrets = MagicMock()
      
          def __init__(self, widgets_dict: Dict=None, secrets_dict: Dict=None):
              self.widgets.text = MagicMock(return_value=None)
              
              if widgets_dict:
                  self.widgets._widgets_dict = widgets_dict
                  self.widgets.get = self._dbutils_widgets_get
                  
              if secrets_dict:
                  self.secrets._secrets_dict = secrets_dict
                  self.secrets.get = self._dbutils_secrets_get
          
          def _dbutils_widgets_get(self, text):
              if self.widgets._widgets_dict:
                  return self.widgets._widgets_dict[text]
              else: 
                  return text
      
          def _dbutils_secrets_get(self, scope, key):
              if self.secrets._secrets_dict:
                  return self.secrets._secrets_dict[scope][key]
              else:
                  return f"{scope}_{key}"
      

      【讨论】:

        【解决方案3】:

        Dbutils 是来自 Databricks 的软件包,代表 Databricks 实用程序。 您有 2 个选项: 1. 从源文件中删除它。 2.从这个链接安装pypy形式的Dbutils:https://pypi.org/project/DBUtils/

        【讨论】:

        • 我知道它是 Databricks 实用程序的一部分,但对于这个特定的测试,根本不应该调用/使用它。这就是让我陷入困境的原因。被调用的函数根本不使用 DButils,所以我不确定它为什么被调用。
        • 这一行是否工作正常:from csv_to_parquet import readAndShowCSV 因为如果函数导入成功,那么它不应该抛出错误。
        • 文件 csv_to_parquet 中还有什么?我怀疑您在调用 dbutils 的函数(或任何函数)之外有一些东西,或者在其中有调用 dbutils 的导入。我会考虑使用 databricks-connect 来执行此操作(单元测试会很慢)。或者从该模块(或它导入的子模块)中删除所有 dbutils 引用。
        • @simon_dmorias 你提出了一个很好的观点,我后来才知道问题出在哪里。我相信“from import ”只会导入一个函数,但事实并非如此。它导入整个类。就像你说的,类中的一个功能是使用 dbutils。我现在将研究 databricks 连接,谢谢!
        • 那个pypi链接不是databricks dbutils
        猜你喜欢
        • 2018-11-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-09-29
        • 2018-01-24
        • 2018-02-21
        • 2020-07-31
        相关资源
        最近更新 更多