Skip to content

Commit

Permalink
Merge pull request #349 from edx/cdyer/python3
Browse files Browse the repository at this point in the history
Introduce python 3 compatibility.
  • Loading branch information
Cliff Dyer authored May 12, 2017
2 parents 161b300 + 4700c7c commit 0496f69
Show file tree
Hide file tree
Showing 47 changed files with 681 additions and 384 deletions.
11 changes: 7 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@ branches:
only:
- master
python:
- "2.7"
- "3.5"
cache: pip
install:
- pip install -r requirements.txt
- pip install -r django_requirements.txt
- pip install tox
- pip install codecov
env:
- TOX_ENV=py27
- TOX_ENV=py35
- TOX_ENV=docs
script:
- make test doc quality
- tox -e $TOX_ENV
after_success:
- codecov
16 changes: 14 additions & 2 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,20 @@ Change history for XBlock

These are notable changes in XBlock.

0.4 - In Progress
-----------------
1.0 - Python 3
--------------

* Introduce Python 3 compatibility to the xblock code base.
This does not enable Python 2 codebases (like edx-platform) to load xblocks
written in Python 3, but it lays the groundwork for future migrations.

0.5 - ???
---------

No notes provided.

0.4
---

* Separate Fragment class out into new web-fragments package

Expand Down
15 changes: 8 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
test:
coverage run -m nose

docs:
cd doc && make html

quality:
pep8
script/max_pylint_violations
pylint --py3k xblock

package:
python setup.py register sdist upload
python setup.py register sdist upload

test:
tox -e py27,py35

docs:
tox -e docs
2 changes: 1 addition & 1 deletion django_requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Install Django requirements, if we're using the optional Django-integrated
# parts of XBlock
Django >= 1.8, < 1.9
django-pyfs
django-pyfs >= 1.0.5
4 changes: 2 additions & 2 deletions doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

import sys
import os
from path import path
from path import Path as path
import sys
import mock

Expand Down Expand Up @@ -223,4 +223,4 @@
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'

exclude_patterns = ['api/*', 'links.rst']
exclude_patterns = ['api/*', 'links.rst']
1 change: 1 addition & 0 deletions doc/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@
lazy
sphinx
sphinxcontrib-napoleon==0.2.6
sphinx_rtd_theme==0.1.9
path.py
17 changes: 8 additions & 9 deletions pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ persistent=yes

# List of plugins (as comma separated values of python modules names) to load,
# usually to register additional checkers.
load-plugins=
load-plugins=caniusepython3.pylint_checker


[MESSAGES CONTROL]
Expand All @@ -46,8 +46,11 @@ disable=
star-args,
abstract-class-not-used,
abstract-class-little-used,
abstract-class-instantiated,
no-init,
too-many-lines,
no-else-return,
arguments-differ,
no-self-use,
too-many-ancestors,
too-many-instance-attributes,
Expand All @@ -56,7 +59,9 @@ disable=
too-many-return-statements,
too-many-branches,
too-many-arguments,
too-many-locals
too-many-locals,
duplicate-code,
len-as-condition,


[REPORTS]
Expand Down Expand Up @@ -93,9 +98,6 @@ comment=no

[BASIC]

# Required attributes for module, separated by a comma
required-attributes=

# List of builtins function names that should not be used, separated by a comma
bad-functions=map,filter,apply,input

Expand Down Expand Up @@ -147,6 +149,7 @@ no-docstring-rgx=__.*__|test_.+|setUp|tearDown
# ones are exempt.
docstring-min-length=-1

extension-pkg-whitelist=lxml

[FORMAT]

Expand Down Expand Up @@ -228,10 +231,6 @@ additional-builtins=

[CLASSES]

# List of interface methods to ignore, separated by a comma. This is used for
# instance to not check methods defines in Zope's Interface base class.
ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by

# List of method names used to declare (i.e. assign) instance attributes.
defining-attr-methods=__init__,__new__,setUp

Expand Down
8 changes: 5 additions & 3 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@ markupsafe
mock
nose
coverage
# pinning astroid b/c it's throwing errors on 2.7.8 altho doc says it shouldn't
astroid == 1.2.1
pylint == 1.3.1
astroid
pylint
rednose
pep8
caniusepython3
diff-cover >= 0.2.1
ddt==0.8.0
tox

# For docs
-r doc/requirements.txt
Expand All @@ -28,6 +29,7 @@ cookiecutter

# For web fragments
web-fragments
#git+https://github.com/edx/[email protected]#egg=web_fragments==0.1.1

# Our own XBlocks
-e .
Expand Down
2 changes: 1 addition & 1 deletion script/max_pylint_violations
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/bin/bash
DEFAULT_MAX=7
DEFAULT_MAX=6

pylint xblock | tee /tmp/pylint-xblock.log
ERR=`grep -E "^[C|R|W|E]:" /tmp/pylint-xblock.log | wc -l`
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ rednose=1

[pep8]
ignore=E501,E402
exclude=doc/*
exclude=doc/*,.tox/
11 changes: 8 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@
Set up for XBlock
"""

from __future__ import absolute_import, division, print_function, unicode_literals

import codecs
import os.path
from setuptools import setup

version_file = os.path.join(os.path.dirname(__file__), 'xblock/VERSION.txt')
VERSION_FILE = os.path.join(os.path.dirname(__file__), 'xblock/VERSION.txt')

setup(
name='XBlock',
version=open(version_file).read().strip(),
version=codecs.open(VERSION_FILE, encoding='ascii').read().strip(),
description='XBlock Core Library',
packages=[
'xblock',
Expand All @@ -33,7 +36,7 @@
'web-fragments',
],
extras_require={
'django': ['django-pyfs']
'django': ['django-pyfs >= 1.0.5']
},
license='Apache 2.0',
classifiers=[
Expand All @@ -47,5 +50,7 @@
'Natural Language :: English',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7',
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.5",
]
)
33 changes: 33 additions & 0 deletions tox.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Tox (http://tox.testrun.org/) is a tool for running tests
# in multiple virtualenvs. This configuration file will run the
# test suite on all supported python versions. To use it, "pip install tox"
# and then run "tox" from this directory.

[tox]
envlist = py27, py35, docs

[testenv]
setenv =
COVERAGE_FILE={envdir}/.coverage
passenv =
CI
TRAVIS
TRAVIS_*
deps =
-rrequirements.txt
-rdjango_requirements.txt
commands =
coverage run -m nose
coverage xml -o {env:TRAVIS_BUILD_DIR}/coverage.xml
make quality
whitelist_externals = make

[testenv:docs]
basepython=python2.7
changedir={toxinidir}/doc
deps=
sphinx
-rrequirements.txt
-rdjango_requirements.txt
-rdoc/requirements.txt
commands=make html
2 changes: 1 addition & 1 deletion xblock/VERSION.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.5.0
1.0.0
9 changes: 8 additions & 1 deletion xblock/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,15 @@
XBlock Courseware Components
"""

# For backwards compatability, provide the XBlockMixin in xblock.fields
# without causing a circular import

from __future__ import absolute_import, division, print_function, unicode_literals

import codecs
import os
import warnings

import xblock.core
import xblock.fields

Expand All @@ -25,4 +32,4 @@ def __init__(self, *args, **kwargs):

VERSION_FILE = os.path.join(os.path.dirname(__file__), 'VERSION.txt')

__version__ = open(VERSION_FILE).read().strip()
__version__ = codecs.open(VERSION_FILE, encoding='ascii').read().strip()
18 changes: 11 additions & 7 deletions xblock/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,18 @@
and used by all runtimes.
"""

from __future__ import absolute_import, division, print_function, unicode_literals

from collections import defaultdict
import inspect
import os
import warnings

import pkg_resources
import six

import xblock.exceptions
from xblock.exceptions import DisallowedFileError
from xblock.fields import String, List, Scope
from xblock.internal import class_lazy
Expand Down Expand Up @@ -91,6 +96,9 @@ def open_local_resource(cls, uri):
unauthorized resource.
"""

if isinstance(uri, six.binary_type):
uri = uri.decode('utf-8')

# If no resources_dir is set, then this XBlock cannot serve local resources.
if cls.resources_dir is None:
raise DisallowedFileError("This XBlock is not configured to serve local resources")
Expand Down Expand Up @@ -276,8 +284,8 @@ def aside_view_declaration(self, view_name):
Returns:
either the function or None
"""
if view_name in self._combined_asides:
return getattr(self, self._combined_asides[view_name])
if view_name in self._combined_asides: # pylint: disable=unsupported-membership-test
return getattr(self, self._combined_asides[view_name]) # pylint: disable=unsubscriptable-object
else:
return None

Expand All @@ -288,11 +296,7 @@ def needs_serialization(self):
If all of the aside's data is empty or a default value, then the aside shouldn't
be serialized as XML at all.
"""
return any([field.is_set_on(self) for field in self.fields.itervalues()])


# Maintain backwards compatibility
import xblock.exceptions
return any(field.is_set_on(self) for field in six.itervalues(self.fields))


class KeyValueMultiSaveError(xblock.exceptions.KeyValueMultiSaveError):
Expand Down
14 changes: 9 additions & 5 deletions xblock/django/request.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
"""Helpers for WebOb requests and responses."""

import webob
from __future__ import absolute_import, division, print_function, unicode_literals

from collections import MutableMapping
from itertools import chain, repeat
from lazy import lazy
from itertools import chain, repeat, izip

import six
import webob
from webob.multidict import MultiDict, NestedMultiDict, NoVars


Expand All @@ -20,7 +24,7 @@ def webob_to_django_response(webob_response):
return django_response


class HeaderDict(MutableMapping):
class HeaderDict(MutableMapping, six.Iterator):
"""
Provide a dictionary view of the HTTP headers in a
Django request.META dictionary that translates the
Expand Down Expand Up @@ -77,8 +81,8 @@ def querydict_to_multidict(query_dict, wrap=None):
"""
wrap = wrap or (lambda val: val)
return MultiDict(chain.from_iterable(
izip(repeat(key), (wrap(v) for v in vals))
for key, vals in query_dict.iterlists()
six.moves.zip(repeat(key), (wrap(v) for v in vals))
for key, vals in six.iterlists(query_dict)
))


Expand Down
Loading

0 comments on commit 0496f69

Please sign in to comment.