Skip to content

Use firefox headless instead of phantomjs #1015

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Nov 20, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 34 additions & 29 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,32 +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 [email protected]:${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)
* 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
```
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 [email protected]:${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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ examples/results/*
/codestyles/*.xml
/_mac/*.xml
/inspection/*.xml
geckodriver.log
13 changes: 12 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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="
Expand Down Expand Up @@ -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 ;
Expand Down
40 changes: 17 additions & 23 deletions folium/folium.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,14 @@

from __future__ import (absolute_import, division, print_function)

import os
import time
import warnings

from branca.element import CssLink, Element, Figure, JavascriptLink, MacroElement

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

Expand Down Expand Up @@ -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 %}
};
Expand Down Expand Up @@ -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 fname:
# We need the tempfile to avoid JS security issues.
driver.get('file:///{path}'.format(path=fname))
driver.maximize_window()
time.sleep(delay)
png = driver.get_screenshot_as_png()
driver.quit()
self._png_image = png
return self._png_image

Expand Down
16 changes: 16 additions & 0 deletions folium/utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
import math
import os
import struct
import tempfile
import zlib
from contextlib import contextmanager

import numpy as np

Expand Down Expand Up @@ -385,3 +387,17 @@ def iter_points(x):
return [x]
else:
return []


@contextmanager
def _tmp_html(data):
"""Yields the path of a temporary HTML file containing data."""
filepath = ''
try:
fid, filepath = tempfile.mkstemp(suffix='.html', prefix='folium_')
os.write(fid, data.encode('utf8'))
os.close(fid)
yield filepath
finally:
if os.path.isfile(filepath):
os.remove(filepath)
32 changes: 18 additions & 14 deletions tests/test_repr.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@

from __future__ import (absolute_import, division, print_function)

import sys
import io
import sys

import PIL.Image

Expand All @@ -19,18 +19,22 @@


@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)


@pytest.fixture
def m_png():
yield folium.Map(png_enabled=True)


def test__repr_html_is_str():
html = make_map()._repr_html_()
def test__repr_html_is_str(m):

Choose a reason for hiding this comment

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

E302 expected 2 blank lines, found 1

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('<div ') == 'style="width:100%;"'
Expand All @@ -41,19 +45,19 @@ def test_valid_html():
assert parts[5] == '/div>'


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)