From 2e3470f803262506ea6c435e7b52ed6f9fb49b0d Mon Sep 17 00:00:00 2001 From: Filipe Fernandes Date: Wed, 7 Nov 2018 15:19:48 -0200 Subject: [PATCH 1/7] use firefox headless --- .github/CONTRIBUTING.md | 1 - .travis.yml | 13 ++++++++++++- folium/folium.py | 38 ++++++++++++++++---------------------- folium/utilities.py | 14 ++++++++++++++ 4 files changed, 42 insertions(+), 24 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 3e974cff2..741362b1a 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -60,7 +60,6 @@ First of all, thanks for your interest in contributing! 4. Make change to your local copy of the folium repository 5. Make sure the tests pass: * in the repository folder do `pip install -e .` (needed for notebook tests) - * along with all the dependencies install `phantomjs` via `npm install -g phantomjs` or by downloading it from [here](http://phantomjs.org/download.html) and installing manually * run `python -m pytest tests` * resolve all errors 6. Commit those changes diff --git a/.travis.yml b/.travis.yml index f1a92e0e5..0dbb3c9b9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,12 @@ language: minimal sudo: false +env: + - MOZ_HEADLESS=1 + +addons: + firefox: latest + env: global: - secure: "gRT413onDOvwgiHpNXRsiqo+ZZSjwwBpjZryQ9h6IqYw6cTN9YVivYF15uTMD//mZyFeHRz+F/7/0EG2z+UYIBKbgktiNMbie/KizwRBnCThGpcch1VeizkBkPluWSQXndXM6STkHvn0eZBZBBh0QdTm1qaI0babUmgZuWhrX38=" @@ -31,8 +37,13 @@ before_install: - conda update conda - conda config --remove channels defaults --force - conda config --add channels conda-forge --force - - conda create --name TEST python=$PY phantomjs --file requirements.txt --file requirements-dev.txt + - conda create --name TEST python=$PY --file requirements.txt --file requirements-dev.txt - source activate TEST + # firefox headless driver + - wget https://github.com/mozilla/geckodriver/releases/download/v0.23.0/geckodriver-v0.23.0-linux64.tar.gz -O geckodriver.tar.gz + - mkdir geckodriver + - tar -xzf geckodriver.tar.gz -C geckodriver + - export PATH=$PATH:$PWD/geckodriver - if [[ "$PY" == "2.7" ]]; then conda install mock ; diff --git a/folium/folium.py b/folium/folium.py index 270e0a065..cce754af4 100644 --- a/folium/folium.py +++ b/folium/folium.py @@ -7,7 +7,6 @@ from __future__ import (absolute_import, division, print_function) -import os import time import warnings @@ -202,10 +201,10 @@ class Map(MacroElement): zoomControl: {{this.zoom_control.__str__().lower()}}, }); {% if this.control_scale %}L.control.scale().addTo({{this.get_name()}});{% endif %} - + {% if this.objects_to_stay_in_front %} function objects_in_front() { - {% for obj in this.objects_to_stay_in_front %} + {% for obj in this.objects_to_stay_in_front %} {{ obj.get_name() }}.bringToFront(); {% endfor %} }; @@ -290,35 +289,30 @@ def _repr_html_(self, **kwargs): def _to_png(self, delay=3): """Export the HTML to byte representation of a PNG image. - Uses Phantom JS to render the HTML and record a PNG. You may need to + Uses selenium to render the HTML and record a PNG. You may need to adjust the `delay` time keyword argument if maps render without data or tiles. Examples -------- >>> map._to_png() >>> map._to_png(time=10) # Wait 10 seconds between render and snapshot. - """ + """ if self._png_image is None: - import selenium.webdriver + from selenium import webdriver + + options = webdriver.firefox.options.Options() + options.add_argument('--headless') + driver = webdriver.Firefox(options=options) - driver = selenium.webdriver.PhantomJS( - service_log_path=os.path.devnull - ) - driver.get('about:blank') html = self.get_root().render() - html = html.replace('\'', '"').replace('"', '\\"') - html = html.replace('\n', '') - driver.execute_script('document.write(\"{}\")'.format(html)) - driver.maximize_window() - # Ignore user map size. - # todo: fix this - # driver.execute_script("document.body.style.width = '100%';") # noqa - # We should probably monitor if some element is present, - # but this is OK for now. - time.sleep(delay) - png = driver.get_screenshot_as_png() - driver.quit() + with _tmp_html(html) as tmp: + # We need the tempfile to avoid JS security issues. + driver.get('file:///{path}'.format(path=tmp.name)) + driver.maximize_window() + time.sleep(delay) + png = driver.get_screenshot_as_png() + driver.quit() self._png_image = png return self._png_image diff --git a/folium/utilities.py b/folium/utilities.py index 2cf2fbfef..ddfacb9a4 100644 --- a/folium/utilities.py +++ b/folium/utilities.py @@ -7,6 +7,8 @@ import os import struct import zlib +from contextlib import contextmanager +from tempfile import NamedTemporaryFile import numpy as np @@ -385,3 +387,15 @@ def iter_points(x): return [x] else: return [] + +@contextmanager +def _tmp_html(data): + tmp = None + try: + tmp = NamedTemporaryFile(suffix='.html', prefix='folium_') + tmp.write(data.encode('utf8')) + tmp.flush() + yield tmp + finally: + if tmp is not None: + tmp.close() From 21adc3ef358922e5c07915a7c0f31f61a243f75f Mon Sep 17 00:00:00 2001 From: Filipe Fernandes Date: Thu, 15 Nov 2018 10:19:12 -0200 Subject: [PATCH 2/7] minor fixes --- folium/folium.py | 2 +- folium/utilities.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/folium/folium.py b/folium/folium.py index cce754af4..44325448c 100644 --- a/folium/folium.py +++ b/folium/folium.py @@ -14,7 +14,7 @@ from folium.map import FitBounds from folium.raster_layers import TileLayer -from folium.utilities import _parse_size, _validate_location +from folium.utilities import _parse_size, _tmp_html, _validate_location from jinja2 import Environment, PackageLoader, Template diff --git a/folium/utilities.py b/folium/utilities.py index ddfacb9a4..101e0a09d 100644 --- a/folium/utilities.py +++ b/folium/utilities.py @@ -388,6 +388,7 @@ def iter_points(x): else: return [] + @contextmanager def _tmp_html(data): tmp = None From 3b3bf76bbda26e57086f02e85150f7055c0fb17c Mon Sep 17 00:00:00 2001 From: Frank <33519926+Conengmo@users.noreply.github.com> Date: Fri, 16 Nov 2018 07:50:05 +0100 Subject: [PATCH 3/7] gitignore geckodriver logs --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 677e7b15a..261ecaa0f 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ examples/results/* /codestyles/*.xml /_mac/*.xml /inspection/*.xml +geckodriver.log From 8ba1ca6c8854fc806eb3b30b0bf99d05de3d9f74 Mon Sep 17 00:00:00 2001 From: Filipe Fernandes Date: Fri, 16 Nov 2018 08:43:12 -0200 Subject: [PATCH 4/7] review actions --- folium/folium.py | 4 ++-- folium/utilities.py | 17 +++++++++-------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/folium/folium.py b/folium/folium.py index 44325448c..f809fa821 100644 --- a/folium/folium.py +++ b/folium/folium.py @@ -306,9 +306,9 @@ def _to_png(self, delay=3): driver = webdriver.Firefox(options=options) html = self.get_root().render() - with _tmp_html(html) as tmp: + with _tmp_html(html) as fname: # We need the tempfile to avoid JS security issues. - driver.get('file:///{path}'.format(path=tmp.name)) + driver.get('file:///{path}'.format(path=fname)) driver.maximize_window() time.sleep(delay) png = driver.get_screenshot_as_png() diff --git a/folium/utilities.py b/folium/utilities.py index 101e0a09d..971f26816 100644 --- a/folium/utilities.py +++ b/folium/utilities.py @@ -6,9 +6,9 @@ import math import os import struct +import tempfile import zlib from contextlib import contextmanager -from tempfile import NamedTemporaryFile import numpy as np @@ -391,12 +391,13 @@ def iter_points(x): @contextmanager def _tmp_html(data): - tmp = None + """Yields the path of a temporary HTML file containing data.""" + filepath = '' try: - tmp = NamedTemporaryFile(suffix='.html', prefix='folium_') - tmp.write(data.encode('utf8')) - tmp.flush() - yield tmp + fid, filepath = tempfile.mkstemp(suffix='.html', prefix='folium_') + os.write(fid, data.encode('utf8')) + os.close(fid) + yield filepath finally: - if tmp is not None: - tmp.close() + if os.path.isfile(filepath): + os.remove(filepath) From ad997a219bf2b583e6572371dcccf3e13cca5dad Mon Sep 17 00:00:00 2001 From: Frank <33519926+Conengmo@users.noreply.github.com> Date: Fri, 16 Nov 2018 12:03:56 +0100 Subject: [PATCH 5/7] guide on installing requirements, running flake8 --- .github/CONTRIBUTING.md | 62 ++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 741362b1a..7a0f090af 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -44,31 +44,37 @@ Whenever possible, please also include a [short, self-contained code example](ht First of all, thanks for your interest in contributing! -- If you are new to git/Github, please take check a few tutorials - on [git](https://git-scm.com/docs/gittutorial) and [GitHub](https://guides.github.com/). -- The basic workflow for contributing is: - 1. [Fork](https://help.github.com/articles/fork-a-repo/) the repository - 2. [Clone](https://help.github.com/articles/cloning-a-repository/) the repository to create a local copy on your computer: - ``` - git clone git@github.com:${user}/folium.git - cd folium - ``` - 3. Create a branch for your changes - ``` - git checkout -b name-of-your-branch - ``` - 4. Make change to your local copy of the folium repository - 5. Make sure the tests pass: - * in the repository folder do `pip install -e .` (needed for notebook tests) - * run `python -m pytest tests` - * resolve all errors - 6. Commit those changes - ``` - git add file1 file2 file3 - git commit -m 'a descriptive commit message' - ``` - 7. Push your updated branch to your fork - ``` - git push origin name-of-your-branch - ``` - 8. [Open a pull request](https://help.github.com/articles/creating-a-pull-request/) to the python-visualization/folium +If you are new to git/Github, please take check a few tutorials +on [git](https://git-scm.com/docs/gittutorial) and [GitHub](https://guides.github.com/). + +The basic workflow for contributing is: + +1. [Fork](https://help.github.com/articles/fork-a-repo/) the repository +2. [Clone](https://help.github.com/articles/cloning-a-repository/) the repository to create a local copy on your computer: + ``` + git clone git@github.com:${user}/folium.git + cd folium + ``` +3. Create a branch for your changes + ``` + git checkout -b name-of-your-branch + ``` +4. Install the dependencies listed in `requirements.txt` and `requirements-dev.txt`. +5. Install Firefox, download [geckodriver](https://github.com/mozilla/geckodriver/releases) + and put it in the PATH. +6. Make changes to your local copy of the folium repository +7. Make sure the tests pass: + * in the repository folder do `pip install -e .` (needed for notebook tests) + * run `python -m pytest tests` + * run `flake8 folium --max-line-length=120` + * resolve all errors +8. Commit those changes + ``` + git add file1 file2 file3 + git commit -m 'a descriptive commit message' + ``` +9. Push your updated branch to your fork + ``` + git push origin name-of-your-branch + ``` +10. [Open a pull request](https://help.github.com/articles/creating-a-pull-request/) to the python-visualization/folium From f7840ee654448d6db7905ed60a80c0d26c32b021 Mon Sep 17 00:00:00 2001 From: Filipe Fernandes Date: Fri, 16 Nov 2018 13:50:03 -0200 Subject: [PATCH 6/7] fix tests for latest pytest --- tests/test_repr.py | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/tests/test_repr.py b/tests/test_repr.py index bccd77067..43b39406f 100644 --- a/tests/test_repr.py +++ b/tests/test_repr.py @@ -19,18 +19,21 @@ @pytest.fixture -def make_map(png_enabled=False): - m = folium.Map(png_enabled=png_enabled) - return m +def m(): + yield folium.Map(png_enabled=False) -def test__repr_html_is_str(): - html = make_map()._repr_html_() +@pytest.fixture +def m_png(): + yield folium.Map(png_enabled=True) + +def test__repr_html_is_str(m): + html = m._repr_html_() assert isinstance(html, str) -def test_valid_html(): - html = make_map()._repr_html_() +def test_valid_html(m): + html = m._repr_html_() parts = html.split('><') assert len(parts) == 6 assert parts[0].lstrip('
' -def test__repr_png_no_image(): - png = make_map(png_enabled=False)._repr_png_() +def test__repr_png_no_image(m): + png = m._repr_png_() assert png is None -def test__repr_png_is_bytes(): - png = make_map(png_enabled=True)._repr_png_() +def test__repr_png_is_bytes(m_png): + png = m_png._repr_png_() assert isinstance(png, bytes) @pytest.mark.skipif(sys.version_info < (3, 0), reason="Doesn't work on Python 2.7.") -def test_valid_png(): - png = make_map(png_enabled=True)._repr_png_() +def test_valid_png(m_png): + png = m_png._repr_png_() img = PIL.Image.open(io.BytesIO(png)) isinstance(img, PIL.PngImagePlugin.PngImageFile) From 86f87c2ed3bf5ccebf6723cea07e6967b0a82b81 Mon Sep 17 00:00:00 2001 From: Filipe Fernandes Date: Fri, 16 Nov 2018 13:55:38 -0200 Subject: [PATCH 7/7] fix lints --- tests/test_repr.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_repr.py b/tests/test_repr.py index 43b39406f..b7073a263 100644 --- a/tests/test_repr.py +++ b/tests/test_repr.py @@ -8,8 +8,8 @@ from __future__ import (absolute_import, division, print_function) -import sys import io +import sys import PIL.Image @@ -27,6 +27,7 @@ def m(): def m_png(): yield folium.Map(png_enabled=True) + def test__repr_html_is_str(m): html = m._repr_html_() assert isinstance(html, str)