Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reworking Excel support to allow for reading of big files #8403

Merged
merged 77 commits into from
Dec 15, 2023
Merged
Show file tree
Hide file tree
Changes from 72 commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
c8e2b40
adding a test for loading big Excel files
radeusgd Nov 21, 2023
8a34596
change how random file is generated
radeusgd Nov 21, 2023
c6d8a37
adapt tests to work for XLS
radeusgd Nov 21, 2023
cd26b95
open workbook as file, instead of materializing whole input stream in…
radeusgd Nov 21, 2023
e5c1bf0
checkpoint
radeusgd Nov 22, 2023
3003bbd
add a test
radeusgd Nov 22, 2023
5a9929f
checkpoint - ExcelConnectionPool
radeusgd Nov 22, 2023
11be28e
checkpoint - moving logic to use the pool
radeusgd Nov 22, 2023
13d4009
checkpoint
radeusgd Nov 23, 2023
9a4e4c0
checkpoint 2
radeusgd Nov 23, 2023
02e76c2
amend test
radeusgd Nov 23, 2023
ad8b60d
checkpoint 3
radeusgd Nov 23, 2023
db2b4e3
checkpoint 4
radeusgd Nov 23, 2023
17e2ab4
test reopening file, change exception on wrong format open
radeusgd Nov 23, 2023
3f35168
fixing some edge cases: use after close, headers in a re-read test
radeusgd Nov 23, 2023
fdf4f41
implement empty overwrite test
radeusgd Nov 23, 2023
deed106
checkpoint
radeusgd Nov 24, 2023
1e8502f
temporary workaround for #8384
radeusgd Nov 24, 2023
408d5bf
fixing smol stuff
radeusgd Nov 24, 2023
6533c38
fix
radeusgd Nov 24, 2023
cf5267b
workaround for the XLSX append
radeusgd Nov 24, 2023
72f9517
checkpoint: change the pool logic for writing, giving the user more f…
radeusgd Nov 25, 2023
38e957a
implement custom Excel writing logic - dry run + backup + tests for e…
radeusgd Nov 25, 2023
9bf9b14
fixes to get it compiling
radeusgd Nov 25, 2023
4b80e9f
writing a read-only workbook fails, trying another strategy - copy an…
radeusgd Nov 25, 2023
b1d6a92
update some tests
radeusgd Nov 25, 2023
464a3f6
remove canonical - it worked only for existing files but we also need…
radeusgd Nov 25, 2023
d313996
writing new files needs other logic
radeusgd Nov 25, 2023
7e739d8
fix backup nonexisting file issue, open empty file issue
radeusgd Nov 25, 2023
a5e5866
fix permissions check, some minor fixes
radeusgd Nov 27, 2023
9590b6a
fixed pre-existing file backup issue
radeusgd Nov 27, 2023
0208dd4
fix reading bak
radeusgd Nov 27, 2023
8da2715
add test for dry run threading thru
radeusgd Nov 27, 2023
fc850d5
update test
radeusgd Nov 28, 2023
882fb19
add some tests for file copy/move
radeusgd Nov 28, 2023
178caf0
fixing dry run logic
radeusgd Nov 28, 2023
9ecb477
disallow nesting of Test.groups
radeusgd Nov 28, 2023
18cdcce
tests for append and backup
radeusgd Nov 28, 2023
f62b36d
unnest group in replace tests
radeusgd Nov 28, 2023
58647b0
allow serving files from httpbin
radeusgd Nov 28, 2023
fc12dce
ability to stop the http server by pressing enter
radeusgd Nov 28, 2023
0bcf194
add some HTTP decode tests
radeusgd Nov 28, 2023
240f1a0
added tests for reading Excel from streams
radeusgd Nov 28, 2023
e989643
implement a prototype of stream reading
radeusgd Nov 28, 2023
bd7fd96
fixes
radeusgd Nov 28, 2023
b604286
modify xls test
radeusgd Nov 29, 2023
5eb516d
infer xls format even in stream mode
radeusgd Nov 29, 2023
fa26641
implement a Temporary_File facility
radeusgd Nov 29, 2023
3b241b2
preparing tests for the temporary file
radeusgd Nov 29, 2023
d80ce7c
WIP: associating a file with a stream
radeusgd Nov 29, 2023
22717b2
integrate Temporary_File with Excel_Workbook.enso
radeusgd Nov 30, 2023
1fcc33c
tests for Temporary_File
radeusgd Nov 30, 2023
fa0faf1
fix wrongly nested groups
radeusgd Nov 30, 2023
37d92d2
docs
radeusgd Nov 30, 2023
b12bf59
Revert "fix wrongly nested groups"
radeusgd Nov 30, 2023
cf5d758
revert group nesting check - tbd in separate PR
radeusgd Nov 30, 2023
29b5caa
update dry run stuff
radeusgd Nov 30, 2023
b8169cd
better exception in HTTP fail
radeusgd Dec 1, 2023
8853469
javafmt
radeusgd Dec 1, 2023
c5cd63f
changelog
radeusgd Dec 1, 2023
0f45573
update prettier ignore
radeusgd Dec 1, 2023
a147278
amendments to HTTP - some optional logging, not include Scala lib in …
radeusgd Dec 1, 2023
3b1ea01
CR, pending TODO
radeusgd Dec 1, 2023
d5d83a1
update test
radeusgd Dec 1, 2023
15ecad5
Merge branch 'develop' into wip/radeusgd/8111-big-excel-fix
radeusgd Dec 1, 2023
9a22d3a
Merge branch 'develop' into wip/radeusgd/8111-big-excel-fix
radeusgd Dec 1, 2023
ddc3b2e
httpbin log stop of server
radeusgd Dec 1, 2023
c5f99c9
javafmt
radeusgd Dec 1, 2023
4b5e589
try removing the Press Enter to stop in hope of fixing CI
radeusgd Dec 1, 2023
f00d2d3
Merge branch 'develop' into wip/radeusgd/8111-big-excel-fix
radeusgd Dec 6, 2023
e427758
Merge branch 'develop' into wip/radeusgd/8111-big-excel-fix
radeusgd Dec 8, 2023
fa11eab
CR: bring back frgaal and change target JDK for simple-httpbin
radeusgd Dec 8, 2023
10ab3e1
Merge branch 'develop' into wip/radeusgd/8111-big-excel-fix
radeusgd Dec 12, 2023
a4ec0e0
Merge branch 'develop' into wip/radeusgd/8111-big-excel-fix
radeusgd Dec 14, 2023
3ea7805
use Faker instead of other helpers
radeusgd Dec 14, 2023
858b1b4
Revert "use Faker instead of other helpers"
radeusgd Dec 14, 2023
0747c08
remove obsolete comment
radeusgd Dec 14, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ resources/python
# The files in the `data` directory of our tests may have specific structure or
# even be malformed on purpose, so we do not want to run prettier on them.
test/**/data
tools/simple-httpbin/www-files

# GUI
**/scala-parser.js
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,7 @@
- [Added `Table.format` for the in-memory backend.][8150]
- [Implemented truncate `Date_Time` for database backend (Postgres only).][8235]
- [Initial Enso Cloud APIs.][8006]
- [Support for loading big Excel files.][8403]

[debug-shortcuts]:
https://github.com/enso-org/enso/blob/develop/app/gui/docs/product/shortcuts.md#debug
Expand Down Expand Up @@ -848,6 +849,7 @@
[8105]: https://github.com/enso-org/enso/pull/8105
[8150]: https://github.com/enso-org/enso/pull/8150
[8235]: https://github.com/enso-org/enso/pull/8235
[8403]: https://github.com/enso-org/enso/pull/8403

#### Enso Compiler

Expand Down
18 changes: 13 additions & 5 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -1330,13 +1330,16 @@ lazy val truffleDslSuppressWarnsSetting = Seq(
)

/** A setting to replace javac with Frgaal compiler, allowing to use latest Java features in the code
* and still compile down to JDK 11
* and still compile down to JDK 17
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we change the -target level to 17?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think there is any sophisticated reason for that. I just thought that it was a good idea to bump that to -target 17. Furthermore, I vaguely remember that we talked about this as well. But I think we can fall back to 11.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have only updated the documentation comment to be aligned with what is actually being done.

*/
lazy val frgaalJavaCompilerSetting = Seq(
lazy val frgaalJavaCompilerSetting =
customFrgaalJavaCompilerSettings(targetJavaVersion)

def customFrgaalJavaCompilerSettings(targetJdk: String) = Seq(
Compile / compile / compilers := FrgaalJavaCompiler.compilers(
(Compile / dependencyClasspath).value,
compilers.value,
targetJavaVersion
targetJdk
),
// This dependency is needed only so that developers don't download Frgaal manually.
// Sadly it cannot be placed under plugins either because meta dependencies are not easily
Expand Down Expand Up @@ -2731,11 +2734,16 @@ val allStdBits: Parser[String] =
lazy val `simple-httpbin` = project
.in(file("tools") / "simple-httpbin")
.settings(
frgaalJavaCompilerSetting,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The frgaal compiler settings have been causing compile error:
cannot find symbol import com.sun.net.httpserver.SimpleFileServer: cannot find symbol.

Apparently SimpleFileServer may not be in the JDK that Frgaal uses? Weird.

Anyway there is no benefit in Frgaal within this sub-project, especially as we are already on JDK21. Removing it allowed me to re-use the SimpleFileServer for serving files for testing, instead of having to roll my own solution or having to bring in some heavy dependencies.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Frgaal by default only exposes only classes that are in API of the JDK. SimpleFileServer isn't.

no benefit in Frgaal within this sub-project

There is a benefit. It already prevented you from using SimpleFileServer!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Frgaal by default only exposes only classes that are in API of the JDK. SimpleFileServer isn't.

no benefit in Frgaal within this sub-project

There is a benefit. It already prevented you from using SimpleFileServer!

I really honestly don't understand. HOW is that a benefit?

Without Frgaal the server is running fine on our JDK. What is the benefit of using it this translation layer at this point?

We introduced it to be able to use newer features before we migrated to the newer JDKs. But now we have these features natively, so what else?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

server is running fine on our JDK.

You have compiled your code in a way that allows running it on JDK 11. However your code cannot run on JDK 11. Without Frgaal you wouldn't even notice that your project is misconfigured as it requires JDK18+ to run.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

server is running fine on our JDK.

You have compiled your code in a way that allows running it on JDK 11. However your code cannot run on JDK 11. Without Frgaal you wouldn't even notice that your project is misconfigured as it requires JDK18+ to run.

Hm, I see. It was hard to appreciate that, because from my perspective, removing Frgaal made it work - I never really specifically wanted to compile simple-httpbin to run on JDK 11 - just the current JDK we use - especially since it's not even an artifact we ship but just an internal test scaffolding.

customFrgaalJavaCompilerSettings(targetJdk = "21"),
autoScalaLibrary := false,
Compile / javacOptions ++= Seq("-Xlint:all"),
Compile / run / mainClass := Some("org.enso.shttp.SimpleHTTPBin"),
assembly / mainClass := (Compile / run / mainClass).value,
libraryDependencies ++= Seq(
"org.apache.commons" % "commons-text" % commonsTextVersion
)
),
(Compile / run / fork) := true,
(Compile / run / connectInput) := true
)
.configs(Test)

Expand Down
12 changes: 6 additions & 6 deletions distribution/lib/Standard/AWS/0.0.0-dev/src/S3/S3_File.enso
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import Standard.Base.Errors.File_Error.File_Error
import Standard.Base.Errors.Illegal_Argument.Illegal_Argument
import Standard.Base.Errors.Unimplemented.Unimplemented
import Standard.Base.System.File_Format.File_For_Read
import Standard.Base.System.File_Format.File_Format_Metadata
import Standard.Base.System.Input_Stream.Input_Stream
import Standard.Base.System.Output_Stream.Output_Stream
from Standard.Base.System.File import find_extension_from_name

import project.AWS_Credential.AWS_Credential
import project.Errors.S3_Error
Expand Down Expand Up @@ -117,7 +119,9 @@ type S3_File
Auto_Detect -> if self.is_directory then format.read self on_problems else
response = S3.get_object self.bucket self.prefix self.credentials
response.decode Auto_Detect
_ -> self.with_input_stream [File_Access.Read] format.read_stream
_ ->
metadata = File_Format_Metadata.Value file_name=self.name
self.with_input_stream [File_Access.Read] (stream-> format.read_stream stream metadata)

## ALIAS load bytes, open bytes
ICON data_input
Expand Down Expand Up @@ -187,11 +191,7 @@ type S3_File
Returns the extension of the file.
extension : Text
extension self = if self.is_directory then Error.throw (S3_Error.Error "Directories do not have extensions." self.uri) else
name = self.name
last_dot = name.locate "." mode=Matching_Mode.Last
if last_dot.is_nothing then "" else
extension = name.drop (Index_Sub_Range.First last_dot.start)
if extension == "." then "" else extension
find_extension_from_name self.name

## GROUP Standard.Base.Input
Lists files contained in the directory denoted by this file.
Expand Down
12 changes: 11 additions & 1 deletion distribution/lib/Standard/Base/0.0.0-dev/src/Any.enso
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ type Any
is_nothing self = False

## GROUP Logical
If `self` is Nothing then returns `function`.
If `self` is Nothing then returns `other`.

> Example
If the value "Hello" is nothing return "".
Expand All @@ -309,6 +309,16 @@ type Any
if_nothing self ~other =
const self other

## If `self` is Nothing then returns Nothing, otherwise returns the result
of running the provided `action`.

> Example
Transform a value only if it is not nothing.

my_result.if_not_nothing <| my_result + 1
if_not_nothing : Any -> Any
if_not_nothing self ~action = action

## GROUP Errors
Executes the provided handler on an error, or returns the value unchanged.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import project.Network.HTTP.HTTP_Method.HTTP_Method
import project.Nothing.Nothing
import project.System.File.File_Access.File_Access
import project.System.File_Format.File_For_Read
import project.System.File_Format.File_Format_Metadata
import project.System.Input_Stream.Input_Stream
import project.System.Output_Stream.Output_Stream
from project.Data.Boolean import Boolean, False, True
Expand Down Expand Up @@ -129,7 +130,9 @@ type Enso_File
real_format = Auto_Detect.get_reading_format self
if real_format == Nothing then Error.throw (File_Error.Unsupported_Type self) else
self.read real_format on_problems
_ -> self.with_input_stream [File_Access.Read] format.read_stream
_ ->
metadata = File_Format_Metadata.Value file_name=self.name
self.with_input_stream [File_Access.Read] (stream-> format.read_stream stream metadata)

## ALIAS load bytes, open bytes
ICON data_input
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import project.Network.URI.URI
import project.Nothing.Nothing
import project.System.File.File
import project.System.File_Format.File_For_Read
import Standard.Base.System.File_Format.File_Format_Metadata
import project.System.Input_Stream.Input_Stream
from project.Data.Text.Extensions import all

Expand Down Expand Up @@ -45,7 +46,8 @@ type XML_Format
XML_Document.from_file file

## PRIVATE
Implements the `Data.parse` for this `File_Format`
read_stream : Input_Stream -> Any
read_stream self stream:Input_Stream =
Implements decoding the format from a stream.
read_stream : Input_Stream -> File_Format_Metadata -> Any
read_stream self stream:Input_Stream (metadata : File_Format_Metadata = File_Format_Metadata.no_information) =
_ = metadata
XML_Document.from_stream stream
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import project.System.File.File
import project.System.File_Format.File_For_Read
import project.System.File_Format.File_Format

polyglot java import java.io.FileNotFoundException
polyglot java import java.io.IOException
polyglot java import java.nio.file.AccessDeniedException
polyglot java import java.nio.file.FileAlreadyExistsException
Expand All @@ -33,7 +34,7 @@ type File_Error
Arguments:
- file: The file that couldn't be read.
- message: The message for the error.
IO_Error (file : File) (message : Text)
IO_Error (file : File | Nothing) (message : Text)

## Indicates that the given file's type is not supported.
Unsupported_Type (file : File_For_Read)
Expand All @@ -51,7 +52,9 @@ type File_Error
to_display_text : Text
to_display_text self = case self of
File_Error.Not_Found file -> "The file at " + file.path + " does not exist."
File_Error.IO_Error file msg -> msg + " (" + file.path + ")."
File_Error.IO_Error file msg ->
suffix = if file.is_nothing then "" else " (" + file.path + ")."
msg + suffix
File_Error.Already_Exists file -> "The file at "+file.path+" already exists."
File_Error.Access_Denied file -> "Insufficient permissions to perform the desired operation on the file at "+file.path+"."
File_Error.Unsupported_Type file -> "The "+file.path+" has a type that is not supported."
Expand All @@ -65,7 +68,7 @@ type File_Error
## PRIVATE

Utility method for running an action with Java exceptions mapping.
handle_java_exceptions file ~action =
handle_java_exceptions (file : File | Nothing) ~action =
Panic.catch IOException action caught_panic->
File_Error.wrap_io_exception file caught_panic.payload

Expand All @@ -78,8 +81,14 @@ type File_Error
## PRIVATE

Converts a Java `IOException` into its Enso counterpart.
wrap_io_exception file io_exception = case io_exception of
_ : NoSuchFileException -> Error.throw (File_Error.Not_Found file)
_ : FileAlreadyExistsException -> Error.throw (File_Error.Already_Exists file)
_ : AccessDeniedException -> File_Error.access_denied file
_ -> Error.throw (File_Error.IO_Error file "An IO error has occurred: "+io_exception.to_text)
wrap_io_exception (file : File | Nothing) io_exception =
## If the file is not known, all we can do is throw a generic IO error.
This will only usually matter on stream operations, where there is no relevant file -
and so the exceptions like `NoSuchFileException` should not occur in such context.
But instead of risking a Type_Error, we just throw the more generic IO_Error.
if file.is_nothing then Error.throw (File_Error.IO_Error Nothing "An IO error has occurred: "+io_exception.to_text) else case io_exception of
_ : NoSuchFileException -> Error.throw (File_Error.Not_Found file)
_ : FileNotFoundException -> Error.throw (File_Error.Not_Found file)
_ : FileAlreadyExistsException -> Error.throw (File_Error.Already_Exists file)
_ : AccessDeniedException -> File_Error.access_denied file
_ -> Error.throw (File_Error.IO_Error file "An IO error has occurred: "+io_exception.to_text)
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import project.Data.Text.Text
import project.Error.Error
import project.Nothing.Nothing
import project.Panic.Panic

polyglot java import java.lang.IllegalStateException

type Illegal_State
## PRIVATE
Expand All @@ -19,3 +23,8 @@ type Illegal_State
Provides a human-readable representation of the encoding error.
to_display_text : Text
to_display_text self = "Illegal State: " + self.message

## PRIVATE
Capture a Java `IllegalStateException` and convert it to an Enso dataflow error - `Illegal_State.Error`.
handle_java_exception =
Panic.catch IllegalStateException handler=(cause-> Error.throw (Illegal_State.Error cause.payload.getMessage cause.payload))
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,10 @@ type HTTP
if fetch_methods.contains req.method || Context.Output.is_enabled then action else
Error.throw (Forbidden_Operation.Error ("Method " + req.method.to_text + " requests are forbidden as the Output context is disabled."))
handle_request_error =
Panic.catch JException handler=(cause-> Error.throw (Request_Error.Error 'IllegalArgumentException' cause.payload.getMessage))
handler caught_panic =
exception = caught_panic.payload
Error.throw (Request_Error.Error (Meta.type_of exception . to_text) exception.getMessage)
Panic.catch JException handler=handler

Panic.recover Any <| handle_request_error <| check_output_context <|
headers = resolve_headers req
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@ import project.Network.URI.URI
import project.Nothing.Nothing
import project.Runtime.Context
import project.Runtime.Managed_Resource.Managed_Resource
import project.System.File.Advanced.Temporary_File.Temporary_File
import project.System.File.Existing_File_Behavior.Existing_File_Behavior
import project.System.File.File
import project.System.File.File_Access.File_Access
import project.System.File.Write_Extensions
import project.System.File_Format.Auto_Detect
import project.System.File_Format.Bytes
import project.System.File_Format.File_Format
import project.System.File_Format.File_Format_Metadata
import project.System.File_Format.Plain_Text_Format
import project.System.Input_Stream.Input_Stream
from project.Data.Boolean import Boolean, False, True
Expand Down Expand Up @@ -58,23 +60,23 @@ type Response_Body
Raw_Stream (raw_stream:Input_Stream) (content_type:Text|Nothing) uri:URI

## PRIVATE
Byte_Array (bytes:Vector) (content_type:Text|Nothing) uri:URI
Materialized_Byte_Array (bytes:Vector) (content_type:Text|Nothing) uri:URI

## PRIVATE
Temporary_File (file_resource:Managed_Resource) (content_type:Text|Nothing) uri:URI
Materialized_Temporary_File (temporary_file:Temporary_File) (content_type:Text|Nothing) uri:URI

## PRIVATE
with_stream : (Input_Stream -> Any ! HTTP_Error) -> Any ! HTTP_Error
with_stream self action = case self of
Response_Body.Raw_Stream raw_stream _ _ ->
Managed_Resource.bracket raw_stream (_.close) action
Response_Body.Byte_Array bytes _ _ ->
Response_Body.Materialized_Byte_Array bytes _ _ ->
byte_stream = Input_Stream.new (ByteArrayInputStream.new bytes) (HTTP_Error.handle_java_exceptions self.uri)
Managed_Resource.bracket byte_stream (_.close) action
Response_Body.Temporary_File file_resource _ _ -> file_resource.with file->
Response_Body.Materialized_Temporary_File temporary_file _ _ -> temporary_file.with_file file->
opts = [File_Access.Read.to_java]
stream = HTTP_Error.handle_java_exceptions self.uri (file.input_stream_builtin opts)
file_stream = Input_Stream.new stream (HTTP_Error.handle_java_exceptions self.uri)
file_stream = Input_Stream.new stream (HTTP_Error.handle_java_exceptions self.uri) associated_file=temporary_file
Managed_Resource.bracket (file_stream) (_.close) action

## PRIVATE
Expand All @@ -88,23 +90,19 @@ type Response_Body
body_stream.with_java_stream body_java_stream->
first_block = body_java_stream.readNBytes maximum_body_in_memory
case first_block.length < maximum_body_in_memory of
True -> Response_Body.Byte_Array (Vector.from_polyglot_array first_block) self.content_type self.uri
False ->
file = File.create_temporary_file self.uri.host

## Write contents to temporary file
Context.Output.with_enabled <|
True -> Response_Body.Materialized_Byte_Array (Vector.from_polyglot_array first_block) self.content_type self.uri
False -> Context.Output.with_enabled <|
## Write contents to a temporary file
temp_file = Temporary_File.new self.uri.host
r = temp_file.with_file file->
file.with_output_stream [File_Access.Write, File_Access.Create, File_Access.Truncate_Existing] output_stream->
output_stream.with_java_stream java_output_stream->
java_output_stream.write first_block
body_java_stream.transferTo java_output_stream
java_output_stream.flush
Nothing
output_stream.close

## Have a file with the correct set up
resource = Managed_Resource.register file delete_file
Response_Body.Temporary_File resource self.content_type self.uri
r.if_not_error <|
Response_Body.Materialized_Temporary_File temp_file self.content_type self.uri
_ -> self

## ALIAS parse
Expand All @@ -128,7 +126,9 @@ type Response_Body
_ ->
type_obj = Meta.type_of format
if can_decode type_obj . not then Error.throw (Illegal_Argument.Error type_obj.to_text+" cannot be used to decode from a stream. It must be saved to a file first.") else
self.with_stream format.read_stream
metadata = File_Format_Metadata.Value content_type=self.content_type
self.with_stream stream->
format.read_stream stream metadata

## ALIAS bytes
GROUP Input
Expand Down
11 changes: 11 additions & 0 deletions distribution/lib/Standard/Base/0.0.0-dev/src/Nothing.enso
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import project.Any.Any
import project.Data.Numbers.Integer
import project.Data.Text.Text
from project.Data.Boolean import Boolean, False, True
from project.Function import const

## The type that has only a singleton value. Nothing in Enso is used as an
universal value to indicate the lack of presence of a value.
Expand Down Expand Up @@ -30,6 +31,16 @@ type Nothing
if_nothing : Any -> Any
if_nothing self ~function = function

## If `self` is Nothing then returns Nothing, otherwise returns the result
of running the provided `action`.

> Example
Transform a value only if it is not nothing.

my_result.if_not_nothing <| my_result + 1
if_not_nothing : Any -> Any
if_not_nothing self ~action = const Nothing action

## Get a value for the key of the object.
As `Nothing` has no keys, returns `if_missing`.

Expand Down
Loading
Loading