Skip to content

Commit

Permalink
Make application/julia a text MIME (#18441)
Browse files Browse the repository at this point in the history
* Make application/julia a text MIME

* Use trait instead of istextmime

* Add a @pure annotation

* Run genstdlib

* Move deprecation to deprecated.jl

* Use boolean instead of traits

* Fix deprecated @textmime

* Fix @textmime depwarn message

* Undo accidental re-helpdbification
  • Loading branch information
TotalVerb authored and stevengj committed Oct 3, 2016
1 parent d2db55a commit bc9b6ef
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 62 deletions.
10 changes: 10 additions & 0 deletions base/deprecated.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1009,4 +1009,14 @@ export @vectorize_1arg, @vectorize_2arg
@deprecate abs(M::SymTridiagonal) abs.(M)
@deprecate abs(x::AbstractSparseVector) abs.(x)

# Deprecate @textmime into the Multimedia module, #18441
eval(Multimedia, :(macro textmime(mime)
Base.depwarn(string("`@textmime \"mime\"` is deprecated; use ",
"`Base.Multimedia.istextmime(::MIME\"mime\") = true` instead"
), :textmime)
quote
Base.Multimedia.istextmime(::MIME{$(Meta.quot(Symbol(mime)))}) = true
end
end))

# End deprecations scheduled for 0.6
23 changes: 0 additions & 23 deletions base/docs/helpdb/Base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2624,22 +2624,6 @@ the current exception (if called within a `catch` block).
"""
rethrow

"""
reprmime(mime, x)
Returns an `AbstractString` or `Vector{UInt8}` containing the representation of `x` in the
requested `mime` type, as written by `show` (throwing a `MethodError` if no appropriate
`show` is available). An `AbstractString` is returned for MIME types with textual
representations (such as `"text/html"` or `"application/postscript"`), whereas binary data
is returned as `Vector{UInt8}`. (The function `istextmime(mime)` returns whether or not Julia
treats a given `mime` type as text.)
As a special case, if `x` is an `AbstractString` (for textual MIME types) or a
`Vector{UInt8}` (for binary MIME types), the `reprmime` function assumes that `x` is already
in the requested `mime` format and simply returns `x`.
"""
reprmime

"""
!(x)
Expand Down Expand Up @@ -3263,13 +3247,6 @@ processes completed successfully.
"""
exit

"""
istextmime(m::MIME)
Determine whether a MIME type is text data.
"""
istextmime

"""
skipchars(stream, predicate; linecomment::Char)
Expand Down
93 changes: 55 additions & 38 deletions base/multimedia.jl
Original file line number Diff line number Diff line change
Expand Up @@ -33,56 +33,73 @@ mimewritable{mime}(::MIME{mime}, x) =
show(io::IO, m::AbstractString, x) = show(io, MIME(m), x)
mimewritable(m::AbstractString, x) = mimewritable(MIME(m), x)

###########################################################################
# MIME types are assumed to be binary data except for a set of types known
# to be text data (possibly Unicode). istextmime(m) returns whether
# m::MIME is text data, and reprmime(m, x) returns x written to either
# a string (for text m::MIME) or a Vector{UInt8} (for binary m::MIME),
# assuming the corresponding write_mime method exists. stringmime
# is like reprmime except that it always returns a string, which in the
# case of binary data is Base64-encoded.
#
# Also, if reprmime is passed a AbstractString for a text type or Vector{UInt8} for
# a binary type, the argument is assumed to already be in the corresponding
# format and is returned unmodified. This is useful so that raw data can be
# passed to display(m::MIME, x).

verbose_show(io, m, x) = show(IOContext(io,limit=false), m, x)

macro textmime(mime)
quote
mimeT = MIME{Symbol($mime)}
# avoid method ambiguities with the general definitions below:
# (Q: should we treat Vector{UInt8} as a String?)
Base.Multimedia.reprmime(m::mimeT, x::Vector{UInt8}) = sprint(verbose_show, m, x)
Base.Multimedia.stringmime(m::mimeT, x::Vector{UInt8}) = reprmime(m, x)

Base.Multimedia.istextmime(::mimeT) = true
if $(mime != "text/plain") # strings are shown escaped for text/plain
Base.Multimedia.reprmime(m::mimeT, x::AbstractString) = x
end
Base.Multimedia.reprmime(m::mimeT, x) = sprint(verbose_show, m, x)
Base.Multimedia.stringmime(m::mimeT, x) = reprmime(m, x)
end
end

istextmime(::MIME) = false
function reprmime(m::MIME, x)
"""
reprmime(mime, x)
Returns an `AbstractString` or `Vector{UInt8}` containing the representation of
`x` in the requested `mime` type, as written by `show` (throwing a
`MethodError` if no appropriate `show` is available). An `AbstractString` is
returned for MIME types with textual representations (such as `"text/html"` or
`"application/postscript"`), whereas binary data is returned as
`Vector{UInt8}`. (The function `istextmime(mime)` returns whether or not Julia
treats a given `mime` type as text.)
As a special case, if `x` is an `AbstractString` (for textual MIME types) or a
`Vector{UInt8}` (for binary MIME types), the `reprmime` function assumes that
`x` is already in the requested `mime` format and simply returns `x`. This
special case does not apply to the `"text/plain"` MIME type. This is useful so
that raw data can be passed to `display(m::MIME, x)`.
"""
reprmime(m::MIME, x) = istextmime(m) ? _textreprmime(m, x) : _binreprmime(m, x)

# strings are shown escaped for text/plain
_textreprmime(m::MIME, x) = sprint(verbose_show, m, x)
_textreprmime(::MIME, x::AbstractString) = x
_textreprmime(m::MIME"text/plain", x::AbstractString) =
sprint(verbose_show, m, x)

function _binreprmime(m::MIME, x)
s = IOBuffer()
verbose_show(s, m, x)
takebuf_array(s)
end
reprmime(m::MIME, x::Vector{UInt8}) = x
stringmime(m::MIME, x) = base64encode(verbose_show, m, x)
stringmime(m::MIME, x::Vector{UInt8}) = base64encode(write, x)
_binreprmime(m::MIME, x::Vector{UInt8}) = x

"""
stringmime(mime, x)
Returns an `AbstractString` containing the representation of `x` in the
requested `mime` type. This is similar to [`reprmime`](:func:`reprmime`) except
that binary data is base64-encoded as an ASCII string.
"""
stringmime(m::MIME, x) = istextmime(m) ? reprmime(m, x) : _binstringmime(m, x)

_binstringmime(m::MIME, x) = base64encode(verbose_show, m, x)
_binstringmime(m::MIME, x::Vector{UInt8}) = base64encode(write, x)

"""
istextmime(m::MIME)
Determine whether a MIME type is text data. MIME types are assumed to be binary
data except for a set of types known to be text data (possibly Unicode).
"""
istextmime(m::MIME) = startswith(string(m), "text/")

# it is convenient to accept strings instead of ::MIME
istextmime(m::AbstractString) = istextmime(MIME(m))
reprmime(m::AbstractString, x) = reprmime(MIME(m), x)
stringmime(m::AbstractString, x) = stringmime(MIME(m), x)

for mime in ["text/vnd.graphviz", "text/latex", "text/calendar", "text/n3", "text/richtext", "text/x-setext", "text/sgml", "text/tab-separated-values", "text/x-vcalendar", "text/x-vcard", "text/cmd", "text/css", "text/csv", "text/html", "text/javascript", "text/markdown", "text/plain", "text/vcard", "text/xml", "application/atom+xml", "application/ecmascript", "application/json", "application/rdf+xml", "application/rss+xml", "application/xml-dtd", "application/postscript", "image/svg+xml", "application/x-latex", "application/xhtml+xml", "application/javascript", "application/xml", "model/x3d+xml", "model/x3d+vrml", "model/vrml"]
@eval @textmime $mime
for mime in ["application/atom+xml", "application/ecmascript",
"application/javascript", "application/julia",
"application/json", "application/postscript",
"application/rdf+xml", "application/rss+xml",
"application/x-latex", "application/xhtml+xml", "application/xml",
"application/xml-dtd", "image/svg+xml", "model/vrml",
"model/x3d+vrml", "model/x3d+xml"]
istextmime(::MIME{Symbol(mime)}) = true
end

###########################################################################
Expand Down
2 changes: 1 addition & 1 deletion doc/stdlib/io-network.rst
Original file line number Diff line number Diff line change
Expand Up @@ -782,7 +782,7 @@ Julia environments (such as the IPython-based IJulia notebook).
Returns an ``AbstractString`` or ``Vector{UInt8}`` containing the representation of ``x`` in the requested ``mime`` type, as written by ``show`` (throwing a ``MethodError`` if no appropriate ``show`` is available). An ``AbstractString`` is returned for MIME types with textual representations (such as ``"text/html"`` or ``"application/postscript"``\ ), whereas binary data is returned as ``Vector{UInt8}``\ . (The function ``istextmime(mime)`` returns whether or not Julia treats a given ``mime`` type as text.)

As a special case, if ``x`` is an ``AbstractString`` (for textual MIME types) or a ``Vector{UInt8}`` (for binary MIME types), the ``reprmime`` function assumes that ``x`` is already in the requested ``mime`` format and simply returns ``x``\ .
As a special case, if ``x`` is an ``AbstractString`` (for textual MIME types) or a ``Vector{UInt8}`` (for binary MIME types), the ``reprmime`` function assumes that ``x`` is already in the requested ``mime`` format and simply returns ``x``\ . This special case does not apply to the ``"text/plain"`` MIME type. This is useful so that raw data can be passed to ``display(m::MIME, x)``\ .

.. function:: stringmime(mime, x)

Expand Down

6 comments on commit bc9b6ef

@nanosoldier
Copy link
Collaborator

Choose a reason for hiding this comment

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

Executing the daily benchmark build, I will reply here when finished:

@nanosoldier runbenchmarks(ALL, isdaily = true)

@nanosoldier
Copy link
Collaborator

Choose a reason for hiding this comment

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

Your benchmark job has completed - possible performance regressions were detected. A full report can be found here. cc @jrevels

@stevengj
Copy link
Member

Choose a reason for hiding this comment

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

Doesn't seem credible that this PR would cause a regression in ["nullable","basic",("isequal","Nullable{BigInt}(1)","Nullable{BigInt}()")]

@KristofferC
Copy link
Member

Choose a reason for hiding this comment

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

The nullable benchmarks are a bit too noisy.

@nalimilan
Copy link
Member

Choose a reason for hiding this comment

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

Yeah, I've noted that too. @jrevels Can something be done about it? Or should I just remove these microbenchmarks?

@jrevels
Copy link
Member

@jrevels jrevels commented on bc9b6ef Oct 4, 2016

Choose a reason for hiding this comment

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

No need to remove benchmarks. I'm just waiting on some tests to pass before I push updated tolerance levels to Nanosoldier. I'm also pushing a a change to BenchmarkTools' GC usage, which should help some benchmarks (though it didn't seem to account for all the noise we generally see).

Please sign in to comment.