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

Improve support for binary assets #326

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

qris
Copy link

@qris qris commented Aug 19, 2014

You may be interested in a new filter that we've developed: Django-Assets SVG. It generates optimised PNG files from SVG sources.

We had a lot of difficulty in processing binary files through Django-Assets, mainly because it's assuming in several places that files should be opened in Unicode and written out in UTF-8. Of course a PNG file does not take kindly to this transformation, let alone not being validly encoded in UTF-8 in the first place :)

The main issues that I saw were:

  • FileHunk opens files for reading with encoding='utf-8'
  • merge() concatenates files using a string separator
  • FilterTool uses a StringIO to store intermediate data, which tries to combine its buffers as unicode strings, and breaks if they're binary str strings.
  • MemoryHunk.save() opens files for writing with encoding='utf-8'
  • There's currently no way to replace any of these parts.

Please could you look into how we can replace these functions when defining our bundles, so that we can process binary files properly? Thanks!

@miracle2k
Copy link
Owner

The whole assets pipeline is using unicode since Python 3 support was added. The only filter that needed binary support was gzip, and that was removed.

If we want to support binary, there are two options:

  • Define a new filter phase "write". Analogous to the filter phase "open", which gets to be the one actually reading the file from the filesystem, "write" could be the one doing the writing. This is where a SVG-to-PNG filter could run. Multiple binary filters in a chain would not be possible.
  • Add back proper support for a binary pipeline. I haven't thought about how best to do this, but it might involve making the hunks operate on bytes, moving encoding/decoding to the filter-application phase, and allowing filters to define a binary=Trueargument.

@qris
Copy link
Author

qris commented Jun 23, 2014

I guess a full binary pipeline would be the "best" option (then users can switch image compression filters easily), but I can see that a "write" phase might be an easy workaround for the main problem in this case. So I'd support either option, whichever you have time for :)

@qris
Copy link
Author

qris commented Jun 23, 2014

Or alternatively if there was a method on Bundle to create a FilterTool and a MemoryHunk, instead of hard-coding the class names, then we could replace them with binary-safe versions just by subclassing Bundle.

@miracle2k
Copy link
Owner

I don't think I will have time to work on either for now, but if you want to have a go, I think even the second option I mentioned shouldn't be to hard; mainly moving the encode/decode calls to the right layer.

Filters that expect binary input will need to declare a `binary_input`
attribute. Otherwise they will be passed data in Unicode strings.

Binary outputs will be converted to Unicode strings before each filter
that doesn't declare itself as supporting binary input. That includes
input files read from disk.

Output files written to disk will be encoded in utf-8 if the last filter
output Unicode, otherwise the binary data output by the last filter.
@@ -125,7 +125,7 @@ def _apply_sass(self, _in, out, cd=None):
# shell: necessary on windows to execute
# ruby files, but doesn't work on linux.
shell=(os.name == 'nt'))
stdout, stderr = proc.communicate(_in.read().encode('utf-8'))
stdout, stderr = proc.communicate(_in.read())
Copy link
Owner

Choose a reason for hiding this comment

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

Do we still need these two lines? In fact, why do they work at all? Since the sass filter doesn't set the binary flags, aren't we trying to write bytes to a StringIO here?

@miracle2k
Copy link
Owner

Apologies for not noticing earlier. I like it a lot!

@miracle2k
Copy link
Owner

The build failures seem pertinent here, in particular on Python 3.

@@ -492,7 +492,7 @@ def created(self):

try:
data = (data.read() if hasattr(data, 'read') else data)
if data is not None:
if isinstance(data, unicode):
Copy link
Contributor

Choose a reason for hiding this comment

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

This change is very similar to my PR about supporting empty files #360, if not even more accurate.

@aconrad
Copy link
Contributor

aconrad commented Oct 30, 2014

As far as I understand, we can't have a bundle of binary files, each binary file must have 1 bundle and 1 output, right? We don't have a way to have output='images/'. Just asking, what's there is a great start and I could certainly work with this.

@k-funk
Copy link

k-funk commented Apr 12, 2016

Was this ever resolved? I'd like webassets to manage my fonts.

@carrete
Copy link

carrete commented May 30, 2017

What's the status of this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants