@@ -740,6 +740,112 @@ def get_data_path(
740740# =============================================================================
741741
742742
743+ def _process_github_url(data: FrameT | Any) -> FrameT | Any:
744+ """
745+ Process data parameter to handle GitHub URLs pointing to CSV or Parquet files.
746+
747+ Handles both standard GitHub URLs and raw GitHub content URLs, downloading the content
748+ and processing it as a local file.
749+
750+ Supports:
751+ - Standard github.com URLs pointing to CSV or Parquet files (automatically transformed to raw URLs)
752+ - Raw raw.githubusercontent.com URLs pointing to CSV or Parquet files (processed directly)
753+ - Both CSV and Parquet file formats
754+ - Automatic temporary file management and cleanup
755+
756+ Parameters
757+ ----------
758+ data : FrameT | Any
759+ The data parameter which may be a GitHub URL string or any other data type.
760+
761+ Returns
762+ -------
763+ FrameT | Any
764+ If the input is a supported GitHub URL, returns a DataFrame loaded from the downloaded file.
765+ Otherwise, returns the original data unchanged.
766+
767+ Examples
768+ --------
769+ Standard GitHub URL (automatically transformed):
770+ >>> url = "https://github.com/user/repo/blob/main/data.csv"
771+ >>> df = _process_github_url(url)
772+
773+ Raw GitHub URL (used directly):
774+ >>> raw_url = "https://raw.githubusercontent.com/user/repo/main/data.csv"
775+ >>> df = _process_github_url(raw_url)
776+ """
777+ import re
778+ import tempfile
779+ from urllib.parse import urlparse
780+ from urllib.request import urlopen
781+
782+ # Check if data is a string that looks like a GitHub URL
783+ if not isinstance(data, str):
784+ return data
785+
786+ # Parse the URL to check if it's a GitHub URL
787+ try:
788+ parsed = urlparse(data)
789+ except Exception:
790+ return data
791+
792+ # Check if it's a GitHub URL (standard or raw)
793+ is_standard_github = parsed.netloc in ["github.com", "www.github.com"]
794+ is_raw_github = parsed.netloc == "raw.githubusercontent.com"
795+
796+ if not (is_standard_github or is_raw_github):
797+ return data
798+
799+ # Check if it points to a CSV or Parquet file
800+ path_lower = parsed.path.lower()
801+ if not (path_lower.endswith(".csv") or path_lower.endswith(".parquet")):
802+ return data
803+
804+ # Determine the raw URL to download from
805+ if is_raw_github:
806+ # Already a raw GitHub URL, use it directly
807+ raw_url = data
808+ else:
809+ # Transform GitHub URL to raw content URL
810+ # Pattern: https://github.com/user/repo/blob/branch/path/file.ext
811+ # Becomes: https://raw.githubusercontent.com/user/repo/branch/path/file.ext
812+ github_pattern = r"github\.com/([^/]+)/([^/]+)/blob/([^/]+)/(.+)"
813+ match = re.search(github_pattern, data)
814+
815+ if not match:
816+ # If URL doesn't match expected GitHub blob pattern, return original data
817+ return data
818+
819+ user, repo, branch, file_path = match.groups()
820+ raw_url = f"https://raw.githubusercontent.com/{user}/{repo}/{branch}/{file_path}"
821+
822+ # Download the file content to a temporary file
823+ try:
824+ with urlopen(raw_url) as response:
825+ content = response.read()
826+
827+ # Determine file extension
828+ file_ext = ".csv" if path_lower.endswith(".csv") else ".parquet"
829+
830+ # Create a temporary file
831+ with tempfile.NamedTemporaryFile(mode="wb", suffix=file_ext, delete=False) as tmp_file:
832+ tmp_file.write(content)
833+ tmp_file_path = tmp_file.name
834+
835+ # Process the temporary file using existing CSV or Parquet processing functions
836+ if file_ext == ".csv":
837+ return _process_csv_input(tmp_file_path)
838+ else: # .parquet
839+ return _process_parquet_input(tmp_file_path)
840+
841+ except Exception:
842+ # If download or processing fails, return original data
843+ return data
844+
845+ except Exception as e:
846+ raise RuntimeError(f"Failed to download or process GitHub file from {raw_url}: {e}") from e
847+
848+
743849def _process_connection_string(data: FrameT | Any) -> FrameT | Any:
744850 """
745851 Process data parameter to handle database connection strings.
@@ -1215,6 +1321,9 @@ def preview(
12151321 """
12161322
12171323 # Process input data to handle different data source types
1324+ # Handle GitHub URL input (e.g., "https://github.com/user/repo/blob/main/data.csv")
1325+ data = _process_github_url(data)
1326+
12181327 # Handle connection string input (e.g., "duckdb:///path/to/file.ddb::table_name")
12191328 data = _process_connection_string(data)
12201329
@@ -1707,6 +1816,9 @@ def missing_vals_tbl(data: FrameT | Any) -> GT:
17071816 """
17081817
17091818 # Process input data to handle different data source types
1819+ # Handle GitHub URL input (e.g., "https://github.com/user/repo/blob/main/data.csv")
1820+ data = _process_github_url(data)
1821+
17101822 # Handle connection string input (e.g., "duckdb:///path/to/file.ddb::table_name")
17111823 data = _process_connection_string(data)
17121824
@@ -2223,6 +2335,11 @@ def get_column_count(data: FrameT | Any) -> int:
22232335 provided. The file will be automatically detected and loaded using the best available DataFrame
22242336 library. The loading preference is Polars first, then Pandas as a fallback.
22252337
2338+ GitHub URLs pointing to CSV or Parquet files are automatically detected and converted to raw
2339+ content URLs for downloading. The URL format should be:
2340+ `https://github.com/user/repo/blob/branch/path/file.csv` or
2341+ `https://github.com/user/repo/blob/branch/path/file.parquet`
2342+
22262343 Connection strings follow database URL formats and must also specify a table using the
22272344 `::table_name` suffix. Examples include:
22282345
@@ -2314,17 +2431,14 @@ def get_column_count(data: FrameT | Any) -> int:
23142431
23152432 # Process different input types
23162433 if isinstance(data, str) or isinstance(data, Path):
2317- if "::" in str(data):
2318- data = _process_connection_string(data)
2319- elif str(data).endswith(".csv") or str(data).endswith(".CSV"):
2320- data = _process_csv_input(data)
2321- elif (
2322- str(data).endswith(".parquet")
2323- or str(data).endswith(".PARQUET")
2324- or "*" in str(data)
2325- or Path(data).is_dir()
2326- ):
2327- data = _process_parquet_input(data)
2434+ # Process GitHub URLs first
2435+ data = _process_github_url(data)
2436+ # Handle connection string input
2437+ data = _process_connection_string(data)
2438+ # Handle CSV file input
2439+ data = _process_csv_input(data)
2440+ # Handle Parquet file input
2441+ data = _process_parquet_input(data)
23282442 elif isinstance(data, list):
23292443 # Handle list of file paths (likely Parquet files)
23302444 data = _process_parquet_input(data)
@@ -2385,6 +2499,7 @@ def get_row_count(data: FrameT | Any) -> int:
23852499 - CSV files (string path or `pathlib.Path` object with `.csv` extension)
23862500 - Parquet files (string path, `pathlib.Path` object, glob pattern, directory with `.parquet`
23872501 extension, or partitioned dataset)
2502+ - GitHub URLs (direct links to CSV or Parquet files on GitHub)
23882503 - Database connection strings (URI format with optional table specification)
23892504
23902505 The table types marked with an asterisk need to be prepared as Ibis tables (with type of
@@ -2396,6 +2511,11 @@ def get_row_count(data: FrameT | Any) -> int:
23962511 provided. The file will be automatically detected and loaded using the best available DataFrame
23972512 library. The loading preference is Polars first, then Pandas as a fallback.
23982513
2514+ GitHub URLs pointing to CSV or Parquet files are automatically detected and converted to raw
2515+ content URLs for downloading. The URL format should be:
2516+ `https://github.com/user/repo/blob/branch/path/file.csv` or
2517+ `https://github.com/user/repo/blob/branch/path/file.parquet`
2518+
23992519 Connection strings follow database URL formats and must also specify a table using the
24002520 `::table_name` suffix. Examples include:
24012521
@@ -2487,17 +2607,14 @@ def get_row_count(data: FrameT | Any) -> int:
24872607
24882608 # Process different input types
24892609 if isinstance(data, str) or isinstance(data, Path):
2490- if "::" in str(data):
2491- data = _process_connection_string(data)
2492- elif str(data).endswith(".csv") or str(data).endswith(".CSV"):
2493- data = _process_csv_input(data)
2494- elif (
2495- str(data).endswith(".parquet")
2496- or str(data).endswith(".PARQUET")
2497- or "*" in str(data)
2498- or Path(data).is_dir()
2499- ):
2500- data = _process_parquet_input(data)
2610+ # Process GitHub URLs first
2611+ data = _process_github_url(data)
2612+ # Handle connection string input
2613+ data = _process_connection_string(data)
2614+ # Handle CSV file input
2615+ data = _process_csv_input(data)
2616+ # Handle Parquet file input
2617+ data = _process_parquet_input(data)
25012618 elif isinstance(data, list):
25022619 # Handle list of file paths (likely Parquet files)
25032620 data = _process_parquet_input(data)
@@ -2905,13 +3022,15 @@ class Validate:
29053022 ----------
29063023 data
29073024 The table to validate, which could be a DataFrame object, an Ibis table object, a CSV
2908- file path, a Parquet file path, or a database connection string. When providing a CSV or
2909- Parquet file path (as a string or `pathlib.Path` object), the file will be automatically
2910- loaded using an available DataFrame library (Polars or Pandas). Parquet input also supports
2911- glob patterns, directories containing .parquet files, and Spark-style partitioned datasets.
2912- Connection strings enable direct database access via Ibis with optional table specification
2913- using the `::table_name` suffix. Read the *Supported Input Table Types* section for details
2914- on the supported table types.
3025+ file path, a Parquet file path, a GitHub URL pointing to a CSV or Parquet file, or a
3026+ database connection string. When providing a CSV or Parquet file path (as a string or
3027+ `pathlib.Path` object), the file will be automatically loaded using an available DataFrame
3028+ library (Polars or Pandas). Parquet input also supports glob patterns, directories
3029+ containing .parquet files, and Spark-style partitioned datasets. GitHub URLs are
3030+ automatically transformed to raw content URLs and downloaded. Connection strings enable
3031+ direct database access via Ibis with optional table specification using the `::table_name`
3032+ suffix. Read the *Supported Input Table Types* section for details on the supported table
3033+ types.
29153034 tbl_name
29163035 An optional name to assign to the input table object. If no value is provided, a name will
29173036 be generated based on whatever information is available. This table name will be displayed
@@ -3431,6 +3550,9 @@ def send_report():
34313550 locale: str | None = None
34323551
34333552 def __post_init__(self):
3553+ # Handle GitHub URL input for the data parameter
3554+ self.data = _process_github_url(self.data)
3555+
34343556 # Handle connection string input for the data parameter
34353557 self.data = _process_connection_string(self.data)
34363558
0 commit comments