def file_uploader( self, label: str, type: Optional[Union[str, List[str]]] = None, accept_multiple_files: bool = False, key: Optional[Key] = None, help: Optional[str] = None, on_change: Optional[WidgetCallback] = None, args: Optional[WidgetArgs] = None, kwargs: Optional[WidgetKwargs] = None, ) -> SomeUploadedFiles: """Display a file uploader widget. By default, uploaded files are limited to 200MB. You can configure this using the `server.maxUploadSize` config option. For more info on how to set config options, see https://docs.streamlit.io/library/advanced-features/configuration#set-configuration-options Parameters ---------- label : str A short label explaining to the user what this file uploader is for. type : str or list of str or None Array of allowed extensions. ['png', 'jpg'] The default is None, which means all extensions are allowed. accept_multiple_files : bool If True, allows the user to upload multiple files at the same time, in which case the return value will be a list of files. Default: False key : str or int An optional string or integer to use as the unique key for the widget. If this is omitted, a key will be generated for the widget based on its content. Multiple widgets of the same type may not share the same key. help : str A tooltip that gets displayed next to the file uploader. on_change : callable An optional callback invoked when this file_uploader's value changes. args : tuple An optional tuple of args to pass to the callback. kwargs : dict An optional dict of kwargs to pass to the callback. Returns ------- None or UploadedFile or list of UploadedFile - If accept_multiple_files is False, returns either None or an UploadedFile object. - If accept_multiple_files is True, returns a list with the uploaded files as UploadedFile objects. If no files were uploaded, returns an empty list. The UploadedFile class is a subclass of BytesIO, and therefore it is "file-like". This means you can pass them anywhere where a file is expected. Examples -------- Insert a file uploader that accepts a single file at a time: >>> uploaded_file = st.file_uploader("Choose a file") >>> if uploaded_file is not None: ... # To read file as bytes: ... bytes_data = uploaded_file.getvalue() ... st.write(bytes_data) >>> ... # To convert to a string based IO: ... stringio = StringIO(uploaded_file.getvalue().decode("utf-8")) ... st.write(stringio) >>> ... # To read file as string: ... string_data = stringio.read() ... st.write(string_data) >>> ... # Can be used wherever a "file-like" object is accepted: ... dataframe = pd.read_csv(uploaded_file) ... st.write(dataframe) Insert a file uploader that accepts multiple files at a time: >>> uploaded_files = st.file_uploader("Choose a CSV file", accept_multiple_files=True) >>> for uploaded_file in uploaded_files: ... bytes_data = uploaded_file.read() ... st.write("filename:", uploaded_file.name) ... st.write(bytes_data) """ key = to_key(key) check_callback_rules(self.dg, on_change) check_session_state_rules(default_value=None, key=key, writes_allowed=False) if type: if isinstance(type, str): type = [type] # May need a regex or a library to validate file types are valid # extensions. type = [ file_type if file_type[0] == "." else f".{file_type}" for file_type in type ] file_uploader_proto = FileUploaderProto() file_uploader_proto.label = label file_uploader_proto.type[:] = type if type is not None else [] file_uploader_proto.max_upload_size_mb = config.get_option( "server.maxUploadSize") file_uploader_proto.multiple_files = accept_multiple_files file_uploader_proto.form_id = current_form_id(self.dg) if help is not None: file_uploader_proto.help = dedent(help) def deserialize_file_uploader( ui_value: Optional[FileUploaderStateProto], widget_id: str) -> SomeUploadedFiles: file_recs = self._get_file_recs(widget_id, ui_value) if len(file_recs) == 0: return_value: Optional[Union[List[UploadedFile], UploadedFile]] = ( [] if accept_multiple_files else None) else: files = [UploadedFile(rec) for rec in file_recs] return_value = files if accept_multiple_files else files[0] return return_value def serialize_file_uploader( files: SomeUploadedFiles) -> FileUploaderStateProto: state_proto = FileUploaderStateProto() ctx = get_report_ctx() if ctx is None: return state_proto # ctx.uploaded_file_mgr._file_id_counter stores the id to use for # the *next* uploaded file, so the current highest file id is the # counter minus 1. state_proto.max_file_id = ctx.uploaded_file_mgr._file_id_counter - 1 if not files: return state_proto elif not isinstance(files, list): files = [files] for f in files: file_info: UploadedFileInfoProto = state_proto.uploaded_file_info.add( ) file_info.id = f.id file_info.name = f.name file_info.size = f.size return state_proto # FileUploader's widget value is a list of file IDs # representing the current set of files that this uploader should # know about. widget_value, _ = register_widget( "file_uploader", file_uploader_proto, user_key=key, on_change_handler=on_change, args=args, kwargs=kwargs, deserializer=deserialize_file_uploader, serializer=serialize_file_uploader, ) ctx = get_report_ctx() file_uploader_state = serialize_file_uploader(widget_value) uploaded_file_info = file_uploader_state.uploaded_file_info if ctx is not None and len(uploaded_file_info) != 0: newest_file_id = file_uploader_state.max_file_id active_file_ids = [f.id for f in uploaded_file_info] ctx.uploaded_file_mgr.remove_orphaned_files( session_id=ctx.session_id, widget_id=file_uploader_proto.id, newest_file_id=newest_file_id, active_file_ids=active_file_ids, ) self.dg._enqueue("file_uploader", file_uploader_proto) return cast(SomeUploadedFiles, widget_value)
def file_uploader(dg, label, type=None, accept_multiple_files=False, key=None, **kwargs): """Display a file uploader widget. By default, uploaded files are limited to 200MB. You can configure this using the `server.maxUploadSize` config option. Parameters ---------- label : str or None A short label explaining to the user what this file uploader is for. type : str or list of str or None Array of allowed extensions. ['png', 'jpg'] The default is None, which means all extensions are allowed. accept_multiple_files : bool If True, allows the user to upload multiple files at the same time, in which case the return value will be a list of files. Default: False key : str An optional string to use as the unique key for the widget. If this is omitted, a key will be generated for the widget based on its content. Multiple widgets of the same type may not share the same key. Returns ------- None or UploadedFile or list of UploadedFile - If allow_multiple_files is False, returns either None or an UploadedFile object. - If allow_multiple_files is True, returns a list with the uploaded files as UploadedFile objects. If no files were uploaded, returns an empty list. The UploadedFile class is a subclass of BytesIO, and therefore it is "file-like". This means you can pass them anywhere where a file is expected. As a subclass of BytesIO, make sure to reset the buffer after reading it with `UploadedFile.seek(0)`. Examples -------- Insert a file uploader that accepts a single file at a time: >>> uploaded_file = st.file_uploader("Choose a file") >>> if uploaded_file is not None: ... # To read file as bytes: ... bytes_data = uploaded_file.read() ... st.write(bytes_data) >>> ... # To convert to a string based IO: ... stringio = StringIO(uploaded_file.decode("utf-8")) ... st.write(stringio) >>> ... # To read file as string: ... string_data = stringio.read() ... st.write(string_data) >>> ... # Can be used wherever a "file-like" object is accepted: ... dataframe = pd.read_csv(uploaded_file) ... st.write(dataframe) Insert a file uploader that accepts multiple files at a time: >>> uploaded_files = st.file_uploader("Choose a CSV file", accept_multiple_files=True) >>> for uploaded_file in uploaded_files: ... bytes_data = uploaded_file.read() ... st.write("filename:", uploaded_file.name) ... st.write(bytes_data) """ if type: if isinstance(type, str): type = [type] # May need a regex or a library to validate file types are valid # extensions. type = [ file_type if file_type[0] == "." else f".{file_type}" for file_type in type ] has_encoding = "encoding" in kwargs show_deprecation_warning = config.get_option( "deprecation.showfileUploaderEncoding") if show_deprecation_warning and has_encoding: dg.exception(FileUploaderEncodingWarning()) # type: ignore file_uploader_proto = FileUploaderProto() file_uploader_proto.label = label file_uploader_proto.type[:] = type if type is not None else [] file_uploader_proto.max_upload_size_mb = config.get_option( "server.maxUploadSize") file_uploader_proto.multiple_files = accept_multiple_files _set_widget_id("file_uploader", file_uploader_proto, user_key=key) files = None ctx = get_report_ctx() if ctx is not None: files = ctx.uploaded_file_mgr.get_files( session_id=ctx.session_id, widget_id=file_uploader_proto.id) if files is None or len(files) == 0: return_value = [] if accept_multiple_files else NoValue else: for file in files: if file.tell() > 0: file.seek(0) return_value = files if accept_multiple_files else files[0] return dg._enqueue("file_uploader", file_uploader_proto, return_value) # type: ignore
def file_uploader( self, label, type=None, accept_multiple_files=False, key=None, help=None ): """Display a file uploader widget. By default, uploaded files are limited to 200MB. You can configure this using the `server.maxUploadSize` config option. Parameters ---------- label : str A short label explaining to the user what this file uploader is for. type : str or list of str or None Array of allowed extensions. ['png', 'jpg'] The default is None, which means all extensions are allowed. accept_multiple_files : bool If True, allows the user to upload multiple files at the same time, in which case the return value will be a list of files. Default: False key : str An optional string to use as the unique key for the widget. If this is omitted, a key will be generated for the widget based on its content. Multiple widgets of the same type may not share the same key. help : str A tooltip that gets displayed next to the file uploader. Returns ------- None or UploadedFile or list of UploadedFile - If accept_multiple_files is False, returns either None or an UploadedFile object. - If accept_multiple_files is True, returns a list with the uploaded files as UploadedFile objects. If no files were uploaded, returns an empty list. The UploadedFile class is a subclass of BytesIO, and therefore it is "file-like". This means you can pass them anywhere where a file is expected. Examples -------- Insert a file uploader that accepts a single file at a time: >>> uploaded_file = st.file_uploader("Choose a file") >>> if uploaded_file is not None: ... # To read file as bytes: ... bytes_data = uploaded_file.getvalue() ... st.write(bytes_data) >>> ... # To convert to a string based IO: ... stringio = StringIO(uploaded_file.getvalue().decode("utf-8")) ... st.write(stringio) >>> ... # To read file as string: ... string_data = stringio.read() ... st.write(string_data) >>> ... # Can be used wherever a "file-like" object is accepted: ... dataframe = pd.read_csv(uploaded_file) ... st.write(dataframe) Insert a file uploader that accepts multiple files at a time: >>> uploaded_files = st.file_uploader("Choose a CSV file", accept_multiple_files=True) >>> for uploaded_file in uploaded_files: ... bytes_data = uploaded_file.read() ... st.write("filename:", uploaded_file.name) ... st.write(bytes_data) """ if type: if isinstance(type, str): type = [type] # May need a regex or a library to validate file types are valid # extensions. type = [ file_type if file_type[0] == "." else f".{file_type}" for file_type in type ] file_uploader_proto = FileUploaderProto() file_uploader_proto.label = label file_uploader_proto.type[:] = type if type is not None else [] file_uploader_proto.max_upload_size_mb = config.get_option( "server.maxUploadSize" ) file_uploader_proto.multiple_files = accept_multiple_files if help is not None: file_uploader_proto.help = help register_widget("file_uploader", file_uploader_proto, user_key=key) # FileUploader's widget value is a list of file IDs # representing the current set of files that this uploader should # know about. widget_value: Optional[SInt64Array] = register_widget( "file_uploader", file_uploader_proto, user_key=key ) file_recs = self._get_file_recs(file_uploader_proto.id, widget_value) if len(file_recs) == 0: return_value = [] if accept_multiple_files else NoValue else: files = [UploadedFile(rec) for rec in file_recs] return_value = files if accept_multiple_files else files[0] return self.dg._enqueue("file_uploader", file_uploader_proto, return_value)
def _file_uploader( self, label: str, type: Optional[Union[str, List[str]]] = None, accept_multiple_files: bool = False, key: Optional[Key] = None, help: Optional[str] = None, on_change: Optional[WidgetCallback] = None, args: Optional[WidgetArgs] = None, kwargs: Optional[WidgetKwargs] = None, *, # keyword-only arguments: disabled: bool = False, ctx: Optional[ScriptRunContext] = None, ): key = to_key(key) check_callback_rules(self.dg, on_change) check_session_state_rules(default_value=None, key=key, writes_allowed=False) if type: if isinstance(type, str): type = [type] # May need a regex or a library to validate file types are valid # extensions. type = [ file_type if file_type[0] == "." else f".{file_type}" for file_type in type ] file_uploader_proto = FileUploaderProto() file_uploader_proto.label = label file_uploader_proto.type[:] = type if type is not None else [] file_uploader_proto.max_upload_size_mb = config.get_option( "server.maxUploadSize") file_uploader_proto.multiple_files = accept_multiple_files file_uploader_proto.form_id = current_form_id(self.dg) file_uploader_proto.disabled = disabled if help is not None: file_uploader_proto.help = dedent(help) def deserialize_file_uploader( ui_value: Optional[FileUploaderStateProto], widget_id: str) -> SomeUploadedFiles: file_recs = self._get_file_recs(widget_id, ui_value) if len(file_recs) == 0: return_value: Optional[Union[List[UploadedFile], UploadedFile]] = ( [] if accept_multiple_files else None) else: files = [UploadedFile(rec) for rec in file_recs] return_value = files if accept_multiple_files else files[0] return return_value def serialize_file_uploader( files: SomeUploadedFiles) -> FileUploaderStateProto: state_proto = FileUploaderStateProto() ctx = get_script_run_ctx() if ctx is None: return state_proto # ctx.uploaded_file_mgr._file_id_counter stores the id to use for # the *next* uploaded file, so the current highest file id is the # counter minus 1. state_proto.max_file_id = ctx.uploaded_file_mgr._file_id_counter - 1 if not files: return state_proto elif not isinstance(files, list): files = [files] for f in files: file_info: UploadedFileInfoProto = state_proto.uploaded_file_info.add( ) file_info.id = f.id file_info.name = f.name file_info.size = f.size return state_proto # FileUploader's widget value is a list of file IDs # representing the current set of files that this uploader should # know about. widget_value, _ = register_widget( "file_uploader", file_uploader_proto, user_key=key, on_change_handler=on_change, args=args, kwargs=kwargs, deserializer=deserialize_file_uploader, serializer=serialize_file_uploader, ctx=ctx, ) file_uploader_state = serialize_file_uploader(widget_value) uploaded_file_info = file_uploader_state.uploaded_file_info if ctx is not None and len(uploaded_file_info) != 0: newest_file_id = file_uploader_state.max_file_id active_file_ids = [f.id for f in uploaded_file_info] ctx.uploaded_file_mgr.remove_orphaned_files( session_id=ctx.session_id, widget_id=file_uploader_proto.id, newest_file_id=newest_file_id, active_file_ids=active_file_ids, ) self.dg._enqueue("file_uploader", file_uploader_proto) return cast(SomeUploadedFiles, widget_value)
def file_uploader(dg, label, type=None, key=None, **kwargs): """Display a file uploader widget. By default, uploaded files are limited to 200MB. You can configure this using the `server.maxUploadSize` config option. Parameters ---------- label : str or None A short label explaining to the user what this file uploader is for. type : str or list of str or None Array of allowed extensions. ['png', 'jpg'] By default, all extensions are allowed. encoding : str or None The encoding to use when opening textual files (i.e. non-binary). For example: 'utf-8'. If set to 'auto', will try to guess the encoding. If None, will assume the file is binary. key : str An optional string to use as the unique key for the widget. If this is omitted, a key will be generated for the widget based on its content. Multiple widgets of the same type may not share the same key. Returns ------- BytesIO or StringIO or or list of BytesIO/StringIO or None If no file has been uploaded, returns None. Otherwise, returns the data for the uploaded file(s): - If the file is in a well-known textual format (or if the encoding parameter is set), the file data is a StringIO. - Otherwise the file data is BytesIO. - If multiple_files is True, a list of file data will be returned. Note that BytesIO/StringIO are "file-like", which means you can pass them anywhere where a file is expected! Examples -------- >>> uploaded_file = st.file_uploader("Choose a CSV file", type="csv") >>> if uploaded_file is not None: ... data = pd.read_csv(uploaded_file) ... st.write(data) """ # Don't release this just yet. (When ready to release, turn test back # on at file_uploader_test.py) accept_multiple_files = False if isinstance(type, str): type = [type] encoding = kwargs.get("encoding") has_encoding = "encoding" in kwargs show_deprecation_warning = config.get_option( "deprecation.showfileUploaderEncoding") if show_deprecation_warning and ( (has_encoding and encoding is not None) or not has_encoding): dg.exception(FileUploaderEncodingWarning()) # type: ignore if not has_encoding: encoding = "auto" file_uploader_proto = FileUploaderProto() file_uploader_proto.label = label file_uploader_proto.type[:] = type if type is not None else [] file_uploader_proto.max_upload_size_mb = config.get_option( "server.maxUploadSize") file_uploader_proto.multiple_files = accept_multiple_files _set_widget_id("file_uploader", file_uploader_proto, user_key=key) files = None ctx = get_report_ctx() if ctx is not None: files = ctx.uploaded_file_mgr.get_files( session_id=ctx.session_id, widget_id=file_uploader_proto.id) if files is None: return_value = NoValue else: file_datas = [ get_encoded_file_data(file.data, encoding) for file in files ] return_value = file_datas if accept_multiple_files else file_datas[ 0] return dg._enqueue("file_uploader", file_uploader_proto, return_value) # type: ignore