Repository: fal-ai/dbt-fal

Issue:
Get metadata on sources
**Context**
To use fal-ai to notify users via slack on failed source tests we would like to use the owner configured within the `metadata` tag, the same way as it's possible for models

**Is your feature request related to a problem? Please describe.**
No

**Describe the solution you'd like**
To have a metadata parameter for each source (callable via list_sources() ) the same way it's already possible with models

**Describe alternatives you've considered**
The only possible, but not viable, alternative I could think of, would be to hardcode it into the script based on the model name

**Additional context**
Add any other context or screenshots about the feature request here.

**Is there an existing feature request for this?**
 * [x]  I have searched the existing issues


Discussion:
Hello, @fredmny! Thanks for the idea. I will take a look at this now.

Resolving patch:
diff --git a/src/fal/typing.py b/src/fal/typing.py
--- a/src/fal/typing.py
+++ b/src/fal/typing.py
@@ -11,7 +11,7 @@
     from fal.fal_script import Context, CurrentModel
 
     class _List_Sources(Protocol):
-        def __call__(self):
+        def __call__(self) -> List[DbtSource]:
             """
             List tables available for `source` usage
             """
diff --git a/src/faldbt/project.py b/src/faldbt/project.py
--- a/src/faldbt/project.py
+++ b/src/faldbt/project.py
@@ -187,6 +187,10 @@ def __repr__(self):
         props = ", ".join([f"{item}={repr(getattr(self, item))}" for item in attrs])
         return f"DbtSource({props})"
 
+    @property
+    def meta(self):
+        return self.node.meta
+
     @property
     def table_name(self) -> str:
         return self.node.name
@@ -217,12 +221,7 @@ def alias(self):
 
     @property
     def meta(self):
-        # BACKWARDS: Change intorduced in XXX (0.20?)
-        # TODO: specify which version is for this
-        if hasattr(self.node.config, "meta"):
-            return self.node.config.meta
-        elif hasattr(self.node, "meta"):
-            return self.node.meta
+        return self.node.meta
 
     def _get_adapter_response(self):
         return self._adapter_response
@@ -537,7 +536,7 @@ def project_name(self):
         return self._config.project_name
 
     @telemetry.log_call("list_sources")
-    def list_sources(self):
+    def list_sources(self) -> List[DbtSource]:
         """
         List tables available for `source` usage
         """


Test patch:
diff --git a/integration_tests/features/context_info.feature b/integration_tests/features/context_info.feature
--- a/integration_tests/features/context_info.feature
+++ b/integration_tests/features/context_info.feature
@@ -15,7 +15,7 @@ Feature: Context object information
     Then the following models are calculated:
       | some_model |
     Then the following scripts are ran:
-      | some_model.context.py |
+      | some_model.lists.py | some_model.context.py |
     And the script some_model.context.py output file has the lines:
       | adapter response: rows affected 1 |
 
@@ -25,7 +25,7 @@ Feature: Context object information
       fal run --profiles-dir $profilesDir --project-dir $baseDir --select some_model --scripts context.py
       """
     Then the following scripts are ran:
-      | some_model.context.py |
+      | some_model.lists.py | some_model.context.py |
     And the script some_model.context.py output file has the lines:
       | adapter response: rows affected 1 |
 
diff --git a/integration_tests/features/meta_object.feature b/integration_tests/features/meta_object.feature
new file mode 100644
--- /dev/null
+++ b/integration_tests/features/meta_object.feature
@@ -0,0 +1,28 @@
+Feature: Access to meta object from schema
+  Background: Project Setup
+    Given the project 005_functions_and_variables
+
+  Scenario: Use meta object from models
+    When the following command is invoked:
+      """
+      fal flow run --profiles-dir $profilesDir --project-dir $baseDir --select some_model
+      """
+    Then the following models are calculated:
+      | some_model |
+    And the following scripts are ran:
+      | some_model.lists.py | some_model.context.py |
+    And the script some_model.lists.py output file has the lines:
+      # only check for 1 of the lines
+      | model: some_model property: 1 |
+
+  Scenario: Use meta object from sources
+    When the following command is invoked:
+      """
+      fal flow run --profiles-dir $profilesDir --project-dir $baseDir --select some_model
+      """
+    Then the following models are calculated:
+      | some_model |
+    And the following scripts are ran:
+      | some_model.lists.py | some_model.context.py |
+    And the script some_model.lists.py output file has the lines:
+      | source: results other_source property: 4 | source: results some_source property: None |
diff --git a/integration_tests/features/write_to_model_function.feature b/integration_tests/features/write_to_model_function.feature
--- a/integration_tests/features/write_to_model_function.feature
+++ b/integration_tests/features/write_to_model_function.feature
@@ -11,7 +11,7 @@ Feature: `write_to_model` function
     Then the following models are calculated:
       | other_model | some_model | third_model |
     And the following scripts are ran:
-      | some_model.write_to_source_twice.py | some_model.context.py | other_model.complete_model.py | third_model.complete_model.py |
+      | some_model.write_to_source_twice.py | some_model.context.py | some_model.lists.py | other_model.complete_model.py | third_model.complete_model.py |
     And the script other_model.complete_model.py output file has the lines:
       | my_int 0.0 | my_int 3.0 | size 1 |
     And the script third_model.complete_model.py output file has the lines:
diff --git a/integration_tests/features/write_to_source_function.feature b/integration_tests/features/write_to_source_function.feature
--- a/integration_tests/features/write_to_source_function.feature
+++ b/integration_tests/features/write_to_source_function.feature
@@ -11,6 +11,6 @@ Feature: `write_to_source` function
     Then the following models are calculated:
       | other_model | some_model | third_model |
     And the following scripts are ran:
-      | some_model.write_to_source_twice.py | some_model.context.py | other_model.complete_model.py | third_model.complete_model.py |
+      | some_model.write_to_source_twice.py | some_model.context.py | some_model.lists.py | other_model.complete_model.py | third_model.complete_model.py |
     And the script some_model.write_to_source_twice.py output file has the lines:
       | source size 1 | source size 2 |
diff --git a/integration_tests/projects/005_functions_and_variables/fal_scripts/lists.py b/integration_tests/projects/005_functions_and_variables/fal_scripts/lists.py
new file mode 100644
--- /dev/null
+++ b/integration_tests/projects/005_functions_and_variables/fal_scripts/lists.py
@@ -0,0 +1,18 @@
+from fal.typing import *
+from _fal_testing.utils import create_dynamic_artifact
+
+assert context.current_model
+
+lines = []
+
+for model in list_models():
+    lines.append(
+        f"model: {model.name} property: {model.meta['property']['other'] if model.meta else None}"
+    )
+
+for source in list_sources():
+    lines.append(
+        f"source: {source.name} {source.table_name} property: {source.meta['property']['other'] if source.meta else None}"
+    )
+
+create_dynamic_artifact(context, additional_data="\n".join(lines))
diff --git a/integration_tests/projects/005_functions_and_variables/models/schema.yml b/integration_tests/projects/005_functions_and_variables/models/schema.yml
--- a/integration_tests/projects/005_functions_and_variables/models/schema.yml
+++ b/integration_tests/projects/005_functions_and_variables/models/schema.yml
@@ -6,6 +6,9 @@ sources:
     schema: "{{ env_var('DBT_SCHEMA', 'dbt_fal') }}"
     tables:
       - name: other_source
+        meta:
+          property:
+            other: 4
       - name: some_source
         columns:
           - name: my_text
@@ -25,15 +28,22 @@ models:
         tests:
           - not_null
     meta:
+      property:
+        name: some_model
+        other: 1
       fal:
         scripts:
           after:
             - fal_scripts/write_to_source_twice.py
         post-hook:
           - fal_scripts/context.py
+          - fal_scripts/lists.py
 
   - name: other_model
     meta:
+      property:
+        name: other_model
+        other: 2
       fal:
         scripts:
           after:
@@ -41,6 +51,9 @@ models:
 
   - name: third_model
     meta:
+      property:
+        name: third_model
+        other: 3
       fal:
         scripts:
           after: