├── CNAME ├── .gitignore ├── assets ├── angr.png ├── ccxt.png ├── cmd2.png ├── kivy.png ├── mne.png ├── yt.png ├── fenics.png ├── geopy.png ├── metpy.png ├── nikola.png ├── pandas.png ├── pylast.png ├── pymc3.png ├── pystan.png ├── rdkit.png ├── skbio.png ├── spyder.png ├── sunpy.png ├── sympy.png ├── tryton.png ├── xarray.png ├── xonsh.png ├── zulip.png ├── astropy.png ├── axelrod.png ├── biobuilds.png ├── biopython.png ├── chaquopy.png ├── dateutil.png ├── fecon235.png ├── fonttools.png ├── ipython.png ├── jupyter.png ├── mitmproxy.png ├── openquake.png ├── osbrain.png ├── pymeasure.png ├── pytest1.png ├── pythran.png ├── tornado.png ├── matplotlib.png ├── psi4square.png ├── swcarpentry.png ├── tensorpack.png ├── adb_enhanced.png ├── scikit-image.png ├── scikit-learn.png ├── rpy2_logo_64x64.png ├── scipyshiny_small.png └── toyplot-256x256.png ├── img └── bgnoise.png ├── Gemfile ├── _includes ├── footer.md ├── analytics.html └── css │ ├── skeleton.css │ ├── main.css │ └── base.css ├── _sections ├── 60-sign.md ├── 70-discuss.md ├── 80-update-my-project.md ├── 40-timeline.md ├── 50-why.md ├── 20-statement.md └── 30-projects.md ├── _config.yml ├── README.md ├── combo.css ├── practicalities └── index.html ├── COPYING.md ├── index.html ├── site.js └── _practicalities └── intro.md /CNAME: -------------------------------------------------------------------------------- 1 | www.python3statement.org -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | _site/ 2 | .DS_Store 3 | *.swo 4 | -------------------------------------------------------------------------------- /assets/angr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/angr.png -------------------------------------------------------------------------------- /assets/ccxt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/ccxt.png -------------------------------------------------------------------------------- /assets/cmd2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/cmd2.png -------------------------------------------------------------------------------- /assets/kivy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/kivy.png -------------------------------------------------------------------------------- /assets/mne.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/mne.png -------------------------------------------------------------------------------- /assets/yt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/yt.png -------------------------------------------------------------------------------- /img/bgnoise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/img/bgnoise.png -------------------------------------------------------------------------------- /assets/fenics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/fenics.png -------------------------------------------------------------------------------- /assets/geopy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/geopy.png -------------------------------------------------------------------------------- /assets/metpy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/metpy.png -------------------------------------------------------------------------------- /assets/nikola.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/nikola.png -------------------------------------------------------------------------------- /assets/pandas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/pandas.png -------------------------------------------------------------------------------- /assets/pylast.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/pylast.png -------------------------------------------------------------------------------- /assets/pymc3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/pymc3.png -------------------------------------------------------------------------------- /assets/pystan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/pystan.png -------------------------------------------------------------------------------- /assets/rdkit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/rdkit.png -------------------------------------------------------------------------------- /assets/skbio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/skbio.png -------------------------------------------------------------------------------- /assets/spyder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/spyder.png -------------------------------------------------------------------------------- /assets/sunpy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/sunpy.png -------------------------------------------------------------------------------- /assets/sympy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/sympy.png -------------------------------------------------------------------------------- /assets/tryton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/tryton.png -------------------------------------------------------------------------------- /assets/xarray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/xarray.png -------------------------------------------------------------------------------- /assets/xonsh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/xonsh.png -------------------------------------------------------------------------------- /assets/zulip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/zulip.png -------------------------------------------------------------------------------- /assets/astropy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/astropy.png -------------------------------------------------------------------------------- /assets/axelrod.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/axelrod.png -------------------------------------------------------------------------------- /assets/biobuilds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/biobuilds.png -------------------------------------------------------------------------------- /assets/biopython.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/biopython.png -------------------------------------------------------------------------------- /assets/chaquopy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/chaquopy.png -------------------------------------------------------------------------------- /assets/dateutil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/dateutil.png -------------------------------------------------------------------------------- /assets/fecon235.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/fecon235.png -------------------------------------------------------------------------------- /assets/fonttools.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/fonttools.png -------------------------------------------------------------------------------- /assets/ipython.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/ipython.png -------------------------------------------------------------------------------- /assets/jupyter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/jupyter.png -------------------------------------------------------------------------------- /assets/mitmproxy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/mitmproxy.png -------------------------------------------------------------------------------- /assets/openquake.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/openquake.png -------------------------------------------------------------------------------- /assets/osbrain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/osbrain.png -------------------------------------------------------------------------------- /assets/pymeasure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/pymeasure.png -------------------------------------------------------------------------------- /assets/pytest1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/pytest1.png -------------------------------------------------------------------------------- /assets/pythran.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/pythran.png -------------------------------------------------------------------------------- /assets/tornado.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/tornado.png -------------------------------------------------------------------------------- /assets/matplotlib.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/matplotlib.png -------------------------------------------------------------------------------- /assets/psi4square.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/psi4square.png -------------------------------------------------------------------------------- /assets/swcarpentry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/swcarpentry.png -------------------------------------------------------------------------------- /assets/tensorpack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/tensorpack.png -------------------------------------------------------------------------------- /assets/adb_enhanced.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/adb_enhanced.png -------------------------------------------------------------------------------- /assets/scikit-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/scikit-image.png -------------------------------------------------------------------------------- /assets/scikit-learn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/scikit-learn.png -------------------------------------------------------------------------------- /assets/rpy2_logo_64x64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/rpy2_logo_64x64.png -------------------------------------------------------------------------------- /assets/scipyshiny_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/scipyshiny_small.png -------------------------------------------------------------------------------- /assets/toyplot-256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmcinnes/python3statement.github.io/master/assets/toyplot-256x256.png -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | gem 'github-pages' 3 | gem "jekyll" 4 | gem "jekyll-redirect-from" 5 | gem "jekyll-paginate" 6 | gem "jekyll-sitemap" 7 | gem "jekyll-feed" 8 | -------------------------------------------------------------------------------- /_includes/footer.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | Design by Tim O'Brien [t413.com](http://t413.com/) 4 | — 5 | [SinglePaged theme](https://github.com/t413/SinglePaged) 6 | — 7 | this site is [open source]({{ site.source_link }}) 8 | 9 | -------------------------------------------------------------------------------- /_sections/60-sign.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: sign 3 | fa-icon: pencil 4 | bg: '#4da45e' 5 | color: 'white' 6 | style: center 7 | --- 8 | 9 | # Sign the statement 10 | 11 | Do you want to sign the statement for your project? 12 | Open an [issue](https://github.com/python3statement/python3statement.github.io/issues) with your project information, 13 | or directly submit a [pull-request](https://github.com/python3statement/python3statement.github.io/pulls). 14 | -------------------------------------------------------------------------------- /_sections/70-discuss.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: discuss 3 | fa-icon: comment 4 | bg: '#a066f3' 5 | color: 'white' 6 | style: center 7 | --- 8 | 9 | # Discuss 10 | 11 | While the above statement is close to final form, it is still open for 12 | discussion. Feel free to [open an 13 | issue](https://github.com/python3statement/python3statement.github.io/issues) 14 | on our GitHub repository or browse the open and closed ones. 15 | 16 | If you think some information is missing or inaccurate, please let us know as 17 | well. 18 | -------------------------------------------------------------------------------- /_includes/analytics.html: -------------------------------------------------------------------------------- 1 | {% if site.google_analytics_key %} 2 | 15 | {% endif %} -------------------------------------------------------------------------------- /_sections/80-update-my-project.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Practicalities 3 | fa-icon: arrow-circle-up 4 | bg: '#49a7e9' 5 | color: 'white' 6 | style: center 7 | --- 8 | 9 | # Practicalities 10 | 11 | While most of the projects that have signed up above are migrating to Python 3 12 | only code bases, we are gathering information about the difficulties that can be 13 | encountered both by developers and users during this process. 14 | 15 | We are thus collecting a list of things to be aware of for when transitioning that 16 | are less obvious. For example : as a developer, how to make sure that 17 | your package manager like pip does not upgrade your libraries to incompatible 18 | versions on Python 2. See the [Practicality Page](/practicalities/) for 19 | information and check [our 20 | repository](https://github.com/python3statement/python3statement.github.io) to 21 | contribute. 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /_sections/40-timeline.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: timeline 3 | bg: 'white' 4 | fa-icon: calendar 5 | style: center 6 | --- 7 | 8 | # Projects Timeline 9 | 10 | In the following chart, you can see many projects that have decided to stop 11 | supporting Python 2 before 2020. The chart is a guideline to show what 12 | versions of each project support Python 2, or not, their release timelines, and 13 | extended support. (Python's own timeline is available 14 | [here](https://docs.python.org/devguide/#status-of-python-branches)). 15 | 16 |
17 | 18 |
19 |

Compatible with Python 2 and Python 3.

20 |

Compatible with Python 3 only.

21 |
22 | See how to [add your project to the list of participating projects](https://github.com/python3statement/python3statement.github.io#add-your-project) and to [this timeline](https://github.com/python3statement/python3statement.github.io#add-timeline-information) 23 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | port: 4000 4 | host: 0.0.0.0 5 | safe: false 6 | 7 | 8 | ### site serving configuration ### 9 | exclude: [CNAME, README.md, .gitignore] 10 | permalink: /:title ## disables post output 11 | timezone: null 12 | lsi: false 13 | markdown: kramdown 14 | 15 | 16 | ### content configuration ### 17 | title: "Sunsetting Python 2 support" 18 | keywords: "Python 3, support, Jupyter, IPython, matplotlib, Python 2, Legacy Python" 19 | description: "A pledge to drop Python 2 support by 2020." 20 | source_link: "https://github.com/python3statement/python3statement.github.io" 21 | favicon: #put a path like: "img/favicon.ico" 22 | touch_icon: #put a path like: "img/apple-touch-icon.png" 23 | google_analytics_key: ## put YOUR key here to enable tracking! (blank to disable) 24 | 25 | 26 | ### template colors, used site-wide via css ### 27 | colors: 28 | black: '#111111' 29 | white: '#f8f8f8' 30 | blue: '#49a7e9' 31 | green: '#9bcf2f' 32 | purple: '#c869bf' 33 | orange: '#fab125' 34 | turquoise: '#0fbfcf' 35 | 36 | collections: 37 | - sections 38 | - practicalities 39 | 40 | -------------------------------------------------------------------------------- /_sections/50-why.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: why 3 | color: 'white' 4 | bg: '#49a7e9 ' 5 | fa-icon: 'question' 6 | style: center 7 | --- 8 | 9 | # Why switch to Python 3? 10 | 11 | Here are some resources on why Python 3 was created, and how and why to update 12 | code to use Python 3: 13 | 14 | - [Why Python 3 exists](https://snarky.ca/why-python-3-exists/) (Brett Cannon) 15 | - [How to add Python 3 support to your code](https://docs.python.org/3/howto/pyporting.html) 16 | - [Python FAQ: Why should I use Python 3?](https://eev.ee/blog/2016/07/31/python-faq-why-should-i-use-python-3/) (lexy munroe) 17 | - [Python FAQ: How do I port to Python 3?](https://eev.ee/blog/2016/07/31/python-faq-how-do-i-port-to-python-3/) (lexy munroe) 18 | - [Stop supporting Python 2.6 for free](https://www.curiousefficiency.org/posts/2015/04/stop-supporting-python26.html) (Nick Coghlan) 19 | - [Why Python 4.0 won't be like Python 3.0](https://www.curiousefficiency.org/posts/2014/08/python-4000.html) (Nick Coghlan) 20 | - [Python 3 for scientists](https://python-3-for-scientists.readthedocs.io/en/latest/) 21 | - [scikit-bio py3-only RFC](https://github.com/biocore/scikit-bio-rfcs/blob/master/accepted/002-py3-only.md) 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A pledge to migrate to Python 3. 2 | 3 | This is the main website for a pledge to stop supporting Python 2 for free in 4 | open source software. 5 | 6 | # Run locally 7 | 8 | Install Jekyll : `gem install jekyll`, `gem install github-pages` 9 | 10 | Clone this locally, `cd` in the newly created directory. 11 | 12 | Run `jekyll serve -w` in one terminal, open your browser to `localhost:4000`. 13 | 14 | Modify the various files, refresh your browser and enjoy. 15 | 16 | PRs welcomed. 17 | 18 | # Add your project 19 | 20 | If you just want to add your project to the list of participating projects, add 21 | a line in [the list of participating projects](_sections/30-projects.md). It's 22 | markdown so feel free to just list your project name or add a link, and make a 23 | pull request. You should even be able to [edit it 24 | online](https://github.com/python3statement/python3statement.github.io/edit/master/_sections/30-projects.md). 25 | 26 | ## Add timeline information 27 | 28 | The front page also has a timeline chart, with past release dates and future 29 | (planned) releases. You can also add your project there, if you have a specific 30 | date where you plan to drop Python 2 support. 31 | 32 | See [site.js](site.js) around [line 33 | 100](https://github.com/python3statement/python3statement.github.io/blob/master/site.js#L103) 34 | to see how to add this kind of data. 35 | 36 | # Base template 37 | 38 | This site is based on 39 | [github.com/t413/SinglePaged](https://github.com/t413/SinglePaged). 40 | -------------------------------------------------------------------------------- /combo.css: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | {% include css/base.css %} 4 | {% include css/skeleton.css %} 5 | {% include css/main.css %} 6 | 7 | div.vis-item , p.py3{ 8 | background-color:#03acf6; 9 | color: white; 10 | } 11 | 12 | 13 | div.vis-item.py2, p.py2 { 14 | background-color: #3dbf18; 15 | border-color: #3dbf18; 16 | color:white; 17 | 18 | } 19 | 20 | p { 21 | font-weight: 300; 22 | } 23 | 24 | p.py2:first-child, p.py3:first-child{ 25 | margin-top: 0px; 26 | margin-bottom: 5px; 27 | 28 | } 29 | 30 | div.vis-item.vis-selected { 31 | background-color: #e8aa2c; 32 | border-color: #bf8a1e; 33 | } 34 | 35 | /* create a custom sized dot at the bottom of the red item */ 36 | .vis-item.red { 37 | background-color: red; 38 | border-color: darkred; 39 | color: white; 40 | font-family: monospace; 41 | box-shadow: 0 0 10px gray; 42 | } 43 | 44 | .center ul { 45 | list-style: none; 46 | } 47 | 48 | .vis-timeline { 49 | text-align: left; 50 | } 51 | 52 | /* hardcode the calendar which is on a clear background to a darker gray that matches the font color.*/ 53 | .fa-calendar { 54 | color: #868686; 55 | } 56 | 57 | .subtlecircle .fa-stack-1x{ 58 | font-size: 80%; 59 | } 60 | 61 | #sections30-projects ul:nth-child(2) a { 62 | text-decoration: none; 63 | } 64 | 65 | 66 | #sections30-projects li { 67 | display: inline-block; 68 | margin: 10px; 69 | padding: 20px; 70 | font-size: 19px; 71 | } 72 | 73 | 74 | #sections30-projects li a > img{ 75 | margin: auto; 76 | margin-bottom:10px; 77 | display: block; 78 | max-height: 80px; 79 | max-width: 160px; 80 | vertical-align: middle; 81 | } 82 | -------------------------------------------------------------------------------- /practicalities/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | 5 | 6 | 7 | 8 | {{ site.title }} 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | {% if site.favicon %}{% endif %} 17 | {% if site.touch_icon %}{% endif %} 18 | 19 | 20 |
21 | 22 | 28 | 29 | 30 | {% for page in site.practicalities %} 31 | {% capture id %}{{ page.id | remove:'/' | downcase }}{% endcapture %} 32 |
33 | 34 |
35 | {{ page.content }} 36 |
37 |
38 | {% endfor %} 39 |
40 | 41 | 42 | -------------------------------------------------------------------------------- /COPYING.md: -------------------------------------------------------------------------------- 1 | The logos of projects which have endorsed the statement are used with the 2 | permission of the projects they represent. They are not covered by any of the 3 | licenses granted by this project. 4 | 5 | The project uses the [SinglePaged template](https://github.com/t413/SinglePaged), 6 | which is under the MIT license: 7 | 8 | Copyright (c) 2014 Tim O'Brien (t413) 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of this software and associated documentation files (the "Software"), to deal 12 | in the Software without restriction, including without limitation the rights 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | copies of the Software, and to permit persons to whom the Software is 15 | furnished to do so, subject to the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included in all 18 | copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | SOFTWARE. 27 | 28 | Any example computer code created for this project is published under a 29 | [CC0 license](https://creativecommons.org/publicdomain/zero/1.0/), meaning it 30 | can be used with no conditions. 31 | 32 | Content not mentioned above (principally the text of the website), is published 33 | under the [CC-BY license](https://creativecommons.org/licenses/by/4.0/). 34 | -------------------------------------------------------------------------------- /_sections/20-statement.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: statement 3 | bg: '#4da45e' 4 | color: white 5 | --- 6 | 7 | # Moving to require Python 3 8 | 9 | Almost all major open source Python packages now support 10 | both Python 3.x and Python 2.7, and many projects have been supporting these 11 | two versions of the language for several years. While we have developed tools 12 | and techniques to maintain compatibility efficiently, it is a small but 13 | constant friction in the development of a lot of code. 14 | 15 | We are keen to use Python 3 to its full potential, and we currently accept the 16 | cost of writing cross-compatible code to allow a smooth transition, but we 17 | don’t intend to maintain this compatibility indefinitely. Although the 18 | transition has not been as quick as we hoped, we do see it taking place, with 19 | more and more people using, teaching and recommending Python 3. 20 | 21 | The developers of the Python language extended support of Python 2.7 from 2015 22 | to January 1, 2020, recognising that many people were still using Python 2. We believe 23 | that the extra 5 years is sufficient to transition off of Python 2, and our 24 | projects plan to stop supporting Python 2 when upstream support ends in 2020, 25 | if not before. We will then be able to simplify our code and take advantage of 26 | the many new features in the current version of the Python language and 27 | standard library. 28 | 29 | In addition, significantly before 2020, many of our projects will step down 30 | Python 2.7 support to only fixing bugs, and require Python 3 for all new 31 | feature releases. Some projects have already made this transition. 32 | This too parallels support for the language itself, as Python 33 | 2.7 releases only include bugfixes and security improvements. 34 | 35 | Third parties may offer paid support for our projects on old Python versions 36 | for longer than we support them ourselves. We won’t obstruct this, and it is a 37 | core principle of free and open source software that this is possible. However, 38 | if you enjoy the free, first party support for many projects including the Scientific 39 | Python stack, please start planning to move to Python 3. 40 | 41 | For all of these reasons, the following projects have pledged to **drop support 42 | for Python 2.7 no later than 2020**, coinciding with the Python development 43 | team's [timeline for dropping support for Python 44 | 2.7](https://www.python.org/dev/peps/pep-0373/#update). 45 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | 5 | 6 | 7 | 8 | {{ site.title }} 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | {% if site.favicon %}{% endif %} 17 | {% if site.touch_icon %}{% endif %} 18 | 19 | 20 |
21 | 22 | 28 | 29 | 30 | {% for page in site.sections %} 31 | {% capture id %}{{ page.id | remove:'/' | downcase }}{% endcapture %} 32 |
33 | {% if page.icon %} 34 |
35 | section icon 36 |
{{ page.title }}
37 |
38 | {% elsif page.fa-icon %} 39 |
40 | 41 | 42 | 43 | 44 |
{{ page.title }}
45 |
46 | {% endif %} 47 |
48 | {{ page.content }} 49 |
50 |
51 | {% endfor %} 52 | 53 | 54 | 60 |
61 | 62 | {% include analytics.html %} 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /_includes/css/skeleton.css: -------------------------------------------------------------------------------- 1 | 2 | /* -----------------------------------*/ 3 | /* ----- 960px wide fancy grid! ----- */ 4 | /* -----------------------------------*/ 5 | 6 | /* by tim o'brien, t413.com 7 | * based on getskeleton.com 8 | */ 9 | 10 | 11 | /* ----- base grid----- */ 12 | 13 | .container { position: relative; width: 960px; margin: 0 auto; padding: 0; } 14 | .container .column { float: left; display: inline; margin-left: 10px; margin-right: 10px; } 15 | .row { margin-bottom: 20px; } 16 | 17 | .container .small.column { width: 300px; } 18 | .container .half.column { width: 460px; } 19 | .container .big.column { width: 620px; } 20 | .container .full.column { width: 940px; } 21 | 22 | 23 | /* ----- Tablet (Portrait) -- 768px ----- */ 24 | @media only screen and (min-width: 768px) and (max-width: 959px) { 25 | .container { width: 768px; } 26 | 27 | .container .small.column { width: 236px; } 28 | .container .half.column { width: 364px; } 29 | .container .big.column { width: 488px; } 30 | .container .full.column { width: 748px; } 31 | } 32 | 33 | 34 | /* ----- Mobile (Portrait) ----- */ 35 | @media only screen and (max-width: 767px) { 36 | .container { width: 96%; } 37 | .container .column { margin: 1%; } 38 | 39 | .container .small.column { width: 48%; } 40 | .container .half.column { width: 48%; } 41 | .container .big.column { width: 98%; } 42 | .container .full.column { width: 98%; } 43 | } 44 | 45 | 46 | /* ----- Mobile (Landscape) -- 480px ----- */ 47 | @media only screen and (min-width: 480px) and (max-width: 767px) { 48 | .container { width: 92%; } 49 | .container .column { margin: 2%; } 50 | 51 | .container .small.column { width: 46%; } 52 | .container .half.column { width: 46%; } 53 | .container .big.column { width: 96%; } 54 | .container .full.column { width: 96%; } 55 | } 56 | 57 | 58 | 59 | /* ----- Clearing ----- */ 60 | 61 | /* Self Clearing Goodness */ 62 | .container:after { content: "\0020"; display: block; height: 0; clear: both; visibility: hidden; } 63 | 64 | /* Use clearfix class on parent to clear nested columns, 65 | or wrap each row of columns in a
*/ 66 | .clearfix:before, 67 | .clearfix:after, 68 | .row:before, 69 | .row:after { 70 | content: '\0020'; 71 | display: block; 72 | overflow: hidden; 73 | visibility: hidden; 74 | width: 0; 75 | height: 0; } 76 | .row:after, 77 | .clearfix:after { 78 | clear: both; } 79 | .row, 80 | .clearfix { 81 | zoom: 1; } 82 | 83 | /* You can also use a
to clear columns */ 84 | .clear { 85 | clear: both; 86 | display: block; 87 | overflow: hidden; 88 | visibility: hidden; 89 | width: 0; 90 | height: 0; 91 | } 92 | -------------------------------------------------------------------------------- /_sections/30-projects.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Projects 3 | bg: '#7ec4ea' 4 | fa-icon: group 5 | color: black 6 | style: center 7 | --- 8 | 9 | # Participating Projects 10 | 11 | These projects pledge to drop Python 2 support in or before 2020. 12 | 13 | - [![](assets/pandas.png)pandas](https://pandas.pydata.org/) 14 | - [![](assets/scikit-learn.png)scikit-learn](https://scikit-learn.org/) 15 | - [![](assets/tornado.png)Tornado](http://www.tornadoweb.org/) 16 | - [![](assets/ipython.png)IPython](https://ipython.org) 17 | - [![](assets/mitmproxy.png)mitmproxy](https://mitmproxy.org/) 18 | - [![](assets/kivy.png)Kivy](https://kivy.org/) 19 | - [![](assets/matplotlib.png)Matplotlib](https://matplotlib.org/) 20 | - [![](assets/numpylogoicon.svg)NumPy](https://www.numpy.org/) 21 | - [![](assets/scipyshiny_small.png)SciPy](https://www.scipy.org/) 22 | - [![](assets/ccxt.png)ccxt](https://github.com/ccxt/ccxt) 23 | - [![](assets/zulip.png)Zulip](https://zulip.org) 24 | - [![](assets/sympy.png)SymPy](https://www.sympy.org/) 25 | - [![](assets/jupyter.png)Jupyter notebook](https://jupyter.org) 26 | - [![](assets/spyder.png)Spyder](https://www.spyder-ide.org) 27 | - [![](assets/scikit-image.png)Scikit Image](http://scikit-image.org/) 28 | - [![](assets/pymc3.png)PyMC3](https://github.com/pymc-devs/pymc3) 29 | - [![](assets/tensorpack.png)Tensorpack](https://github.com/tensorpack/tensorpack) 30 | - [![](assets/pytest1.png)pytest](https://docs.pytest.org/en/latest) 31 | - [![](assets/xonsh.png)xonsh](http://xon.sh) 32 | - [![](assets/astropy.png)Astropy](https://www.astropy.org/) 33 | - [![](assets/geopy.png)geopy](https://geopy.readthedocs.io/) 34 | - [![](assets/biopython.png)Biopython](https://biopython.org/) 35 | - [![](assets/nikola.png)Nikola](https://getnikola.com) 36 | - [![](assets/fonttools.png)FontTools](https://github.com/fonttools/fonttools) 37 | - [![](assets/pythran.png)Pythran](https://github.com/serge-sans-paille/pythran) 38 | - [![](assets/xarray.png)xarray](https://xarray.pydata.org/) 39 | - [![](assets/dateutil.png)dateutil](https://github.com/dateutil/dateutil) 40 | - [![](//cherrypy.org/images/cherrypy.png)CherryPy](https://cherrypy.org/) 41 | - [![](assets/tryton.png)Tryton](https://www.tryton.org/) 42 | - [![](assets/pystan.png)PyStan](https://github.com/stan-dev/pystan) 43 | - [![](assets/mne.png)MNE](https://www.martinos.org/mne/stable/index.html) 44 | - [![](assets/swcarpentry.png)Software Carpentry](https://software-carpentry.org) 45 | - [![](assets/adb_enhanced.png)ADB-Enhanced](https://github.com/ashishb/adb-enhanced) 46 | - [![](assets/skbio.png)scikit-bio](http://scikit-bio.org) 47 | - [![](assets/fecon235.png)fecon235](https://github.com/rsvp/fecon235) 48 | - [![](assets/sunpy.png)SunPy](https://sunpy.org/) 49 | - [![](assets/axelrod.png)Axelrod](https://github.com/Axelrod-Python/Axelrod) 50 | - [![](assets/rpy2_logo_64x64.png)rpy2](https://rpy2.bitbucket.io) 51 | - [![](assets/fenics.png)FEniCS](https://fenicsproject.org/) 52 | - [![](assets/rdkit.png)RDKit](https://github.com/rdkit/rdkit) 53 | - [![](assets/toyplot-256x256.png)Toyplot](https://github.com/sandialabs/toyplot) 54 | - [![](assets/metpy.png)MetPy](https://unidata.github.io/MetPy) 55 | - [![](assets/pylast.png)pyLast](https://github.com/pylast/pylast) 56 | - [![](assets/psi4square.png)Psi4](http://psicode.org/) 57 | - [![](assets/openquake.png)OpenQuake engine](https://github.com/gem/oq-engine) 58 | - [![](assets/yt.png)yt](https://yt-project.org/) 59 | - [![](assets/cmd2.png)cmd2](https://github.com/python-cmd2/cmd2) 60 | - [![](assets/osbrain.png)osBrain](https://github.com/opensistemas-hub/osbrain) 61 | - [![](assets/pymeasure.png)PyMeasure](https://github.com/ralph-group/pymeasure) 62 | - [![](assets/chaquopy.png)Chaquopy](https://chaquo.com/chaquopy/) 63 | - [![](assets/angr.png)angr](http://angr.io/) 64 | - [![](assets/biobuilds.png)BioBuilds](https://www.biobuilds.org/) 65 | 66 | 69 | 70 |   71 | 72 | - [Hypothesis](https://github.com/HypothesisWorks/hypothesis) 73 | - [better-exceptions](https://github.com/qix-/better-exceptions) 74 | - [python-chess](https://github.com/niklasf/python-chess) 75 | - [Altair](https://github.com/ellisonbg/altair) 76 | - [music21](http://web.mit.edu/music21/) 77 | - [imageio](https://imageio.github.io) 78 | - [An Introduction to Applied Bioinformatics](http://readiab.org) 79 | - [pvlib-python](https://github.com/pvlib/pvlib-python) 80 | - [QIIME](http://qiime.org) 81 | - [PySCIPOpt](https://github.com/SCIP-Interfaces/PySCIPOpt) 82 | - [SPADE](https://github.com/javipalanca/spade) 83 | - [gala](https://gala.readthedocs.io) 84 | - [CIS](https://github.com/cedadev/cis) 85 | - [cual-id](https://github.com/johnchase/cual-id) 86 | - [stomp.py](https://github.com/jasonrbriggs/stomp.py) 87 | - [tinytext](https://github.com/hugovk/tinytext) 88 | - [OSMViz](https://github.com/hugovk/osmviz) 89 | - [fino](https://github.com/hugovk/fino) 90 | - [MambuPy](https://github.com/jstitch/MambuPy) 91 | - [Pyramid](https://trypyramid.com) 92 | 93 | 96 | -------------------------------------------------------------------------------- /_includes/css/main.css: -------------------------------------------------------------------------------- 1 | html { box-sizing: border-box; } 2 | *, *:before, *:after { box-sizing: inherit; } 3 | 4 | /* ---------------------------*/ 5 | /* ----- Special Styles ----- */ 6 | /* ---------------------------*/ 7 | 8 | /* ----- colors (autogenerated from _config.yml)----- */ 9 | 10 | {% for c in site.colors %} 11 | .border-{{c[0]}} { border-color: {{ c[1] }} !important; } 12 | .text-{{c[0]}} { color: {{ c[1] }}; } 13 | .text-{{c[0]}} a { color: {{ c[1] }}; } 14 | .bg-{{c[0]}} { background-color: {{ c[1] }} !important; } 15 | {% endfor %} 16 | 17 | /* ----- per-post colors! ----- */ 18 | {% for node in site.sections %} 19 | {% capture id %}{{ node.id | remove:'/' | downcase }}{% endcapture %} 20 | {% capture bg %}{% if site.colors[node.bg] %}{{ site.colors[node.bg] }}{% else %}{{ node.bg }}{% endif %}{% endcapture %} 21 | {% capture fg %}{% if site.colors[node.color] %}{{ site.colors[node.color] }}{% else %}{{ node.color }}{% endif %}{% endcapture %} 22 | nav .p-{{id}} { border-color: {{ bg }}; } 23 | #{{id}} { background-color: {{ bg }} !important; color: {{ fg }}; } 24 | #{{id}} a { color: {{ fg }}; } 25 | #{{id}} .sectiondivider { color: {{ bg }}; } 26 | {% endfor %} 27 | 28 | {% for node in site.practicalities %} 29 | {% capture id %}{{ node.id | remove:'/' | downcase }}{% endcapture %} 30 | {% capture bg %}{% if site.colors[node.bg] %}{{ site.colors[node.bg] }}{% else %}{{ node.bg }}{% endif %}{% endcapture %} 31 | {% capture fg %}{% if site.colors[node.color] %}{{ site.colors[node.color] }}{% else %}{{ node.color }}{% endif %}{% endcapture %} 32 | nav .p-{{id}} { border-color: {{ bg }}; } 33 | #{{id}} { background-color: {{ bg }} !important; color: {{ fg }}; } 34 | #{{id}} a { color: {{ fg }}; } 35 | #{{id}} .sectiondivider { color: {{ bg }}; } 36 | {% endfor %} 37 | 38 | 39 | /* ----- code, syntax highlighting, etc ----- */ 40 | 41 | code, pre { font-family: Monaco, Menlo, Consolas, "Courier New", monospace; } 42 | 43 | /* spesifically inline code */ 44 | code, pre { 45 | background: rgba(255,255,255,0.2); 46 | display: inline; 47 | word-wrap: break-word; 48 | } 49 | 50 | /* block code */ 51 | pre code { background: none; display: block; } 52 | pre { 53 | display: block; 54 | margin: 20px 5%; 55 | padding: 4px 8px; 56 | background: rgba(255,255,255,0.1); 57 | word-wrap: break-word; 58 | } 59 | 60 | .highlight { margin:20px 5%; } 61 | 62 | 63 | /* ----- base elements ----- */ 64 | 65 | img { 66 | max-width:100%; 67 | height:auto; 68 | vertical-align:middle; 69 | } 70 | 71 | hr { 72 | margin:60px auto; 73 | width:50%; 74 | border-color: {{ site.colors.black }}; 75 | } 76 | 77 | .container { word-wrap: break-word; } 78 | .center { text-align: center; } 79 | .left, .container .left { text-align: left; } 80 | 81 | .container h1, .container h2, .container h3, .container h4 { 82 | margin-bottom: 20px; 83 | text-align: center; 84 | padding: 0 4%; 85 | } 86 | .container p, .container ol, .container ul { 87 | font-size: 17px; 88 | padding: 0 5%; 89 | } 90 | .container ol, .container ul { padding: 0 8%; } 91 | .container p:first-of-type { 92 | margin-top: 40px; 93 | } 94 | 95 | /* keep embedded videos fluid! */ 96 | .icontain { 97 | position: relative; 98 | height: 0; 99 | overflow: hidden; 100 | padding-bottom: 56.25%; /* keep 16x9 Aspect Ratio */ 101 | } 102 | .i4x3 { padding-bottom: 75.00%; } /* keep 4x3 Aspect Ratio */ 103 | .icontain iframe { 104 | position: absolute; 105 | top:0; 106 | left: 0; 107 | width: 100%; 108 | height: 100%; 109 | } 110 | 111 | .inlineblock { 112 | display:-moz-inline-stack; 113 | display:inline-block; 114 | zoom:1; 115 | *display:inline; 116 | } 117 | 118 | /* ---------------------------*/ 119 | /* ----- Main Structure ----- */ 120 | /* ---------------------------*/ 121 | 122 | /* ----- top menu ----- */ 123 | 124 | {% assign navborder = 3 %} 125 | {% assign navborder_active = 6 %} 126 | 127 | nav { 128 | font-size:15px; 129 | width:100%; 130 | position:fixed; 131 | z-index:100; 132 | top:0; 133 | left:0; 134 | background:#2e2e2e; 135 | } 136 | 137 | nav ul { 138 | list-style:none; 139 | text-align:center; 140 | padding:0; 141 | margin:0; 142 | letter-spacing:-4px; 143 | } 144 | 145 | nav ul li { 146 | display:inline-block; 147 | border-top:{{navborder}}px solid; 148 | padding: {{navborder}}px 0; 149 | *display:inline; 150 | zoom:1; 151 | line-height:normal; 152 | letter-spacing:normal; 153 | text-transform:uppercase; 154 | min-width:110px; 155 | line-height:60px; 156 | margin:0; 157 | } 158 | 159 | nav ul li a, nav ul li a:visited { 160 | display:block; 161 | color:#fff; 162 | text-decoration:none; 163 | font-weight:600; 164 | opacity:.75; 165 | } 166 | 167 | nav ul li a:hover { 168 | opacity:1 169 | } 170 | nav ul li:hover, nav ul li.active { 171 | border-top-width: {{navborder_active}}px; 172 | padding-top: 0; 173 | } 174 | 175 | 176 | /* ----- sections/articles ----- */ 177 | 178 | .section { 179 | position:relative; 180 | display:block; 181 | width:100%; 182 | min-height:300px; 183 | padding:210px 0; 184 | background:url(img/bgnoise.png); 185 | /* generated noise from noisetexturegenerator.com */ 186 | } 187 | 188 | .section:first-of-type { 189 | padding-top: 140px; 190 | } 191 | 192 | 193 | #footer { 194 | padding: 8px 0; 195 | min-height:0; 196 | text-align:center; 197 | background-color:#2e2e2e; 198 | background-image:none; 199 | } 200 | #footer .container p { font-size:13px; margin:0; } 201 | 202 | .subtlecircle { 203 | text-align:center; 204 | z-index:3; 205 | border-radius:50%; 206 | -moz-border-radius:50%; 207 | -webkit-border-radius:50%; 208 | box-shadow: 0px 1px 15px rgba(0,0,0,0.05); 209 | background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAF0lEQVQIHWP8//+/MQMaYELjg7kUCgIASm8DOqGzfp8AAAAASUVORK5CYII=); 210 | } 211 | 212 | .sectiondivider { 213 | width:270px; 214 | height:270px; 215 | padding:15px; 216 | position:absolute; 217 | top:-135px; 218 | left:50%; 219 | margin-left:-135px; 220 | } 221 | 222 | .sectiondivider img { 223 | width:200px; 224 | height:240px; 225 | position: static; 226 | margin-top: -20px; 227 | } 228 | 229 | .sectiondivider .fa-stack { 230 | font-size: 130px; 231 | position: static; 232 | margin-top: -8px; 233 | } 234 | .sectiondivider .fa-circle { color: #fff; } 235 | 236 | .sectiondivider h5 { 237 | font-size:15px; 238 | font-weight:700; 239 | text-transform:uppercase; 240 | position:absolute; 241 | bottom:50px; 242 | left:auto; 243 | text-align:center; 244 | display:block; 245 | z-index:6; 246 | width:240px; 247 | } 248 | 249 | .sectiondivider.imaged { 250 | text-shadow: 1px 1px 3px #333; 251 | } 252 | 253 | 254 | .columned { 255 | -webkit-column-count: 3; 256 | -moz-column-count: 3; 257 | column-count: 3; 258 | 259 | -webkit-column-gap: 40px; 260 | -moz-column-gap: 40px; 261 | column-gap: 40px; 262 | 263 | -webkit-column-rule: 1px outset rgba(255,255,255,0.5); 264 | -moz-column-rule: 1px outset rgba(255,255,255,0.5); 265 | column-rule: 1px outset rgba(255,255,255,0.5); 266 | } 267 | .longlist { font-size: 14px !important; } 268 | .longlist li { margin-bottom: 3px; } 269 | 270 | 271 | 272 | /* ----- fork on github banner ----- */ 273 | #forkongithub a { 274 | color:#fff; 275 | text-decoration:none; 276 | font-family:arial,sans-serif; 277 | text-align:center; 278 | font-weight:700; 279 | font-size:1rem; 280 | line-height:2rem; 281 | position:relative; 282 | transition:.5s; 283 | padding:5px 40px; 284 | } 285 | #forkongithub a::before, #forkongithub a::after { 286 | content:""; width:100%; display:block; position:absolute; 287 | top:1px; left:0; height:1px; background:#fff; 288 | } 289 | #forkongithub a::after { bottom:1px; top:auto; } 290 | @media screen and (min-width:800px) { 291 | #forkongithub { 292 | position:fixed; 293 | display:block; 294 | top:0; 295 | right:0; 296 | width:200px; 297 | overflow:hidden; 298 | height:200px; 299 | z-index:9999; 300 | } 301 | #forkongithub a { 302 | width:200px; 303 | position:absolute; 304 | top:60px; 305 | right:-60px; 306 | transform:rotate(45deg); 307 | -webkit-transform:rotate(45deg); 308 | -ms-transform:rotate(45deg); 309 | -moz-transform:rotate(45deg); 310 | -o-transform:rotate(45deg); 311 | box-shadow:4px 4px 10px rgba(0,0,0,0.8); 312 | box-sizing: content-box; 313 | } 314 | } 315 | 316 | 317 | 318 | /* mid size (tablets, landscapes) */ 319 | @media only screen and (max-width: 679px) { 320 | nav { font-size:11px; } 321 | nav ul li { 322 | min-width:60px; 323 | line-height:40px; 324 | } 325 | } 326 | 327 | /* tiny size (phones) */ 328 | @media only screen and (max-width: 380px) { 329 | nav ul li { min-width:90px; line-height:20px; } 330 | } 331 | 332 | /* anything not desktop */ 333 | @media only screen and (max-width: 767px) { 334 | .container h1 { font-size: 30px; } 335 | .container h2 { font-size: 24px; } 336 | .container h3 { font-size: 20px; } 337 | .container h4 { font-size: 18px; } 338 | 339 | 340 | .section { padding:130px 0; } 341 | .sectiondivider { 342 | width:200px; 343 | height:200px; 344 | padding:15px; 345 | top:-100px; 346 | margin-left:-100px; 347 | } 348 | .sectiondivider img { 349 | width:150px; 350 | height:180px; 351 | } 352 | .sectiondivider .fa-stack { 353 | font-size: 100px; 354 | margin-top: -14px; 355 | } 356 | .sectiondivider h5 { 357 | font-size:15px; 358 | bottom:30px; 359 | width:170px 360 | } 361 | 362 | .columned { 363 | -webkit-column-count: 2; 364 | -moz-column-count: 2; 365 | column-count: 2; 366 | } 367 | } 368 | -------------------------------------------------------------------------------- /site.js: -------------------------------------------------------------------------------- 1 | 2 | $.extend($.easing, 3 | { 4 | def: 'easeOutQuad', 5 | easeInOutExpo: function (x, t, b, c, d) { 6 | if (t==0) return b; 7 | if (t==d) return b+c; 8 | if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b; 9 | return c/2 * (-Math.pow(2, -10 * --t) + 2) + b; 10 | } 11 | }); 12 | 13 | (function( $ ) { 14 | 15 | var settings; 16 | var disableScrollFn = false; 17 | var navItems; 18 | var navs = {}, sections = {}; 19 | 20 | $.fn.navScroller = function(options) { 21 | settings = $.extend({ 22 | scrollToOffset: 170, 23 | scrollSpeed: 800, 24 | activateParentNode: true, 25 | }, options ); 26 | navItems = this; 27 | 28 | //attatch click listeners 29 | navItems.on('click', function(event){ 30 | event.preventDefault(); 31 | var navID = $(this).attr("href").substring(1); 32 | disableScrollFn = true; 33 | activateNav(navID); 34 | populateDestinations(); //recalculate these! 35 | $('html,body').animate({scrollTop: sections[navID] - settings.scrollToOffset}, 36 | settings.scrollSpeed, "easeInOutExpo", function(){ 37 | disableScrollFn = false; 38 | } 39 | ); 40 | }); 41 | 42 | //populate lookup of clicable elements and destination sections 43 | populateDestinations(); //should also be run on browser resize, btw 44 | 45 | // setup scroll listener 46 | $(document).scroll(function(){ 47 | if (disableScrollFn) { return; } 48 | var page_height = $(window).height(); 49 | var pos = $(this).scrollTop(); 50 | for (i in sections) { 51 | if ((pos + settings.scrollToOffset >= sections[i]) && sections[i] < pos + page_height){ 52 | activateNav(i); 53 | } 54 | } 55 | }); 56 | }; 57 | 58 | function populateDestinations() { 59 | navItems.each(function(){ 60 | var scrollID = $(this).attr('href').substring(1); 61 | navs[scrollID] = (settings.activateParentNode)? this.parentNode : this; 62 | sections[scrollID] = $(document.getElementById(scrollID)).offset().top; 63 | }); 64 | } 65 | 66 | function activateNav(navID) { 67 | for (nav in navs) { $(navs[nav]).removeClass('active'); } 68 | $(navs[navID]).addClass('active'); 69 | } 70 | })( jQuery ); 71 | 72 | 73 | $(document).ready(function (){ 74 | 75 | $('nav li a').navScroller(); 76 | 77 | //section divider icon click gently scrolls to reveal the section 78 | $(".sectiondivider").on('click', function(event) { 79 | $('html,body').animate({scrollTop: $(event.target.parentNode).offset().top - 50}, 400, "linear"); 80 | }); 81 | 82 | //links going to other sections nicely scroll 83 | $(".container a").each(function(){ 84 | if ($(this).attr("href").charAt(0) == '#'){ 85 | $(this).on('click', function(event) { 86 | event.preventDefault(); 87 | var target = $(event.target).closest("a"); 88 | var targetHight = $(target.attr("href")).offset().top 89 | $('html,body').animate({scrollTop: targetHight - 170}, 800, "easeInOutExpo"); 90 | }); 91 | } 92 | }); 93 | 94 | // DOM element where the Timeline will be attached 95 | var container = document.getElementById('visualization'); 96 | 97 | // add your project here with the following format 98 | // 99 | // ' : [ 100 | // { content:'', start: , end: , py2:}, 101 | // ... 102 | // ] 103 | var data = { 104 | 'CPython':[ 105 | {content:'Python 2.7', start: '2010-07-03', end: '2020-01-01', py2:true}, 106 | {content:'Python 3.3', start: '2012-09-29', end: '2017-09-29'}, 107 | // EOL for Python 3.4 - 3.7 not announced yet; project 5 years from initial release to follow CPython policy. 108 | {content:'Python 3.4', start: '2014-03-16', end: '2019-03-16'}, 109 | {content:'Python 3.5', start: '2015-09-13', end: '2020-09-13'}, 110 | {content:'Python 3.6', start: '2016-12-23', end: '2021-12-23'}, 111 | {content:'Python 3.7', start: '2018-06-15', end: '2023-06-01'}, 112 | ], 113 | 'IPython':[ 114 | {content: '1.x', start: '2013-08-08', end:'2014-03-31', py2:true}, 115 | {content: '2.x', start: '2014-04-01', end:'2015-02-26', py2:true}, 116 | {content: '3.x', start: '2015-02-27', end:'2015-08-10', py2:true}, 117 | {content: '4.x', start: '2015-08-11', end:'2016-07-07', py2:true}, 118 | {content: 'IPython 5.x LTS', start: '2016-07-08', end:'2019-06-01', py2:true}, 119 | {content: '6.x', start: '2017-04-19', end:'2018-09-27'}, 120 | {content: '7.x', start: '2018-09-27', end:'2019-12-12'}, 121 | {content: '8.x', start: '2019-12-12', end:'2020-12-01'}, 122 | ], 123 | 'pandas':[ 124 | {content: 'Python 2 & 3', start: '2011-10-10', end:'2018-12-31', py2:true}, 125 | {content: 'Python 3 only', start: '2019-01-01', end:'2021-12-16'}, 126 | ], 127 | 'scikit-learn':[ 128 | {content: 'Python 2 & 3', start: '2010-03-25', end:'2019-03-18', py2:true}, 129 | {content: 'Python 3 only', start: '2019-03-19', end:'2023-12-31'}, 130 | ], 131 | 'ccxt':[ 132 | {content: 'Python 2 & 3', start: '2017-05-14', end:'2019-12-31', py2:true}, 133 | {content: 'Python 3 only', start: '2020-01-01', end:'2023-12-31'}, 134 | ], 135 | 'Numpy':[ 136 | {content: 'Py 2 & 3 full', start: '2010-08-31', end:'2018-12-31', py2:true}, 137 | {content: 'Py 2 bug fix', start: '2019-01-01', end:'2019-12-31', py2:true}, 138 | {content: 'Py 3 full', start: '2019-01-01', end:'2021-12-16'}, 139 | ], 140 | 'Scipy':[ 141 | {content: 'Py 2 & 3 full', start: '2010-08-31', end:'2018-12-31', py2:true}, 142 | {content: 'Py 2 bug fix', start: '2019-01-01', end:'2019-12-31', py2:true}, 143 | {content: 'Py 3 full', start: '2019-01-01', end:'2021-12-16'}, 144 | ], 145 | 'Matplotlib':[ 146 | {content: '2.2 LTS', start: '2018-03-05', end: '2020-01-10', py2:true}, 147 | {content: '3.0', start: '2018-07-01', end: '2019-01-01'}, 148 | {content: '3.1', start: '2019-01-01', end: '2019-07-01'}, 149 | {content: '3.2', start: '2019-07-01', end: '2020-01-01'} 150 | ], 151 | 'Spyder':[ 152 | {content: '3', start: '2016-09-24', end: '2019-01-15', py2:true}, 153 | {content: '4', start: '2019-01-15', end: '2020-01-01', py2:true}, 154 | {content: '5', start: '2019-12-31', end: '2021-12-16'} 155 | ], 156 | 'Xonsh':[ 157 | {content: '0.x series – Python 3.4+', start: '2015-03-09', end: '2021-12-16'}, 158 | ], 159 | 'scikit-bio':[ 160 | {content: '0.1.1 - 0.4.2', start: '2014-05-16', end: '2016-05-30', py2:true}, 161 | {content: '0.5.0+', start: '2016-05-31', end: '2021-12-16'}, 162 | ], 163 | 'QIIME':[ 164 | {content: '1.x', start: '2010-04-09', end: '2017-12-31', py2:true}, 165 | {content: '2.x+', start: '2016-07-11', end: '2021-12-16'}, 166 | ], 167 | 'SunPy':[ 168 | {content: '0.7', start: '2016-05-24', end: '2017-08-07', py2:true}, 169 | {content: '0.8', start: '2017-08-07', end: '2018-04-23', py2:true}, 170 | {content: '0.9', start: '2018-04-23', end: '2020-01-01', py2:true}, 171 | {content: '1.0', start: '2019-01-01', end: '2020-01-01'}, 172 | {content: '1.1', start: '2020-01-01', end: '2020-06-01'}, 173 | ], 174 | 'Astropy':[ 175 | {content: '1.0 LTS', start: '2015-02-19', end: '2017-06-01', py2:true}, 176 | {content: '1.1', start: '2015-12-11', end: '2016-06-23', py2:true}, 177 | {content: '1.2', start: '2016-06-23', end: '2016-12-16', py2:true}, 178 | {content: '1.3', start: '2016-12-16', end: '2017-06-01', py2:true}, 179 | {content: '2.0 LTS', start: '2017-06-01', end: '2019-12-31', py2:true}, 180 | {content: '3.0', start: '2018-02-19', end: '2018-11-30'}, 181 | {content: '3.1', start: '2018-11-30', end: '2019-05-01'}, 182 | {content: '3.2', start: '2019-05-01', end: '2019-11-30'}, 183 | {content: '4.0 LTS', start: '2019-11-30', end: '2021-12-01'}, 184 | ], 185 | 'geopy':[ 186 | {content: '1.x', start: '2014-09-07', end:'2019-04-01', py2:true}, 187 | {content: '2.x', start: '2019-04-01', end:'2023-12-31'}, 188 | ], 189 | 'Tryton':[ 190 | {content: '4.0', start: '2016-05-02', end: '2018-10-01', py2:true}, 191 | {content: '4.2', start: '2016-11-28', end: '2019-05-01', py2:true}, 192 | {content: '4.4', start: '2017-05-01', end: '2019-10-01', py2:true}, 193 | {content: '4.6', start: '2017-10-30', end: '2020-05-01', py2:true}, 194 | {content: '4.8', start: '2018-04-23', end: '2020-10-01', py2:true}, 195 | {content: '5.0', start: '2018-10-01', end: '2023-10-01'}, 196 | {content: '5.2', start: '2019-05-01', end: '2020-05-01'}, 197 | ], 198 | 'osBrain':[ 199 | {content: '0.x', start: '2016-07-01', end: '2021-12-16'}, 200 | ], 201 | 'PyMeasure':[ 202 | {content: '0.4', start: '2016-07-29', end: '2017-10-18'}, 203 | {content: '0.5', start: '2017-10-18', end: '2019-01-14'}, 204 | {content: '0.6', start: '2019-01-14', end: '2020-01-01'}, 205 | ], 206 | 'rpy2':[ 207 | {content: '2.8.x', start: '2016-12-21', end:'2018-12-21', py2:true}, 208 | {content: '2.9.x', start: '2017-07-14', end:'2018-07-14'}, 209 | ], 210 | 'FEniCS':[ 211 | {content: '2017.1.0', start: '2017-05-12', end: '2017-12-31', py2:true}, 212 | {content: '2018.1.0', start: '2018-01-01', end: '2018-06-01'} 213 | ], 214 | 'RDKit':[ 215 | {content: '2014.9.1 - 2019.03.1', start: '2014-09-1', end: '2019-09-1', py2:true}, 216 | {content: '2019.9.1 -' , start: '2019-09-01', end: '2021-03-01'} 217 | ], 218 | 'Toyplot':[ 219 | {content: 'Python 2 & 3', start: '2014-11-05', end:'2018-12-31', py2:true}, 220 | {content: 'Python 3 only', start: '2019-01-01', end:'2021-12-31'}, 221 | ], 222 | 'music21':[ 223 | {content: 'v3', start: '2016-08-22', end: '2017-08-06', py2:true}, 224 | {content: 'v4', start: '2017-08-22', end: '2019-06-01', py2:true}, 225 | {content: 'v5', start: '2018-03-17', end: '2019-08-01'}, 226 | {content: 'v6', start: '2019-08-01', end: '2020-08-01'}, 227 | ], 228 | 'mitmproxy':[ 229 | {content: '0.18.x', start: '2016-10-16', end: '2017-10-16', py2:true}, 230 | {content: '1.0.x -', start: '2016-12-26', end: '2021-12-23'} 231 | ], 232 | 'SPADE':[ 233 | {content: '2.0', start: '2010-08-01', end: '2012-11-09', py2:true}, 234 | {content: '2.1', start: '2012-11-09', end: '2013-05-27', py2:true}, 235 | {content: '2.2', start: '2013-05-27', end: '2017-06-09', py2:true}, 236 | {content: '2.3', start: '2017-06-09', end: '2018-12-31', py2:true}, 237 | {content: '3.x -', start: '2018-09-15', end: '2020-12-31', py2:false} 238 | ], 239 | 'dateutil': [ 240 | {content: '2.x', start: '2011-12-01', end: '2018-09-01', py2:true}, 241 | {content: '3.x', start: '2018-09-01', end: '2019-07-01', py2:true}, 242 | {content: '4.x', start: '2019-01-01', end: '2020-07-01', py2:false}, 243 | ], 244 | 'CherryPy': [ 245 | {content: '3.2-17.x', start: '2011-02-25', end: '2019-12-31', py2: true}, 246 | {content: '18.x+', start: '2018-09-01', end: '2023-12-31', py2: false}, 247 | ], 248 | 'stomp.py':[ 249 | {content: '3.x', start: '2010-04-01', end: '2013-09-30', py2:true}, 250 | {content: '4.x', start: '2013-10-01', end: '2020-01-09', py2:true}, 251 | {content: '5.x+', start: '2020-01-10', end: '2023-12-31', py2:false}, 252 | ], 253 | 'cmd2':[ 254 | {content: '0.7.x', start: '2017-02-23', end: '2018-01-04', py2:true}, 255 | {content: '0.8.x', start: '2018-02-01', end: '2018-08-31', py2:true}, 256 | {content: '0.9.x', start: '2018-05-28', end: '2023-12-31', py2:false}, 257 | ], 258 | 'angr':[ 259 | {content: '7.x', start: '2017-09-09', end: '2018-09-26', py2: true}, 260 | {content: '8.x', start: '2018-09-28', end: '2023-12-31', py2: false}, 261 | ], 262 | 'FontTools':[ 263 | {content: 'Py 2 & 3 full', start: '2014-09-24', end:'2018-12-31', py2:true}, 264 | {content: 'Py 2 bug fix', start: '2019-01-01', end:'2019-06-30', py2:true}, 265 | {content: 'Py 3 full', start: '2019-01-01', end:'2023-12-31'}, 266 | ], 267 | 268 | // for tests, rando example 269 | //'matplotlib':[ 270 | // {content: 'matplotlib 2.x', start: '2015-06-01', end:'2018-06-01', py2:true}, 271 | // {content: 'matplotlib 3.x', start: '2018-6-12', end:'2019-12-01'}, 272 | //], 273 | //'scikit-bio':[ 274 | // {content: '0.18', start: '2016-05-01', end:'2016-11-01', py2:true}, 275 | // {content: '0.19', start: '2016-11-02', end:'2017-12-01'}, 276 | //] 277 | 278 | 279 | } 280 | 281 | // Create a DataSet (allows two way data-binding) 282 | var items = new vis.DataSet([ 283 | ]); 284 | 285 | 286 | 287 | var groups = new vis.DataSet(); 288 | var g=0; 289 | var i=0; 290 | for (var gname in data) { 291 | g++; 292 | groups.add({id: g, content: gname}); 293 | gr = data[gname]; 294 | for(var k in gr){ 295 | i++; 296 | gr[k].id = i; 297 | gr[k].group = g; 298 | if(gr[k].py2) gr[k].className ='py2' 299 | items.add(gr[k]) 300 | } 301 | } 302 | 303 | // Configuration for the Timeline 304 | var options = {}; 305 | 306 | var options = { 307 | clickToUse: true, 308 | groupOrder: 'group' 309 | }; 310 | 311 | // Create a Timeline 312 | var timeline = new vis.Timeline(container, items, options); 313 | timeline.setGroups(groups); 314 | timeline.setItems(items); 315 | timeline.addCustomTime(Date.parse('2020-01-01')) 316 | 317 | }); 318 | -------------------------------------------------------------------------------- /_includes/css/base.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Skeleton V1.2 3 | * Copyright 2011, Dave Gamache 4 | * www.getskeleton.com 5 | * Free to use under the MIT license. 6 | * http://www.opensource.org/licenses/mit-license.php 7 | * 6/20/2012 8 | */ 9 | 10 | 11 | /* Table of Content 12 | ================================================== 13 | #Reset & Basics 14 | #Basic Styles 15 | #Site Styles 16 | #Typography 17 | #Links 18 | #Lists 19 | #Images 20 | #Buttons 21 | #Forms 22 | #Misc */ 23 | 24 | 25 | /* #Reset & Basics (Inspired by E. Meyers) 26 | ================================================== */ 27 | html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video { 28 | margin: 0; 29 | padding: 0; 30 | border: 0; 31 | font-size: 100%; 32 | font: inherit; 33 | vertical-align: baseline; } 34 | article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { 35 | display: block; } 36 | body { 37 | line-height: 1; } 38 | ol, ul { 39 | list-style: none; } 40 | blockquote, q { 41 | quotes: none; } 42 | blockquote:before, blockquote:after, 43 | q:before, q:after { 44 | content: ''; 45 | content: none; } 46 | table { 47 | border-collapse: collapse; 48 | border-spacing: 0; } 49 | 50 | 51 | /* #Basic Styles 52 | ================================================== */ 53 | body { 54 | background: #fff; 55 | font: 14px/21px "Raleway", "HelveticaNeue", Arial, sans-serif; 56 | color: #444; 57 | -webkit-font-smoothing: antialiased; /* Fix for webkit rendering */ 58 | -webkit-text-size-adjust: 100%; 59 | } 60 | 61 | 62 | /* #Typography 63 | ================================================== */ 64 | h1, h2, h3, h4, h5, h6 { 65 | font-weight: 300; } 66 | h1 a, h2 a, h3 a, h4 a, h5 a, h6 a { font-weight: inherit; } 67 | h1 { font-size: 46px; line-height: 50px; margin-bottom: 14px;} 68 | h2 { font-size: 35px; line-height: 40px; margin-bottom: 10px; } 69 | h3 { font-size: 28px; line-height: 34px; margin-bottom: 8px; } 70 | h4 { font-size: 21px; line-height: 30px; margin-bottom: 4px; } 71 | h5 { font-size: 17px; line-height: 24px; } 72 | h6 { font-size: 14px; line-height: 21px; } 73 | .subheader { color: #777; } 74 | 75 | p { margin: 0 0 20px 0; } 76 | p img { margin: 0; } 77 | p.lead { font-size: 21px; line-height: 27px; color: #777; } 78 | 79 | em { font-style: italic; } 80 | strong { font-weight: bold; } 81 | small { font-size: 80%; } 82 | 83 | /* Blockquotes */ 84 | blockquote, blockquote p { font-size: 17px; line-height: 24px; color: #777; font-style: italic; } 85 | blockquote { margin: 0 0 20px; padding: 9px 20px 0 19px; border-left: 1px solid #ddd; } 86 | blockquote cite { display: block; font-size: 12px; color: #555; } 87 | blockquote cite:before { content: "\2014 \0020"; } 88 | blockquote cite a, blockquote cite a:visited, blockquote cite a:visited { color: #555; } 89 | 90 | hr { border: solid #ddd; border-width: 1px 0 0; clear: both; margin: 10px 0 30px; height: 0; } 91 | 92 | 93 | /* #Links 94 | ================================================== */ 95 | a, a:visited { text-decoration: underline; outline: 0; } 96 | a:hover, a:focus { } 97 | p a, p a:visited { line-height: inherit; } 98 | 99 | 100 | /* #Lists 101 | ================================================== */ 102 | ul, ol { margin-bottom: 20px; } 103 | ul { list-style: none outside; } 104 | ol { list-style: decimal; } 105 | ul, ul.square { list-style: square outside; } 106 | ul ul, ul.circle { list-style: circle outside; } 107 | ul ul ul, ul.disc { list-style: disc outside; } 108 | ul ul li, ul ol li, 109 | ol ol li, ol ul li { margin-bottom: 6px; } 110 | li { line-height: 18px; margin-bottom: 12px; } 111 | ul.large li { line-height: 21px; } 112 | li p { line-height: 21px; } 113 | 114 | /* #Images 115 | ================================================== */ 116 | 117 | img.scale-with-grid { 118 | max-width: 100%; 119 | height: auto; } 120 | 121 | 122 | /* #Buttons 123 | ================================================== */ 124 | 125 | .button, 126 | button, 127 | input[type="submit"], 128 | input[type="reset"], 129 | input[type="button"] { 130 | background: #eee; /* Old browsers */ 131 | background: #eee -moz-linear-gradient(top, rgba(255,255,255,.2) 0%, rgba(0,0,0,.2) 100%); /* FF3.6+ */ 132 | background: #eee -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(255,255,255,.2)), color-stop(100%,rgba(0,0,0,.2))); /* Chrome,Safari4+ */ 133 | background: #eee -webkit-linear-gradient(top, rgba(255,255,255,.2) 0%,rgba(0,0,0,.2) 100%); /* Chrome10+,Safari5.1+ */ 134 | background: #eee -o-linear-gradient(top, rgba(255,255,255,.2) 0%,rgba(0,0,0,.2) 100%); /* Opera11.10+ */ 135 | background: #eee -ms-linear-gradient(top, rgba(255,255,255,.2) 0%,rgba(0,0,0,.2) 100%); /* IE10+ */ 136 | background: #eee linear-gradient(top, rgba(255,255,255,.2) 0%,rgba(0,0,0,.2) 100%); /* W3C */ 137 | border: 1px solid #aaa; 138 | border-top: 1px solid #ccc; 139 | border-left: 1px solid #ccc; 140 | -moz-border-radius: 3px; 141 | -webkit-border-radius: 3px; 142 | border-radius: 3px; 143 | color: #444; 144 | display: inline-block; 145 | font-size: 11px; 146 | font-weight: bold; 147 | text-decoration: none; 148 | text-shadow: 0 1px rgba(255, 255, 255, .75); 149 | cursor: pointer; 150 | margin-bottom: 20px; 151 | line-height: normal; 152 | padding: 8px 10px; 153 | font-family: "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif; } 154 | 155 | .button:hover, 156 | button:hover, 157 | input[type="submit"]:hover, 158 | input[type="reset"]:hover, 159 | input[type="button"]:hover { 160 | color: #222; 161 | background: #ddd; /* Old browsers */ 162 | background: #ddd -moz-linear-gradient(top, rgba(255,255,255,.3) 0%, rgba(0,0,0,.3) 100%); /* FF3.6+ */ 163 | background: #ddd -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(255,255,255,.3)), color-stop(100%,rgba(0,0,0,.3))); /* Chrome,Safari4+ */ 164 | background: #ddd -webkit-linear-gradient(top, rgba(255,255,255,.3) 0%,rgba(0,0,0,.3) 100%); /* Chrome10+,Safari5.1+ */ 165 | background: #ddd -o-linear-gradient(top, rgba(255,255,255,.3) 0%,rgba(0,0,0,.3) 100%); /* Opera11.10+ */ 166 | background: #ddd -ms-linear-gradient(top, rgba(255,255,255,.3) 0%,rgba(0,0,0,.3) 100%); /* IE10+ */ 167 | background: #ddd linear-gradient(top, rgba(255,255,255,.3) 0%,rgba(0,0,0,.3) 100%); /* W3C */ 168 | border: 1px solid #888; 169 | border-top: 1px solid #aaa; 170 | border-left: 1px solid #aaa; } 171 | 172 | .button:active, 173 | button:active, 174 | input[type="submit"]:active, 175 | input[type="reset"]:active, 176 | input[type="button"]:active { 177 | border: 1px solid #666; 178 | background: #ccc; /* Old browsers */ 179 | background: #ccc -moz-linear-gradient(top, rgba(255,255,255,.35) 0%, rgba(10,10,10,.4) 100%); /* FF3.6+ */ 180 | background: #ccc -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(255,255,255,.35)), color-stop(100%,rgba(10,10,10,.4))); /* Chrome,Safari4+ */ 181 | background: #ccc -webkit-linear-gradient(top, rgba(255,255,255,.35) 0%,rgba(10,10,10,.4) 100%); /* Chrome10+,Safari5.1+ */ 182 | background: #ccc -o-linear-gradient(top, rgba(255,255,255,.35) 0%,rgba(10,10,10,.4) 100%); /* Opera11.10+ */ 183 | background: #ccc -ms-linear-gradient(top, rgba(255,255,255,.35) 0%,rgba(10,10,10,.4) 100%); /* IE10+ */ 184 | background: #ccc linear-gradient(top, rgba(255,255,255,.35) 0%,rgba(10,10,10,.4) 100%); /* W3C */ } 185 | 186 | .button.full-width, 187 | button.full-width, 188 | input[type="submit"].full-width, 189 | input[type="reset"].full-width, 190 | input[type="button"].full-width { 191 | width: 100%; 192 | padding-left: 0 !important; 193 | padding-right: 0 !important; 194 | text-align: center; } 195 | 196 | /* Fix for odd Mozilla border & padding issues */ 197 | button::-moz-focus-inner, 198 | input::-moz-focus-inner { 199 | border: 0; 200 | padding: 0; 201 | } 202 | 203 | 204 | /* #Forms 205 | ================================================== */ 206 | 207 | form { 208 | margin-bottom: 20px; } 209 | fieldset { 210 | margin-bottom: 20px; } 211 | input[type="text"], 212 | input[type="password"], 213 | input[type="email"], 214 | textarea, 215 | select { 216 | border: 1px solid #ccc; 217 | padding: 6px 4px; 218 | outline: none; 219 | -moz-border-radius: 2px; 220 | -webkit-border-radius: 2px; 221 | border-radius: 2px; 222 | font: 13px "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif; 223 | color: #777; 224 | margin: 0; 225 | width: 210px; 226 | max-width: 100%; 227 | display: block; 228 | margin-bottom: 20px; 229 | background: #fff; } 230 | select { 231 | padding: 0; } 232 | input[type="text"]:focus, 233 | input[type="password"]:focus, 234 | input[type="email"]:focus, 235 | textarea:focus { 236 | border: 1px solid #aaa; 237 | color: #444; 238 | -moz-box-shadow: 0 0 3px rgba(0,0,0,.2); 239 | -webkit-box-shadow: 0 0 3px rgba(0,0,0,.2); 240 | box-shadow: 0 0 3px rgba(0,0,0,.2); } 241 | textarea { 242 | min-height: 60px; } 243 | label, 244 | legend { 245 | display: block; 246 | font-weight: bold; 247 | font-size: 13px; } 248 | select { 249 | width: 220px; } 250 | input[type="checkbox"] { 251 | display: inline; } 252 | label span, 253 | legend span { 254 | font-weight: normal; 255 | font-size: 13px; 256 | color: #444; } 257 | 258 | /* #Misc 259 | ================================================== */ 260 | .remove-bottom { margin-bottom: 0 !important; } 261 | .half-bottom { margin-bottom: 10px !important; } 262 | .add-bottom { margin-bottom: 20px !important; } 263 | 264 | 265 | 266 | /* #Syntax highlighting 267 | ================================================== */ 268 | 269 | 270 | .highlight { 271 | color: #f8f8f2; 272 | table-layout: fixed; 273 | white-space: nowrap; 274 | width:90%; 275 | } 276 | 277 | .highlight pre, .highlight code { 278 | display:block; 279 | margin:0; 280 | padding:0; 281 | background: 282 | none; 283 | overflow:auto; 284 | word-wrap: normal; 285 | white-space: pre; 286 | } 287 | 288 | .highlight, .linenodiv { 289 | background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIHWPQ1dU1BgABzQC7XXMTYQAAAABJRU5ErkJggg==); 290 | display:block; 291 | padding: 10px; 292 | margin-bottom:20px; 293 | } 294 | .gutter, .lineno { color: #ccc; } 295 | 296 | td.gl { width: 40px; } 297 | 298 | .gutter { 299 | border-right: none; 300 | padding: 10px; 301 | text-align: right; 302 | } 303 | span.lineno { 304 | display: block; 305 | float: left; 306 | width: 40px; 307 | padding-right: 8px; 308 | text-align: right; 309 | } 310 | 311 | 312 | .hll { background-color: #49483e } 313 | .c { color: #75715e } /* Comment */ 314 | .err { color: #960050; background-color: #1e0010 } /* Error */ 315 | .k { color: #66d9ef } /* Keyword */ 316 | .l { color: #ae81ff } /* Literal */ 317 | .n { color: #f8f8f2 } /* Name */ 318 | .o { color: #f92672 } /* Operator */ 319 | .p { color: #f8f8f2 } /* Punctuation */ 320 | .cm { color: #75715e } /* Comment.Multiline */ 321 | .cp { color: #75715e } /* Comment.Preproc */ 322 | .c1 { color: #75715e } /* Comment.Single */ 323 | .cs { color: #75715e } /* Comment.Special */ 324 | .ge { font-style: italic } /* Generic.Emph */ 325 | .gs { font-weight: bold } /* Generic.Strong */ 326 | .kc { color: #66d9ef } /* Keyword.Constant */ 327 | .kd { color: #66d9ef } /* Keyword.Declaration */ 328 | .kn { color: #f92672 } /* Keyword.Namespace */ 329 | .kp { color: #66d9ef } /* Keyword.Pseudo */ 330 | .kr { color: #66d9ef } /* Keyword.Reserved */ 331 | .kt { color: #66d9ef } /* Keyword.Type */ 332 | .ld { color: #e6db74 } /* Literal.Date */ 333 | .m { color: #ae81ff } /* Literal.Number */ 334 | .s { color: #e6db74 } /* Literal.String */ 335 | .na { color: #a6e22e } /* Name.Attribute */ 336 | .nb { color: #f8f8f2 } /* Name.Builtin */ 337 | .nc { color: #a6e22e } /* Name.Class */ 338 | .no { color: #66d9ef } /* Name.Constant */ 339 | .nd { color: #a6e22e } /* Name.Decorator */ 340 | .ni { color: #f8f8f2 } /* Name.Entity */ 341 | .ne { color: #a6e22e } /* Name.Exception */ 342 | .nf { color: #a6e22e } /* Name.Function */ 343 | .nl { color: #f8f8f2 } /* Name.Label */ 344 | .nn { color: #f8f8f2 } /* Name.Namespace */ 345 | .nx { color: #a6e22e } /* Name.Other */ 346 | .py { color: #f8f8f2 } /* Name.Property */ 347 | .nt { color: #f92672 } /* Name.Tag */ 348 | .nv { color: #f8f8f2 } /* Name.Variable */ 349 | .ow { color: #f92672 } /* Operator.Word */ 350 | .w { color: #f8f8f2 } /* Text.Whitespace */ 351 | .mf { color: #ae81ff } /* Literal.Number.Float */ 352 | .mh { color: #ae81ff } /* Literal.Number.Hex */ 353 | .mi { color: #ae81ff } /* Literal.Number.Integer */ 354 | .mo { color: #ae81ff } /* Literal.Number.Oct */ 355 | .sb { color: #e6db74 } /* Literal.String.Backtick */ 356 | .sc { color: #e6db74 } /* Literal.String.Char */ 357 | .sd { color: #e6db74 } /* Literal.String.Doc */ 358 | .s2 { color: #e6db74 } /* Literal.String.Double */ 359 | .se { color: #ae81ff } /* Literal.String.Escape */ 360 | .sh { color: #e6db74 } /* Literal.String.Heredoc */ 361 | .si { color: #e6db74 } /* Literal.String.Interpol */ 362 | .sx { color: #e6db74 } /* Literal.String.Other */ 363 | .sr { color: #e6db74 } /* Literal.String.Regex */ 364 | .s1 { color: #e6db74 } /* Literal.String.Single */ 365 | .ss { color: #e6db74 } /* Literal.String.Symbol */ 366 | .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */ 367 | .vc { color: #f8f8f2 } /* Name.Variable.Class */ 368 | .vg { color: #f8f8f2 } /* Name.Variable.Global */ 369 | .vi { color: #f8f8f2 } /* Name.Variable.Instance */ 370 | .il { color: #ae81ff } /* Literal.Number.Integer.Long */ 371 | 372 | .gh { } /* Generic Heading & Diff Header */ 373 | .gu { color: #75715e; } /* Generic.Subheading & Diff Unified/Comment? */ 374 | .gd { color: #f92672; } /* Generic.Deleted & Diff Deleted */ 375 | .gi { color: #a6e22e; } /* Generic.Inserted & Diff Inserted */ 376 | -------------------------------------------------------------------------------- /_practicalities/intro.md: -------------------------------------------------------------------------------- 1 | --- 2 | bg: '#4da45e' 3 | color: white 4 | title: practicalities 5 | fa-icon: pencil 6 | id: bar 7 | --- 8 | 9 | We do not discourage authors to release software on Python 2. While this guide 10 | is mostly written with the assumption that software are going to stop Python 2 11 | support, it does perfectly apply to a package that wishes to not support Python 3, 12 | or is stopping support for any minor version. 13 | 14 | 15 | This page gathers information and links to resources allowing a library 16 | to stop supporting an older version of Python without causing too 17 | much disruption for users who haven't upgraded to this new version. 18 | 19 | Whether you are a user or a developer, being aware of the issue listed here -- at 20 | least the main points -- should ease lots of the pain. 21 | 22 | # Too long, did not read: 23 | 24 | - Help and encourage users to install **pip 9.0+** 25 | - Help and encourage users to install **setuptools 24.3+** 26 | - As maintainer, use the new `setup(..., python_requires='>=3.4')` option. 27 | - Use `pip install [-e] .` and do **not** invoke `setup.py` directly. 28 | - **Fail** early at **install time** if user is on Python 2. 29 | 30 | We gave a 31 | [talk at PyCon 2017](https://www.youtube.com/watch?v=2DkfPzWWC2Q) 32 | ([slides](https://speakerdeck.com/pycon2017/py3-compatibility-in-a-user-friendly-manner)), and at 33 | [PyBay](https://www.youtube.com/watch?v=3i6n1RwqQCo) 34 | ([slides](https://speakerdeck.com/pybay/2017-building-bridges-stopping-python-2-without-damages)). 35 | 36 | ## The problem 37 | 38 | Up until December 2016 it was hard to publish a new major version of a library 39 | that changed requirements in Python version and mark it as such so that a user's 40 | system will not try to upgrade said library. 41 | 42 | With the recent changes in Python packaging this is now possible. 43 | 44 | As an example let's look at a non-existent `fictitious` library. 45 | 46 | - `fictitious` 1.1, 1.2, 1.3, 1.4 are compatible Python 2.7 and 3.3+ 47 | - `fictitious` 2.0 has been released and is python 3.4+ only. 48 | 49 | As a Python 2.7 user, if I don't pay attention, or if the library is not 50 | correctly tagged, there can be issues when you try to update the library: 51 | 52 | $ python -c 'import fictitious; print(fictitious.__version__)' 53 | 1.3.2 54 | $ pip install fictitious --upgrade 55 | 56 | Either my system will install 2.0, which will not work -- the worst case 57 | scenario -- or fail to install, in which case I will not get the critical 1.4 58 | upgrade. 59 | 60 | ## As a user 61 | 62 | ### Install pip 9.0 63 | 64 | If you are already a Python 3 user, you should not encounter a lot of 65 | disruption. Please still check that the libraries you use follow best practices 66 | not to break for Python 2 users. Python is a community regardless of which 67 | python version you have to (or decided to) run, making sure that everything 68 | works makes the community strong. 69 | 70 | Make sure you have Pip ≥ 9.0, this is especially important if you have Python 71 | 2 installations. Having pip 9.0+ is not a guarantee of a flawless upgrade. But pip 72 | 9.0+ does have a number of safety check not available in previous versions. 73 | 74 | Having a version of pip < 9.0 can lead your system to try to upgrade to 75 | non-compatible versions of Python packages even if these are marked as 76 | non-compatible. 77 | 78 | Help as many other _users_ as possible to install pip ≥ 9.0. For the 79 | transition, it is the slowest part of the ecosystem to update, and is the only 80 | piece that requires action of all Python users. 81 | 82 | The simplest way to make sure all is up to date is to run the following for 83 | each installation of Python: 84 | 85 | $ pip install --upgrade setuptools pip 86 | 87 | This will install the latest version of pip and setuptools. 88 | 89 | You can issue the following to see the version of pip: 90 | 91 | $ pip --version 92 | 9.0.0 93 | 94 | All good. 95 | 96 | 97 | 98 | ## Setuptools 99 | 100 | If you are on a system for which no wheel is available, pip will try to 101 | install a source distribution (aka `sdist`). 102 | 103 | Installing an `sdist` will require setuptools, so make sure you have setuptools 104 | ≥ 24.2.0 or building Python 3-only libraries will likely fail. In particular 105 | if library authors have taken time to mark their library as Python 3 only, the 106 | `python_requires` argument to `setup()` may not be recognized and installation 107 | will fail. 108 | 109 | Use the following to check your setuptools version : 110 | 111 | $ python -c 'import setuptools; print(setuptools.__version__)' 112 | 24.2.0 113 | 114 | Again make sure to upgrade pip and setuptools to make sure you have an up to 115 | date system: 116 | 117 | $ pip install --upgrade setuptools pip 118 | 119 | ## Local package index 120 | 121 | If you are using a custom local package index, for example if you are working 122 | at a company with private packages, make sure it correctly implements 123 | [pep-503](https://www.python.org/dev/peps/pep-0503/) to let pip know about 124 | the `python_requires` field. This _mostly_ mean that the HTML you are exposing 125 | should get a `data-python-requires` data attribute with the (html escaped) 126 | version specifier. 127 | 128 | ## The state of PyPI 129 | 130 | [Warehouse](https://github.com/pypi/warehouse) and [Legacy 131 | PyPI](https://github.com/pypa/legacy-pypi) have received various patches to 132 | insure they support this new functionality. 133 | 134 | # Preparing your library 135 | 136 | 137 | As a library author one of the most important factors in a smooth transition is 138 | planning and communication, letting your user base know in advance that the 139 | transition is happening and what step to take is critical for a transition. 140 | 141 | For your library code here the steps you need to take to ensure that 142 | installation will fail in the least number of cases: 143 | 144 | You need to release your package's new version with 145 | [setuptools](https://pypi.python.org/pypi/setuptools) version 24.2.0 or above. 146 | You can also use one of the alternate package managers that can set the 147 | [Requires-Python](https://www.python.org/dev/peps/pep-0345/#requires-python) 148 | metadata field. Without this, pip 9.0 **will try** to install a non-compatible 149 | version of your software on Python 2. This version of setuptools is recent 150 | (July 20, 2016) and this is all possible thanks to the [work of Xavier 151 | Fernandez](https://github.com/pypa/setuptools/pull/631) 152 | 153 | Add the following to your `setup.py` 154 | 155 | ``` 156 | setup( 157 | ... 158 | python_requires='>=3.3' 159 | ... 160 | ) 161 | ``` 162 | 163 | Change `>=3.3` accordingly depending on what version your library decides to 164 | support. In particular you can use `>=2.6` or `>=3.5` ! Note that this also 165 | support the _compatible with_ syntax: `~=2.5` (meaning, `>=2.5` and `<3`). 166 | 167 | This will make [PyPI aware](https://github.com/pypa/warehouse/pull/1448) that 168 | your package is Python 3.3+ only, and [allow 169 | pip](https://github.com/pypa/pip/pull/3877) to be [made aware of 170 | this](https://github.com/pypa/pypi-legacy/pull/506). 171 | 172 | Thus as long as your user have recent enough versions of pip and setuptools 173 | they will get the right version of your library. 174 | 175 | # Unit testing and documentation 176 | 177 | It is recommended **not** to invoke `setup.py` directly either with `install` or 178 | `develop` subcommands. These may not correctly resolve dependencies, and can 179 | install incompatible versions of dependencies. Please recommend and use `pip 180 | install .` and `pip install -e .` for regular and developer installs, respectively. 181 | 182 | Check in scripts and documentation that the correct installation command is 183 | used. 184 | 185 | # Recommended mitigations 186 | 187 | These are not mandatory but should make the transition seamless by warning your 188 | users early enough _and_ providing useful error messages. 189 | 190 | ## Runtime warning on master 191 | 192 | Add a warning at _runtime_ that triggers early on master 193 | (before switching to Python 3 only) 194 | 195 | ``` 196 | import warnings 197 | import sys 198 | if sys.version_info < (3,): 199 | warnings.warn('You are using master of `Frobulator` with Python 2. ' 200 | 'Frobulator will soon be Python 3 only. ' 201 | 'See this issue to know more.', 202 | UserWarning) 203 | ``` 204 | 205 | Your Python 2 users will have a chance to upgrade, or get off master, 206 | (for example on the LTS branch). 207 | 208 | ## Fail early at import time 209 | 210 | Add an error early through import at runtime with a clear error message, leave the 211 | early import compatible Python 2 as users will not feel welcomed with a useless 212 | `SyntaxError` due to their Python 2 usage. Don't hesitate to use multi-line strings 213 | in error messages. 214 | 215 | Error at import time _will_ happen on systems with old version of pip and 216 | setuptools. Keep in mind that saying the package is Python 3 only is not a lot 217 | more helpful than a `SyntaxError`. The most reasonable reason would be 218 | out-of-date pip and setuptools: 219 | 220 | 221 | ``` 222 | import sys 223 | 224 | if sys.version_info < (3,): 225 | raise ImportError( 226 | """You are running Frobulator 6.0 on Python 2 227 | 228 | Frobulator 6.0 and above are no longer compatible with Python 2, and you still 229 | ended up with this version installed. That's unfortunate; sorry about that. 230 | It should not have happened. Make sure you have pip >= 9.0 to avoid this kind 231 | of issue, as well as setuptools >= 24.2: 232 | 233 | $ pip install pip setuptools --upgrade 234 | 235 | Your choices: 236 | 237 | - Upgrade to Python 3. 238 | 239 | - Install an older version of Frobulator: 240 | 241 | $ pip install 'frobulator<6.0' 242 | 243 | It would be great if you can figure out how this version ended up being 244 | installed, and try to check how to prevent that for future users. 245 | 246 | See the following URL for more up-to-date information: 247 | 248 | https://i.am.an/url 249 | 250 | """) 251 | 252 | ``` 253 | 254 | ## Watch out for beta releases 255 | 256 | 257 | Make sure your version number matches 258 | [PEP 440](https://www.python.org/dev/peps/pep-0440/) or you will get surprises 259 | during beta, in particular as the `sdist` and `wheel` will appear as being 260 | different versions (the sdist (during beta/rc/post) can appear with 261 | a greater version number than wheels). Pip thus will try to install the sdist 262 | instead of the wheel, which has more chance of failing, in particular with 263 | pre-24.2 versions of setuptools. 264 | 265 | The regular expression to check for validity of pep440 can be found below: 266 | 267 | ^ 268 | ([1-9]\\d*!)? 269 | (0|[1-9]\\d*) 270 | (\\.(0|[1-9]\\d*))* 271 | ((a|b|rc)(0|[1-9]\\d*))? 272 | (\\.post(0|[1-9]\\d*))? 273 | (\\.dev(0|[1-9]\\d*))? 274 | 275 | 276 | ## Fail early in setup.py 277 | 278 | Leave `setup.py` python 2 compatible and fail early. If you detect Python 2 279 | raise a clear error message and ask the user to make sure they have pip > 9.0 (or 280 | migrate to Python 3). You can (try to) conditionally import pip and check for 281 | its version but this might not be the same pip. Failing early is important to 282 | make sure the Python installation does not install an incompatible version. 283 | Otherwise user code can fail at runtime arbitrarily later in the future, which can 284 | be a difficult to debug and fix. Get inspiration from the message of failure at 285 | runtime, and adapt for installation time. 286 | 287 | 288 | Here is for a simple version of how IPython handle old versions of Python and 289 | Pip that still try to install IPython 7.0+ on Python `< (3,4)`. 290 | 291 | ```python 292 | if sys.version_info < (3, 4): 293 | 294 | error = """ 295 | IPython 7.0+ supports Python 3.4 and above. 296 | When using Python 2.7, please install IPython 5.x LTS Long Term Support version. 297 | Python 3.3 was supported up to IPython 6.x. 298 | 299 | See IPython `README.rst` file for more information: 300 | 301 | https://github.com/ipython/ipython/blob/master/README.rst 302 | 303 | Python {py} detected. 304 | 305 | Try upgrading pip and retry. 306 | """.format(py='.'.join([str(v) for v in sys.version_info[:3]])) 307 | 308 | print(error, file=sys.stderr) 309 | sys.exit(1) 310 | ``` 311 | 312 | You can look at the [full 313 | check](https://github.com/ipython/ipython/blob/6a3e2db0c299dc05e636653c4a43d0aa756fb1c8/setup.py#L23-L58) 314 | that attempt to detect which version of pip is in used. 315 | 316 | ## Upload with Twine. 317 | 318 | You _must_ upload your package with ``twine`` and NOT with ``setup.py upload``. 319 | If you have an old version of setuptools or ``distutils``, even if 320 | ``python_requires`` is set, metadata may not be uploaded correctyl. See [This 321 | issue](https://github.com/pypa/warehouse/issues/3889) on PyPI repository 322 | 323 | ## Fix dependant libraries 324 | 325 | If you control dependant packages, Make sure to include conditional dependencies 326 | depending on the version of Python. 327 | 328 | # Non-recommended mitigations 329 | 330 | This is a collection of "mitigation" or "solutions" you will find on the web 331 | and that you will hear about. This is an attempt to acknowledge them, and 332 | explain why they can't work and what are their drawbacks before you attempt to 333 | implement them. 334 | 335 | ### Use a meta-package 336 | 337 | It is possible to release a meta-package that has _virtually_ no code and relies 338 | on a conditional dependency to install its actual core code on the user system. 339 | For example, Frob-6.0 could be a meta-package which depends on 340 | Frob-real-py2 on Python < 3.0, and Frob-real-py3 on Python ≥ 3.4. While 341 | this approach is _doable_ this can make imports confusing. 342 | 343 | ## Depend on setuptools 344 | 345 | You can mark your library as dependent on setuptools greater than 24.3 as this 346 | will insure that during the next upgrade (when the packages drop python 2 347 | support) will have the right version of setuptools. 348 | 349 | Of course regardless of all the care you will take for your library to no break 350 | and to install only on python 2, you will likely have cases where it will still 351 | end up being installed on incompatible versions of Python. Simply because users 352 | upgrade rarely and only an old version of pip or setuptools is enough to make 353 | the update process broken. 354 | 355 | Plus setuptools is rarely an actual dependency of your project but a 356 | requirement to build wheels. 357 | 358 | 359 | ### Multiple sdist files 360 | 361 | Pip (used to) support a "feature" where a sdist ending in `-pyX.Y.tar.gz` would 362 | only be seen as compatible on Python X.Y, thus it used to be possible to 363 | publish multiple sdist of a package targeting various python version. 364 | 365 | It is not possible anymore to upload multiple sdist files on PyPI, so this 366 | solution is no longer tenable. 367 | 368 | ### Wheel only? 369 | 370 | Releasing a package only using wheels for a given python version is doable, but 371 | this will break downstream packages that may require the original source to 372 | reproduce their build. 373 | 374 | # Why all *this*?!? 375 | 376 | You might wonder why all this, it's 2018 already, so how come this is still an 377 | issue? Python 3 has been out for 9+ years now! 378 | 379 | Well there are many reasons for this. First of all, this issue mostly affects 380 | libraries that are currently python 2 and Python 3 compatible at the same time. 381 | Many libraries have transitioned from Python 2-only to Python 2 + 3. And the 382 | issue of transitioning to Python 3 only is relatively recent. Technically it 383 | can also apply to libraries that are only stopping support for 2.6, or are even 384 | already Python 3 only, but are starting to stop supporting earlier versions of 385 | Python (for example a library releasing a Python 3.4+ only version). 386 | 387 | Python 3.3 was released at the end of 2012, and was the first version to 388 | support (again) `u` as a prefix for Unicode string. It was one of the first 389 | minor versions of Python 3 that saw a majority of single-source projects working 390 | both on Python 2 and Python 3. These are the projects that will likely be 391 | affected by this issue. 392 | 393 | The introduction of Python 3 was chaotic; there are still strong arguments in both 394 | the Python 2 and Python 3 camps. Regardless of what side you take, the ones suffering 395 | the most from this are users (starting with the fact that inevitably some libraries 396 | will stop supporting for Python 2 and release Python 3 only library). Inevitably, some 397 | systems and people will not be upgraded to Python 3, so this document hopefully 398 | helps to _ensure_ that users get the _least_ breakage as possible and what are the best 399 | practices are to follow. 400 | --------------------------------------------------------------------------------