DatabricksIntellisense Tutorial

The DatabricksIntellisense extension reads the #MAGIC %run command in your Databricks notebooks and intelligently imports files based on relative or absolute references, enhancing your coding experience.

Relative Imports

Let's begin by examining main.py. At the top of the file, you'll notice a few relative imports. The first one, #MAGIC %run ./data_processor, imports the data_processor.py notebook, which resides in the same directory as main.py.

When using relative imports, it's crucial to prepend the file name with ./ to indicate the relative path. Also, note that the .py extension is always omitted in the #MAGIC %run command.

Absolute Imports and Mappings

There are scenarios where specifying an absolute import becomes necessary, especially when a Databricks notebook is located in a different repository or folder structure.

To configure an absolute import, you'll need to utilize the DatabricksIntellisense extension's mapping feature:

  1. Open the DatabricksIntellisense extension panel, typically found in your editor's sidebar.

  2. Click on the "Add Mapping" button. This will open a configuration interface.

  3. In the "From" field, specify the absolute path as you would write it in your Databricks notebook. For instance, to import printer.py from the another_folder, you would enter:

    #MAGIC %run /another_folder/printer

  4. Click the "Browse" button. This will open a file explorer dialog.

  5. Use the file explorer to navigate and select the printer.py file on your local filesystem that corresponds to the absolute path you specified.

  6. Finally, click "Save Mappings" to store your configuration.

main.py


# Databricks Notebook source
# MAGIC %run ./data_processor
# MAGIC %run ./other_folder/string_analyzer
# MAGIC %run ./average
# All files are either imported using a relative path (shown above) or an absolute path (show below). Absolute paths should not use the ./ notation and instead should be specified in the extention's menu.
# MAGIC %run /another_folder/printer

# COMMAND ----------
# This is a second databricks notebook which reuses the classes and functions from the first notebook

# COMMAND ----------
# Example Usage: Reusing DataProcessor Class

# Create an instance of the DataProcessor class
dp = DataProcessor([1, 2, 3])
new_input_numbers = [10, 20, 30, 40]
new_processor = DataProcessor(new_input_numbers)


new_processor_2 = DataProcessor(new_input_numbers)

s = StringAnalyzer("hello world")
s.get_unique_words()


lp = ListProcessor(numbers)
lp.sum_of_list()

s.get_word_count(self)
# Process the data
new_processor.square_numbers()
new_processor.add_constant(5)

# Get the processed data
new_processed_numbers = new_processor.get_processed_data()

# Print the new processed data
print(f"New processed numbers: {new_processed_numbers}")

# COMMAND ----------
# Example Usage: Reusing calculate_average function

# Calculate average of new data
new_average = calculate_average(new_processed_numbers)

if new_average is not None:
    print(f"The average of the new processed data: {new_average}")
else:
    print("Could not calculate average as input list was empty")


# COMMAND ----------
# Example with more complex data

# Create a new instance with more complex input
complex_input = [1.5, 2.5, 3.5, 4.5, 5.5]
complex_processor = DataProcessor(complex_input)
complex_processor.

# Process the complex data
complex_processor.square_numbers()
complex_processor.add_constant(-2)
complex_processed_data = complex_processor.get_processed_data()

# Print results
print(f"Complex processed data: {complex_processed_data}")

# Calculate and print average
complex_average = calculate_average(complex_processed_data)

if complex_average is not None:
    print(f"Average of complex processed data: {complex_average}")
else:
    print("Could not calculate average as input list was empty")


# COMMAND ----------
# Example with different constant value

#Create an instance
diff_const_processor = DataProcessor(new_input_numbers)

#Process the data
diff_const_processor.add_constant(-10)

#Get the data
diff_const_numbers = diff_const_processor.get_processed_data()

#Print the data
print(f"Processed numbers with add constant function: {diff_const_numbers}")

#Calculate average
diff_const_average = calculate_average(diff_const_numbers)
if diff_const_average is not None:
    print(f"The average of the processed numbers: {diff_const_average}")
else:
    print("Could not calculate average as input list was empty")

data_processor.py


# Databricks Notebook source

# COMMAND ----------
# This is a dummy databricks notebook to demonstrate classes and functions

# COMMAND ----------
# Define a simple class

class DataProcessor:
    """
    A simple class for processing data.
    """

    def __init__(self, input_data):
        """
        Constructor to initialize the DataProcessor.

        Args:
            input_data (list): The initial data to be processed.
        """
        self.data = input_data
        self.processed_data = []

    def square_numbers(self):
        """
        Squares each number in the input data and stores in the processed data.
        """
        self.processed_data = [x**2 for x in self.data]

    def add_constant(self, constant):
        """
        Adds a constant value to each number in the processed data.

        Args:
            constant (int or float): The constant value to add.
        """
        if not self.processed_data:
            print("Warning: No processed data available, running square numbers function...")
            self.square_numbers()
        self.processed_data = [x + constant for x in self.processed_data]
    def add_2_constants(self, constant, constant2):
        """
        Adds a constant value to each number in the processed data.

        Args:
            constant (int or float): The constant value to add.
        """
        if not self.processed_data:
            print("Warning: No processed data available, running square numbers function...")
            self.square_numbers()
        self.processed_data = [x + constant + constant2 for x in self.processed_data]

    def get_processed_data(self):
        """
        Returns processed data.
        """
        return self.processed_data

# COMMAND ----------
# Define a simple function


# COMMAND ----------
# Example Usage

# Create an instance of the DataProcessor class
input_numbers = [1, 2, 3, 4, 5]
processor = DataProcessor(input_numbers)

# Process the data
processor.square_numbers()
processor.add_constant(10)

# Get the processed data
processed_numbers = processor.get_processed_data()

# Print the processed data
print(f"Processed numbers: {processed_numbers}")


# Calculate the average using the function
average_value = calculate_average(processed_numbers)

if average_value is not None:
    print(f"Average of the processed numbers: {average_value}")
else:
    print("Could not calculate average due to empty list.")

# Example with empty list
empty_numbers = []
average_value_empty = calculate_average(empty_numbers)
if average_value_empty is not None:
    print(f"Average of empty list {average_value_empty}")
else:
    print("Could not calculate average due to empty list.")

# Example with only add_constant function
input_numbers_2 = [6,7,8]
processor2 = DataProcessor(input_numbers_2)
processor2.add_constant(2)
processed_numbers_2 = processor2.get_processed_data()
print(f"Processed numbers from processor 2: {processed_numbers_2}")

average.py


def calculate_average(numbers):
"""
Calculates the average of a list of numbers.

Args:
    numbers (list): A list of numbers.

Returns:
    float: The average of the numbers or None if empty list.
"""
if not numbers:
    print("Warning: Input list is empty")
    return None
return sum(numbers) / len(numbers)

string_analyzer.py


# Databricks Notebook source

# COMMAND ----------
# This is a third dummy databricks notebook with several classes and functions

# COMMAND ----------
# Utility Functions

def greet(name, greeting="Hello"):
    """
    Generates a personalized greeting.

    Args:
        name (str): The name of the person to greet.
        greeting (str, optional): The greeting message. Defaults to "Hello".

    Returns:
        str: A greeting string.
    """
    return f"{greeting}, {name}!"


def is_even(number):
    """
    Checks if a number is even.

    Args:
        number (int): The number to check.

    Returns:
        bool: True if the number is even, False otherwise.
    """
    return number % 2 == 0


def factorial(n):
    """
    Calculates the factorial of a non-negative integer.

    Args:
        n (int): A non-negative integer.

    Returns:
        int: The factorial of n, or 1 if n is 0
        ValueError: If n is negative
    """
    if n < 0:
        raise ValueError("Factorial is not defined for negative numbers.")
    if n == 0:
        return 1
    result = 1
    for i in range(1, n + 1):
        result *= i
    return result

# COMMAND ----------
# Data Processing Classes

class StringAnalyzer:
    """
    A class to analyze strings.
    """

    def __init__(self, text):
        """
        Initializes the StringAnalyzer.

        Args:
            text (str): The text to analyze.
        """
        self.text = text

    def get_word_count(self):
        """
        Counts the number of words in the text.

        Returns:
            int: The number of words.
        """
        words = self.text.split()
        return len(words)

    def get_unique_words(self):
        """
        Returns a set of unique words in the text.

        Returns:
            set: A set of unique words
        """
        words = self.text.lower().split()
        return set(words)

    def reverse_string(self):
        """
        Reverses the string.

        Returns:
            str: The reversed string
        """
        return self.text[::-1]


class ListProcessor:
    """
    A class to process lists of numbers.
    """
    def __init__(self,numbers):
        """
        Initializes the ListProcessor.

        Args:
            numbers (list): The list of numbers to process.
        """
        self.numbers = numbers

    def sum_of_list(self):
        """
        Calculates the sum of numbers in the list.

        Returns:
            int: the sum of the list.
        """
        if not self.numbers:
            print("Warning: list is empty")
            return 0
        return sum(self.numbers)

    def filter_even(self):
    """
    Returns a new list with only even numbers

    Returns:
        list: List with only even numbers from the input
    """
    return [number for number in self.numbers if is_even(number)]

    def multiply_list(self, multiplier):
    """
    Multiply all elements in a list with a number

    Args:
        multiplier (int/float): The number to multiply with.

    Returns:
        list: new list with values multiplied by the multiplier.
    """
    return [number * multiplier for number in self.numbers]

# COMMAND ----------
# Example Usage

# Demonstrate utility functions
print(greet("Alice"))
print(greet("Bob", "Good morning"))
print(f"Is 10 even? {is_even(10)}")
print(f"Is 7 even? {is_even(7)}")

try:
    print(f"Factorial of 5: {factorial(5)}")
    print(f"Factorial of 0: {factorial(0)}")
    print(f"Factorial of -1: {factorial(-1)}")
except ValueError as e:
    print(f"Error {e}")



# Demonstrate StringAnalyzer
text_analyzer = StringAnalyzer("This is a sample text to test the analyzer class")
print(f"Word count: {text_analyzer.get_word_count()}")
print(f"Unique words: {text_analyzer.get_unique_words()}")
print(f"Reversed text: {text_analyzer.reverse_string()}")

# Demonstrate ListProcessor
numbers_processor = ListProcessor([1, 2, 3, 4, 5, 6])
print(f"Sum of numbers: {numbers_processor.sum_of_list()}")
print(f"Even numbers in the list: {numbers_processor.filter_even()}")
print(f"List multiplied by 2: {numbers_processor.multiply_list(2)}")

numbers_processor_2 = ListProcessor([])
print(f"Sum of numbers in an empty list: {numbers_processor_2.sum_of_list()}")

printer.py


# Databricks Notebook source
class Printer:
    def __init__(self):
        pass
    def print_string(self, string):
        print(string)