From e36bdef0b34c16def20ecbb8248950070eb5fa33 Mon Sep 17 00:00:00 2001 From: Bolke de Bruin Date: Tue, 15 Jan 2019 20:37:08 +0100 Subject: [PATCH] [AIRFLOW-3697] Vendorize nvd3 and slugify nvd3 has a dependency on python-slugify which pulls in a GPL dependency by default, which we don't want. This commit brings in nvd3 0.15.0 and slugify 2.0.1 WITH NO CHANGES - those will come in the next commit --- .flake8 | 1 + .rat-excludes | 3 + .travis.yml | 1 - LICENSE | 2 + MANIFEST.in | 3 +- NOTICE | 12 + airflow/_vendor/README | 13 + airflow/_vendor/__init__.py | 18 + airflow/_vendor/nvd3/LICENSE | 24 + airflow/_vendor/nvd3/NVD3Chart.py | 505 ++++++++++++++++++ airflow/_vendor/nvd3/__init__.py | 29 + airflow/_vendor/nvd3/cumulativeLineChart.py | 104 ++++ airflow/_vendor/nvd3/discreteBarChart.py | 91 ++++ airflow/_vendor/nvd3/ipynb.py | 91 ++++ airflow/_vendor/nvd3/lineChart.py | 120 +++++ airflow/_vendor/nvd3/linePlusBarChart.py | 131 +++++ airflow/_vendor/nvd3/lineWithFocusChart.py | 105 ++++ airflow/_vendor/nvd3/multiBarChart.py | 95 ++++ .../_vendor/nvd3/multiBarHorizontalChart.py | 100 ++++ airflow/_vendor/nvd3/pieChart.py | 101 ++++ airflow/_vendor/nvd3/scatterChart.py | 121 +++++ airflow/_vendor/nvd3/stackedAreaChart.py | 99 ++++ airflow/_vendor/nvd3/templates/base.html | 35 ++ airflow/_vendor/nvd3/templates/content.html | 123 +++++ .../nvd3/templates/cumulativelinechart.html | 11 + .../nvd3/templates/discretebarchart.html | 31 ++ .../nvd3/templates/linebarwfocuschart.html | 60 +++ airflow/_vendor/nvd3/templates/linechart.html | 47 ++ .../nvd3/templates/lineplusbarchart.html | 44 ++ .../nvd3/templates/linewfocuschart.html | 10 + .../_vendor/nvd3/templates/multibarchart.html | 10 + .../templates/multibarcharthorizontal.html | 10 + airflow/_vendor/nvd3/templates/page.html | 12 + airflow/_vendor/nvd3/templates/piechart.html | 80 +++ .../_vendor/nvd3/templates/scatterchart.html | 52 ++ .../nvd3/templates/stackedareachart.html | 7 + airflow/_vendor/nvd3/translator.py | 71 +++ airflow/_vendor/slugify/LICENSE | 21 + airflow/_vendor/slugify/__init__.py | 6 + airflow/_vendor/slugify/slugify.py | 188 +++++++ licenses/LICENSE-python-nvd3.txt | 24 + licenses/LICENSE-python-slugify.txt | 21 + 42 files changed, 2630 insertions(+), 2 deletions(-) create mode 100644 airflow/_vendor/README create mode 100644 airflow/_vendor/__init__.py create mode 100644 airflow/_vendor/nvd3/LICENSE create mode 100644 airflow/_vendor/nvd3/NVD3Chart.py create mode 100755 airflow/_vendor/nvd3/__init__.py create mode 100644 airflow/_vendor/nvd3/cumulativeLineChart.py create mode 100644 airflow/_vendor/nvd3/discreteBarChart.py create mode 100644 airflow/_vendor/nvd3/ipynb.py create mode 100644 airflow/_vendor/nvd3/lineChart.py create mode 100644 airflow/_vendor/nvd3/linePlusBarChart.py create mode 100644 airflow/_vendor/nvd3/lineWithFocusChart.py create mode 100644 airflow/_vendor/nvd3/multiBarChart.py create mode 100644 airflow/_vendor/nvd3/multiBarHorizontalChart.py create mode 100644 airflow/_vendor/nvd3/pieChart.py create mode 100644 airflow/_vendor/nvd3/scatterChart.py create mode 100644 airflow/_vendor/nvd3/stackedAreaChart.py create mode 100644 airflow/_vendor/nvd3/templates/base.html create mode 100644 airflow/_vendor/nvd3/templates/content.html create mode 100644 airflow/_vendor/nvd3/templates/cumulativelinechart.html create mode 100644 airflow/_vendor/nvd3/templates/discretebarchart.html create mode 100644 airflow/_vendor/nvd3/templates/linebarwfocuschart.html create mode 100644 airflow/_vendor/nvd3/templates/linechart.html create mode 100644 airflow/_vendor/nvd3/templates/lineplusbarchart.html create mode 100644 airflow/_vendor/nvd3/templates/linewfocuschart.html create mode 100644 airflow/_vendor/nvd3/templates/multibarchart.html create mode 100644 airflow/_vendor/nvd3/templates/multibarcharthorizontal.html create mode 100644 airflow/_vendor/nvd3/templates/page.html create mode 100644 airflow/_vendor/nvd3/templates/piechart.html create mode 100644 airflow/_vendor/nvd3/templates/scatterchart.html create mode 100644 airflow/_vendor/nvd3/templates/stackedareachart.html create mode 100644 airflow/_vendor/nvd3/translator.py create mode 100644 airflow/_vendor/slugify/LICENSE create mode 100644 airflow/_vendor/slugify/__init__.py create mode 100644 airflow/_vendor/slugify/slugify.py create mode 100644 licenses/LICENSE-python-nvd3.txt create mode 100644 licenses/LICENSE-python-slugify.txt diff --git a/.flake8 b/.flake8 index e2ba4cbf6f631..368fdb4331a12 100644 --- a/.flake8 +++ b/.flake8 @@ -1,3 +1,4 @@ [flake8] max-line-length = 110 ignore = E731,W504 +exclude = .svn,CVS,.bzr,.hg,.git,__pycache__,.tox,.eggs,*.egg,*/_vendor/* diff --git a/.rat-excludes b/.rat-excludes index 786920076dd57..fb9361f7f39fc 100644 --- a/.rat-excludes +++ b/.rat-excludes @@ -59,3 +59,6 @@ coverage.xml rat-results.txt apache-airflow-.*\+source.tar.gz.* apache-airflow-.*\+bin.tar.gz.* + +# vendored modules +_vendor/* diff --git a/.travis.yml b/.travis.yml index 59e87d7fb192d..68b8f61e5fe1f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,7 +24,6 @@ python: env: global: - DOCKER_COMPOSE_VERSION=1.20.0 - - SLUGIFY_USES_TEXT_UNIDECODE=yes - TRAVIS_CACHE=$HOME/.travis_cache/ matrix: - TOX_ENV=py27-backend_mysql-env_docker diff --git a/LICENSE b/LICENSE index debddc0d7bb79..e3335acb8014a 100644 --- a/LICENSE +++ b/LICENSE @@ -240,6 +240,8 @@ The text of each license is also included at licenses/LICENSE-[project].txt. (MIT License) normalize.css v3.0.2 (http://necolas.github.io/normalize.css/) (MIT License) ElasticMock v1.3.2 (https://github.com/vrcmarcos/elasticmock) (MIT License) MomentJS v2.22.2 (http://momentjs.com/) + (MIT License) python-slugify v2.0.1 (https://github.com/un33k/python-slugify) + (MIT License) python-nvd3 v0.15.0 (https://github.com/areski/python-nvd3) ======================================================================== BSD 2-Clause licenses diff --git a/MANIFEST.in b/MANIFEST.in index 2ae1b2a434680..755f1548c8f07 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -24,9 +24,10 @@ graft licenses/ graft airflow/www graft airflow/www/static graft airflow/www/templates -graft airflow/www/translations +graft airflow/_vendor/ include airflow/alembic.ini graft scripts/systemd graft scripts/upstart graft airflow/config_templates recursive-exclude airflow/www/node_modules * +global-exclude __pycache__ *.pyc diff --git a/NOTICE b/NOTICE index b478303ed644d..130353a3b8b75 100644 --- a/NOTICE +++ b/NOTICE @@ -17,3 +17,15 @@ This product contains a modified portion of 'Hue' developed by Cloudera, Inc. (https://github.com/cloudera/hue/). * Copyright 2009-2017 Cloudera Inc. + +python-slugify: +--------------- + +* Copyright (c) Val Neekman @ Neekware Inc. http://neekware.com + +python-nvd3: +------------ + +* Copyright (c) 2013 Arezqui Belaid and other contributors + + diff --git a/airflow/_vendor/README b/airflow/_vendor/README new file mode 100644 index 0000000000000..a79ea89eae536 --- /dev/null +++ b/airflow/_vendor/README @@ -0,0 +1,13 @@ +Original files in this directory were created with the following commands:: + + mkdir -p slugify/ + curl -fsSL -O https://files.pythonhosted.org/packages/1f/9c/8b07d625e9c9df567986d887f0375075abb1923e49d074a7803cd1527dae/python-slugify-2.0.1.tar.gz + tar -xzf python-slugify-*.tar.gz --strip-components=2 -C slugify/ '*/slugify/*' + tar -xzf python-slugify-*.tar.gz --strip-components=1 -C slugify/ '*/LICENSE' + rm *.tar.gz + + mkdir -p nvd3/ + curl -fsSL -O https://files.pythonhosted.org/packages/0b/aa/97165daa6e319409c5c2582e62736a7353bda3c90d90fdcb0b11e116dd2d/python-nvd3-0.15.0.tar.gz + tar -xzf python-nvd3-*.tar.gz --strip-components=2 -C nvd3/ '*/nvd3/*' + tar -xzf python-nvd3-*.tar.gz --strip-components=1 -C nvd3/ '*/LICENSE' + rm *.tar.gz diff --git a/airflow/_vendor/__init__.py b/airflow/_vendor/__init__.py new file mode 100644 index 0000000000000..114d189da14ab --- /dev/null +++ b/airflow/_vendor/__init__.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. diff --git a/airflow/_vendor/nvd3/LICENSE b/airflow/_vendor/nvd3/LICENSE new file mode 100644 index 0000000000000..1add6249e57b4 --- /dev/null +++ b/airflow/_vendor/nvd3/LICENSE @@ -0,0 +1,24 @@ +The MIT License (MIT) + +Python-nvd3 + +Copyright (c) 2013 Arezqui Belaid and other contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/airflow/_vendor/nvd3/NVD3Chart.py b/airflow/_vendor/nvd3/NVD3Chart.py new file mode 100644 index 0000000000000..666993638de65 --- /dev/null +++ b/airflow/_vendor/nvd3/NVD3Chart.py @@ -0,0 +1,505 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Python-nvd3 is a Python wrapper for NVD3 graph library. +NVD3 is an attempt to build re-usable charts and chart components +for d3.js without taking away the power that d3.js gives you. + +Project location : https://github.com/areski/python-nvd3 +""" + +from __future__ import unicode_literals +from optparse import OptionParser +from jinja2 import Environment, PackageLoader +from slugify import slugify +try: + import simplejson as json +except ImportError: + import json + +CONTENT_FILENAME = "./content.html" +PAGE_FILENAME = "./page.html" + + +pl = PackageLoader('nvd3', 'templates') +jinja2_env = Environment(lstrip_blocks=True, trim_blocks=True, loader=pl) + +template_content = jinja2_env.get_template(CONTENT_FILENAME) +template_page = jinja2_env.get_template(PAGE_FILENAME) + + +def stab(tab=1): + """ + create space tabulation + """ + return ' ' * 4 * tab + + +class NVD3Chart(object): + """ + NVD3Chart Base class. + """ + #: chart count + count = 0 + #: directory holding the assets (bower_components) + assets_directory = './bower_components/' + + # this attribute is overriden by children of this + # class + CHART_FILENAME = None + template_environment = Environment(lstrip_blocks=True, trim_blocks=True, + loader=pl) + + def __init__(self, **kwargs): + """ + This is the base class for all the charts. The following keywords are + accepted: + + :keyword: **display_container** - default: ``True`` + :keyword: **jquery_on_ready** - default: ``False`` + :keyword: **charttooltip_dateformat** - default: ``'%d %b %Y'`` + :keyword: **name** - default: the class name + ``model`` - set the model (e.g. ``pieChart``, ` + ``LineWithFocusChart``, ``MultiBarChart``). + :keyword: **color_category** - default - ``None`` + :keyword: **color_list** - default - ``None`` + used by pieChart (e.g. ``['red', 'blue', 'orange']``) + :keyword: **margin_bottom** - default - ``20`` + :keyword: **margin_left** - default - ``60`` + :keyword: **margin_right** - default - ``60`` + :keyword: **margin_top** - default - ``30`` + :keyword: **height** - default - ``''`` + :keyword: **width** - default - ``''`` + :keyword: **stacked** - default - ``False`` + :keyword: **focus_enable** - default - ``False`` + :keyword: **resize** - define - ``False`` + :keyword: **show_legend** - default - ``True`` + :keyword: **show_labels** - default - ``True`` + :keyword: **tag_script_js** - default - ``True`` + :keyword: **use_interactive_guideline** - default - ``False`` + :keyword: **chart_attr** - default - ``None`` + :keyword: **extras** - default - ``None`` + + Extra chart modifiers. Use this to modify different attributes of + the chart. + :keyword: **x_axis_date** - default - False + Signal that x axis is a date axis + :keyword: **date_format** - default - ``%x`` + see https://github.com/mbostock/d3/wiki/Time-Formatting + :keyword: **x_axis_format** - default - ``''``. + :keyword: **y_axis_format** - default - ``''``. + :keyword: **style** - default - ``''`` + Style modifiers for the DIV container. + :keyword: **color_category** - default - ``category10`` + + Acceptable values are nvd3 categories such as + ``category10``, ``category20``, ``category20c``. + """ + # set the model + self.model = self.__class__.__name__ #: The chart model, + + #: an Instance of Jinja2 template + self.template_page_nvd3 = template_page + self.template_content_nvd3 = template_content + self.series = [] + self.axislist = {} + # accepted keywords + self.display_container = kwargs.get('display_container', True) + self.charttooltip_dateformat = kwargs.get('charttooltip_dateformat', + '%d %b %Y') + self._slugify_name(kwargs.get('name', self.model)) + self.jquery_on_ready = kwargs.get('jquery_on_ready', False) + self.color_category = kwargs.get('color_category', None) + self.color_list = kwargs.get('color_list', None) + self.margin_bottom = kwargs.get('margin_bottom', 20) + self.margin_left = kwargs.get('margin_left', 60) + self.margin_right = kwargs.get('margin_right', 60) + self.margin_top = kwargs.get('margin_top', 30) + self.height = kwargs.get('height', '') + self.width = kwargs.get('width', '') + self.stacked = kwargs.get('stacked', False) + self.focus_enable = kwargs.get('focus_enable', False) + self.resize = kwargs.get('resize', False) + self.show_legend = kwargs.get('show_legend', True) + self.show_labels = kwargs.get('show_labels', True) + self.tag_script_js = kwargs.get('tag_script_js', True) + self.use_interactive_guideline = kwargs.get("use_interactive_guideline", + False) + self.chart_attr = kwargs.get("chart_attr", {}) + self.extras = kwargs.get('extras', None) + self.style = kwargs.get('style', '') + self.date_format = kwargs.get('date_format', '%x') + self.x_axis_date = kwargs.get('x_axis_date', False) + #: x-axis contain date format or not + # possible duplicate of x_axis_date + self.date_flag = kwargs.get('date_flag', False) + self.x_axis_format = kwargs.get('x_axis_format', '') + # Load remote JS assets or use the local bower assets? + self.remote_js_assets = kwargs.get('remote_js_assets', True) + + # None keywords attribute that should be modified by methods + # We should change all these to _attr + + self.htmlcontent = '' #: written by buildhtml + self.htmlheader = '' + #: Place holder for the graph (the HTML div) + #: Written by ``buildcontainer`` + self.container = u'' + #: Header for javascript code + self.containerheader = u'' + # CDN http://cdnjs.com/libraries/nvd3/ needs to make sure it's up to + # date + self.header_css = [ + '' % h for h in + ( + 'https://cdnjs.cloudflare.com/ajax/libs/nvd3/1.7.0/nv.d3.min.css' if self.remote_js_assets else self.assets_directory + 'nvd3/src/nv.d3.css', + ) + ] + + self.header_js = [ + '' % h for h in + ( + 'https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js' if self.remote_js_assets else self.assets_directory + 'd3/d3.min.js', + 'https://cdnjs.cloudflare.com/ajax/libs/nvd3/1.7.0/nv.d3.min.js' if self.remote_js_assets else self.assets_directory + 'nvd3/nv.d3.min.js' + ) + ] + + #: Javascript code as string + self.jschart = None + self.custom_tooltip_flag = False + self.tooltip_condition_string = '' + self.charttooltip = '' + self.serie_no = 1 + + def _slugify_name(self, name): + """Slufigy name with underscore""" + self.name = slugify(name, separator='_') + + def add_serie(self, y, x, name=None, extra=None, **kwargs): + """ + add serie - Series are list of data that will be plotted + y {1, 2, 3, 4, 5} / x {1, 2, 3, 4, 5} + + **Attributes**: + + * ``name`` - set Serie name + * ``x`` - x-axis data + * ``y`` - y-axis data + + kwargs: + + * ``shape`` - for scatterChart, you can set different shapes + (circle, triangle etc...) + * ``size`` - for scatterChart, you can set size of different shapes + * ``type`` - for multiChart, type should be bar + * ``bar`` - to display bars in Chart + * ``color_list`` - define list of colors which will be + used by pieChart + * ``color`` - set axis color + * ``disabled`` - + + extra: + + * ``tooltip`` - set tooltip flag + * ``date_format`` - set date_format for tooltip if x-axis is in + date format + + """ + if not name: + name = "Serie %d" % (self.serie_no) + + # For scatterChart shape & size fields are added in serie + if 'shape' in kwargs or 'size' in kwargs: + csize = kwargs.get('size', 1) + cshape = kwargs.get('shape', 'circle') + + serie = [{ + 'x': x[i], + 'y': j, + 'shape': cshape, + 'size': csize[i] if isinstance(csize, list) else csize + } for i, j in enumerate(y)] + else: + if self.model == 'pieChart': + serie = [{'label': x[i], 'value': y} for i, y in enumerate(y)] + else: + serie = [{'x': x[i], 'y': y} for i, y in enumerate(y)] + + data_keyvalue = {'values': serie, 'key': name} + + # multiChart + # Histogram type='bar' for the series + if 'type' in kwargs and kwargs['type']: + data_keyvalue['type'] = kwargs['type'] + + # Define on which Y axis the serie is related + # a chart can have 2 Y axis, left and right, by default only one Y Axis is used + if 'yaxis' in kwargs and kwargs['yaxis']: + data_keyvalue['yAxis'] = kwargs['yaxis'] + else: + if self.model != 'pieChart': + data_keyvalue['yAxis'] = '1' + + if 'bar' in kwargs and kwargs['bar']: + data_keyvalue['bar'] = 'true' + + if 'disabled' in kwargs and kwargs['disabled']: + data_keyvalue['disabled'] = 'true' + + if 'color' in kwargs and kwargs['color']: + data_keyvalue['color'] = kwargs['color'] + + if extra: + if self.model == 'pieChart': + if 'color_list' in extra and extra['color_list']: + self.color_list = extra['color_list'] + + if extra.get('date_format'): + self.charttooltip_dateformat = extra['date_format'] + + if extra.get('tooltip'): + self.custom_tooltip_flag = True + + if self.model != 'pieChart': + _start = extra['tooltip']['y_start'] + _end = extra['tooltip']['y_end'] + _start = ("'" + str(_start) + "' + ") if _start else '' + _end = (" + '" + str(_end) + "'") if _end else '' + + if self.model == 'linePlusBarChart': + if self.tooltip_condition_string: + self.tooltip_condition_string += stab(5) + self.tooltip_condition_string += stab(0) + "if(key.indexOf('" + name + "') > -1 ){\n" +\ + stab(6) + "var y = " + _start + " String(graph.point.y) " + _end + ";\n" +\ + stab(5) + "}\n" + elif self.model == 'cumulativeLineChart': + self.tooltip_condition_string += stab(0) + "if(key == '" + name + "'){\n" +\ + stab(6) + "var y = " + _start + " String(e) " + _end + ";\n" +\ + stab(5) + "}\n" + else: + self.tooltip_condition_string += stab(5) + "if(key == '" + name + "'){\n" +\ + stab(6) + "var y = " + _start + " String(graph.point.y) " + _end + ";\n" +\ + stab(5) + "}\n" + + if self.model == 'pieChart': + _start = extra['tooltip']['y_start'] + _end = extra['tooltip']['y_end'] + _start = ("'" + str(_start) + "' + ") if _start else '' + _end = (" + '" + str(_end) + "'") if _end else '' + self.tooltip_condition_string += "var y = " + _start + " String(y) " + _end + ";\n" + + # Increment series counter & append + self.serie_no += 1 + self.series.append(data_keyvalue) + + def add_chart_extras(self, extras): + """ + Use this method to add extra d3 properties to your chart. + For example, you want to change the text color of the graph:: + + chart = pieChart(name='pieChart', color_category='category20c', height=400, width=400) + + xdata = ["Orange", "Banana", "Pear", "Kiwi", "Apple", "Strawberry", "Pineapple"] + ydata = [3, 4, 0, 1, 5, 7, 3] + + extra_serie = {"tooltip": {"y_start": "", "y_end": " cal"}} + chart.add_serie(y=ydata, x=xdata, extra=extra_serie) + + The above code will create graph with a black text, the following will change it:: + + text_white="d3.selectAll('#pieChart text').style('fill', 'white');" + chart.add_chart_extras(text_white) + + The above extras will be appended to the java script generated. + + Alternatively, you can use the following initialization:: + + chart = pieChart(name='pieChart', + color_category='category20c', + height=400, width=400, + extras=text_white) + """ + self.extras = extras + + def set_graph_height(self, height): + """Set Graph height""" + self.height = str(height) + + def set_graph_width(self, width): + """Set Graph width""" + self.width = str(width) + + def set_containerheader(self, containerheader): + """Set containerheader""" + self.containerheader = containerheader + + def set_date_flag(self, date_flag=False): + """Set date flag""" + self.date_flag = date_flag + + def set_custom_tooltip_flag(self, custom_tooltip_flag): + """Set custom_tooltip_flag & date_flag""" + self.custom_tooltip_flag = custom_tooltip_flag + + def __str__(self): + """return htmlcontent""" + self.buildhtml() + return self.htmlcontent + + def buildcontent(self): + """Build HTML content only, no header or body tags. To be useful this + will usually require the attribute `juqery_on_ready` to be set which + will wrap the js in $(function(){};) + """ + self.buildcontainer() + # if the subclass has a method buildjs this method will be + # called instead of the method defined here + # when this subclass method is entered it does call + # the method buildjschart defined here + self.buildjschart() + self.htmlcontent = self.template_content_nvd3.render(chart=self) + + def buildhtml(self): + """Build the HTML page + Create the htmlheader with css / js + Create html page + Add Js code for nvd3 + """ + self.buildcontent() + self.content = self.htmlcontent + self.htmlcontent = self.template_page_nvd3.render(chart=self) + + # this is used by django-nvd3 + def buildhtmlheader(self): + """generate HTML header content""" + self.htmlheader = '' + # If the JavaScript assets have already been injected, don't bother re-sourcing them. + global _js_initialized + if '_js_initialized' not in globals() or not _js_initialized: + for css in self.header_css: + self.htmlheader += css + for js in self.header_js: + self.htmlheader += js + + def buildcontainer(self): + """generate HTML div""" + if self.container: + return + + # Create SVG div with style + if self.width: + if self.width[-1] != '%': + self.style += 'width:%spx;' % self.width + else: + self.style += 'width:%s;' % self.width + if self.height: + if self.height[-1] != '%': + self.style += 'height:%spx;' % self.height + else: + self.style += 'height:%s;' % self.height + if self.style: + self.style = 'style="%s"' % self.style + + self.container = self.containerheader + \ + '
\n' % (self.name, self.style) + + def buildjschart(self): + """generate javascript code for the chart""" + self.jschart = '' + + # add custom tooltip string in jschart + # default condition (if build_custom_tooltip is not called explicitly with date_flag=True) + if self.tooltip_condition_string == '': + self.tooltip_condition_string = 'var y = String(graph.point.y);\n' + + # Include data + self.series_js = json.dumps(self.series) + + def create_x_axis(self, name, label=None, format=None, date=False, custom_format=False): + """Create X-axis""" + axis = {} + if custom_format and format: + axis['tickFormat'] = format + elif format: + if format == 'AM_PM': + axis['tickFormat'] = "function(d) { return get_am_pm(parseInt(d)); }" + else: + axis['tickFormat'] = "d3.format(',%s')" % format + + if label: + axis['axisLabel'] = "'" + label + "'" + + # date format : see https://github.com/mbostock/d3/wiki/Time-Formatting + if date: + self.dateformat = format + axis['tickFormat'] = ("function(d) { return d3.time.format('%s')" + "(new Date(parseInt(d))) }\n" + "" % self.dateformat) + # flag is the x Axis is a date + if name[0] == 'x': + self.x_axis_date = True + + # Add new axis to list of axis + self.axislist[name] = axis + + # Create x2Axis if focus_enable + if name == "xAxis" and self.focus_enable: + self.axislist['x2Axis'] = axis + + def create_y_axis(self, name, label=None, format=None, custom_format=False): + """ + Create Y-axis + """ + axis = {} + + if custom_format and format: + axis['tickFormat'] = format + elif format: + axis['tickFormat'] = "d3.format(',%s')" % format + + if label: + axis['axisLabel'] = "'" + label + "'" + + # Add new axis to list of axis + self.axislist[name] = axis + + +class TemplateMixin(object): + """ + A mixin that override buildcontent. Instead of building the complex + content template we exploit Jinja2 inheritance. Thus each chart class + renders it's own chart template which inherits from content.html + """ + def buildcontent(self): + """Build HTML content only, no header or body tags. To be useful this + will usually require the attribute `juqery_on_ready` to be set which + will wrap the js in $(function(){};) + """ + self.buildcontainer() + # if the subclass has a method buildjs this method will be + # called instead of the method defined here + # when this subclass method is entered it does call + # the method buildjschart defined here + self.buildjschart() + self.htmlcontent = self.template_chart_nvd3.render(chart=self) + + +def _main(): + """ + Parse options and process commands + """ + # Parse arguments + usage = "usage: nvd3.py [options]" + parser = OptionParser(usage=usage, + version=("python-nvd3 - Charts generator with " + "nvd3.js and d3.js")) + parser.add_option("-q", "--quiet", + action="store_false", dest="verbose", default=True, + help="don't print messages to stdout") + + (options, args) = parser.parse_args() + + +if __name__ == '__main__': + _main() diff --git a/airflow/_vendor/nvd3/__init__.py b/airflow/_vendor/nvd3/__init__.py new file mode 100755 index 0000000000000..5b737b45361ad --- /dev/null +++ b/airflow/_vendor/nvd3/__init__.py @@ -0,0 +1,29 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Python-nvd3 is a Python wrapper for NVD3 graph library. +NVD3 is an attempt to build re-usable charts and chart components +for d3.js without taking away the power that d3.js gives you. + +Project location : https://github.com/areski/python-nvd3 +""" + +__version__ = '0.15.0' +__all__ = ['lineChart', 'pieChart', 'lineWithFocusChart', + 'stackedAreaChart', 'multiBarHorizontalChart', + 'linePlusBarChart', 'cumulativeLineChart', + 'scatterChart', 'discreteBarChart', 'multiBarChart'] + + +from .lineChart import lineChart +from .pieChart import pieChart +from .lineWithFocusChart import lineWithFocusChart +from .stackedAreaChart import stackedAreaChart +from .multiBarHorizontalChart import multiBarHorizontalChart +from .linePlusBarChart import linePlusBarChart +from .cumulativeLineChart import cumulativeLineChart +from .scatterChart import scatterChart +from .discreteBarChart import discreteBarChart +from .multiBarChart import multiBarChart +from . import ipynb diff --git a/airflow/_vendor/nvd3/cumulativeLineChart.py b/airflow/_vendor/nvd3/cumulativeLineChart.py new file mode 100644 index 0000000000000..d98d0867e4d99 --- /dev/null +++ b/airflow/_vendor/nvd3/cumulativeLineChart.py @@ -0,0 +1,104 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Python-nvd3 is a Python wrapper for NVD3 graph library. +NVD3 is an attempt to build re-usable charts and chart components +for d3.js without taking away the power that d3.js gives you. + +Project location : https://github.com/areski/python-nvd3 +""" + +from .NVD3Chart import NVD3Chart, TemplateMixin + + +class cumulativeLineChart(TemplateMixin, NVD3Chart): + """ + A cumulative line chart is used when you have one important grouping representing + an ordered set of data and one value to show, summed over time. + + Python example:: + + from nvd3 import cumulativeLineChart + chart = cumulativeLineChart(name='cumulativeLineChart', x_is_date=True) + xdata = [1365026400000000, 1365026500000000, 1365026600000000] + ydata = [6, 5, 1] + y2data = [36, 55, 11] + + extra_serie = {"tooltip": {"y_start": "There are ", "y_end": " calls"}} + chart.add_serie(name="Serie 1", y=ydata, x=xdata, extra=extra_serie) + + extra_serie = {"tooltip": {"y_start": "", "y_end": " mins"}} + chart.add_serie(name="Serie 2", y=y2data, x=xdata, extra=extra_serie) + chart.buildhtml() + + Javascript generated: + + .. raw:: html + +
+ + + """ + + CHART_FILENAME = "./cumulativelinechart.html" + template_chart_nvd3 = NVD3Chart.template_environment.get_template(CHART_FILENAME) + + def __init__(self, **kwargs): + super(cumulativeLineChart, self).__init__(**kwargs) + self.model = 'cumulativeLineChart' + + height = kwargs.get('height', 450) + width = kwargs.get('width', None) + + if kwargs.get('x_is_date', False): + self.set_date_flag(True) + self.create_x_axis('xAxis', + format=kwargs.get('x_axis_format', '%d %b %Y'), + date=True) + self.set_custom_tooltip_flag(True) + else: + self.create_x_axis('xAxis', format=kwargs.get( + 'x_axis_format', '.2f')) + + self.create_y_axis('yAxis', format=kwargs.get('y_axis_format', '.1%')) + + self.set_graph_height(height) + if width: + self.set_graph_width(width) diff --git a/airflow/_vendor/nvd3/discreteBarChart.py b/airflow/_vendor/nvd3/discreteBarChart.py new file mode 100644 index 0000000000000..cf6c8a4a8ff4b --- /dev/null +++ b/airflow/_vendor/nvd3/discreteBarChart.py @@ -0,0 +1,91 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Python-nvd3 is a Python wrapper for NVD3 graph library. +NVD3 is an attempt to build re-usable charts and chart components +for d3.js without taking away the power that d3.js gives you. + +Project location : https://github.com/areski/python-nvd3 +""" + +from .NVD3Chart import NVD3Chart, TemplateMixin + + +class discreteBarChart(TemplateMixin, NVD3Chart): + """ + A discrete bar chart or bar graph is a chart with rectangular bars with + lengths proportional to the values that they represent. + + Python example:: + + from nvd3 import discreteBarChart + chart = discreteBarChart(name='discreteBarChart', height=400, width=400) + + xdata = ["A", "B", "C", "D", "E", "F"] + ydata = [3, 4, 0, -3, 5, 7] + + chart.add_serie(y=ydata, x=xdata) + chart.buildhtml() + + Javascript generated: + + .. raw:: html + +
+ + + + """ + CHART_FILENAME = "./discretebarchart.html" + template_chart_nvd3 = NVD3Chart.template_environment.get_template(CHART_FILENAME) + + def __init__(self, **kwargs): + super(discreteBarChart, self).__init__(**kwargs) + self.model = 'discreteBarChart' + height = kwargs.get('height', 450) + width = kwargs.get('width', None) + + if kwargs.get('x_is_date', False): + self.set_date_flag(True) + self.create_x_axis('xAxis', + format=kwargs.get('x_axis_format', + "%d %b %Y %H %S"), + date=True) + else: + self.create_x_axis('xAxis', format=None) + + self.create_y_axis('yAxis', format=kwargs.get('y_axis_format', ".0f")) + + self.set_custom_tooltip_flag(True) + + self.set_graph_height(height) + if width: + self.set_graph_width(width) diff --git a/airflow/_vendor/nvd3/ipynb.py b/airflow/_vendor/nvd3/ipynb.py new file mode 100644 index 0000000000000..f421afc0a8a50 --- /dev/null +++ b/airflow/_vendor/nvd3/ipynb.py @@ -0,0 +1,91 @@ +''' +ipython compatability module for nvd3-python +This adds simple ipython compatibility to the nvd3-python package, without making any +major modifications to how the main package is structured. It utilizes the IPython +display-formatter functionality, as described at: +http://nbviewer.ipython.org/github/ipython/ipython/blob/master/examples/notebooks/Custom%20Display%20Logic.ipynb +For additional examples, see: +https://github.com/sympy/sympy/blob/master/sympy/interactive/printing.py +''' + +try: + _ip = get_ipython() +except: + _ip = None +if _ip and _ip.__module__.lower().startswith('ipy'): + global _js_initialized + _js_initialized = False + + def _print_html(chart): + '''Function to return the HTML code for the div container plus the javascript + to generate the chart. This function is bound to the ipython formatter so that + charts are displayed inline.''' + global _js_initialized + if not _js_initialized: + print('js not initialized - pausing to allow time for it to load...') + initialize_javascript() + import time + time.sleep(5) + chart.buildhtml() + return chart.htmlcontent + + def _setup_ipython_formatter(ip): + ''' Set up the ipython formatter to display HTML formatted output inline''' + from IPython import __version__ as IPython_version + from nvd3 import __all__ as nvd3_all + + if IPython_version >= '0.11': + html_formatter = ip.display_formatter.formatters['text/html'] + for chart_type in nvd3_all: + html_formatter.for_type_by_name('nvd3.' + chart_type, chart_type, _print_html) + + def initialize_javascript(d3_js_url='https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js', + nvd3_js_url='https://cdnjs.cloudflare.com/ajax/libs/nvd3/1.7.0/nv.d3.min.js', + nvd3_css_url='https://cdnjs.cloudflare.com/ajax/libs/nvd3/1.7.0/nv.d3.min.css', + use_remote=False): + '''Initialize the ipython notebook to be able to display nvd3 results. + by instructing IPython to load the nvd3 JS and css files, and the d3 JS file. + + by default, it looks for the files in your IPython Notebook working directory. + + Takes the following options: + + use_remote: use remote hosts for d3.js, nvd3.js, and nv.d3.css (default False) + * Note: the following options are ignored if use_remote is False: + nvd3_css_url: location of nvd3 css file (default https://cdnjs.cloudflare.com/ajax/libs/nvd3/1.7.0/nv.d3.min.css) + nvd3_js_url: location of nvd3 javascript file (default https://cdnjs.cloudflare.com/ajax/libs/nvd3/1.7.0/nv.d3.min.css) + d3_js_url: location of d3 javascript file (default https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js) + ''' + from IPython.display import display, Javascript, HTML + + if not use_remote: + # these file locations are for IPython 1.x, and will probably change when 2.x is released + d3_js_url = 'files/d3.v3.js' + nvd3_js_url = 'files/nv.d3.js' + nvd3_css_url = 'files/nv.d3.css' + + # load the required javascript files + + #display(Javascript('''$.getScript("%s")''' %(d3_js_url))) + display(HTML('''''' % (nvd3_css_url))) + # The following two methods for loading the script file are redundant. + # This is intentional. + # Ipython's loading of javscript in version 1.x is a bit squirrely, especially + # when creating demos to view in nbviewer. + # by trying twice, in two different ways (one using jquery and one using plain old + # HTML), we maximize our chances of successfully loading the script. + display(Javascript('''$.getScript("%s")''' % (nvd3_js_url))) + display(Javascript('''$.getScript("%s", function() { + $.getScript("%s", function() {})});''' % (d3_js_url, nvd3_js_url))) + display(HTML('' % (d3_js_url))) + display(HTML('' % (nvd3_js_url))) + + global _js_initialized + _js_initialized = True + + print('loaded nvd3 IPython extension\n' + 'run nvd3.ipynb.initialize_javascript() to set up the notebook\n' + 'help(nvd3.ipynb.initialize_javascript) for options') + + _setup_ipython_formatter(_ip) diff --git a/airflow/_vendor/nvd3/lineChart.py b/airflow/_vendor/nvd3/lineChart.py new file mode 100644 index 0000000000000..c237d069802ad --- /dev/null +++ b/airflow/_vendor/nvd3/lineChart.py @@ -0,0 +1,120 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Python-nvd3 is a Python wrapper for NVD3 graph library. +NVD3 is an attempt to build re-usable charts and chart components +for d3.js without taking away the power that d3.js gives you. + +Project location : https://github.com/areski/python-nvd3 +""" + +from .NVD3Chart import NVD3Chart, TemplateMixin + + +class lineChart(TemplateMixin, NVD3Chart): + + """ + A line chart or line graph is a type of chart which displays information + as a series of data points connected by straight line segments. + + Python example:: + + from nvd3 import lineChart + chart = lineChart(name="lineChart", x_is_date=False, x_axis_format="AM_PM") + + xdata = range(24) + ydata = [0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 4, 3, 3, 5, 7, 5, 3, 16, 6, 9, 15, 4, 12] + ydata2 = [9, 8, 11, 8, 3, 7, 10, 8, 6, 6, 9, 6, 5, 4, 3, 10, 0, 6, 3, 1, 0, 0, 0, 1] + + extra_serie = {"tooltip": {"y_start": "There are ", "y_end": " calls"}} + chart.add_serie(y=ydata, x=xdata, name='sine', extra=extra_serie, **kwargs1) + extra_serie = {"tooltip": {"y_start": "", "y_end": " min"}} + chart.add_serie(y=ydata2, x=xdata, name='cose', extra=extra_serie, **kwargs2) + chart.buildhtml() + + Javascript renderd to: + + .. raw:: html + +
+ + + See the source code of this page, to see the underlying javascript. + """ + CHART_FILENAME = "./linechart.html" + template_chart_nvd3 = NVD3Chart.template_environment.get_template(CHART_FILENAME) + + def __init__(self, **kwargs): + super(lineChart, self).__init__(**kwargs) + self.model = 'lineChart' + + height = kwargs.get('height', 450) + width = kwargs.get('width', None) + + if kwargs.get('x_is_date', False): + self.set_date_flag(True) + self.create_x_axis('xAxis', + format=kwargs.get('x_axis_format', '%d %b %Y'), + date=True) + self.set_custom_tooltip_flag(True) + else: + if kwargs.get('x_axis_format') == 'AM_PM': + self.x_axis_format = format = 'AM_PM' + else: + format = kwargs.get('x_axis_format', 'r') + self.create_x_axis('xAxis', format=format, + custom_format=kwargs.get('x_custom_format', + False)) + self.create_y_axis( + 'yAxis', + format=kwargs.get('y_axis_format', '.02f'), + custom_format=kwargs.get('y_custom_format', False)) + + # must have a specified height, otherwise it superimposes both chars + self.set_graph_height(height) + if width: + self.set_graph_width(width) diff --git a/airflow/_vendor/nvd3/linePlusBarChart.py b/airflow/_vendor/nvd3/linePlusBarChart.py new file mode 100644 index 0000000000000..4eaa5fc6ffdbf --- /dev/null +++ b/airflow/_vendor/nvd3/linePlusBarChart.py @@ -0,0 +1,131 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Python-nvd3 is a Python wrapper for NVD3 graph library. +NVD3 is an attempt to build re-usable charts and chart components +for d3.js without taking away the power that d3.js gives you. + +Project location : https://github.com/areski/python-nvd3 +""" + +from .NVD3Chart import NVD3Chart, TemplateMixin + + +class linePlusBarChart(TemplateMixin, NVD3Chart): + + """ + A linePlusBarChart Chart is a type of chart which displays information + as a series of data points connected by straight line segments + and with some series with rectangular bars with lengths proportional + to the values that they represent. + + Python example:: + + from nvd3 import linePlusBarChart + chart = linePlusBarChart(name="linePlusBarChart", + width=500, height=400, x_axis_format="%d %b %Y", + x_is_date=True, focus_enable=True, + yaxis2_format="function(d) { return d3.format(',0.3f')(d) }") + + xdata = [1338501600000, 1345501600000, 1353501600000] + ydata = [6, 5, 1] + y2data = [0.002, 0.003, 0.004] + + extra_serie = {"tooltip": {"y_start": "There are ", "y_end": " calls"}, + "date_format": "%d %b %Y %H:%S" } + chart.add_serie(name="Serie 1", y=ydata, x=xdata, extra=extra_serie, + bar=True) + + extra_serie = {"tooltip": {"y_start": "There are ", "y_end": " min"}} + chart.add_serie(name="Serie 2", y=y2data, x=xdata, extra=extra_serie) + chart.buildcontent() + + Note that in case you have two data serie with extreme different numbers, + that you would like to format in different ways, + you can pass a keyword *yaxis1_format* or *yaxis2_format* when + creating the graph. + + In the example above the graph created presents the values of the second + data series with three digits right of the decimal point. + + Javascript generated: + + .. raw:: html + +
+ + + """ + CHART_FILENAME = "./lineplusbarchart.html" + template_chart_nvd3 = NVD3Chart.template_environment.get_template(CHART_FILENAME) + + def __init__(self, **kwargs): + super(linePlusBarChart, self).__init__(**kwargs) + self.model = 'linePlusBarChart' + + height = kwargs.get('height', 450) + width = kwargs.get('width', None) + self.yaxis1_format = kwargs.get('yaxis1_format', + "function(d) { return d3.format(',f')(d) }") + self.yaxis2_format = kwargs.get('yaxis2_format', + "function(d) { return d3.format(',f')(d) }") + + if kwargs.get('x_is_date', False): + self.set_date_flag(True) + self.create_x_axis('xAxis', + format=kwargs.get('x_axis_format', + '%d %b %Y %H %S'), + date=True) + self.create_x_axis('x2Axis', format=kwargs.get('x_axis_format', + '%d %b %Y %H %S'), + date=True) + self.set_custom_tooltip_flag(True) + else: + self.create_x_axis('xAxis', format=kwargs.get('x_axis_format', + '.2f')) + self.create_x_axis('x2Axis', format=kwargs.get('x_axis_format', + '.2f')) + + self.create_y_axis('y1Axis', format=self.yaxis1_format, + custom_format=True) + self.create_y_axis('y2Axis', format=self.yaxis2_format, + custom_format=True) + + self.set_graph_height(height) + if width: + self.set_graph_width(width) diff --git a/airflow/_vendor/nvd3/lineWithFocusChart.py b/airflow/_vendor/nvd3/lineWithFocusChart.py new file mode 100644 index 0000000000000..cd26cd4716652 --- /dev/null +++ b/airflow/_vendor/nvd3/lineWithFocusChart.py @@ -0,0 +1,105 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Python-nvd3 is a Python wrapper for NVD3 graph library. +NVD3 is an attempt to build re-usable charts and chart components +for d3.js without taking away the power that d3.js gives you. + +Project location : https://github.com/areski/python-nvd3 +""" + +from .NVD3Chart import NVD3Chart, TemplateMixin + + +class lineWithFocusChart(TemplateMixin, NVD3Chart): + """ + A lineWithFocusChart or line graph is a type of chart which displays information + as a series of data points connected by straight line segments. + The lineWithFocusChart provide a smaller chart that act as a selector, + this is very useful if you want to zoom on a specific time period. + + Python example:: + + from nvd3 import lineWithFocusChart + chart = lineWithFocusChart(name='lineWithFocusChart', x_is_date=True, x_axis_format="%d %b %Y") + xdata = [1365026400000000, 1365026500000000, 1365026600000000, 1365026700000000, 1365026800000000, 1365026900000000, 1365027000000000] + ydata = [-6, 5, -1, 2, 4, 8, 10] + + extra_serie = {"tooltip": {"y_start": "", "y_end": " ext"}, + "date_format": "%d %b %Y"} + chart.add_serie(name="Serie 1", y=ydata, x=xdata, extra=extra_serie) + chart.buildhtml() + + Javascript generated: + + .. raw:: html + +
+ + + """ + + CHART_FILENAME = "./linewfocuschart.html" + template_chart_nvd3 = NVD3Chart.template_environment.get_template(CHART_FILENAME) + + def __init__(self, **kwargs): + super(lineWithFocusChart, self).__init__(**kwargs) + self.model = 'lineWithFocusChart' + + height = kwargs.get('height', 450) + width = kwargs.get('width', None) + + if kwargs.get('x_is_date', False): + self.set_date_flag(True) + self.create_x_axis('xAxis', format=kwargs.get('x_axis_format', + '%d %b %Y %H %S'), + date=True) + self.create_x_axis('x2Axis', format=kwargs.get('x_axis_format', + '%d %b %Y %H %S'), + date=True) + self.set_custom_tooltip_flag(True) + else: + self.create_x_axis('xAxis', format=kwargs.get('x_axis_format', + '.2f')) + self.create_x_axis('x2Axis', format=kwargs.get('x_axis_format', + '.2f')) + + self.create_y_axis('yAxis', format=kwargs.get('y_axis_format', '.2f')) + self.create_y_axis('y2Axis', format=kwargs.get('y_axis_format', '.2f')) + + self.set_graph_height(height) + if width: + self.set_graph_width(width) diff --git a/airflow/_vendor/nvd3/multiBarChart.py b/airflow/_vendor/nvd3/multiBarChart.py new file mode 100644 index 0000000000000..cf335919a84c7 --- /dev/null +++ b/airflow/_vendor/nvd3/multiBarChart.py @@ -0,0 +1,95 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Python-nvd3 is a Python wrapper for NVD3 graph library. +NVD3 is an attempt to build re-usable charts and chart components +for d3.js without taking away the power that d3.js gives you. + +Project location : https://github.com/areski/python-nvd3 +""" + +from .NVD3Chart import NVD3Chart, TemplateMixin + + +class multiBarChart(TemplateMixin, NVD3Chart): + """ + A multiple bar graph contains comparisons of two or more categories or bars. + One axis represents a quantity and the other axis identifies a specific feature + about the categories. Reading a multiple bar graph includes looking at extremes + (tallest/longest vs. shortest) in each grouping. + + Python example:: + + from nvd3 import multiBarChart + chart = multiBarChart(width=500, height=400, x_axis_format=None) + xdata = ['one', 'two', 'three', 'four'] + ydata1 = [6, 12, 9, 16] + ydata2 = [8, 14, 7, 11] + + chart.add_serie(name="Serie 1", y=ydata1, x=xdata) + chart.add_serie(name="Serie 2", y=ydata2, x=xdata) + chart.buildhtml() + + Javascript generated: + + .. raw:: html + +
+ + + """ + + CHART_FILENAME = "./multibarchart.html" + template_chart_nvd3 = NVD3Chart.template_environment.get_template(CHART_FILENAME) + + def __init__(self, **kwargs): + super(multiBarChart, self).__init__(**kwargs) + + height = kwargs.get('height', 450) + width = kwargs.get('width', None) + + if kwargs.get('x_is_date', False): + self.set_date_flag(True) + self.create_x_axis('xAxis', + format=kwargs.get('x_axis_format', '%d %b %Y'), + date=True) + self.set_custom_tooltip_flag(True) + else: + self.create_x_axis('xAxis', format=kwargs.get('x_axis_format', '.2f')) + self.create_y_axis('yAxis', format=kwargs.get('y_axis_format', '.2f')) + + self.set_graph_height(height) + if width: + self.set_graph_width(width) diff --git a/airflow/_vendor/nvd3/multiBarHorizontalChart.py b/airflow/_vendor/nvd3/multiBarHorizontalChart.py new file mode 100644 index 0000000000000..ac969c31b548c --- /dev/null +++ b/airflow/_vendor/nvd3/multiBarHorizontalChart.py @@ -0,0 +1,100 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Python-nvd3 is a Python wrapper for NVD3 graph library. +NVD3 is an attempt to build re-usable charts and chart components +for d3.js without taking away the power that d3.js gives you. + +Project location : https://github.com/areski/python-nvd3 +""" + +from .NVD3Chart import NVD3Chart, TemplateMixin + + +class multiBarHorizontalChart(TemplateMixin, NVD3Chart): + """ + A multiple horizontal bar graph contains comparisons of two or more categories or bars. + + Python example:: + + from nvd3 import multiBarHorizontalChart + chart = multiBarHorizontalChart(name='multiBarHorizontalChart', height=400, width=400) + xdata = [-14, -7, 7, 14] + ydata = [-6, 5, -1, 9] + y2data = [-23, -6, -32, 9] + + extra_serie = {"tooltip": {"y_start": "", "y_end": " balls"}} + chart.add_serie(name="Serie 1", y=ydata, x=xdata, extra=extra_serie) + + extra_serie = {"tooltip": {"y_start": "", "y_end": " calls"}} + chart.add_serie(name="Serie 2", y=y2data, x=xdata, extra=extra_serie) + chart.buildcontent() + + Javascript generated: + + .. raw:: html + +
+ + + """ + + CHART_FILENAME = "./multibarcharthorizontal.html" + template_chart_nvd3 = NVD3Chart.template_environment.get_template(CHART_FILENAME) + + def __init__(self, **kwargs): + super(multiBarHorizontalChart, self).__init__(**kwargs) + height = kwargs.get('height', 450) + width = kwargs.get('width', None) + + self.create_x_axis('xAxis', format=kwargs.get('x_axis_format', '.2f')) + self.create_y_axis('yAxis', format=kwargs.get('y_axis_format', '.2f')) + + self.set_graph_height(height) + if width: + self.set_graph_width(width) diff --git a/airflow/_vendor/nvd3/pieChart.py b/airflow/_vendor/nvd3/pieChart.py new file mode 100644 index 0000000000000..1db76bdb3424c --- /dev/null +++ b/airflow/_vendor/nvd3/pieChart.py @@ -0,0 +1,101 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Python-nvd3 is a Python wrapper for NVD3 graph library. +NVD3 is an attempt to build re-usable charts and chart components +for d3.js without taking away the power that d3.js gives you. + +Project location : https://github.com/areski/python-nvd3 +""" + +from .NVD3Chart import NVD3Chart, TemplateMixin + + +class pieChart(TemplateMixin, NVD3Chart): + + """ + A pie chart (or a circle graph) is a circular chart divided into sectors, + illustrating numerical proportion. In chart, the arc length of each sector + is proportional to the quantity it represents. + + Python example:: + + from nvd3 import pieChart + chart = pieChart(name='pieChart', color_category='category20c', + height=400, width=400) + + xdata = ["Orange", "Banana", "Pear", "Kiwi", "Apple", "Strawbery", + "Pineapple"] + ydata = [3, 4, 0, 1, 5, 7, 3] + + extra_serie = {"tooltip": {"y_start": "", "y_end": " cal"}} + chart.add_serie(y=ydata, x=xdata, extra=extra_serie) + chart.buildhtml() + + Javascript generated: + + .. raw:: html + +
+ + + """ + CHART_FILENAME = "./piechart.html" + template_chart_nvd3 = NVD3Chart.template_environment.get_template(CHART_FILENAME) + + def __init__(self, **kwargs): + super(pieChart, self).__init__(**kwargs) + + height = kwargs.get('height', 450) + width = kwargs.get('width', None) + self.donut = kwargs.get('donut', False) + self.donutRatio = kwargs.get('donutRatio', 0.35) + self.color_list = [] + self.create_x_axis('xAxis', format=None) + self.create_y_axis('yAxis', format=None) + # must have a specified height, otherwise it superimposes both chars + if height: + self.set_graph_height(height) + if width: + self.set_graph_width(width) + self.donut = kwargs.get('donut', False) + self.donutRatio = kwargs.get('donutRatio', 0.35) diff --git a/airflow/_vendor/nvd3/scatterChart.py b/airflow/_vendor/nvd3/scatterChart.py new file mode 100644 index 0000000000000..c3a87d2908bde --- /dev/null +++ b/airflow/_vendor/nvd3/scatterChart.py @@ -0,0 +1,121 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Python-nvd3 is a Python wrapper for NVD3 graph library. +NVD3 is an attempt to build re-usable charts and chart components +for d3.js without taking away the power that d3.js gives you. + +Project location : https://github.com/areski/python-nvd3 +""" + +from .NVD3Chart import NVD3Chart, TemplateMixin + + +class scatterChart(TemplateMixin, NVD3Chart): + + """ + A scatter plot or scattergraph is a type of mathematical diagram using Cartesian + coordinates to display values for two variables for a set of data. + The data is displayed as a collection of points, each having the value of one variable + determining the position on the horizontal axis and the value of the other variable + determining the position on the vertical axis. + + Python example:: + + from nvd3 import scatterChart + chart = scatterChart(name='scatterChart', height=400, width=400) + xdata = [3, 4, 0, -3, 5, 7] + ydata = [-1, 2, 3, 3, 15, 2] + ydata2 = [1, -2, 4, 7, -5, 3] + + kwargs1 = {'shape': 'circle', 'size': '1'} + kwargs2 = {'shape': 'cross', 'size': '10'} + + extra_serie = {"tooltip": {"y_start": "", "y_end": " call"}} + chart.add_serie(name="series 1", y=ydata, x=xdata, extra=extra_serie, **kwargs1) + + extra_serie = {"tooltip": {"y_start": "", "y_end": " min"}} + chart.add_serie(name="series 2", y=ydata2, x=xdata, extra=extra_serie, **kwargs2) + chart.buildhtml() + + Javascript generated: + + .. raw:: html + +
+ + + """ + + CHART_FILENAME = "./scatterchart.html" + template_chart_nvd3 = NVD3Chart.template_environment.get_template(CHART_FILENAME) + + def __init__(self, **kwargs): + super(scatterChart, self).__init__(**kwargs) + self.model = 'scatterChart' + height = kwargs.get('height', 450) + width = kwargs.get('width', None) + self.create_x_axis('xAxis', format=kwargs.get('x_axis_format', '.02f'), + label=kwargs.get('x_axis_label', None)) + self.create_y_axis('yAxis', format=kwargs.get('y_axis_format', '.02f'), + label=kwargs.get('y_axis_label', None)) + self.set_graph_height(height) + if width: + self.set_graph_width(width) diff --git a/airflow/_vendor/nvd3/stackedAreaChart.py b/airflow/_vendor/nvd3/stackedAreaChart.py new file mode 100644 index 0000000000000..8346cd2c53879 --- /dev/null +++ b/airflow/_vendor/nvd3/stackedAreaChart.py @@ -0,0 +1,99 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Python-nvd3 is a Python wrapper for NVD3 graph library. +NVD3 is an attempt to build re-usable charts and chart components +for d3.js without taking away the power that d3.js gives you. + +Project location : https://github.com/areski/python-nvd3 +""" + +from .NVD3Chart import NVD3Chart, TemplateMixin + + +class stackedAreaChart(TemplateMixin, NVD3Chart): + """ + The stacked area chart is identical to the area chart, except the areas are stacked + on top of each other, rather than overlapping. This can make the chart much easier to read. + + Python example:: + + from nvd3 import stackedAreaChart + chart = stackedAreaChart(name='stackedAreaChart', height=400, width=400) + + xdata = [100, 101, 102, 103, 104, 105, 106,] + ydata = [6, 11, 12, 7, 11, 10, 11] + ydata2 = [8, 20, 16, 12, 20, 28, 28] + + extra_serie = {"tooltip": {"y_start": "There is ", "y_end": " min"}} + chart.add_serie(name="Serie 1", y=ydata, x=xdata, extra=extra_serie) + chart.add_serie(name="Serie 2", y=ydata2, x=xdata, extra=extra_serie) + chart.buildhtml() + + Javascript generated: + + .. raw:: html + +
+ + + """ + + CHART_FILENAME = "./stackedareachart.html" + template_chart_nvd3 = NVD3Chart.template_environment.get_template(CHART_FILENAME) + + def __init__(self, **kwargs): + super(stackedAreaChart, self).__init__(**kwargs) + height = kwargs.get('height', 450) + width = kwargs.get('width', None) + self.model = 'stackedAreaChart' + + if kwargs.get('x_is_date', False): + self.set_date_flag(True) + self.create_x_axis('xAxis', + format=kwargs.get('x_axis_format', '%d %b %Y'), + date=True) + self.set_custom_tooltip_flag(True) + else: + self.create_x_axis('xAxis', format=kwargs.get('x_axis_format', + '.2f')) + self.create_y_axis('yAxis', format=kwargs.get('y_axis_format', '.2f')) + + self.set_graph_height(height) + if width: + self.set_graph_width(width) diff --git a/airflow/_vendor/nvd3/templates/base.html b/airflow/_vendor/nvd3/templates/base.html new file mode 100644 index 0000000000000..e2d39dd7642cb --- /dev/null +++ b/airflow/_vendor/nvd3/templates/base.html @@ -0,0 +1,35 @@ +{% block container %} +{% endblock %} + +{% block start_script %} + {% if chart.tag_script_js %} + + {% endif %} +{% endblock endscript %} diff --git a/airflow/_vendor/nvd3/templates/content.html b/airflow/_vendor/nvd3/templates/content.html new file mode 100644 index 0000000000000..787f39b555a4a --- /dev/null +++ b/airflow/_vendor/nvd3/templates/content.html @@ -0,0 +1,123 @@ +{% extends "base.html" %} +{% block container %} +{% if chart.display_container %} + {{ chart.container }} +{% endif %} +{% endblock container %} + +{% block body %} + {% block data %} + data_{{ chart.name }}={{ chart.series_js }}; + {% endblock data %} + + {% block init %} + nv.addGraph(function() { + var chart = nv.models.{{ chart.model }}(){% if chart.use_interactive_guideline %}.useInteractiveGuideline(true){% endif %}; + + chart.margin({top: {{ chart.margin_top }}, right: {{ chart.margin_right }}, bottom: {{ chart.margin_bottom }}, left: {{ chart.margin_left }}}); + + var datum = data_{{ chart.name }}; + + {% if not chart.color_list and chart.color_category %} + chart.color(d3.scale.{{ chart.color_category }}().range()); + {% endif %} + {% endblock init %} + + {% if chart.stacked %} + chart.stacked(true); + {% endif %} + + {% block focus %} + {% endblock focus %} + + + {% block axes %} + {% for axis, a in chart.axislist.items() %} + {% if a.items() %} + chart.{{ axis }} + {% for attr, value in a.items() %} + .{{ attr}}({{ value}}){% if loop.last %}; + {% endif %} + {% endfor %} + {% endif %} + {% endfor %} + {% endblock axes %} + + {# generate custom tooltip for the chart #} + {% block tooltip %} + {% if chart.custom_tooltip_flag %} + {% if not chart.date_flag %} + {% if chart.model == 'pieChart' %} + {% block pietooltip %} + {% endblock pietooltip %} + {% else %} + chart.tooltipContent(function(key, y, e, graph) { + var x = String(graph.point.x); + var y = String(graph.point.y); + {{ chart.tooltip_condition_string }} + tooltip_str = '
'+key+'
' + y + ' at ' + x; + return tooltip_str; + }); + {% endif %} + {% else %} + chart.tooltipContent(function(key, y, e, graph) { + var x = d3.time.format("{{ chart.charttooltip_dateformat }}")(new Date(parseInt(graph.point.x))); + var y = String(graph.point.y); + {{ chart.tooltip_condition_string }} + tooltip_str = '
'+key+'
' + y + ' on ' + x; + return tooltip_str; + }); + {% endif %} + {% endif %} + {% endblock tooltip %} + + {# the shape attribute in kwargs is not applied when #} + {# not allowing other shapes to be rendered #} + {% block legend %} + chart.showLegend({{chart.show_legend|lower}}); + {% endblock legend %} + + {% block custoattr %} + {# add custom chart attributes #} + {% for attr, value in chart.chart_attr.items() %} + {% if value is string and value.startswith(".") %}: + chart.{{ attr }}{{ value }}; + {% else %} + chart.{{ attr }}({{ value }}); + {% endif %} + {% endfor %} + + {% if chart.resize %} + nv.utils.windowResize(chart.update); + {% endif %} + + {# include specific subchart #} + {{ chart.jschart }} + + {% endblock custoattr %} + + {% block inject %} + {# Inject data to D3 #} + d3.select('#{{ chart.name }} svg') + .datum(datum) + .transition().duration(500) + {% if chart.width %} + .attr('width', {{ chart.width}}) + {% endif %} + {% if chart.height %} + .attr('height', {{ chart.height}}) + {% endif %} + .call(chart); + {% endblock inject %} + + {# extra chart attributes #} + {% if chart.extras %} + {{ chart.extras }} + {% endif %} + + {# closing nv.addGraph #} + {% block close %} + }); + {% endblock close %} + +{% endblock body %} diff --git a/airflow/_vendor/nvd3/templates/cumulativelinechart.html b/airflow/_vendor/nvd3/templates/cumulativelinechart.html new file mode 100644 index 0000000000000..546a3e8e55171 --- /dev/null +++ b/airflow/_vendor/nvd3/templates/cumulativelinechart.html @@ -0,0 +1,11 @@ +{# This template adds attributes unique + to cumulativeLineChart #} + +{% extends "content.html" %} +{% block body %} + +{# calling super guarantees everying in content is also found here ...#} +{{super()}} + +{% endblock body %} + diff --git a/airflow/_vendor/nvd3/templates/discretebarchart.html b/airflow/_vendor/nvd3/templates/discretebarchart.html new file mode 100644 index 0000000000000..2e31ae4874be0 --- /dev/null +++ b/airflow/_vendor/nvd3/templates/discretebarchart.html @@ -0,0 +1,31 @@ +{# This is a dummy template, we can use that template to add attributes unique + to discreteBarChart #} + +{% extends "content.html" %} +{% block body %} + + {% block data %} + {{super()}} + {% endblock data %} + + {% block init %} + {{super()}} + {% endblock init %} + + {% block axes %} + {{super()}} + {% endblock axes %} + + {% block custoattr %} + {{super()}} + {% endblock custoattr %} + + {% block inject %} + {{ super() }} + {% endblock inject %} + + {% block close %} + {{ super() }} + {% endblock close %} + +{% endblock body %} diff --git a/airflow/_vendor/nvd3/templates/linebarwfocuschart.html b/airflow/_vendor/nvd3/templates/linebarwfocuschart.html new file mode 100644 index 0000000000000..ad4866c8153f9 --- /dev/null +++ b/airflow/_vendor/nvd3/templates/linebarwfocuschart.html @@ -0,0 +1,60 @@ +{# This template adds attributes unique + to lineChart #} + +{% extends "content.html" %} +{% block body %} + {% block data %} + data_{{ chart.name }}={{ chart.series_js }}; + {% endblock data %} + + + {% block init %} + {{super()}} + {% endblock init %} + {% block axes %} + {{super()}} + {% endblock axes %} + {% block tooltip %} + {{super()}} + {% endblock tooltip %} + + chart.showLegend({{chart.show_legend|lower}}); + + {# add custom chart attributes #} + {% for attr, value in chart.chart_attr.items() %} + {% if value is string and value.startswith(".") %}: + chart.{{ attr }}{{ value }}; + {% else %} + chart.{{ attr }}({{ value }}); + {% endif %} + {% endfor %} + + {% if chart.x_axis_format == 'AM_PM' %} + function get_am_pm(d){ + if (d > 12) { + d = d - 12; return (String(d) + 'PM'); + } + else { + return (String(d) + 'AM'); + } + }; + {% else %} + chart.x(function(d,i) { return i }); + {% endif %} + + {% if chart.resize %} + nv.utils.windowResize(chart.update); + {% endif %} + {% block inject %} + {{super()}} + {% endblock inject %} + + {% if chart.extras %} + {{ chart.extras }} + {% endif %} + + {% block close %} + }); + {% endblock close %} + +{% endblock body %} diff --git a/airflow/_vendor/nvd3/templates/linechart.html b/airflow/_vendor/nvd3/templates/linechart.html new file mode 100644 index 0000000000000..cf15d33041558 --- /dev/null +++ b/airflow/_vendor/nvd3/templates/linechart.html @@ -0,0 +1,47 @@ +{# This template adds attributes unique + to lineChart #} + +{% extends "content.html" %} +{% block body %} + + {% block data %} + {{super()}} + {% endblock data %} + + {% block init %} + {{super()}} + {% endblock init %} + + {% block axes %} + {{super()}} + {% endblock axes %} + + {% if chart.x_axis_format == 'AM_PM' %} + function get_am_pm(d){ + if (d > 12) { + d = d - 12; return (String(d) + 'PM'); + } + else { + return (String(d) + 'AM'); + } + }; + {% endif %} + + {% block legend %} + {{super()}} + {% endblock legend %} + + {% block custoattr %} + {{super()}} + {% endblock custoattr %} + + {% block inject %} + {{ super() }} + {% endblock inject %} + + {% block close %} + {{ super() }} + {% endblock close %} + +{% endblock body %} + diff --git a/airflow/_vendor/nvd3/templates/lineplusbarchart.html b/airflow/_vendor/nvd3/templates/lineplusbarchart.html new file mode 100644 index 0000000000000..73aeceacd2419 --- /dev/null +++ b/airflow/_vendor/nvd3/templates/lineplusbarchart.html @@ -0,0 +1,44 @@ +{# This template adds attributes unique + to linePlusBarChart #} + +{% extends "content.html" %} +{% block body %} + + {% block data %} + {{super()}} + {% endblock data %} + + {% block init %} + {{super()}} + {% endblock init %} + + {% block focus %} + {% if chart.focus_enable %} + chart.focusEnable(true); + {% else %} + chart.focusEnable(false); + {% endif %} + {% endblock focus %} + + {% block axes %} + {{super()}} + {% endblock axes %} + + {% block legend %} + {{super()}} + {% endblock legend %} + + {% block custoattr %} + {{super()}} + {% endblock custoattr %} + + {% block inject %} + {{ super() }} + {% endblock inject %} + + {% block close %} + {{ super() }} + {% endblock close %} + +{% endblock body %} + diff --git a/airflow/_vendor/nvd3/templates/linewfocuschart.html b/airflow/_vendor/nvd3/templates/linewfocuschart.html new file mode 100644 index 0000000000000..5abe983d7efc3 --- /dev/null +++ b/airflow/_vendor/nvd3/templates/linewfocuschart.html @@ -0,0 +1,10 @@ +{# This template adds attributes unique + to lineWithFocusChart #} + +{% extends "content.html" %} +{% block body %} + +{# calling super guarantees everying in content is also found here ...#} +{{super()}} + +{% endblock body %} diff --git a/airflow/_vendor/nvd3/templates/multibarchart.html b/airflow/_vendor/nvd3/templates/multibarchart.html new file mode 100644 index 0000000000000..17eae7a634fef --- /dev/null +++ b/airflow/_vendor/nvd3/templates/multibarchart.html @@ -0,0 +1,10 @@ +{# This template adds attributes unique + to multiBarChart #} + +{% extends "content.html" %} +{% block body %} + +{# calling super guarantees everying in content is also found here ...#} +{{super()}} + +{% endblock body %} diff --git a/airflow/_vendor/nvd3/templates/multibarcharthorizontal.html b/airflow/_vendor/nvd3/templates/multibarcharthorizontal.html new file mode 100644 index 0000000000000..17eae7a634fef --- /dev/null +++ b/airflow/_vendor/nvd3/templates/multibarcharthorizontal.html @@ -0,0 +1,10 @@ +{# This template adds attributes unique + to multiBarChart #} + +{% extends "content.html" %} +{% block body %} + +{# calling super guarantees everying in content is also found here ...#} +{{super()}} + +{% endblock body %} diff --git a/airflow/_vendor/nvd3/templates/page.html b/airflow/_vendor/nvd3/templates/page.html new file mode 100644 index 0000000000000..2dd0f5d16f829 --- /dev/null +++ b/airflow/_vendor/nvd3/templates/page.html @@ -0,0 +1,12 @@ + + + + + {% for header_element in chart.header_css+chart.header_js %} + {{ header_element }} + {% endfor %} + + + {{ chart.content }} + + diff --git a/airflow/_vendor/nvd3/templates/piechart.html b/airflow/_vendor/nvd3/templates/piechart.html new file mode 100644 index 0000000000000..a200e6d4a21bb --- /dev/null +++ b/airflow/_vendor/nvd3/templates/piechart.html @@ -0,0 +1,80 @@ +{# This template adds attributes unique + to pieChart #} + +{% extends "content.html" %} +{% block body %} + + data_{{ chart.name }}={{ chart.series_js }}; + + nv.addGraph(function() { + var chart = nv.models.{{ chart.model }}(){% if chart.use_interactive_guideline %}.useInteractiveGuideline(true){% endif %}; + chart.margin({top: {{ chart.margin_top }}, right: {{ chart.margin_right }}, bottom: {{ chart.margin_bottom }}, left: {{ chart.margin_left }}}); + var datum = data_{{ chart.name }}[0].values; + + {% if not chart.color_list and chart.color_category %} + chart.color(d3.scale.{{ chart.color_category }}().range()); + {% endif %} + + chart.tooltipContent(function(key, y, e, graph) { + var x = String(key); + {{ chart.tooltip_condition_string }} + tooltip_str = '
'+x+'
' + y; + return tooltip_str; + }); + {# showLabels only supported in pieChart #} + chart.showLabels({{chart.show_labels|lower}}); + + {% if chart.donut %} + chart.donut(true); + chart.donutRatio({{ chart.donutRatio }}); + {% else %} + chart.donut(false); + {% endif %} + + chart.showLegend({{chart.show_legend|lower}}); + + {# add custom chart attributes #} + {% for attr, value in chart.chart_attr.items() %} + {% if value is string and value.startswith(".") %}: + chart.{{ attr }}{{ value }}; + {% else %} + chart.{{ attr }}({{ value }}); + {% endif %} + {% endfor %} + + {% if chart.resize %} + nv.utils.windowResize(chart.update); + {% endif %} + + {% if chart.color_list %} + var mycolor = new Array(); + {% for color in chart.color_list %} + mycolor[{{ loop.index - 1}}] = "{{ color }}"; + {% endfor %} + {% endif %} + + chart + .x(function(d) { return d.label }) + .y(function(d) { return d.value }); + + {% if chart.width %} + chart.width({{ chart.width }}); + {% endif %} + + {% if chart.height %} + chart.height({{ chart.height }}); + {% endif %} + + {% if chart.color_list %} + chart.color(mycolor); + {% endif %} + + {% block inject %} + {{super()}} + {% endblock inject %} + + {% block close %} + {{ super() }} + {% endblock close %} + +{% endblock body %} diff --git a/airflow/_vendor/nvd3/templates/scatterchart.html b/airflow/_vendor/nvd3/templates/scatterchart.html new file mode 100644 index 0000000000000..8c2adaae34cee --- /dev/null +++ b/airflow/_vendor/nvd3/templates/scatterchart.html @@ -0,0 +1,52 @@ +{# This template adds attributes unique + to scatterChart #} + +{% extends "content.html" %} +{% block body %} + + {% block data %} + {{super()}} + {% endblock data %} + + {% block init %} + {{super()}} + {% endblock init %} + + {% block axes %} + {{super()}} + {% endblock axes %} + + {% if chart.x_axis_format == 'AM_PM' %} + function get_am_pm(d){ + if (d > 12) { + d = d - 12; return (String(d) + 'PM'); + } + else { + return (String(d) + 'AM'); + } + }; + {% endif %} + + {% block legend %} + {{super()}} + {% endblock legend %} + + {% block custoattr %} + {{super()}} + {% endblock custoattr %} + + {% block inject %} + + chart + .showDistX(true) + .showDistY(true) + .color(d3.scale.category10().range()); + + {{ super() }} + {% endblock inject %} + + {% block close %} + {{ super() }} + {% endblock close %} + +{% endblock body %} diff --git a/airflow/_vendor/nvd3/templates/stackedareachart.html b/airflow/_vendor/nvd3/templates/stackedareachart.html new file mode 100644 index 0000000000000..b70833d2b385d --- /dev/null +++ b/airflow/_vendor/nvd3/templates/stackedareachart.html @@ -0,0 +1,7 @@ +{# This is a dummy template, we can use that template to add attributes unique + to stackedareachart #} + +{% extends "content.html" %} +{% block body %} + {{ super() }} +{% endblock body %} diff --git a/airflow/_vendor/nvd3/translator.py b/airflow/_vendor/nvd3/translator.py new file mode 100644 index 0000000000000..ffde2c2a1cec9 --- /dev/null +++ b/airflow/_vendor/nvd3/translator.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + + +class Tag(object): + """Tag class""" + + def __init__(self, content=None): + self.content = content + self.attrs = ' '.join(['%s="%s"' % (attr, value) + for attr, value in self.attrs]) + + def __str__(self): + return '<%s%s>\n %s\n' % (self.name, + ' ' + self.attrs if self.attrs else '', + self.content, + self.name) + + +class ScriptTag(Tag): + name = 'script' + attrs = (('type', 'text/javascript'),) + + +class AnonymousFunction(object): + def __init__(self, arguments, content): + self.arguments = arguments + self.content = content + + def __str__(self): + return 'function(%s) { %s }' % (self.arguments, self.content) + + +class Function(object): + + def __init__(self, name): + self.name = name + self._calls = [] + + def __str__(self): + operations = [self.name] + operations.extend(str(call) for call in self._calls) + return '%s' % ('.'.join(operations),) + + def __getattr__(self, attr): + self._calls.append(attr) + return self + + def __call__(self, *args): + if not args: + self._calls[-1] = self._calls[-1] + '()' + else: + arguments = ','.join([str(arg) for arg in args]) + self._calls[-1] = self._calls[-1] + '(%s)' % (arguments,) + return self + + +class Assignment(object): + + def __init__(self, key, value, scoped=True): + self.key = key + self.value = value + self.scoped = scoped + + def __str__(self): + return '%s%s = %s;' % ('var ' if self.scoped else '', self.key, self.value) + + +def indent(func): + # TODO: Add indents to function str + return str(func) diff --git a/airflow/_vendor/slugify/LICENSE b/airflow/_vendor/slugify/LICENSE new file mode 100644 index 0000000000000..82af695f594e8 --- /dev/null +++ b/airflow/_vendor/slugify/LICENSE @@ -0,0 +1,21 @@ +The MIT License + +Copyright (c) Val Neekman @ Neekware Inc. http://neekware.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/airflow/_vendor/slugify/__init__.py b/airflow/_vendor/slugify/__init__.py new file mode 100644 index 0000000000000..7358b998cd543 --- /dev/null +++ b/airflow/_vendor/slugify/__init__.py @@ -0,0 +1,6 @@ +from .slugify import * + + +__author__ = 'Val Neekman @ Neekware Inc. [@vneekman]' +__description__ = 'A Python slugify application that also handles Unicode' +__version__ = '2.0.1' diff --git a/airflow/_vendor/slugify/slugify.py b/airflow/_vendor/slugify/slugify.py new file mode 100644 index 0000000000000..59e9672a16c5b --- /dev/null +++ b/airflow/_vendor/slugify/slugify.py @@ -0,0 +1,188 @@ +import re +import unicodedata +import types +import sys + +try: + from htmlentitydefs import name2codepoint + _unicode = unicode + _unicode_type = types.UnicodeType +except ImportError: + from html.entities import name2codepoint + _unicode = str + _unicode_type = str + unichr = chr + +try: + import unidecode +except ImportError: + import text_unidecode as unidecode + +__all__ = ['slugify', 'smart_truncate'] + + +CHAR_ENTITY_PATTERN = re.compile(r'&(%s);' % '|'.join(name2codepoint)) +DECIMAL_PATTERN = re.compile(r'&#(\d+);') +HEX_PATTERN = re.compile(r'&#x([\da-fA-F]+);') +QUOTE_PATTERN = re.compile(r'[\']+') +ALLOWED_CHARS_PATTERN = re.compile(r'[^-a-z0-9]+') +ALLOWED_CHARS_PATTERN_WITH_UPPERCASE = re.compile(r'[^-a-zA-Z0-9]+') +DUPLICATE_DASH_PATTERN = re.compile(r'-{2,}') +NUMBERS_PATTERN = re.compile(r'(?<=\d),(?=\d)') +DEFAULT_SEPARATOR = '-' + + +def smart_truncate(string, max_length=0, word_boundary=False, separator=' ', save_order=False): + """ + Truncate a string. + :param string (str): string for modification + :param max_length (int): output string length + :param word_boundary (bool): + :param save_order (bool): if True then word order of output string is like input string + :param separator (str): separator between words + :return: + """ + + string = string.strip(separator) + + if not max_length: + return string + + if len(string) < max_length: + return string + + if not word_boundary: + return string[:max_length].strip(separator) + + if separator not in string: + return string[:max_length] + + truncated = '' + for word in string.split(separator): + if word: + next_len = len(truncated) + len(word) + if next_len < max_length: + truncated += '{0}{1}'.format(word, separator) + elif next_len == max_length: + truncated += '{0}'.format(word) + break + else: + if save_order: + break + if not truncated: # pragma: no cover + truncated = string[:max_length] + return truncated.strip(separator) + + +def slugify(text, entities=True, decimal=True, hexadecimal=True, max_length=0, word_boundary=False, + separator=DEFAULT_SEPARATOR, save_order=False, stopwords=(), regex_pattern=None, lowercase=True, + replacements=()): + """ + Make a slug from the given text. + :param text (str): initial text + :param entities (bool): + :param decimal (bool): + :param hexadecimal (bool): + :param max_length (int): output string length + :param word_boundary (bool): + :param save_order (bool): if parameter is True and max_length > 0 return whole words in the initial order + :param separator (str): separator between words + :param stopwords (iterable): words to discount + :param regex_pattern (str): regex pattern for allowed characters + :param lowercase (bool): activate case sensitivity by setting it to False + :param replacements (iterable): list of replacement rules e.g. [['|', 'or'], ['%', 'percent']] + :return (str): + """ + + # user-specific replacements + if replacements: + for old, new in replacements: + text = text.replace(old, new) + + # ensure text is unicode + if not isinstance(text, _unicode_type): + text = _unicode(text, 'utf-8', 'ignore') + + # replace quotes with dashes - pre-process + text = QUOTE_PATTERN.sub(DEFAULT_SEPARATOR, text) + + # decode unicode + text = unidecode.unidecode(text) + + # ensure text is still in unicode + if not isinstance(text, _unicode_type): + text = _unicode(text, 'utf-8', 'ignore') + + # character entity reference + if entities: + text = CHAR_ENTITY_PATTERN.sub(lambda m: unichr(name2codepoint[m.group(1)]), text) + + # decimal character reference + if decimal: + try: + text = DECIMAL_PATTERN.sub(lambda m: unichr(int(m.group(1))), text) + except Exception: + pass + + # hexadecimal character reference + if hexadecimal: + try: + text = HEX_PATTERN.sub(lambda m: unichr(int(m.group(1), 16)), text) + except Exception: + pass + + # translate + text = unicodedata.normalize('NFKD', text) + if sys.version_info < (3,): + text = text.encode('ascii', 'ignore') + + # make the text lowercase (optional) + if lowercase: + text = text.lower() + + # remove generated quotes -- post-process + text = QUOTE_PATTERN.sub('', text) + + # cleanup numbers + text = NUMBERS_PATTERN.sub('', text) + + # replace all other unwanted characters + if lowercase: + pattern = regex_pattern or ALLOWED_CHARS_PATTERN + else: + pattern = regex_pattern or ALLOWED_CHARS_PATTERN_WITH_UPPERCASE + text = re.sub(pattern, DEFAULT_SEPARATOR, text) + + # remove redundant + text = DUPLICATE_DASH_PATTERN.sub(DEFAULT_SEPARATOR, text).strip(DEFAULT_SEPARATOR) + + # remove stopwords + if stopwords: + if lowercase: + stopwords_lower = [s.lower() for s in stopwords] + words = [w for w in text.split(DEFAULT_SEPARATOR) if w not in stopwords_lower] + else: + words = [w for w in text.split(DEFAULT_SEPARATOR) if w not in stopwords] + text = DEFAULT_SEPARATOR.join(words) + + # finalize user-specific replacements + if replacements: + for old, new in replacements: + text = text.replace(old, new) + + # smart truncate if requested + if max_length > 0: + text = smart_truncate(text, max_length, word_boundary, DEFAULT_SEPARATOR, save_order) + + if separator != DEFAULT_SEPARATOR: + text = text.replace(DEFAULT_SEPARATOR, separator) + + return text + + +def main(): # pragma: no cover + if len(sys.argv) < 2: + print("Usage %s TEXT TO SLUGIFY" % sys.argv[0]) + else: + text = ' '.join(sys.argv[1:]) + print(slugify(text)) diff --git a/licenses/LICENSE-python-nvd3.txt b/licenses/LICENSE-python-nvd3.txt new file mode 100644 index 0000000000000..1add6249e57b4 --- /dev/null +++ b/licenses/LICENSE-python-nvd3.txt @@ -0,0 +1,24 @@ +The MIT License (MIT) + +Python-nvd3 + +Copyright (c) 2013 Arezqui Belaid and other contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/licenses/LICENSE-python-slugify.txt b/licenses/LICENSE-python-slugify.txt new file mode 100644 index 0000000000000..82af695f594e8 --- /dev/null +++ b/licenses/LICENSE-python-slugify.txt @@ -0,0 +1,21 @@ +The MIT License + +Copyright (c) Val Neekman @ Neekware Inc. http://neekware.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.