Commit dcd3836d authored by Hugo Lefeuvre's avatar Hugo Lefeuvre

New upstream version 6.0

parent e9db5971
*.pyc
.tox
dist/
.coverage
htmlcov/
build/
qrcode.egg-info/
.pytest_cache/
......@@ -2,8 +2,17 @@
Change log
==========
Version 5.3
===========
6.0 (23 March 2018)
===================
- Fix optimize length being ignored in ``QRCode.add_data``.
- Better calculation of the best mask pattern and related optimizations. Big
thanks to cryptogun!
5.3 (18 May 2016)
=================
* Fix incomplete block table for QR version 15. Thanks Rodrigo Queiro for the
report and Jacob Welsh for the investigation and fix.
......@@ -13,8 +22,8 @@ Version 5.3
* Make ``BaseImage.get_image()`` actually work.
Version 5.2
===========
5.2 (25 Jan 2016)
=================
* Add ``--error-correction`` option to qr script.
......@@ -29,20 +38,20 @@ Version 5.2
* Fix terminal output to display correctly on MS command line.
Version 5.2.1
-------------
5.2.1
-----
* Small fix to terminal output in Python 3 (and fix tests)
Version 5.2.2
-------------
5.2.2
-----
* Revert some terminal changes from 5.2 that broke Python 3's real life tty
code generation and introduce a better way from Jacob Welsh.
Version 5.1
===========
5.1 (22 Oct 2014)
=================
* Make ``qr`` script work in Windows. Thanks Ionel Cristian Mărieș
......@@ -54,8 +63,8 @@ Version 5.1
* Much better test coverage (now only officially supporting Python 2.6+)
Version 5.0
===========
5.0 (17 Jun 2014)
=================
* Speed optimizations.
......@@ -69,14 +78,14 @@ Version 5.0
* Introduce a ``print_ascii`` method and use it as the default for the ``qr``
script rather than ``print_tty``.
Version 5.0.1
-------------
5.0.1
-----
* Update version numbers correctly.
Version 4.0
===========
4.0 (4 Sep 2013)
================
* Made qrcode work on Python 2.4 - Thanks tcely.
Note: officially, qrcode only supports 2.5+.
......@@ -92,32 +101,32 @@ Version 4.0
* Added some extra simple SVG factories that fill the background white.
Version 4.0.1
-------------
4.0.1
-----
* Fix the pymaging backend not able to save the image to a buffer. Thanks ilj!
Version 4.0.2
-------------
4.0.2
-----
* Fix incorrect regex causing a comma to be considered part of the alphanumeric
set.
* Switch to using setuptools for setup.py.
Version 4.0.3
-------------
4.0.3
-----
* Fix bad QR code generation due to the regex comma fix in version 4.0.2.
Version 4.0.4
-------------
4.0.4
-----
* Bad version number for previous hotfix release.
Version 3.1
===========
3.1 (12 Aug 2013)
=================
* Important fixes for incorrect matches of the alpha-numeric encoding mode.
Previously, the pattern would match if a single line was alpha-numeric only
......@@ -127,8 +136,8 @@ Version 3.1
* Optimized chunking -- if the parts of the data stream can be encoded more
efficiently, the data will be split into chunks of the most efficient modes.
Version 3.1.1
-------------
3.1.1
-----
* Update change log to contain version 3.1 changes. :P
......@@ -136,8 +145,8 @@ Version 3.1.1
optimization setting.
Version 3.0
===========
3.0 (25 Jun 2013)
=================
* Python 3 support.
......@@ -151,14 +160,14 @@ Version 3.0
Python platforms.
Version 2.7
===========
2.7 (5 Mar 2013)
================
* Fix incorrect termination padding.
Version 2.6
===========
2.6 (2 Apr 2013)
================
* Fix the first four columns incorrectly shifted by one. Thanks to Josep
Gómez-Suay for the report and fix.
......@@ -167,52 +176,52 @@ Version 2.6
terminated. Thanks to zhjie231 for the report.
Version 2.5
===========
2.5 (12 Mar 2013)
=================
* The PilImage wrapper is more transparent - you can use any methods or
attributes available to the underlying PIL Image instance.
* Fixed the first column of the QR Code coming up empty! Thanks to BecoKo.
Version 2.5.1
-------------
2.5.1
-----
* Fix installation error on Windows.
Version 2.4
===========
2.4 (23 Apr 2012)
=================
* Use a pluggable backend system for generating images, thanks to Branko Čibej!
Comes with PIL and SVG backends built in.
Version 2.4.1
-------------
2.4.1
-----
* Fix a packaging issue
Version 2.4.2
-------------
2.4.2
-----
* Added a ``show`` method to the PIL image wrapper so the ``run_example``
function actually works.
Version 2.3
===========
2.3 (29 Jan 2012)
=================
* When adding data, auto-select the more efficient encoding methods for numbers
and alphanumeric data (KANJI still not supported).
Version 2.3.1
-------------
2.3.1
-----
* Encode unicode to utf-8 bytestrings when adding data to a QRCode.
Version 2.2
===========
2.2 (18 Jan 2012)
=================
* Fixed tty output to work on both white and black backgrounds.
......@@ -220,8 +229,8 @@ Version 2.2
create the border of the QR code
Version 2.1
===========
2.1 (17 Jan 2012)
=================
* Added a ``qr`` script which can be used to output a qr code to the tty using
background colors, or to a file via a pipe.
include LICENSE *.rst doc/qr.1
include *.rst
include LICENSE
include signing-key.asc
include tox.ini
include doc/qr.1
This diff is collapsed.
......@@ -2,10 +2,12 @@
Pure python QR Code generator
=============================
This module uses image libraries, Python Imaging Library (PIL) by default, to
generate QR Codes.
Generate QR codes.
It is recommended to use the pillow_ fork rather than PIL itself.
For a standard install (which will include pillow_ for generating images),
run::
pip install qrcode[pil]
.. _pillow: https://pypi.python.org/pypi/Pillow
......@@ -26,7 +28,9 @@ From the command line, use the installed ``qr`` script::
qr "Some text" > test.png
Or in Python, use the ``make`` shortcut function::
Or in Python, use the ``make`` shortcut function:
.. code:: python
import qrcode
img = qrcode.make('Some data here')
......@@ -34,7 +38,9 @@ Or in Python, use the ``make`` shortcut function::
Advanced Usage
--------------
For more control, use the ``QRCode`` class. For example::
For more control, use the ``QRCode`` class. For example:
.. code:: python
import qrcode
qr = qrcode.QRCode(
......@@ -46,13 +52,16 @@ For more control, use the ``QRCode`` class. For example::
qr.add_data('Some data')
qr.make(fit=True)
img = qr.make_image()
img = qr.make_image(fill_color="black", back_color="white")
The ``version`` parameter is an integer from 1 to 40 that controls the size of
the QR Code (the smallest, version 1, is a 21x21 matrix).
Set to ``None`` and use the ``fit`` parameter when making the code to determine
this automatically.
``fill_color`` and ``back_color`` can change the background and the painting
color of the QR, when using the default image factory.
The ``error_correction`` parameter controls the error correction used for the
QR Code. The following four constants are made available on the ``qrcode``
package:
......@@ -85,9 +94,6 @@ usage.
SVG
---
On Python 2.6 must install lxml since the older xml.etree.ElementTree version
can not be used to create SVG images.
You can create the entire SVG or an SVG fragment. When building an entire SVG
image, you can use the factory that combines as a path (recommended, and
default for the script) or a factory that creates a simple set of rectangles.
......@@ -98,7 +104,9 @@ From your command line::
qr --factory=svg "Some text" > test.svg
qr --factory=svg-fragment "Some text" > test.svg
Or in Python::
Or in Python:
.. code:: python
import qrcode
import qrcode.image.svg
......@@ -134,7 +142,9 @@ From your command line::
qr --factory=pymaging "Some text" > test.png
Or in Python::
Or in Python:
.. code:: python
import qrcode
from qrcode.image.pure import PymagingImage
......
......@@ -3,19 +3,17 @@ Testing
First, install tox into your virtualenv::
pip install -U tox
pip install --upgrade tox
To run all the qrcode tests, you'll need to install the older Python
interpreters. Here's how you'll do it on a modern Ubuntu distribution::
To run all tests, you'll need to install multiple Python interpreters. On a
modern Ubuntu distribution you can use ``add-apt-repository
ppa:deadsnakes/ppa``.
sudo add-apt-repository ppa:fkrull/deadsnakes
sudo apt-get update
sudo apt-get install python2.4-dev python2.6-dev
Depending on if you can install the wheels directly for your OS, you may need
the libraries to build PIL, too. Here's the Ubuntu commands::
Ensure you have the libraries to build PIL, too::
sudo apt-get install build-essential python-dev python3-dev
sudo apt-get install build-essential python-dev python3-dev
sudo apt-get install libjpeg8-dev zlib1g-dev
Finally, just run ``tox``!
If you want, you can test against a specific version like this: ``tox -e py33``
If you want, you can test against a specific version like this: ``tox -e py36``
.\" Manpage for qr
.TH QR 1 "25 Jun 2013" "5.3" "Python QR tool"
.TH QR 1 "23 Mar 2018" "6.0" "Python QR tool"
.SH NAME
qr \- script to create QR codes at the command line
.SH SYNOPSIS
......
This diff is collapsed.
.gitignore
CHANGES.rst
LICENSE
MANIFEST.in
......@@ -6,19 +7,23 @@ README.rst
TESTING.rst
setup.cfg
setup.py
signing-key.asc
tox.ini
doc/qr.1
qrcode/LUT.py
qrcode/__init__.py
qrcode/base.py
qrcode/console_scripts.py
qrcode/constants.py
qrcode/exceptions.py
qrcode/main.py
qrcode/release.py
qrcode/util.py
qrcode.egg-info/PKG-INFO
qrcode.egg-info/SOURCES.txt
qrcode.egg-info/dependency_links.txt
qrcode.egg-info/entry_points.txt
qrcode.egg-info/pbr.json
qrcode.egg-info/not-zip-safe
qrcode.egg-info/requires.txt
qrcode.egg-info/top_level.txt
qrcode/image/__init__.py
......@@ -30,4 +35,5 @@ qrcode/tests/__init__.py
qrcode/tests/svg.py
qrcode/tests/test_example.py
qrcode/tests/test_qrcode.py
qrcode/tests/test_release.py
qrcode/tests/test_script.py
\ No newline at end of file
{"git_version": "a2e3516", "is_release": false}
\ No newline at end of file
six
[:platform_system == "Windows"]
colorama
[dev]
tox
pytest
[dev:python_version < "3"]
mock
[maintainer]
zest.releaser[recommended]
[pil]
pillow
[test]
pytest
pytest-cov
[test:python_version < "3"]
mock
# Store all kinds of lookup table.
# # generate rsPoly lookup table.
# from qrcode import base
# def create_bytes(rs_blocks):
# for r in range(len(rs_blocks)):
# dcCount = rs_blocks[r].data_count
# ecCount = rs_blocks[r].total_count - dcCount
# rsPoly = base.Polynomial([1], 0)
# for i in range(ecCount):
# rsPoly = rsPoly * base.Polynomial([1, base.gexp(i)], 0)
# return ecCount, rsPoly
# rsPoly_LUT = {}
# for version in range(1,41):
# for error_correction in range(4):
# rs_blocks_list = base.rs_blocks(version, error_correction)
# ecCount, rsPoly = create_bytes(rs_blocks_list)
# rsPoly_LUT[ecCount]=rsPoly.num
# print(rsPoly_LUT)
# Result. Usage: input: ecCount, output: Polynomial.num
# e.g. rsPoly = base.Polynomial(LUT.rsPoly_LUT[ecCount], 0)
rsPoly_LUT = {
7: [1, 127, 122, 154, 164, 11, 68, 117],
10: [1, 216, 194, 159, 111, 199, 94, 95, 113, 157, 193],
13: [1, 137, 73, 227, 17, 177, 17, 52, 13, 46, 43, 83, 132, 120],
15: [1, 29, 196, 111, 163, 112, 74, 10, 105, 105, 139, 132, 151,
32, 134, 26],
16: [1, 59, 13, 104, 189, 68, 209, 30, 8, 163, 65, 41, 229, 98, 50, 36, 59],
17: [1, 119, 66, 83, 120, 119, 22, 197, 83, 249, 41, 143, 134, 85, 53, 125,
99, 79],
18: [1, 239, 251, 183, 113, 149, 175, 199, 215, 240, 220, 73, 82, 173, 75,
32, 67, 217, 146],
20: [1, 152, 185, 240, 5, 111, 99, 6, 220, 112, 150, 69, 36, 187, 22, 228,
198, 121, 121, 165, 174],
22: [1, 89, 179, 131, 176, 182, 244, 19, 189, 69, 40, 28, 137, 29, 123, 67,
253, 86, 218, 230, 26, 145, 245],
24: [1, 122, 118, 169, 70, 178, 237, 216, 102, 115, 150, 229, 73, 130, 72,
61, 43, 206, 1, 237, 247, 127, 217, 144, 117],
26: [1, 246, 51, 183, 4, 136, 98, 199, 152, 77, 56, 206, 24, 145, 40, 209,
117, 233, 42, 135, 68, 70, 144, 146, 77, 43, 94],
28: [1, 252, 9, 28, 13, 18, 251, 208, 150, 103, 174, 100, 41, 167, 12, 247,
56, 117, 119, 233, 127, 181, 100, 121, 147, 176, 74, 58, 197],
30: [1, 212, 246, 77, 73, 195, 192, 75, 98, 5, 70, 103, 177, 22, 217, 138,
51, 181, 246, 72, 25, 18, 46, 228, 74, 216, 195, 11, 106, 130, 150]
}
......@@ -288,16 +288,13 @@ class Polynomial:
if not num: # pragma: no cover
raise Exception("%s/%s" % (len(num), shift))
offset = 0
for item in num:
if item != 0:
for offset in range(len(num)):
if num[offset] != 0:
break
else:
offset += 1
self.num = [0] * (len(num) - offset + shift)
for i in range(len(num) - offset):
self.num[i] = num[i + offset]
self.num = num[offset:] + [0] * shift
def __getitem__(self, index):
return self.num[index]
......@@ -324,8 +321,6 @@ class Polynomial:
ratio = glog(self[0]) - glog(other[0])
num = self[:]
num = [
item ^ gexp(glog(other_item) + ratio)
for item, other_item in zip(self, other)]
......
......@@ -30,8 +30,12 @@ error_correction = {
}
def main(args=sys.argv[1:]):
parser = optparse.OptionParser(usage=__doc__.strip())
def main(args=None):
if args is None:
args = sys.argv[1:]
from pkg_resources import get_distribution
version = get_distribution('qrcode').version
parser = optparse.OptionParser(usage=__doc__.strip(), version=version)
parser.add_option(
"--factory", help="Full python path to the image factory class to "
"create the image with. You can use the following shortcuts to the "
......
......@@ -18,8 +18,8 @@ class PilImage(qrcode.image.base.BaseImage):
kind = "PNG"
def new_image(self, **kwargs):
back_color = kwargs.get("fill_color", "white")
fill_color = kwargs.get("back_color", "black")
back_color = kwargs.get("back_color", "white")
fill_color = kwargs.get("fill_color", "black")
if fill_color.lower() != "black" or back_color.lower() != "white":
if back_color.lower() == "transparent":
......@@ -29,6 +29,9 @@ class PilImage(qrcode.image.base.BaseImage):
mode = "RGB"
else:
mode = "1"
# L mode (1 mode) color = (r*299 + g*587 + b*114)//1000
if fill_color.lower() == "black": fill_color = 0
if back_color.lower() == "white": back_color = 255
img = Image.new(mode, (self.pixel_size, self.pixel_size), back_color)
self.fill_color = fill_color
......
......@@ -23,12 +23,23 @@ def _check_box_size(size):
"Invalid box size (was %s, expected larger than 0)" % size)
def _check_mask_pattern(mask_pattern):
if mask_pattern is None:
return
if not isinstance(mask_pattern, int):
raise TypeError(
"Invalid mask pattern (was %s, expected int)" % type(mask_pattern))
if mask_pattern < 0 or mask_pattern > 7:
raise ValueError(
"Mask pattern should be in range(8) (got %s)" % mask_pattern)
class QRCode:
def __init__(self, version=None,
error_correction=constants.ERROR_CORRECT_M,
box_size=10, border=4,
image_factory=None):
image_factory=None,
mask_pattern=None):
_check_box_size(box_size)
self.version = version and int(version)
self.error_correction = int(error_correction)
......@@ -36,6 +47,8 @@ class QRCode:
# Spec says border should be at least four boxes wide, but allow for
# any (e.g. for producing printable QR codes).
self.border = int(border)
_check_mask_pattern(mask_pattern)
self.mask_pattern = mask_pattern
self.image_factory = image_factory
if image_factory is not None:
assert issubclass(image_factory, BaseImage)
......@@ -62,7 +75,8 @@ class QRCode:
self.data_list.append(data)
else:
if optimize:
self.data_list.extend(util.optimal_data_chunks(data))
self.data_list.extend(
util.optimal_data_chunks(data, minimum=optimize))
else:
self.data_list.append(util.QRData(data))
self.data_cache = None
......@@ -76,7 +90,10 @@ class QRCode:
"""
if fit or (self.version is None):
self.best_fit(start=self.version)
self.makeImpl(False, self.best_mask_pattern())
if self.mask_pattern is None:
self.makeImpl(False, self.best_mask_pattern())
else:
self.makeImpl(False, self.mask_pattern)
def makeImpl(self, test, mask_pattern):
_check_version(self.version)
......
"""
This file provides zest.releaser entrypoints using when releasing new
qrcode versions.
"""
import os
import re
import datetime
def update_manpage(data):
"""
Update the version in the manpage document.
"""
if data['name'] != 'qrcode':
print('no qrcode')
return
base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
filename = os.path.join(base_dir, 'doc', 'qr.1')
with open(filename, 'r') as f:
lines = f.readlines()
changed = False
for i, line in enumerate(lines):
if not line.startswith('.TH '):
continue
parts = re.split(r'"([^"]*)"', line)
if len(parts) < 5:
continue
changed = parts[3] != data['new_version']
if changed:
# Update version
parts[3] = data['new_version']
# Update date
parts[1] = datetime.datetime.now().strftime('%-d %b %Y')
lines[i] = '"'.join(parts)
break
if changed:
with open(filename, 'w') as f:
for line in lines:
f.write(line)
......@@ -168,12 +168,25 @@ class QRCodeTests(unittest.TestCase):
text = 'A1abc12345def1HELLOa'
qr.add_data(text, optimize=4)
qr.make()
self.assertEqual(len(qr.data_list), 5)
self.assertEqual(qr.data_list[0].mode, MODE_8BIT_BYTE)
self.assertEqual(qr.data_list[1].mode, MODE_NUMBER)
self.assertEqual(qr.data_list[2].mode, MODE_8BIT_BYTE)
self.assertEqual(qr.data_list[3].mode, MODE_ALPHA_NUM)
self.assertEqual(qr.data_list[4].mode, MODE_8BIT_BYTE)
self.assertEqual(
[d.mode for d in qr.data_list],
[
MODE_8BIT_BYTE, MODE_NUMBER, MODE_8BIT_BYTE, MODE_ALPHA_NUM,
MODE_8BIT_BYTE
]
)
self.assertEqual(qr.version, 2)
def test_optimize_short(self):
qr = qrcode.QRCode()
text = 'A1abc1234567def1HELLOa'
qr.add_data(text, optimize=7)
qr.make()
self.assertEqual(len(qr.data_list), 3)
self.assertEqual(
[d.mode for d in qr.data_list],
[MODE_8BIT_BYTE, MODE_NUMBER, MODE_8BIT_BYTE]
)
self.assertEqual(qr.version, 2)
def test_optimize_size(self):
......
import re
import datetime
import unittest
try:
from unittest import mock
except ImportError:
import mock
from qrcode.release import update_manpage
OPEN = '.'.join((open.__module__, open.__name__))
DATA = 'test\n.TH "date" "version" "description"\nthis'
class UpdateManpageTests(unittest.TestCase):
@mock.patch(OPEN, new_callable=mock.mock_open, read_data='.TH invalid')
def test_invalid_data(self, mock_file):
update_manpage({'name': 'qrcode', 'new_version': '1.23'})
mock_file.assert_called()
mock_file().write.assert_not_called()
@mock.patch(OPEN, new_callable=mock.mock_open, read_data=DATA)
def test_not_qrcode(self, mock_file):
update_manpage({'name': 'not-qrcode'})
mock_file.assert_not_called()
@mock.patch(OPEN, new_callable=mock.mock_open, read_data=DATA)
def test_no_change(self, mock_file):
update_manpage({'name': 'qrcode', 'new_version': 'version'})
mock_file.assert_called()
mock_file().write.assert_not_called()
@mock.patch(OPEN, new_callable=mock.mock_open, read_data=DATA)
def test_change(self, mock_file):
update_manpage({'name': 'qrcode', 'new_version': '3.11'})
expected = re.split(r'([^\n]*(?:\n|$))', DATA)[1::2]
expected[1] = expected[1].replace('version', '3.11').replace(
'date', datetime.datetime.now().strftime('%-d %b %Y'))
mock_file().write.has_calls([mock.call(line) for line in expected])
......@@ -47,6 +47,9 @@ class ScriptTest(unittest.TestCase):
mock_stdin.buffer.read.return_value = 'testtext'
mock_stdin.read.side_effect = bad_read
with mock.patch('sys.stdin', mock_stdin):
# sys.stdin.read() will raise an error...
self.assertRaises(UnicodeDecodeError, sys.stdin.read)
# ... but it won't be used now.
main([])
mock_print_ascii.assert_called_with(tty=True)
......
......@@ -4,7 +4,7 @@ import math
import six
from six.moves import xrange
from qrcode import base, exceptions
from qrcode import base, exceptions, LUT
# QR encoding modes.