Exemple #1
0
    def _serve_compressed_histograms(self, request):
        """Given a tag and single run, return an array of compressed histograms."""
        tag = request.args.get('tag')
        run = request.args.get('run')
        compressed_histograms = self._multiplexer.CompressedHistograms(
            run, tag)
        if request.args.get('format') == _OutputFormat.CSV:
            string_io = StringIO()
            writer = csv.writer(string_io)

            # Build the headers; we have two columns for timing and two columns for
            # each compressed histogram bucket.
            headers = ['Wall time', 'Step']
            if compressed_histograms:
                bucket_count = len(
                    compressed_histograms[0].compressed_histogram_values)
                for i in xrange(bucket_count):
                    headers += [
                        'Edge %d basis points' % i,
                        'Edge %d value' % i
                    ]
            writer.writerow(headers)

            for compressed_histogram in compressed_histograms:
                row = [
                    compressed_histogram.wall_time, compressed_histogram.step
                ]
                for value in compressed_histogram.compressed_histogram_values:
                    row += [value.rank_in_bps, value.value]
                writer.writerow(row)
            return http_util.Respond(request, string_io.getvalue(), 'text/csv')
        else:
            return http_util.Respond(request, compressed_histograms,
                                     'application/json')
Exemple #2
0
 def testContentLength_isInBytes(self):
     q = wrappers.Request(wtest.EnvironBuilder().get_environ())
     r = http_util.Respond(q, '爱', 'text/plain')
     self.assertEqual(r.headers.get('Content-Length'), '3')
     q = wrappers.Request(wtest.EnvironBuilder().get_environ())
     r = http_util.Respond(q, '爱'.encode('utf-8'), 'text/plain')
     self.assertEqual(r.headers.get('Content-Length'), '3')
Exemple #3
0
    def _serve_graph(self, request):
        """Given a single run, return the graph definition in json format."""
        run = request.args.get('run', None)
        if run is None:
            return http_util.Respond(request,
                                     'query parameter "run" is required',
                                     'text/plain', 400)

        try:
            graph = self._multiplexer.Graph(run)
        except ValueError:
            return http_util.Respond(request,
                                     '404 Not Found',
                                     'text/plain; charset=UTF-8',
                                     code=404)

        limit_attr_size = request.args.get('limit_attr_size', None)
        if limit_attr_size is not None:
            try:
                limit_attr_size = int(limit_attr_size)
            except ValueError:
                return http_util.Respond(
                    request,
                    'query parameter `limit_attr_size` must be integer',
                    'text/plain', 400)

        large_attrs_key = request.args.get('large_attrs_key', None)
        try:
            process_graph.prepare_graph_for_ui(graph, limit_attr_size,
                                               large_attrs_key)
        except ValueError as e:
            return http_util.Respond(request, e.message, 'text/plain', 400)

        return http_util.Respond(request, str(graph),
                                 'text/x-protobuf')  # pbtxt
Exemple #4
0
    def testResponseCharsetTranscoding(self):
        bean = '要依法治国是赞美那些谁是公义的和惩罚恶人。 - 韩非'

        # input is unicode string, output is gbk string
        q = wrappers.Request(wtest.EnvironBuilder().get_environ())
        r = http_util.Respond(q, bean, 'text/plain; charset=gbk')
        self.assertEqual(r.response[0], bean.encode('gbk'))

        # input is utf-8 string, output is gbk string
        q = wrappers.Request(wtest.EnvironBuilder().get_environ())
        r = http_util.Respond(q, bean.encode('utf-8'),
                              'text/plain; charset=gbk')
        self.assertEqual(r.response[0], bean.encode('gbk'))

        # input is object with unicode strings, output is gbk json
        q = wrappers.Request(wtest.EnvironBuilder().get_environ())
        r = http_util.Respond(q, {'red': bean},
                              'application/json; charset=gbk')
        self.assertEqual(r.response[0],
                         b'{"red": "' + bean.encode('gbk') + b'"}')

        # input is object with utf-8 strings, output is gbk json
        q = wrappers.Request(wtest.EnvironBuilder().get_environ())
        r = http_util.Respond(q, {'red': bean.encode('utf-8')},
                              'application/json; charset=gbk')
        self.assertEqual(r.response[0],
                         b'{"red": "' + bean.encode('gbk') + b'"}')

        # input is object with gbk strings, output is gbk json
        q = wrappers.Request(wtest.EnvironBuilder().get_environ())
        r = http_util.Respond(q, {'red': bean.encode('gbk')},
                              'application/json; charset=gbk',
                              encoding='gbk')
        self.assertEqual(r.response[0],
                         b'{"red": "' + bean.encode('gbk') + b'"}')
Exemple #5
0
    def _serve_static_file(self, request, path):
        """Serves the static file located at the given path.

    Args:
      request: A werkzeug Request
      path: The path of the static file, relative to the tensorboard/ directory.

    Returns:
      A werkzeug.Response application.
    """
        # Strip off the leading forward slash.
        orig_path = path.lstrip('/')
        if not self._path_is_safe(orig_path):
            logging.warning('path not safe: %s', orig_path)
            return http_util.Respond(request, 'Naughty naughty!', 'text/plain',
                                     400)
            # Resource loader wants a path relative to //WORKSPACE/tensorflow.
        path = os.path.join('tensorboard', orig_path)
        # Open the file and read it.
        try:
            contents = resource_loader.load_resource(path)
        except IOError:
            # For compatibility with latest version of Bazel, we renamed bower
            # packages to use '_' rather than '-' in their package name.
            # This means that the directory structure is changed too.
            # So that all our recursive imports work, we need to modify incoming
            # requests to map onto the new directory structure.
            path = orig_path
            components = path.split('/')
            components[0] = components[0].replace('-', '_')
            path = ('/').join(components)
            # Bazel keeps all the external dependencies in //WORKSPACE/external.
            # and resource loader wants a path relative to //WORKSPACE/tensorflow/.
            path = os.path.join('../external', path)
            try:
                contents = resource_loader.load_resource(path)
            except IOError:
                logging.warning('path %s not found, sending 404', path)
                return http_util.Respond(request,
                                         'Not found',
                                         'text/plain',
                                         code=404)
        mimetype, content_encoding = mimetypes.guess_type(path)
        mimetype = mimetype or 'application/octet-stream'
        return http_util.Respond(request,
                                 contents,
                                 mimetype,
                                 expires=3600,
                                 content_encoding=content_encoding)
Exemple #6
0
    def testAcceptGzip_compressesResponse(self):
        fall_of_hyperion_canto1_stanza1 = '\n'.join([
            'Fanatics have their dreams, wherewith they weave',
            'A paradise for a sect; the savage too',
            'From forth the loftiest fashion of his sleep',
            'Guesses at Heaven; pity these have not',
            'Trac\'d upon vellum or wild Indian leaf',
            'The shadows of melodious utterance.',
            'But bare of laurel they live, dream, and die;',
            'For Poesy alone can tell her dreams,',
            'With the fine spell of words alone can save',
            'Imagination from the sable charm',
            'And dumb enchantment. Who alive can say,',
            '\'Thou art no Poet may\'st not tell thy dreams?\'',
            'Since every man whose soul is not a clod',
            'Hath visions, and would speak, if he had loved',
            'And been well nurtured in his mother tongue.',
            'Whether the dream now purpos\'d to rehearse',
            'Be poet\'s or fanatic\'s will be known',
            'When this warm scribe my hand is in the grave.',
        ])

        e1 = wtest.EnvironBuilder(headers={
            'Accept-Encoding': '*'
        }).get_environ()
        any_encoding = wrappers.Request(e1)

        r = http_util.Respond(any_encoding, fall_of_hyperion_canto1_stanza1,
                              'text/plain')
        self.assertEqual(r.headers.get('Content-Encoding'), 'gzip')

        self.assertEqual(_gunzip(r.response[0]),
                         fall_of_hyperion_canto1_stanza1.encode('utf-8'))

        e2 = wtest.EnvironBuilder(headers={
            'Accept-Encoding': 'gzip'
        }).get_environ()
        gzip_encoding = wrappers.Request(e2)

        r = http_util.Respond(gzip_encoding, fall_of_hyperion_canto1_stanza1,
                              'text/plain')
        self.assertEqual(r.headers.get('Content-Encoding'), 'gzip')
        self.assertEqual(_gunzip(r.response[0]),
                         fall_of_hyperion_canto1_stanza1.encode('utf-8'))

        r = http_util.Respond(any_encoding, fall_of_hyperion_canto1_stanza1,
                              'image/png')
        self.assertEqual(r.response[0],
                         fall_of_hyperion_canto1_stanza1.encode('utf-8'))
Exemple #7
0
    def _serve_scalars(self, request):
        """Given a tag and single run, return array of ScalarEvents."""
        # TODO(cassandrax): return HTTP status code for malformed requests
        tag = request.args.get('tag')
        run = request.args.get('run')
        values = self._multiplexer.Scalars(run, tag)

        if request.args.get('format') == _OutputFormat.CSV:
            string_io = StringIO()
            writer = csv.writer(string_io)
            writer.writerow(['Wall time', 'Step', 'Value'])
            writer.writerows(values)
            return http_util.Respond(request, string_io.getvalue(), 'text/csv')
        else:
            return http_util.Respond(request, values, 'application/json')
Exemple #8
0
    def __call__(self, environ, start_response):  # pylint: disable=invalid-name
        """Central entry point for the TensorBoard application.

    This method handles routing to sub-applications. It does simple routing
    using regular expression matching.

    This __call__ method conforms to the WSGI spec, so that instances of this
    class are WSGI applications.

    Args:
      environ: See WSGI spec.
      start_response: See WSGI spec.

    Returns:
      A werkzeug Response.
    """
        request = wrappers.Request(environ)
        parsed_url = urlparse.urlparse(request.path)

        # Remove a trailing slash, if present.
        clean_path = parsed_url.path
        if clean_path.endswith('/'):
            clean_path = clean_path[:-1]
        # pylint: disable=too-many-function-args
        if clean_path in self.data_applications:
            return self.data_applications[clean_path](environ, start_response)
        elif clean_path in TAB_ROUTES:
            return self._serve_index(environ, start_response)
        else:
            tf.logging.warning('path %s not found, sending 404', clean_path)
            return http_util.Respond(request,
                                     'Not found',
                                     'text/plain',
                                     code=404)(environ, start_response)
Exemple #9
0
 def testHeadRequest_doesNotWrite(self):
     builder = wtest.EnvironBuilder(method='HEAD')
     env = builder.get_environ()
     request = wrappers.Request(env)
     r = http_util.Respond(request, '<b>hello world</b>', 'text/html')
     self.assertEqual(r.status_code, 200)
     self.assertEqual(r.response[0], six.b(''))
Exemple #10
0
    def _serve_runs(self, request):
        """WSGI app serving a JSON object about runs and tags.

    Returns a mapping from runs to tagType to list of tags for that run.

    Args:
      request: A werkzeug request

    Returns:
      A werkzeug Response with the following content:
      {runName: {firstEventTimestamp: 123456.789}}
    """
        run_names = sorted(
            self._multiplexer.Runs())  # Why `sorted`? See below.

        def get_first_event_timestamp(run_name):
            try:
                return self._multiplexer.FirstEventTimestamp(run_name)
            except ValueError:
                tf.logging.warning(
                    'Unable to get first event timestamp for run %s', run_name)
                # Put runs without a timestamp at the end. Their internal
                # ordering would be nondeterministic, but Python's sorts are
                # stable, so `sorted`ing the initial list above provides a
                # deterministic ordering. Of course, we cannot guarantee that
                # this will be append-only for new event-less runs.
                return float('inf')

        first_event_timestamps = {
            run_name: get_first_event_timestamp(run_name)
            for run_name in run_names
        }
        run_names.sort(key=first_event_timestamps.get)
        return http_util.Respond(request, run_names, 'application/json')
Exemple #11
0
    def _serve_runs(self, request):
        """WSGI app serving a JSON object about runs and tags.

    Returns a mapping from runs to tagType to list of tags for that run.

    Args:
      request: A werkzeug request

    Returns:
      A werkzeug Response with the following content:
      {runName: {images: [tag1, tag2, tag3],
                 audio: [tag4, tag5, tag6],
                 scalars: [tagA, tagB, tagC],
                 histograms: [tagX, tagY, tagZ],
                 firstEventTimestamp: 123456.789}}
    """
        runs = self._multiplexer.Runs()
        for run_name, run_data in runs.items():
            try:
                run_data[
                    'firstEventTimestamp'] = self._multiplexer.FirstEventTimestamp(
                        run_name)
            except ValueError:
                logging.warning(
                    'Unable to get first event timestamp for run %s', run_name)
                run_data['firstEventTimestamp'] = None
        return http_util.Respond(request, runs, 'application/json')
Exemple #12
0
    def _serve_runs(self, request):
        """WSGI app serving a JSON object about runs and tags.

    Returns a mapping from runs to tagType to list of tags for that run.

    Args:
      request: A werkzeug request

    Returns:
      A werkzeug Response with the following content:
      {runName: {audio: [tag4, tag5, tag6],
                 firstEventTimestamp: 123456.789}}
    """
        runs = self._multiplexer.Runs()
        for run_name, run_data in runs.items():
            for key in _MIGRATED_DATA_KEYS:
                if key in run_data:
                    del run_data[key]
            try:
                run_data[
                    'firstEventTimestamp'] = self._multiplexer.FirstEventTimestamp(
                        run_name)
            except ValueError:
                tf.logging.warning(
                    'Unable to get first event timestamp for run %s', run_name)
                run_data['firstEventTimestamp'] = None
        return http_util.Respond(request, runs, 'application/json')
Exemple #13
0
 def scalars_route(self, request):
     """Given a tag and single run, return array of ScalarEvents."""
     # TODO(cassandrax): return HTTP status code for malformed requests
     tag = request.args.get('tag')
     run = request.args.get('run')
     output_format = request.args.get('format')
     (body, mime_type) = self.scalars_impl(tag, run, output_format)
     return http_util.Respond(request, body, mime_type)
Exemple #14
0
 def _serve_run_metadata(self, request):
   """Given a tag and a TensorFlow run, return the session.run() metadata."""
   tag = request.args.get('tag', None)
   run = request.args.get('run', None)
   if tag is None:
     return http_util.Respond(
         request, 'query parameter "tag" is required', 'text/plain', 400)
   if run is None:
     return http_util.Respond(
         request, 'query parameter "run" is required', 'text/plain', 400)
   try:
     run_metadata = self._multiplexer.RunMetadata(run, tag)
   except ValueError:
     return http_util.Respond(
         request, '404 Not Found', 'text/plain; charset=UTF-8', code=404)
   return http_util.Respond(
       request, str(run_metadata), 'text/x-protobuf')  # pbtxt
Exemple #15
0
 def _serve_individual_audio(self, request):
     """Serves an individual audio clip."""
     tag = request.args.get('tag')
     run = request.args.get('run')
     index = int(request.args.get('index'))
     audio = self._multiplexer.Audio(run, tag)[index]
     return http_util.Respond(request, audio.encoded_audio_string,
                              audio.content_type)
Exemple #16
0
 def _serve_image(self, request):
     """Serves an individual image."""
     tag = request.args.get('tag')
     run = request.args.get('run')
     index = int(request.args.get('index'))
     image = self._multiplexer.Images(run, tag)[index]
     encoded_image_string = image.encoded_image_string
     content_type = _content_type_for_image(encoded_image_string)
     return http_util.Respond(request, encoded_image_string, content_type)
Exemple #17
0
 def _serve_individual_image(self, request):
     """Serves an individual image."""
     tag = request.args.get('tag')
     run = request.args.get('run')
     index = int(request.args.get('index'))
     image = self._multiplexer.Images(run, tag)[index]
     image_type = imghdr.what(None, image.encoded_image_string)
     content_type = _IMGHDR_TO_MIMETYPE.get(image_type,
                                            _DEFAULT_IMAGE_MIMETYPE)
     return http_util.Respond(request, image.encoded_image_string,
                              content_type)
Exemple #18
0
 def run_metadata_route(self, request):
     """Given a tag and a run, return the session.run() metadata."""
     tag = request.args.get('tag')
     run = request.args.get('run')
     if tag is None:
         return http_util.Respond(request,
                                  'query parameter "tag" is required',
                                  'text/plain', 400)
     if run is None:
         return http_util.Respond(request,
                                  'query parameter "run" is required',
                                  'text/plain', 400)
     result = self.run_metadata_impl(run, tag)
     if result is not None:
         (body, mime_type) = result  # pylint: disable=unpacking-non-sequence
         return http_util.Respond(request, body, mime_type)
     else:
         return http_util.Respond(request,
                                  '404 Not Found',
                                  'text/plain',
                                  code=404)
Exemple #19
0
    def _serve_plugins_listing(self, request):
        """Serves an object mapping plugin name to whether it is enabled.

    Args:
      request: The werkzeug.Request object.

    Returns:
      A werkzeug.Response object.
    """
        return http_util.Respond(request, {
            plugin.plugin_name: plugin.is_active()
            for plugin in self._plugins
        }, 'application/json')
Exemple #20
0
    def graph_route(self, request):
        """Given a single run, return the graph definition in protobuf format."""
        run = request.args.get('run')
        if run is None:
            return http_util.Respond(request,
                                     'query parameter "run" is required',
                                     'text/plain', 400)

        limit_attr_size = request.args.get('limit_attr_size', None)
        if limit_attr_size is not None:
            try:
                limit_attr_size = int(limit_attr_size)
            except ValueError:
                return http_util.Respond(
                    request,
                    'query parameter `limit_attr_size` must be an integer',
                    'text/plain', 400)

        large_attrs_key = request.args.get('large_attrs_key', None)

        try:
            result = self.graph_impl(run, limit_attr_size, large_attrs_key)
        except ValueError as e:
            return http_util.Respond(request,
                                     e.message,
                                     'text/plain',
                                     code=400)
        else:
            if result is not None:
                (body, mime_type) = result  # pylint: disable=unpacking-non-sequence
                return http_util.Respond(request, body, mime_type)
            else:
                return http_util.Respond(request,
                                         '404 Not Found',
                                         'text/plain',
                                         code=404)
Exemple #21
0
    def _serve_audio(self, request):
        """Given a tag and list of runs, serve a list of audio.

    Note that the audio clips themselves are not sent; instead, we respond with
    URLs to the audio. The frontend should treat these URLs as opaque and should
    not try to parse information about them or generate them itself, as the
    format may change.

    Args:
      request: A werkzeug.wrappers.Request object.

    Returns:
      A werkzeug.Response application.
    """
        tag = request.args.get('tag')
        run = request.args.get('run')

        audio_list = self._multiplexer.Audio(run, tag)
        response = self._audio_response_for_run(audio_list, run, tag)
        return http_util.Respond(request, response, 'application/json')
Exemple #22
0
 def text_route(self, request):
     run = request.args.get('run')
     tag = request.args.get('tag')
     response = self.text_impl(run, tag)
     return http_util.Respond(request, response, 'application/json')
Exemple #23
0
 def runs_route(self, request):
     index = self.index_impl()
     return http_util.Respond(request, index, 'application/json')
Exemple #24
0
 def _serve_histograms(self, request):
     """Given a tag and single run, return an array of histogram values."""
     tag = request.args.get('tag')
     run = request.args.get('run')
     values = self._multiplexer.Histograms(run, tag)
     return http_util.Respond(request, values, 'application/json')
Exemple #25
0
 def testPlainText_appendsUtf8ToContentType(self):
     q = wrappers.Request(wtest.EnvironBuilder().get_environ())
     r = http_util.Respond(q, 'hello', 'text/plain')
     h = r.headers
     self.assertEqual(h.get('Content-Type'), 'text/plain; charset=utf-8')
Exemple #26
0
 def _serve_logdir(self, request):
     """Respond with a JSON object containing this TensorBoard's logdir."""
     return http_util.Respond(request, {'logdir': self._logdir},
                              'application/json')
Exemple #27
0
 def testHelloWorld(self):
     q = wrappers.Request(wtest.EnvironBuilder().get_environ())
     r = http_util.Respond(q, '<b>hello world</b>', 'text/html')
     self.assertEqual(r.status_code, 200)
     self.assertEqual(r.response[0], six.b('<b>hello world</b>'))
Exemple #28
0
 def testExpires_setsCruiseControl(self):
     q = wrappers.Request(wtest.EnvironBuilder().get_environ())
     r = http_util.Respond(q, '<b>hello world</b>', 'text/html', expires=60)
     self.assertEqual(r.headers.get('Cache-Control'), 'private, max-age=60')
Exemple #29
0
 def testJson_getsAutoSerialized(self):
     q = wrappers.Request(wtest.EnvironBuilder().get_environ())
     r = http_util.Respond(q, [1, 2, 3], 'application/json')
     self.assertEqual(r.response[0], b'[1, 2, 3]')
Exemple #30
0
 def _serve_index(self, request):
     """Serves the index page (i.e., the tensorboard app itself)."""
     contents = tf.resource_loader.load_resource(
         'tensorboard/components/index.html')
     return http_util.Respond(request, contents, 'text/html', expires=3600)