1919import logging
2020import os
2121import random
22+ import re
2223import shutil
2324import string
2425import tempfile
@@ -196,10 +197,8 @@ def create_bq_remote_function(
196197 import bigframes .core .utils
197198
198199 # removes anything that isn't letter, number or underscore
199- sql_func_legal_name = bigframes .core .utils .label_to_identifier (
200- name , strict = True
201- )
202- bq_function_name_escaped = bigframes .core .sql .identifier (sql_func_legal_name )
200+ _validate_routine_name (name )
201+ bq_function_name_escaped = bigframes .core .sql .identifier (name )
203202 create_function_ddl = f"""
204203 CREATE OR REPLACE FUNCTION `{ self ._gcp_project_id } .{ self ._bq_dataset } `.{ bq_function_name_escaped } ({ udf_def .signature .to_sql_input_signature ()} )
205204 RETURNS { udf_def .signature .with_devirtualize ().output .sql_type }
@@ -263,7 +262,10 @@ def provision_bq_managed_function(
263262 # Augment user package requirements with any internal package
264263 # requirements.
265264 packages = _utils .get_updated_package_requirements (
266- packages , is_row_processor , capture_references , ignore_package_version = True
265+ packages or [],
266+ is_row_processor ,
267+ capture_references ,
268+ ignore_package_version = True ,
267269 )
268270 if packages :
269271 managed_function_options ["packages" ] = packages
@@ -579,7 +581,7 @@ def provision_bq_remote_function(
579581 reuse : bool ,
580582 name : str | None ,
581583 package_requirements : tuple [str , ...],
582- max_batching_rows : int ,
584+ max_batching_rows : int | None ,
583585 cloud_function_timeout : int | None ,
584586 cloud_function_max_instance_count : int | None ,
585587 cloud_function_vpc_connector : str | None ,
@@ -591,7 +593,7 @@ def provision_bq_remote_function(
591593 """Provision a BigQuery remote function."""
592594 # Augment user package requirements with any internal package
593595 # requirements
594- package_requirements = _utils .get_updated_package_requirements (
596+ full_package_requirements = _utils .get_updated_package_requirements (
595597 package_requirements , func_signature .is_row_processor
596598 )
597599
@@ -611,7 +613,7 @@ def provision_bq_remote_function(
611613 concurrency = (workers * threads ) if (expected_milli_cpus >= 1000 ) else 1
612614
613615 cloud_func_spec = udf_def .CloudRunFunctionConfig (
614- code = udf_def .CodeDef .from_func (def_ , package_requirements ),
616+ code = udf_def .CodeDef .from_func (def_ , full_package_requirements ),
615617 signature = func_signature ,
616618 timeout_seconds = cloud_function_timeout ,
617619 max_instance_count = cloud_function_max_instance_count ,
@@ -655,7 +657,7 @@ def provision_bq_remote_function(
655657 intended_rf_spec = udf_def .RemoteFunctionConfig (
656658 endpoint = cf_endpoint ,
657659 connection_id = self ._bq_connection_id ,
658- max_batching_rows = max_batching_rows ,
660+ max_batching_rows = max_batching_rows or 1000 ,
659661 signature = func_signature ,
660662 bq_metadata = func_signature .protocol_metadata ,
661663 )
@@ -728,6 +730,15 @@ def get_bigframes_function_name(
728730 return _BQ_FUNCTION_NAME_SEPERATOR .join (parts )
729731
730732
733+ def _validate_routine_name (name : str ) -> None :
734+ """Validate that the given name is a valid BigQuery routine name."""
735+ # Routine IDs can contain only letters (a-z, A-Z), numbers (0-9), or underscores (_)
736+ if not re .match (r"^[a-zA-Z0-9_]+$" , name ):
737+ raise ValueError (
738+ "Routine ID can contain only letters (a-z, A-Z), numbers (0-9), or underscores (_)"
739+ )
740+
741+
731742def _infer_milli_cpus_from_memory (memory_mib : int ) -> int :
732743 # observed values, not formally documented by cloud run functions
733744 if memory_mib < 128 :
0 commit comments