Repository: Textualize/textual

Issue:
CSS errors have a broken path
CSS errors will create an invalid path to the CSS, if the CSS is in code. This is because it adds the widget name to the path.

Here's an example:

![Image](https://github.com/Textualize/textual/assets/554369/a24d2eae-c16e-4757-8c21-abeecde746c8)

If you click the heading it should take you to the file containing the error, but it doesn't because the path is invalid.

It would be nice to display the widget within the title, but it should probably be a separate field.


Discussion:

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b3ea067bc..2c6ecb38e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,13 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
 and this project adheres to [Semantic Versioning](http://semver.org/).
 
 
+## Unreleased
+
+### Changed
+
+- CSS error reporting will no longer provide links to the files in question https://github.com/Textualize/textual/pull/3582
+- inline CSS error reporting will report widget/class variable where the CSS was read from https://github.com/Textualize/textual/pull/3582
+
 ## [0.41.0] - 2023-10-31
 
 ### Fixed
diff --git a/src/textual/app.py b/src/textual/app.py
index c09fa0365..f7296edb6 100644
--- a/src/textual/app.py
+++ b/src/textual/app.py
@@ -1771,20 +1771,20 @@ class App(Generic[ReturnType], DOMNode):
 
         update = False
         for path in screen.css_path:
-            if not self.stylesheet.has_source(path):
+            if not self.stylesheet.has_source(str(path), ""):
                 self.stylesheet.read(path)
                 update = True
         if screen.CSS:
             try:
-                screen_css_path = (
-                    f"{inspect.getfile(screen.__class__)}:{screen.__class__.__name__}"
-                )
+                screen_path = inspect.getfile(screen.__class__)
             except (TypeError, OSError):
-                screen_css_path = f"{screen.__class__.__name__}"
-            if not self.stylesheet.has_source(screen_css_path):
+                screen_path = ""
+            screen_class_var = f"{screen.__class__.__name__}.CSS"
+            read_from = (screen_path, screen_class_var)
+            if not self.stylesheet.has_source(screen_path, screen_class_var):
                 self.stylesheet.add_source(
                     screen.CSS,
-                    path=screen_css_path,
+                    read_from=read_from,
                     is_default_css=False,
                     scope=screen._css_type_name if screen.SCOPED_CSS else "",
                 )
@@ -2145,23 +2145,22 @@ class App(Generic[ReturnType], DOMNode):
         try:
             if self.css_path:
                 self.stylesheet.read_all(self.css_path)
-            for path, css, tie_breaker, scope in self._get_default_css():
+            for read_from, css, tie_breaker, scope in self._get_default_css():
                 self.stylesheet.add_source(
                     css,
-                    path=path,
+                    read_from=read_from,
                     is_default_css=True,
                     tie_breaker=tie_breaker,
                     scope=scope,
                 )
             if self.CSS:
                 try:
-                    app_css_path = (
-                        f"{inspect.getfile(self.__class__)}:{self.__class__.__name__}"
-                    )
+                    app_path = inspect.getfile(self.__class__)
                 except (TypeError, OSError):
-                    app_css_path = f"{self.__class__.__name__}"
+                    app_path = ""
+                read_from = (app_path, f"{self.__class__.__name__}.CSS")
                 self.stylesheet.add_source(
-                    self.CSS, path=app_css_path, is_default_css=False
+                    self.CSS, read_from=read_from, is_default_css=False
                 )
         except Exception as error:
             self._handle_exception(error)
diff --git a/src/textual/css/_styles_builder.py b/src/textual/css/_styles_builder.py
index 7f375dfaa..06da1ca5d 100644
--- a/src/textual/css/_styles_builder.py
+++ b/src/textual/css/_styles_builder.py
@@ -65,19 +65,6 @@ from .transition import Transition
 from .types import BoxSizing, Display, EdgeType, Overflow, Visibility
 
 
-def _join_tokens(tokens: Iterable[Token], joiner: str = "") -> str:
-    """Convert tokens into a string by joining their values
-
-    Args:
-        tokens: Tokens to join
-        joiner: String to join on.
-
-    Returns:
-        The tokens, joined together to form a string.
-    """
-    return joiner.join(token.value for token in tokens)
-
-
 class StylesBuilder:
     """
     The StylesBuilder object takes tokens parsed from the CSS and converts
diff --git a/src/textual/css/parse.py b/src/textual/css/parse.py
index a9ee06d15..9be5047f3 100644
--- a/src/textual/css/parse.py
+++ b/src/textual/css/parse.py
@@ -1,7 +1,6 @@
 from __future__ import annotations
 
 from functools import lru_cache
-from pathlib import PurePath
 from typing import Iterable, Iterator, NoReturn
 
 from ..suggestions import get_suggestion
@@ -19,7 +18,7 @@ from .model import (
 from .styles import Styles
 from .tokenize import Token, tokenize, tokenize_declarations, tokenize_values
 from .tokenizer import EOFError, ReferencedBy
-from .types import Specificity3
+from .types import CSSLocation, Specificity3
 
 SELECTOR_MAP: dict[str, tuple[SelectorType, Specificity3]] = {
     "selector": (SelectorType.TYPE, (0, 0, 1)),
@@ -38,7 +37,7 @@ def parse_selectors(css_selectors: str) -> tuple[SelectorSet, ...]:
     if not css_selectors.strip():
         return ()
 
-    tokens = iter(tokenize(css_selectors, ""))
+    tokens = iter(tokenize(css_selectors, ("", "")))
 
     get_selector = SELECTOR_MAP.get
     combinator: CombinatorType | None = CombinatorType.DESCENDENT
@@ -180,18 +179,18 @@ def parse_rule_set(
     yield rule_set
 
 
-def parse_declarations(css: str, path: str) -> Styles:
+def parse_declarations(css: str, read_from: CSSLocation) -> Styles:
     """Parse declarations and return a Styles object.
 
     Args:
         css: String containing CSS.
-        path: Path to the CSS, or something else to identify the location.
+        read_from: The location where the CSS was read from.
 
     Returns:
         A styles object.
     """
 
-    tokens = iter(tokenize_declarations(css, path))
+    tokens = iter(tokenize_declarations(css, read_from))
     styles_builder = StylesBuilder()
 
     declaration: Declaration | None = None
@@ -245,7 +244,7 @@ def _unresolved(variable_name: str, variables: Iterable[str], token: Token) -> N
         message += f"; did you mean '${suggested_variable}'?"
 
     raise UnresolvedVariableError(
-        token.path,
+        token.read_from,
         token.code,
         token.start,
         message,
@@ -341,7 +340,7 @@ def substitute_references(
 def parse(
     scope: str,
     css: str,
-    path: str | PurePath,
+    read_from: CSSLocation,
     variables: dict[str, str] | None = None,
     variable_tokens: dict[str, list[Token]] | None = None,
     is_default_rules: bool = False,
@@ -351,9 +350,9 @@ def parse(
     and generating rule sets from it.
 
     Args:
-        scope: CSS type name
-        css: The input CSS
-        path: Path to the CSS
+        scope: CSS type name.
+        css: The input CSS.
+        read_from: The source location of the CSS.
         variables: Substitution variables to substitute tokens for.
         is_default_rules: True if the rules we're extracting are
             default (i.e. in Widget.DEFAULT_CSS) rules. False if they're from user defined CSS.
@@ -363,7 +362,7 @@ def parse(
     if variable_tokens:
         reference_tokens.update(variable_tokens)
 
-    tokens = iter(substitute_references(tokenize(css, path), variable_tokens))
+    tokens = iter(substitute_references(tokenize(css, read_from), variable_tokens))
     while True:
         token = next(tokens, None)
         if token is None:
diff --git a/src/textual/css/query.py b/src/textual/css/query.py
index a6af6ae67..7df103e7a 100644
--- a/src/textual/css/query.py
+++ b/src/textual/css/query.py
@@ -407,7 +407,7 @@ class DOMQuery(Generic[QueryType]):
             node.set_styles(**update_styles)
         if css is not None:
             try:
-                new_styles = parse_declarations(css, path="set_styles")
+                new_styles = parse_declarations(css, read_from=("set_styles", ""))
             except DeclarationError as error:
                 raise DeclarationError(error.name, error.token, error.message) from None
             for node in self:
diff --git a/src/textual/css/styles.py b/src/textual/css/styles.py
index 03f944852..b6b6cdd3f 100644
--- a/src/textual/css/styles.py
+++ b/src/textual/css/styles.py
@@ -69,6 +69,7 @@ from .types import (
 if TYPE_CHECKING:
     from .._layout import Layout
     from ..dom import DOMNode
+    from .types import CSSLocation
 
 
 class RulesMap(TypedDict, total=False):
@@ -534,12 +535,14 @@ class StylesBase(ABC):
 
     @classmethod
     @lru_cache(maxsize=1024)
-    def parse(cls, css: str, path: str, *, node: DOMNode | None = None) -> Styles:
+    def parse(
+        cls, css: str, read_from: CSSLocation, *, node: DOMNode | None = None
+    ) -> Styles:
         """Parse CSS and return a Styles object.
 
         Args:
             css: Textual CSS.
-            path: Path or string indicating source of CSS.
+            read_from: Location where the CSS was read from.
             node: Node to associate with the Styles.
 
         Returns:
@@ -547,7 +550,7 @@ class StylesBase(ABC):
         """
         from .parse import parse_declarations
 
-        styles = parse_declarations(css, path)
+        styles = parse_declarations(css, read_from)
         styles.node = node
         return styles
 
diff --git a/src/textual/css/stylesheet.py b/src/textual/css/stylesheet.py
index 336252029..3acbb5652 100644
--- a/src/textual/css/stylesheet.py
+++ b/src/textual/css/stylesheet.py
@@ -12,7 +12,6 @@ from rich.console import Console, ConsoleOptions, RenderableType, RenderResult
 from rich.markup import render
 from rich.padding import Padding
 from rich.panel import Panel
-from rich.style import Style
 from rich.syntax import Syntax
 from rich.text import Text
 
@@ -26,7 +25,7 @@ from .parse import parse
 from .styles import RulesMap, Styles
 from .tokenize import Token, tokenize_values
 from .tokenizer import TokenError
-from .types import Specificity3, Specificity6
+from .types import CSSLocation, Specificity3, Specificity6
 
 _DEFAULT_STYLES = Styles()
 
@@ -68,27 +67,34 @@ class StylesheetErrors:
         for token, message in errors:
             error_count += 1
 
-            if token.path:
-                path = Path(token.path)
-                filename = path.name
-            else:
-                path = None
-                filename = "<unknown>"
-
             if token.referenced_by:
                 line_idx, col_idx = token.referenced_by.location
             else:
                 line_idx, col_idx = token.location
             line_no, col_no = line_idx + 1, col_idx + 1
-            path_string = f"{path.absolute() if path else filename}:{line_no}:{col_no}"
-            link_style = Style(
-                link=f"file://{path.absolute()}" if path else None,
-                color="red",
-                bold=True,
-                italic=True,
+
+            display_path, widget_var = token.read_from
+            if display_path:
+                link_path = str(Path(display_path).absolute())
+                filename = Path(link_path).name
+            else:
+                link_path = ""
+                filename = "<unknown>"
+            # If we have a widget/variable from where the CSS was read, then line/column
+            # numbers are relative to the inline CSS and we'll display them next to the
+            # widget/variable.
+            # Otherwise, they're absolute positions in a TCSS file and we can show them
+            # next to the file path.
+            if widget_var:
+                path_string = link_path or filename
+                widget_string = f" in {widget_var}:{line_no}:{col_no}"
+            else:
+                path_string = f"{link_path or filename}:{line_no}:{col_no}"
+                widget_string = ""
+
+            title = Text.assemble(
+                "Error at ", path_string, widget_string, style="bold red"
             )
-            path_text = Text(path_string, style=link_style)
-            title = Text.assemble(Text("Error at ", style="bold red"), path_text)
             yield ""
             yield Panel(
                 self._get_snippet(
@@ -132,7 +138,7 @@ class Stylesheet:
         self._rules_map: dict[str, list[RuleSet]] | None = None
         self._variables = variables or {}
         self.__variable_tokens: dict[str, list[Token]] | None = None
-        self.source: dict[str, CssSource] = {}
+        self.source: dict[CSSLocation, CssSource] = {}
         self._require_parse = False
         self._invalid_css: set[str] = set()
         self._parse_cache: LRUCache[tuple, list[RuleSet]] = LRUCache(64)
@@ -202,7 +208,7 @@ class Stylesheet:
     def _parse_rules(
         self,
         css: str,
-        path: str | PurePath,
+        read_from: CSSLocation,
         is_default_rules: bool = False,
         tie_breaker: int = 0,
         scope: str = "",
@@ -211,7 +217,7 @@ class Stylesheet:
 
         Args:
             css: String containing Textual CSS.
-            path: Path to CSS or unique identifier
+            read_from: Original CSS location.
             is_default_rules: True if the rules we're extracting are
                 default (i.e. in Widget.DEFAULT_CSS) rules. False if they're from user defined CSS.
             scope: Scope of rules, or empty string for global scope.
@@ -222,7 +228,7 @@ class Stylesheet:
         Returns:
             List of RuleSets.
         """
-        cache_key = (css, path, is_default_rules, tie_breaker, scope)
+        cache_key = (css, read_from, is_default_rules, tie_breaker, scope)
         try:
             return self._parse_cache[cache_key]
         except KeyError:
@@ -232,7 +238,7 @@ class Stylesheet:
                 parse(
                     scope,
                     css,
-                    path,
+                    read_from,
                     variable_tokens=self._variable_tokens,
                     is_default_rules=is_default_rules,
                     tie_breaker=tie_breaker,
@@ -263,7 +269,7 @@ class Stylesheet:
             path = os.path.abspath(filename)
         except Exception:
             raise StylesheetError(f"unable to read CSS file {filename!r}") from None
-        self.source[str(path)] = CssSource(css, False, 0)
+        self.source[(str(path), "")] = CssSource(css, False, 0)
         self._require_parse = True
 
     def read_all(self, paths: Sequence[PurePath]) -> None:
@@ -279,18 +285,22 @@ class Stylesheet:
         for path in paths:
             self.read(path)
 
-    def has_source(self, path: str | PurePath) -> bool:
+    def has_source(self, path: str, class_var: str = "") -> bool:
         """Check if the stylesheet has this CSS source already.
 
+        Args:
+            path: The file path of the source in question.
+            class_var: The widget class variable we might be reading the CSS from.
+
         Returns:
             Whether the stylesheet is aware of this CSS source or not.
         """
-        return str(path) in self.source
+        return (path, class_var) in self.source
 
     def add_source(
         self,
         css: str,
-        path: str | PurePath | None = None,
+        read_from: CSSLocation | None = None,
         is_default_css: bool = False,
         tie_breaker: int = 0,
         scope: str = "",
@@ -299,6 +309,7 @@ class Stylesheet:
 
         Args:
             css: String with CSS source.
+            read_from: The original source location of the CSS.
             path: The path of the source if a file, or some other identifier.
             is_default_css: True if the CSS is defined in the Widget, False if the CSS is defined
                 in a user stylesheet.
@@ -310,17 +321,18 @@ class Stylesheet:
             StylesheetParseError: If the CSS is invalid.
         """
 
-        if path is None:
-            path = str(hash(css))
-        elif isinstance(path, PurePath):
-            path = str(css)
-        if path in self.source and self.source[path].content == css:
-            # Path already in source, and CSS is identical
-            content, is_defaults, source_tie_breaker, scope = self.source[path]
+        if read_from is None:
+            read_from = ("", str(hash(css)))
+
+        if read_from in self.source and self.source[read_from].content == css:
+            # Location already in source and CSS is identical.
+            content, is_defaults, source_tie_breaker, scope = self.source[read_from]
             if source_tie_breaker > tie_breaker:
-                self.source[path] = CssSource(content, is_defaults, tie_breaker, scope)
+                self.source[read_from] = CssSource(
+                    content, is_defaults, tie_breaker, scope
+                )
             return
-        self.source[path] = CssSource(css, is_default_css, tie_breaker, scope)
+        self.source[read_from] = CssSource(css, is_default_css, tie_breaker, scope)
         self._require_parse = True
 
     def parse(self) -> None:
@@ -332,13 +344,18 @@ class Stylesheet:
         rules: list[RuleSet] = []
         add_rules = rules.extend
 
-        for path, (css, is_default_rules, tie_breaker, scope) in self.source.items():
+        for read_from, (
+            css,
+            is_default_rules,
+            tie_breaker,
+            scope,
+        ) in self.source.items():
             if css in self._invalid_css:
                 continue
             try:
                 css_rules = self._parse_rules(
                     css,
-                    path,
+                    read_from=read_from,
                     is_default_rules=is_default_rules,
                     tie_breaker=tie_breaker,
                     scope=scope,
@@ -364,10 +381,10 @@ class Stylesheet:
         """
         # Do this in a fresh Stylesheet so if there are errors we don't break self.
         stylesheet = Stylesheet(variables=self._variables)
-        for path, (css, is_defaults, tie_breaker, scope) in self.source.items():
+        for read_from, (css, is_defaults, tie_breaker, scope) in self.source.items():
             stylesheet.add_source(
                 css,
-                path,
+                read_from=read_from,
                 is_default_css=is_defaults,
                 tie_breaker=tie_breaker,
                 scope=scope,
diff --git a/src/textual/css/tokenize.py b/src/textual/css/tokenize.py
index 12e7ed6e2..de9f80787 100644
--- a/src/textual/css/tokenize.py
+++ b/src/textual/css/tokenize.py
@@ -1,10 +1,12 @@
 from __future__ import annotations
 
 import re
-from pathlib import PurePath
-from typing import Iterable
+from typing import TYPE_CHECKING, Iterable
 
-from textual.css.tokenizer import Expect, Token, Tokenizer
+from .tokenizer import Expect, Token, Tokenizer
+
+if TYPE_CHECKING:
+    from .types import CSSLocation
 
 PERCENT = r"-?\d+\.?\d*%"
 DECIMAL = r"-?\d+\.?\d*"
@@ -157,8 +159,8 @@ class TokenizerState:
         "declaration_set_end": expect_root_scope,
     }
 
-    def __call__(self, code: str, path: str | PurePath) -> Iterable[Token]:
-        tokenizer = Tokenizer(code, path=path)
+    def __call__(self, code: str, read_from: CSSLocation) -> Iterable[Token]:
+        tokenizer = Tokenizer(code, read_from=read_from)
         expect = self.EXPECT
         get_token = tokenizer.get_token
         get_state = self.STATE_MAP.get
@@ -194,7 +196,7 @@ tokenize_value = ValueTokenizerState()
 
 
 def tokenize_values(values: dict[str, str]) -> dict[str, list[Token]]:
-    """Tokens the values in a dict of strings.
+    """Tokenizes the values in a dict of strings.
 
     Args:
         values: A mapping of CSS variable name on to a value, to be
@@ -204,6 +206,7 @@ def tokenize_values(values: dict[str, str]) -> dict[str, list[Token]]:
         A mapping of name on to a list of tokens,
     """
     value_tokens = {
-        name: list(tokenize_value(value, "__name__")) for name, value in values.items()
+        name: list(tokenize_value(value, ("__name__", "")))
+        for name, value in values.items()
     }
     return value_tokens
diff --git a/src/textual/css/tokenizer.py b/src/textual/css/tokenizer.py
index 276b22b54..d7cfc449d 100644
--- a/src/textual/css/tokenizer.py
+++ b/src/textual/css/tokenizer.py
@@ -1,8 +1,7 @@
 from __future__ import annotations
 
 import re
-from pathlib import PurePath
-from typing import NamedTuple
+from typing import TYPE_CHECKING, NamedTuple
 
 import rich.repr
 from rich.console import Group, RenderableType
@@ -16,13 +15,16 @@ from ..suggestions import get_suggestion
 from ._error_tools import friendly_list
 from .constants import VALID_PSEUDO_CLASSES
 
+if TYPE_CHECKING:
+    from .types import CSSLocation
+
 
 class TokenError(Exception):
     """Error raised when the CSS cannot be tokenized (syntax error)."""
 
     def __init__(
         self,
-        path: str,
+        read_from: CSSLocation,
         code: str,
         start: tuple[int, int],
         message: str,
@@ -30,14 +32,14 @@ class TokenError(Exception):
     ) -> None:
         """
         Args:
-            path: Path to source or "<object>" if source is parsed from a literal.
+            read_from: The location where the CSS was read from.
             code: The code being parsed.
             start: Line number of the error.
             message: A message associated with the error.
             end: End location of token, or None if not known.
         """
 
-        self.path = path
+        self.read_from = read_from
         self.code = code
         self.start = start
         self.end = end or start
@@ -72,7 +74,12 @@ class TokenError(Exception):
 
         line_no, col_no = self.start
 
-        errors.append(highlighter(f" {self.path or '<unknown>'}:{line_no}:{col_no}"))
+        path, widget_variable = self.read_from
+        if widget_variable:
+            css_location = f" {path}, {widget_variable}:{line_no}:{col_no}"
+        else:
+            css_location = f" {path}:{line_no}:{col_no}"
+        errors.append(highlighter(css_location))
         errors.append(self._get_snippet())
 
         final_message = "\n".join(
@@ -126,7 +133,7 @@ class ReferencedBy(NamedTuple):
 class Token(NamedTuple):
     name: str
     value: str
-    path: str
+    read_from: CSSLocation
     code: str
     location: tuple[int, int]
     referenced_by: ReferencedBy | None = None
@@ -153,7 +160,7 @@ class Token(NamedTuple):
         return Token(
             name=self.name,
             value=self.value,
-            path=self.path,
+            read_from=self.read_from,
             code=self.code,
             location=self.location,
             referenced_by=by,
@@ -165,15 +172,18 @@ class Token(NamedTuple):
     def __rich_repr__(self) -> rich.repr.Result:
         yield "name", self.name
         yield "value", self.value
-        yield "path", self.path
+        yield (
+            "read_from",
+            self.read_from[0] if not self.read_from[1] else self.read_from,
+        )
         yield "code", self.code if len(self.code) < 40 else self.code[:40] + "..."
         yield "location", self.location
         yield "referenced_by", self.referenced_by, None
 
 
 class Tokenizer:
-    def __init__(self, text: str, path: str | PurePath = "") -> None:
-        self.path = str(path)
+    def __init__(self, text: str, read_from: CSSLocation = ("", "")) -> None:
+        self.read_from = read_from
         self.code = text
         self.lines = text.splitlines(keepends=True)
         self.line_no = 0
@@ -187,14 +197,14 @@ class Tokenizer:
                 return Token(
                     "eof",
                     "",
-                    self.path,
+                    self.read_from,
                     self.code,
                     (line_no + 1, col_no + 1),
                     None,
                 )
             else:
                 raise EOFError(
-                    self.path,
+                    self.read_from,
                     self.code,
                     (line_no + 1, col_no + 1),
                     "Unexpected end of file",
@@ -205,7 +215,7 @@ class Tokenizer:
             expected = friendly_list(" ".join(name.split("_")) for name in expect.names)
             message = f"Expected one of {expected}.; Did you forget a semicolon at the end of a line?"
             raise TokenError(
-                self.path,
+                self.read_from,
                 self.code,
                 (line_no, col_no),
                 message,
@@ -224,7 +234,7 @@ class Tokenizer:
         token = Token(
             name,
             value,
-            self.path,
+            self.read_from,
             self.code,
             (line_no, col_no),
             referenced_by=None,
@@ -239,14 +249,14 @@ class Tokenizer:
             all_valid = f"must be one of {friendly_list(VALID_PSEUDO_CLASSES)}"
             if suggestion:
                 raise TokenError(
-                    self.path,
+                    self.read_from,
                     self.code,
                     (line_no, col_no),
                     f"unknown pseudo-class {pseudo_class!r}; did you mean {suggestion!r}?; {all_valid}",
                 )
             else:
                 raise TokenError(
-                    self.path,
+                    self.read_from,
                     self.code,
                     (line_no, col_no),
                     f"unknown pseudo-class {pseudo_class!r}; {all_valid}",
@@ -267,7 +277,10 @@ class Tokenizer:
         while True:
             if line_no >= len(self.lines):
                 raise EOFError(
-                    self.path, self.code, (line_no, col_no), "Unexpected end of file"
+                    self.read_from,
+                    self.code,
+                    (line_no, col_no),
+                    "Unexpected end of file",
                 )
             line = self.lines[line_no]
             match = expect.search(line, col_no)
diff --git a/src/textual/css/types.py b/src/textual/css/types.py
index c723e0b5f..ce4cebdd0 100644
--- a/src/textual/css/types.py
+++ b/src/textual/css/types.py
@@ -42,3 +42,12 @@ Overlay = Literal["none", "screen"]
 
 Specificity3 = Tuple[int, int, int]
 Specificity6 = Tuple[int, int, int, int, int, int]
+
+CSSLocation = Tuple[str, str]
+"""Represents the definition location of a piece of CSS code.
+
+The first element of the tuple is the file path from where the CSS was read.
+If the CSS was read from a Python source file, the second element contains the class
+variable from where the CSS was read (e.g., "Widget.DEFAULT_CSS"), otherwise it's an
+empty string.
+"""
diff --git a/src/textual/dom.py b/src/textual/dom.py
index 6b16a0242..b1b7dd0fb 100644
--- a/src/textual/dom.py
+++ b/src/textual/dom.py
@@ -50,6 +50,7 @@ if TYPE_CHECKING:
     from rich.console import RenderableType
     from .app import App
     from .css.query import DOMQuery, QueryType
+    from .css.types import CSSLocation
     from .message import Message
     from .screen import Screen
     from .widget import Widget
@@ -423,33 +424,41 @@ class DOMNode(MessagePump):
         if hasattr(self, "_classes") and self._classes:
             yield "classes", " ".join(self._classes)
 
-    def _get_default_css(self) -> list[tuple[str, str, int, str]]:
+    def _get_default_css(self) -> list[tuple[CSSLocation, str, int, str]]:
         """Gets the CSS for this class and inherited from bases.
 
         Default CSS is inherited from base classes, unless `inherit_css` is set to
         `False` when subclassing.
 
         Returns:
-            A list of tuples containing (PATH, SOURCE, SPECIFICITY, SCOPE) for this
-                and inherited from base classes.
+            A list of tuples containing (LOCATION, SOURCE, SPECIFICITY, SCOPE) for this
+                class and inherited from base classes.
         """
 
-        css_stack: list[tuple[str, str, int, str]] = []
+        css_stack: list[tuple[CSSLocation, str, int, str]] = []
 
-        def get_path(base: Type[DOMNode]) -> str:
-            """Get a path to the DOM Node"""
+        def get_location(base: Type[DOMNode]) -> CSSLocation:
+            """Get the original location of this DEFAULT_CSS.
+
+            Args:
+                base: The class from which the default css was extracted.
+
+            Returns:
+                The filename where the class was defined (if possible) and the class
+                    variable the CSS was extracted from.
+            """
             try:
-                return f"{getfile(base)}:{base.__name__}"
+                return (getfile(base), f"{base.__name__}.DEFAULT_CSS")
             except (TypeError, OSError):
-                return f"{base.__name__}"
+                return ("", f"{base.__name__}.DEFAULT_CSS")
 
         for tie_breaker, base in enumerate(self._node_bases):
-            css: str = base.__dict__.get("DEFAULT_CSS", "").strip()
+            css: str = base.__dict__.get("DEFAULT_CSS", "")
             if css:
                 scoped: bool = base.__dict__.get("SCOPED_CSS", True)
                 css_stack.append(
                     (
-                        get_path(base),
+                        get_location(base),
                         css,
                         -tie_breaker,
                         base._css_type_name if scoped else "",
@@ -1143,7 +1152,7 @@ class DOMNode(MessagePump):
 
         if css is not None:
             try:
-                new_styles = parse_declarations(css, path="set_styles")
+                new_styles = parse_declarations(css, read_from=("set_styles", ""))
             except DeclarationError as error:
                 raise DeclarationError(error.name, error.token, error.message) from None
             self._inline_styles.merge(new_styles)
diff --git a/src/textual/widget.py b/src/textual/widget.py
index 05f3df524..005fdf14d 100644
--- a/src/textual/widget.py
+++ b/src/textual/widget.py
@@ -940,10 +940,10 @@ class Widget(DOMNode):
             app: App instance.
         """
         # Parse the Widget's CSS
-        for path, css, tie_breaker, scope in self._get_default_css():
+        for read_from, css, tie_breaker, scope in self._get_default_css():
             self.app.stylesheet.add_source(
                 css,
-                path=path,
+                read_from=read_from,
                 is_default_css=True,
                 tie_breaker=tie_breaker,
                 scope=scope,


Test patch:
diff --git a/tests/css/test_parse.py b/tests/css/test_parse.py
index 6f31bf094..124f820d5 100644
--- a/tests/css/test_parse.py
+++ b/tests/css/test_parse.py
@@ -17,12 +17,12 @@ from textual.layouts.vertical import VerticalLayout
 class TestVariableReferenceSubstitution:
     def test_simple_reference(self):
         css = "$x: 1; #some-widget{border: $x;}"
-        variables = substitute_references(tokenize(css, ""))
+        variables = substitute_references(tokenize(css, ("", "")))
         assert list(variables) == [
             Token(
                 name="variable_name",
                 value="$x:",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 0),
                 referenced_by=None,
@@ -30,7 +30,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="whitespace",
                 value=" ",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 3),
                 referenced_by=None,
@@ -38,7 +38,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="number",
                 value="1",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 4),
                 referenced_by=None,
@@ -46,7 +46,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="variable_value_end",
                 value=";",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 5),
                 referenced_by=None,
@@ -54,7 +54,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="whitespace",
                 value=" ",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 6),
                 referenced_by=None,
@@ -62,7 +62,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="selector_start_id",
                 value="#some-widget",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 7),
                 referenced_by=None,
@@ -70,7 +70,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="declaration_set_start",
                 value="{",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 19),
                 referenced_by=None,
@@ -78,7 +78,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="declaration_name",
                 value="border:",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 20),
                 referenced_by=None,
@@ -86,7 +86,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="whitespace",
                 value=" ",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 27),
                 referenced_by=None,
@@ -94,7 +94,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="number",
                 value="1",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 4),
                 referenced_by=ReferencedBy(
@@ -104,7 +104,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="declaration_end",
                 value=";",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 30),
                 referenced_by=None,
@@ -112,7 +112,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="declaration_set_end",
                 value="}",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 31),
                 referenced_by=None,
@@ -121,12 +121,12 @@ class TestVariableReferenceSubstitution:
 
     def test_simple_reference_no_whitespace(self):
         css = "$x:1; #some-widget{border: $x;}"
-        variables = substitute_references(tokenize(css, ""))
+        variables = substitute_references(tokenize(css, ("", "")))
         assert list(variables) == [
             Token(
                 name="variable_name",
                 value="$x:",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 0),
                 referenced_by=None,
@@ -134,7 +134,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="number",
                 value="1",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 3),
                 referenced_by=None,
@@ -142,7 +142,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="variable_value_end",
                 value=";",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 4),
                 referenced_by=None,
@@ -150,7 +150,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="whitespace",
                 value=" ",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 5),
                 referenced_by=None,
@@ -158,7 +158,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="selector_start_id",
                 value="#some-widget",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 6),
                 referenced_by=None,
@@ -166,7 +166,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="declaration_set_start",
                 value="{",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 18),
                 referenced_by=None,
@@ -174,7 +174,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="declaration_name",
                 value="border:",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 19),
                 referenced_by=None,
@@ -182,7 +182,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="whitespace",
                 value=" ",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 26),
                 referenced_by=None,
@@ -190,7 +190,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="number",
                 value="1",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 3),
                 referenced_by=ReferencedBy(
@@ -200,7 +200,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="declaration_end",
                 value=";",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 29),
                 referenced_by=None,
@@ -208,7 +208,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="declaration_set_end",
                 value="}",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 30),
                 referenced_by=None,
@@ -218,11 +218,11 @@ class TestVariableReferenceSubstitution:
     def test_undefined_variable(self):
         css = ".thing { border: $not-defined; }"
         with pytest.raises(UnresolvedVariableError):
-            list(substitute_references(tokenize(css, "")))
+            list(substitute_references(tokenize(css, ("", ""))))
 
     def test_empty_variable(self):
         css = "$x:\n* { background:$x; }"
-        result = list(substitute_references(tokenize(css, "")))
+        result = list(substitute_references(tokenize(css, ("", ""))))
         assert [(t.name, t.value) for t in result] == [
             ("variable_name", "$x:"),
             ("variable_value_end", "\n"),
@@ -238,11 +238,11 @@ class TestVariableReferenceSubstitution:
 
     def test_transitive_reference(self):
         css = "$x: 1\n$y: $x\n.thing { border: $y }"
-        assert list(substitute_references(tokenize(css, ""))) == [
+        assert list(substitute_references(tokenize(css, ("", "")))) == [
             Token(
                 name="variable_name",
                 value="$x:",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 0),
                 referenced_by=None,
@@ -250,7 +250,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="whitespace",
                 value=" ",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 3),
                 referenced_by=None,
@@ -258,7 +258,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="number",
                 value="1",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 4),
                 referenced_by=None,
@@ -266,7 +266,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="variable_value_end",
                 value="\n",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 5),
                 referenced_by=None,
@@ -274,7 +274,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="variable_name",
                 value="$y:",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(1, 0),
                 referenced_by=None,
@@ -282,7 +282,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="whitespace",
                 value=" ",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(1, 3),
                 referenced_by=None,
@@ -290,7 +290,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="number",
                 value="1",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 4),
                 referenced_by=ReferencedBy(
@@ -300,7 +300,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="variable_value_end",
                 value="\n",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(1, 6),
                 referenced_by=None,
@@ -308,7 +308,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="selector_start_class",
                 value=".thing",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(2, 0),
                 referenced_by=None,
@@ -316,7 +316,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="whitespace",
                 value=" ",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(2, 6),
                 referenced_by=None,
@@ -324,7 +324,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="declaration_set_start",
                 value="{",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(2, 7),
                 referenced_by=None,
@@ -332,7 +332,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="whitespace",
                 value=" ",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(2, 8),
                 referenced_by=None,
@@ -340,7 +340,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="declaration_name",
                 value="border:",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(2, 9),
                 referenced_by=None,
@@ -348,7 +348,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="whitespace",
                 value=" ",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(2, 16),
                 referenced_by=None,
@@ -356,7 +356,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="number",
                 value="1",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 4),
                 referenced_by=ReferencedBy(
@@ -366,7 +366,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="whitespace",
                 value=" ",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(2, 19),
                 referenced_by=None,
@@ -374,7 +374,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="declaration_set_end",
                 value="}",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(2, 20),
                 referenced_by=None,
@@ -383,11 +383,11 @@ class TestVariableReferenceSubstitution:
 
     def test_multi_value_variable(self):
         css = "$x: 2 4\n$y: 6 $x 2\n.thing { border: $y }"
-        assert list(substitute_references(tokenize(css, ""))) == [
+        assert list(substitute_references(tokenize(css, ("", "")))) == [
             Token(
                 name="variable_name",
                 value="$x:",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 0),
                 referenced_by=None,
@@ -395,7 +395,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="whitespace",
                 value=" ",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 3),
                 referenced_by=None,
@@ -403,7 +403,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="number",
                 value="2",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 4),
                 referenced_by=None,
@@ -411,7 +411,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="whitespace",
                 value=" ",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 5),
                 referenced_by=None,
@@ -419,7 +419,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="number",
                 value="4",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 6),
                 referenced_by=None,
@@ -427,7 +427,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="variable_value_end",
                 value="\n",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 7),
                 referenced_by=None,
@@ -435,7 +435,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="variable_name",
                 value="$y:",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(1, 0),
                 referenced_by=None,
@@ -443,7 +443,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="whitespace",
                 value=" ",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(1, 3),
                 referenced_by=None,
@@ -451,7 +451,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="number",
                 value="6",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(1, 4),
                 referenced_by=None,
@@ -459,7 +459,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="whitespace",
                 value=" ",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(1, 5),
                 referenced_by=None,
@@ -467,7 +467,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="number",
                 value="2",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 4),
                 referenced_by=ReferencedBy(
@@ -477,7 +477,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="whitespace",
                 value=" ",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 5),
                 referenced_by=ReferencedBy(
@@ -487,7 +487,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="number",
                 value="4",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 6),
                 referenced_by=ReferencedBy(
@@ -497,7 +497,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="whitespace",
                 value=" ",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(1, 8),
                 referenced_by=None,
@@ -505,7 +505,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="number",
                 value="2",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(1, 9),
                 referenced_by=None,
@@ -513,7 +513,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="variable_value_end",
                 value="\n",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(1, 10),
                 referenced_by=None,
@@ -521,7 +521,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="selector_start_class",
                 value=".thing",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(2, 0),
                 referenced_by=None,
@@ -529,7 +529,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="whitespace",
                 value=" ",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(2, 6),
                 referenced_by=None,
@@ -537,7 +537,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="declaration_set_start",
                 value="{",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(2, 7),
                 referenced_by=None,
@@ -545,7 +545,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="whitespace",
                 value=" ",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(2, 8),
                 referenced_by=None,
@@ -553,7 +553,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="declaration_name",
                 value="border:",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(2, 9),
                 referenced_by=None,
@@ -561,7 +561,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="whitespace",
                 value=" ",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(2, 16),
                 referenced_by=None,
@@ -569,7 +569,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="number",
                 value="6",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(1, 4),
                 referenced_by=ReferencedBy(
@@ -579,7 +579,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="whitespace",
                 value=" ",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(1, 5),
                 referenced_by=ReferencedBy(
@@ -589,7 +589,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="number",
                 value="2",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 4),
                 referenced_by=ReferencedBy(
@@ -599,7 +599,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="whitespace",
                 value=" ",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 5),
                 referenced_by=ReferencedBy(
@@ -609,7 +609,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="number",
                 value="4",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 6),
                 referenced_by=ReferencedBy(
@@ -619,7 +619,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="whitespace",
                 value=" ",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(1, 8),
                 referenced_by=ReferencedBy(
@@ -629,7 +629,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="number",
                 value="2",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(1, 9),
                 referenced_by=ReferencedBy(
@@ -639,7 +639,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="whitespace",
                 value=" ",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(2, 19),
                 referenced_by=None,
@@ -647,7 +647,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="declaration_set_end",
                 value="}",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(2, 20),
                 referenced_by=None,
@@ -656,11 +656,11 @@ class TestVariableReferenceSubstitution:
 
     def test_variable_used_inside_property_value(self):
         css = "$x: red\n.thing { border: on $x; }"
-        assert list(substitute_references(tokenize(css, ""))) == [
+        assert list(substitute_references(tokenize(css, ("", "")))) == [
             Token(
                 name="variable_name",
                 value="$x:",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 0),
                 referenced_by=None,
@@ -668,7 +668,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="whitespace",
                 value=" ",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 3),
                 referenced_by=None,
@@ -676,7 +676,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="token",
                 value="red",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 4),
                 referenced_by=None,
@@ -684,7 +684,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="variable_value_end",
                 value="\n",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 7),
                 referenced_by=None,
@@ -692,7 +692,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="selector_start_class",
                 value=".thing",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(1, 0),
                 referenced_by=None,
@@ -700,7 +700,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="whitespace",
                 value=" ",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(1, 6),
                 referenced_by=None,
@@ -708,7 +708,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="declaration_set_start",
                 value="{",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(1, 7),
                 referenced_by=None,
@@ -716,7 +716,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="whitespace",
                 value=" ",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(1, 8),
                 referenced_by=None,
@@ -724,7 +724,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="declaration_name",
                 value="border:",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(1, 9),
                 referenced_by=None,
@@ -732,7 +732,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="whitespace",
                 value=" ",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(1, 16),
                 referenced_by=None,
@@ -740,7 +740,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="token",
                 value="on",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(1, 17),
                 referenced_by=None,
@@ -748,7 +748,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="whitespace",
                 value=" ",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(1, 19),
                 referenced_by=None,
@@ -756,7 +756,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="token",
                 value="red",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 4),
                 referenced_by=ReferencedBy(
@@ -766,7 +766,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="declaration_end",
                 value=";",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(1, 22),
                 referenced_by=None,
@@ -774,7 +774,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="whitespace",
                 value=" ",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(1, 23),
                 referenced_by=None,
@@ -782,7 +782,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="declaration_set_end",
                 value="}",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(1, 24),
                 referenced_by=None,
@@ -791,11 +791,11 @@ class TestVariableReferenceSubstitution:
 
     def test_variable_definition_eof(self):
         css = "$x: 1"
-        assert list(substitute_references(tokenize(css, ""))) == [
+        assert list(substitute_references(tokenize(css, ("", "")))) == [
             Token(
                 name="variable_name",
                 value="$x:",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 0),
                 referenced_by=None,
@@ -803,7 +803,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="whitespace",
                 value=" ",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 3),
                 referenced_by=None,
@@ -811,7 +811,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="number",
                 value="1",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 4),
                 referenced_by=None,
@@ -820,11 +820,11 @@ class TestVariableReferenceSubstitution:
 
     def test_variable_reference_whitespace_trimming(self):
         css = "$x:    123;.thing{border: $x}"
-        assert list(substitute_references(tokenize(css, ""))) == [
+        assert list(substitute_references(tokenize(css, ("", "")))) == [
             Token(
                 name="variable_name",
                 value="$x:",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 0),
                 referenced_by=None,
@@ -832,7 +832,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="whitespace",
                 value="    ",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 3),
                 referenced_by=None,
@@ -840,7 +840,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="number",
                 value="123",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 7),
                 referenced_by=None,
@@ -848,7 +848,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="variable_value_end",
                 value=";",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 10),
                 referenced_by=None,
@@ -856,7 +856,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="selector_start_class",
                 value=".thing",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 11),
                 referenced_by=None,
@@ -864,7 +864,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="declaration_set_start",
                 value="{",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 17),
                 referenced_by=None,
@@ -872,7 +872,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="declaration_name",
                 value="border:",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 18),
                 referenced_by=None,
@@ -880,7 +880,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="whitespace",
                 value=" ",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 25),
                 referenced_by=None,
@@ -888,7 +888,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="number",
                 value="123",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 7),
                 referenced_by=ReferencedBy(
@@ -898,7 +898,7 @@ class TestVariableReferenceSubstitution:
             Token(
                 name="declaration_set_end",
                 value="}",
-                path="",
+                read_from=("", ""),
                 code=css,
                 location=(0, 28),
                 referenced_by=None,
diff --git a/tests/css/test_styles.py b/tests/css/test_styles.py
index b31ad4654..7a4578200 100644
--- a/tests/css/test_styles.py
+++ b/tests/css/test_styles.py
@@ -115,7 +115,7 @@ def test_get_opacity_default():
 
 def test_styles_css_property():
     css = "opacity: 50%; text-opacity: 20%; background: green; color: red; tint: dodgerblue 20%;"
-    styles = Styles().parse(css, path="")
+    styles = Styles().parse(css, read_from=("", ""))
     assert styles.css == (
         "background: #008000;\n"
         "color: #FF0000;\n"
diff --git a/tests/css/test_tokenize.py b/tests/css/test_tokenize.py
index 01945c9db..d4dfba888 100644
--- a/tests/css/test_tokenize.py
+++ b/tests/css/test_tokenize.py
@@ -21,11 +21,11 @@ VALID_VARIABLE_NAMES = [
 @pytest.mark.parametrize("name", VALID_VARIABLE_NAMES)
 def test_variable_declaration_valid_names(name):
     css = f"${name}: black on red;"
-    assert list(tokenize(css, "")) == [
+    assert list(tokenize(css, ("", ""))) == [
         Token(
             name="variable_name",
             value=f"${name}:",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 0),
             referenced_by=None,
@@ -33,7 +33,7 @@ def test_variable_declaration_valid_names(name):
         Token(
             name="whitespace",
             value=" ",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 14),
             referenced_by=None,
@@ -41,7 +41,7 @@ def test_variable_declaration_valid_names(name):
         Token(
             name="token",
             value="black",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 15),
             referenced_by=None,
@@ -49,7 +49,7 @@ def test_variable_declaration_valid_names(name):
         Token(
             name="whitespace",
             value=" ",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 20),
             referenced_by=None,
@@ -57,7 +57,7 @@ def test_variable_declaration_valid_names(name):
         Token(
             name="token",
             value="on",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 21),
             referenced_by=None,
@@ -65,7 +65,7 @@ def test_variable_declaration_valid_names(name):
         Token(
             name="whitespace",
             value=" ",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 23),
             referenced_by=None,
@@ -73,7 +73,7 @@ def test_variable_declaration_valid_names(name):
         Token(
             name="token",
             value="red",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 24),
             referenced_by=None,
@@ -81,7 +81,7 @@ def test_variable_declaration_valid_names(name):
         Token(
             name="variable_value_end",
             value=";",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 27),
             referenced_by=None,
@@ -91,11 +91,11 @@ def test_variable_declaration_valid_names(name):
 
 def test_variable_declaration_multiple_values():
     css = "$x: 2vw\t4% 6s  red;"
-    assert list(tokenize(css, "")) == [
+    assert list(tokenize(css, ("", ""))) == [
         Token(
             name="variable_name",
             value="$x:",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 0),
             referenced_by=None,
@@ -103,7 +103,7 @@ def test_variable_declaration_multiple_values():
         Token(
             name="whitespace",
             value=" ",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 3),
             referenced_by=None,
@@ -111,7 +111,7 @@ def test_variable_declaration_multiple_values():
         Token(
             name="scalar",
             value="2vw",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 4),
             referenced_by=None,
@@ -119,7 +119,7 @@ def test_variable_declaration_multiple_values():
         Token(
             name="whitespace",
             value="\t",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 7),
             referenced_by=None,
@@ -127,7 +127,7 @@ def test_variable_declaration_multiple_values():
         Token(
             name="scalar",
             value="4%",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 8),
             referenced_by=None,
@@ -135,7 +135,7 @@ def test_variable_declaration_multiple_values():
         Token(
             name="whitespace",
             value=" ",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 10),
             referenced_by=None,
@@ -143,7 +143,7 @@ def test_variable_declaration_multiple_values():
         Token(
             name="duration",
             value="6s",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 11),
             referenced_by=None,
@@ -151,7 +151,7 @@ def test_variable_declaration_multiple_values():
         Token(
             name="whitespace",
             value="  ",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 13),
             referenced_by=None,
@@ -159,7 +159,7 @@ def test_variable_declaration_multiple_values():
         Token(
             name="token",
             value="red",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 15),
             referenced_by=None,
@@ -167,7 +167,7 @@ def test_variable_declaration_multiple_values():
         Token(
             name="variable_value_end",
             value=";",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 18),
             referenced_by=None,
@@ -183,112 +183,112 @@ def test_single_line_comment():
 } # Nada"""
     # Check the css parses
     # list(parse(css, "<foo>"))
-    result = list(tokenize(css, ""))
+    result = list(tokenize(css, ("", "")))
 
     print(result)
     expected = [
         Token(
             name="whitespace",
             value="\n",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 9),
         ),
         Token(
             name="selector_start_id",
             value="#foo",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(1, 0),
         ),
         Token(
             name="whitespace",
             value=" ",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(1, 4),
         ),
         Token(
             name="declaration_set_start",
             value="{",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(1, 5),
         ),
         Token(
             name="whitespace",
             value=" ",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(1, 6),
         ),
         Token(
             name="whitespace",
             value="\n",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(1, 16),
         ),
         Token(
             name="whitespace",
             value="    ",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(2, 0),
         ),
         Token(
             name="declaration_name",
             value="color:",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(2, 4),
         ),
         Token(
             name="whitespace",
             value=" ",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(2, 10),
         ),
         Token(
             name="token",
             value="red",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(2, 11),
         ),
         Token(
             name="declaration_end",
             value=";",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(2, 14),
         ),
         Token(
             name="whitespace",
             value=" ",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(2, 15),
         ),
         Token(
             name="whitespace",
             value="\n",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(2, 30),
         ),
         Token(
             name="declaration_set_end",
             value="}",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(3, 0),
         ),
         Token(
             name="whitespace",
             value=" ",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(3, 1),
         ),
@@ -298,11 +298,11 @@ def test_single_line_comment():
 
 def test_variable_declaration_comment_ignored():
     css = "$x: red; /* comment */"
-    assert list(tokenize(css, "")) == [
+    assert list(tokenize(css, ("", ""))) == [
         Token(
             name="variable_name",
             value="$x:",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 0),
             referenced_by=None,
@@ -310,7 +310,7 @@ def test_variable_declaration_comment_ignored():
         Token(
             name="whitespace",
             value=" ",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 3),
             referenced_by=None,
@@ -318,7 +318,7 @@ def test_variable_declaration_comment_ignored():
         Token(
             name="token",
             value="red",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 4),
             referenced_by=None,
@@ -326,7 +326,7 @@ def test_variable_declaration_comment_ignored():
         Token(
             name="variable_value_end",
             value=";",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 7),
             referenced_by=None,
@@ -334,7 +334,7 @@ def test_variable_declaration_comment_ignored():
         Token(
             name="whitespace",
             value=" ",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 8),
             referenced_by=None,
@@ -344,11 +344,11 @@ def test_variable_declaration_comment_ignored():
 
 def test_variable_declaration_comment_interspersed_ignored():
     css = "$x: re/* comment */d;"
-    assert list(tokenize(css, "")) == [
+    assert list(tokenize(css, ("", ""))) == [
         Token(
             name="variable_name",
             value="$x:",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 0),
             referenced_by=None,
@@ -356,7 +356,7 @@ def test_variable_declaration_comment_interspersed_ignored():
         Token(
             name="whitespace",
             value=" ",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 3),
             referenced_by=None,
@@ -364,7 +364,7 @@ def test_variable_declaration_comment_interspersed_ignored():
         Token(
             name="token",
             value="re",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 4),
             referenced_by=None,
@@ -372,7 +372,7 @@ def test_variable_declaration_comment_interspersed_ignored():
         Token(
             name="token",
             value="d",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 19),
             referenced_by=None,
@@ -380,7 +380,7 @@ def test_variable_declaration_comment_interspersed_ignored():
         Token(
             name="variable_value_end",
             value=";",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 20),
             referenced_by=None,
@@ -390,11 +390,11 @@ def test_variable_declaration_comment_interspersed_ignored():
 
 def test_variable_declaration_no_semicolon():
     css = "$x: 1\n$y: 2"
-    assert list(tokenize(css, "")) == [
+    assert list(tokenize(css, ("", ""))) == [
         Token(
             name="variable_name",
             value="$x:",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 0),
             referenced_by=None,
@@ -402,7 +402,7 @@ def test_variable_declaration_no_semicolon():
         Token(
             name="whitespace",
             value=" ",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 3),
             referenced_by=None,
@@ -410,7 +410,7 @@ def test_variable_declaration_no_semicolon():
         Token(
             name="number",
             value="1",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 4),
             referenced_by=None,
@@ -418,7 +418,7 @@ def test_variable_declaration_no_semicolon():
         Token(
             name="variable_value_end",
             value="\n",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 5),
             referenced_by=None,
@@ -426,7 +426,7 @@ def test_variable_declaration_no_semicolon():
         Token(
             name="variable_name",
             value="$y:",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(1, 0),
             referenced_by=None,
@@ -434,7 +434,7 @@ def test_variable_declaration_no_semicolon():
         Token(
             name="whitespace",
             value=" ",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(1, 3),
             referenced_by=None,
@@ -442,7 +442,7 @@ def test_variable_declaration_no_semicolon():
         Token(
             name="number",
             value="2",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(1, 4),
             referenced_by=None,
@@ -453,17 +453,17 @@ def test_variable_declaration_no_semicolon():
 def test_variable_declaration_invalid_value():
     css = "$x:(@$12x)"
     with pytest.raises(TokenError):
-        list(tokenize(css, ""))
+        list(tokenize(css, ("", "")))
 
 
 def test_variables_declarations_amongst_rulesets():
     css = "$x:1; .thing{text:red;} $y:2;"
-    tokens = list(tokenize(css, ""))
+    tokens = list(tokenize(css, ("", "")))
     assert tokens == [
         Token(
             name="variable_name",
             value="$x:",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 0),
             referenced_by=None,
@@ -471,7 +471,7 @@ def test_variables_declarations_amongst_rulesets():
         Token(
             name="number",
             value="1",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 3),
             referenced_by=None,
@@ -479,7 +479,7 @@ def test_variables_declarations_amongst_rulesets():
         Token(
             name="variable_value_end",
             value=";",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 4),
             referenced_by=None,
@@ -487,7 +487,7 @@ def test_variables_declarations_amongst_rulesets():
         Token(
             name="whitespace",
             value=" ",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 5),
             referenced_by=None,
@@ -495,7 +495,7 @@ def test_variables_declarations_amongst_rulesets():
         Token(
             name="selector_start_class",
             value=".thing",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 6),
             referenced_by=None,
@@ -503,7 +503,7 @@ def test_variables_declarations_amongst_rulesets():
         Token(
             name="declaration_set_start",
             value="{",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 12),
             referenced_by=None,
@@ -511,7 +511,7 @@ def test_variables_declarations_amongst_rulesets():
         Token(
             name="declaration_name",
             value="text:",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 13),
             referenced_by=None,
@@ -519,7 +519,7 @@ def test_variables_declarations_amongst_rulesets():
         Token(
             name="token",
             value="red",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 18),
             referenced_by=None,
@@ -527,7 +527,7 @@ def test_variables_declarations_amongst_rulesets():
         Token(
             name="declaration_end",
             value=";",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 21),
             referenced_by=None,
@@ -535,7 +535,7 @@ def test_variables_declarations_amongst_rulesets():
         Token(
             name="declaration_set_end",
             value="}",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 22),
             referenced_by=None,
@@ -543,7 +543,7 @@ def test_variables_declarations_amongst_rulesets():
         Token(
             name="whitespace",
             value=" ",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 23),
             referenced_by=None,
@@ -551,7 +551,7 @@ def test_variables_declarations_amongst_rulesets():
         Token(
             name="variable_name",
             value="$y:",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 24),
             referenced_by=None,
@@ -559,7 +559,7 @@ def test_variables_declarations_amongst_rulesets():
         Token(
             name="number",
             value="2",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 27),
             referenced_by=None,
@@ -567,7 +567,7 @@ def test_variables_declarations_amongst_rulesets():
         Token(
             name="variable_value_end",
             value=";",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 28),
             referenced_by=None,
@@ -577,11 +577,11 @@ def test_variables_declarations_amongst_rulesets():
 
 def test_variables_reference_in_rule_declaration_value():
     css = ".warn{text: $warning;}"
-    assert list(tokenize(css, "")) == [
+    assert list(tokenize(css, ("", ""))) == [
         Token(
             name="selector_start_class",
             value=".warn",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 0),
             referenced_by=None,
@@ -589,7 +589,7 @@ def test_variables_reference_in_rule_declaration_value():
         Token(
             name="declaration_set_start",
             value="{",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 5),
             referenced_by=None,
@@ -597,7 +597,7 @@ def test_variables_reference_in_rule_declaration_value():
         Token(
             name="declaration_name",
             value="text:",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 6),
             referenced_by=None,
@@ -605,7 +605,7 @@ def test_variables_reference_in_rule_declaration_value():
         Token(
             name="whitespace",
             value=" ",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 11),
             referenced_by=None,
@@ -613,7 +613,7 @@ def test_variables_reference_in_rule_declaration_value():
         Token(
             name="variable_ref",
             value="$warning",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 12),
             referenced_by=None,
@@ -621,7 +621,7 @@ def test_variables_reference_in_rule_declaration_value():
         Token(
             name="declaration_end",
             value=";",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 20),
             referenced_by=None,
@@ -629,7 +629,7 @@ def test_variables_reference_in_rule_declaration_value():
         Token(
             name="declaration_set_end",
             value="}",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 21),
             referenced_by=None,
@@ -639,11 +639,11 @@ def test_variables_reference_in_rule_declaration_value():
 
 def test_variables_reference_in_rule_declaration_value_multiple():
     css = ".card{padding: $pad-y $pad-x;}"
-    assert list(tokenize(css, "")) == [
+    assert list(tokenize(css, ("", ""))) == [
         Token(
             name="selector_start_class",
             value=".card",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 0),
             referenced_by=None,
@@ -651,7 +651,7 @@ def test_variables_reference_in_rule_declaration_value_multiple():
         Token(
             name="declaration_set_start",
             value="{",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 5),
             referenced_by=None,
@@ -659,7 +659,7 @@ def test_variables_reference_in_rule_declaration_value_multiple():
         Token(
             name="declaration_name",
             value="padding:",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 6),
             referenced_by=None,
@@ -667,7 +667,7 @@ def test_variables_reference_in_rule_declaration_value_multiple():
         Token(
             name="whitespace",
             value=" ",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 14),
             referenced_by=None,
@@ -675,7 +675,7 @@ def test_variables_reference_in_rule_declaration_value_multiple():
         Token(
             name="variable_ref",
             value="$pad-y",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 15),
             referenced_by=None,
@@ -683,7 +683,7 @@ def test_variables_reference_in_rule_declaration_value_multiple():
         Token(
             name="whitespace",
             value=" ",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 21),
             referenced_by=None,
@@ -691,7 +691,7 @@ def test_variables_reference_in_rule_declaration_value_multiple():
         Token(
             name="variable_ref",
             value="$pad-x",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 22),
             referenced_by=None,
@@ -699,7 +699,7 @@ def test_variables_reference_in_rule_declaration_value_multiple():
         Token(
             name="declaration_end",
             value=";",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 28),
             referenced_by=None,
@@ -707,7 +707,7 @@ def test_variables_reference_in_rule_declaration_value_multiple():
         Token(
             name="declaration_set_end",
             value="}",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 29),
             referenced_by=None,
@@ -717,11 +717,11 @@ def test_variables_reference_in_rule_declaration_value_multiple():
 
 def test_variables_reference_in_variable_declaration():
     css = "$x: $y;"
-    assert list(tokenize(css, "")) == [
+    assert list(tokenize(css, ("", ""))) == [
         Token(
             name="variable_name",
             value="$x:",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 0),
             referenced_by=None,
@@ -729,7 +729,7 @@ def test_variables_reference_in_variable_declaration():
         Token(
             name="whitespace",
             value=" ",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 3),
             referenced_by=None,
@@ -737,7 +737,7 @@ def test_variables_reference_in_variable_declaration():
         Token(
             name="variable_ref",
             value="$y",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 4),
             referenced_by=None,
@@ -745,7 +745,7 @@ def test_variables_reference_in_variable_declaration():
         Token(
             name="variable_value_end",
             value=";",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 6),
             referenced_by=None,
@@ -755,11 +755,11 @@ def test_variables_reference_in_variable_declaration():
 
 def test_variable_references_in_variable_declaration_multiple():
     css = "$x: $y  $z\n"
-    assert list(tokenize(css, "")) == [
+    assert list(tokenize(css, ("", ""))) == [
         Token(
             name="variable_name",
             value="$x:",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 0),
             referenced_by=None,
@@ -767,7 +767,7 @@ def test_variable_references_in_variable_declaration_multiple():
         Token(
             name="whitespace",
             value=" ",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 3),
             referenced_by=None,
@@ -775,7 +775,7 @@ def test_variable_references_in_variable_declaration_multiple():
         Token(
             name="variable_ref",
             value="$y",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 4),
             referenced_by=None,
@@ -783,7 +783,7 @@ def test_variable_references_in_variable_declaration_multiple():
         Token(
             name="whitespace",
             value="  ",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 6),
             referenced_by=None,
@@ -791,7 +791,7 @@ def test_variable_references_in_variable_declaration_multiple():
         Token(
             name="variable_ref",
             value="$z",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 8),
             referenced_by=None,
@@ -799,7 +799,7 @@ def test_variable_references_in_variable_declaration_multiple():
         Token(
             name="variable_value_end",
             value="\n",
-            path="",
+            read_from=("", ""),
             code=css,
             location=(0, 10),
             referenced_by=None,
@@ -809,92 +809,92 @@ def test_variable_references_in_variable_declaration_multiple():
 
 def test_allow_new_lines():
     css = ".foo{margin: 1\n1 0 0}"
-    tokens = list(tokenize(css, ""))
+    tokens = list(tokenize(css, ("", "")))
     print(repr(tokens))
     expected = [
         Token(
             name="selector_start_class",
             value=".foo",
-            path="",
+            read_from=("", ""),
             code=".foo{margin: 1\n1 0 0}",
             location=(0, 0),
         ),
         Token(
             name="declaration_set_start",
             value="{",
-            path="",
+            read_from=("", ""),
             code=".foo{margin: 1\n1 0 0}",
             location=(0, 4),
         ),
         Token(
             name="declaration_name",
             value="margin:",
-            path="",
+            read_from=("", ""),
             code=".foo{margin: 1\n1 0 0}",
             location=(0, 5),
         ),
         Token(
             name="whitespace",
             value=" ",
-            path="",
+            read_from=("", ""),
             code=".foo{margin: 1\n1 0 0}",
             location=(0, 12),
         ),
         Token(
             name="number",
             value="1",
-            path="",
+            read_from=("", ""),
             code=".foo{margin: 1\n1 0 0}",
             location=(0, 13),
         ),
         Token(
             name="whitespace",
             value="\n",
-            path="",
+            read_from=("", ""),
             code=".foo{margin: 1\n1 0 0}",
             location=(0, 14),
         ),
         Token(
             name="number",
             value="1",
-            path="",
+            read_from=("", ""),
             code=".foo{margin: 1\n1 0 0}",
             location=(1, 0),
         ),
         Token(
             name="whitespace",
             value=" ",
-            path="",
+            read_from=("", ""),
             code=".foo{margin: 1\n1 0 0}",
             location=(1, 1),
         ),
         Token(
             name="number",
             value="0",
-            path="",
+            read_from=("", ""),
             code=".foo{margin: 1\n1 0 0}",
             location=(1, 2),
         ),
         Token(
             name="whitespace",
             value=" ",
-            path="",
+            read_from=("", ""),
             code=".foo{margin: 1\n1 0 0}",
             location=(1, 3),
         ),
         Token(
             name="number",
             value="0",
-            path="",
+            read_from=("", ""),
             code=".foo{margin: 1\n1 0 0}",
             location=(1, 4),
         ),
         Token(
             name="declaration_set_end",
             value="}",
-            path="",
+            read_from=("", ""),
             code=".foo{margin: 1\n1 0 0}",
             location=(1, 5),
         ),
     ]
-    assert list(tokenize(css, "")) == expected
+    assert list(tokenize(css, ("", ""))) == expected