<commit_before>from __future__ import unicode_literals
from __future__ import print_function

from datetime import datetime
import io
import mimetypes

import six

from fs.path import basename
from fs.errors import FSError

from .response import MoyaResponse
from .compat import PY2, py2bytes
from . import http
from .tools import md5_hexdigest, file_chunker
from . import logic
from . import __version__


SERVER_NAME = "Moya/{}.{}".format(*__version__.split('.')[:2])


class _Reader(object):

    def __init__(self, file):
        self._file = file
        if six.callable(file.fileno):
            try:
                fileno = file.fileno()
            except:
                fileno = None
        else:
            fileno = file.fileno
        self._fileno = fileno

    def read(self, size):
        return self._file.read(size)

    def tell(self):
        return self._file.tell()

    def fileno(self):
        if self._fileno is None:
            raise io.UnsupportedOperation
        return self._fileno


def serve_file(req, fs, path, filename=None):
    """Serve a static file"""
    res = MoyaResponse()
    mime_type, encoding = mimetypes.guess_type(basename(path))
    if mime_type is None:
        mime_type = b"application/octet-stream" if PY2 else "application/octet-stream"

    # File does not exist
    if not path or not fs.isfile(path):
        raise logic.EndLogic(http.RespondNotFound())

    serve_file = None
    # Get file info
    try:
        info = fs.getdetails(path)
        serve_file = fs.open(path, 'rb')
    except FSError:
        # Files system open failed for some reason
        if serve_file is not None:
            serve_file.close()
        raise logic.EndLogic(http.RespondNotFound())
    else:
        # Make a response
        file_size = info.size
        mtime = info.modified or datetime.utcnow()
        res.date = datetime.utcnow()
        res.content_type = py2bytes(mime_type)
        res.last_modified = mtime
        res.etag = "{}-{}-{}".format(mtime, file_size, md5_hexdigest(path))
        res.server = SERVER_NAME
        if filename is not None:
            res.content_disposition = 'attachment; filename="{}"'.format(filename)

        # Detect 304 not-modified
        status304 = False
        if req.if_none_match and res.etag:
            status304 = res.etag in req.if_none_match
        elif req.if_modified_since and res.last_modified:
            status304 = res.last_modified <= req.if_modified_since
        if status304:
            res.status = 304
            serve_file.close()
        else:
            # Use high performance file wrapper if available
            if 'wsgi.file_wrapper' in req.environ:
                res.app_iter = req.environ['wsgi.file_wrapper'](serve_file)
            else:
                res.app_iter = file_chunker(serve_file)
        # Set content length
        if not status304:
            res.content_length = file_size
    raise logic.EndLogic(res)<commit_msg>experiment<commit_after>from __future__ import unicode_literals
from __future__ import print_function

from datetime import datetime
import io
import mimetypes

import six

from fs.path import basename
from fs.errors import FSError

from .response import MoyaResponse
from .compat import PY2, py2bytes
from . import http
from .tools import md5_hexdigest, file_chunker
from . import logic
from . import __version__


SERVER_NAME = "Moya/{}.{}".format(*__version__.split('.')[:2])


class _Reader(object):

    def __init__(self, file):
        self._file = file
        if six.callable(file.fileno):
            try:
                fileno = file.fileno()
            except:
                fileno = None
        else:
            fileno = file.fileno
        self._fileno = fileno

    def read(self, size):
        return self._file.read(size)

    def tell(self):
        return self._file.tell()

    def fileno(self):
        if self._fileno is None:
            raise io.UnsupportedOperation
        return self._fileno


def serve_file(req, fs, path, filename=None):
    """Serve a static file"""
    res = MoyaResponse()
    mime_type, encoding = mimetypes.guess_type(basename(path))
    if mime_type is None:
        mime_type = b"application/octet-stream" if PY2 else "application/octet-stream"

    # File does not exist
    if not path or not fs.isfile(path):
        raise logic.EndLogic(http.RespondNotFound())

    serve_file = None
    # Get file info
    try:
        info = fs.getdetails(path)
        serve_file = fs.open(path, 'rb')
    except FSError:
        # Files system open failed for some reason
        if serve_file is not None:
            serve_file.close()
        raise logic.EndLogic(http.RespondNotFound())
    else:
        # Make a response
        file_size = info.size
        mtime = info.modified or datetime.utcnow()
        res.date = datetime.utcnow()
        res.content_type = py2bytes(mime_type)
        res.last_modified = mtime
        res.etag = "{}-{}-{}".format(mtime, file_size, md5_hexdigest(path))
        res.server = SERVER_NAME
        if filename is not None:
            res.content_disposition = 'attachment; filename="{}"'.format(filename)

        # Detect 304 not-modified
        status304 = False
        if req.if_none_match and res.etag:
            status304 = res.etag in req.if_none_match
        elif req.if_modified_since and res.last_modified:
            status304 = res.last_modified <= req.if_modified_since
        if status304:
            res.status = 304
            serve_file.close()
        else:
            # Use high performance file wrapper if available
            res.app_iter = file_chunker(serve_file)
            # if 'wsgi.file_wrapper' in req.environ:
            #     res.app_iter = req.environ['wsgi.file_wrapper'](serve_file)
            # else:
            #     res.app_iter = file_chunker(serve_file)
        # Set content length
        if not status304:
            res.content_length = file_size
    raise logic.EndLogic(res)
{'fraction_non_alphanumeric': 0.08792672772689425, 'fraction_numerical': 0.0093255620316403, 'mean_word_length': 2.2482422931314225, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2169013', 'n_tokens_mistral': 1845, 'n_tokens_neox': 1763, 'n_words': 473}