Commit b0bf131b 董杰

感应式料架代码首次上传

0 个父辈
正在显示 185 个修改的文件 包含 4664 行增加0 行删除
#!/usr/bin/env bash
workdir=/prog/smartshelf/logs
cd $workdir
: > smart.log &
echo "log clear"
#!/usr/bin/env bash
workdir=/prog/smartshelf
cd $workdir
flask run -p 5000 -h 0.0.0.0 &
echo "server started"
此文件类型无法预览
Metadata-Version: 2.1
Name: Flask-Babel
Version: 2.0.0
Summary: Adds i18n/l10n support to Flask applications
Home-page: http://github.com/python-babel/flask-babel
Author: Armin Ronacher
Author-email: armin.ronacher@active-4.com
Maintainer: Tyler Kennedy
Maintainer-email: tk@tkte.ch
License: BSD
Description: # Flask Babel
![Tests](https://github.com/python-babel/flask-babel/workflows/Tests/badge.svg?branch=master)
[![PyPI](https://img.shields.io/pypi/v/flask-babel.svg?maxAge=2592000)](https://pypi.python.org/pypi/Flask-Babel)
Implements i18n and l10n support for Flask. This is based on the Python
[babel][] module as well as [pytz][] both of which are installed automatically
for you if you install this library.
# Documention
The latest documentation is available [here][docs].
[babel]: https://github.com/python-babel/babel
[pytz]: https://pypi.python.org/pypi/pytz/
[docs]: https://flask-babel.tkte.ch/
[semver]: https://semver.org/
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Web Environment
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Description-Content-Type: text/markdown
Provides-Extra: dev
LICENSE
MANIFEST.in
README.md
setup.cfg
setup.py
Flask_Babel.egg-info/PKG-INFO
Flask_Babel.egg-info/SOURCES.txt
Flask_Babel.egg-info/dependency_links.txt
Flask_Babel.egg-info/not-zip-safe
Flask_Babel.egg-info/requires.txt
Flask_Babel.egg-info/top_level.txt
docs/Makefile
docs/conf.py
docs/index.rst
docs/make.bat
flask_babel/__init__.py
flask_babel/speaklater.py
tests/babel.cfg
tests/test_date_formatting.py
tests/test_gettext.py
tests/test_integration.py
tests/test_number_formatting.py
tests/renamed_translations/messages.pot
tests/renamed_translations/de/LC_MESSAGES/messages.mo
tests/renamed_translations/de/LC_MESSAGES/messages.po
tests/renamed_translations/de/LC_MESSAGES/myapp.mo
tests/renamed_translations/de/LC_MESSAGES/myapp.po
tests/translations/messages.pot
tests/translations/de/LC_MESSAGES/messages.mo
tests/translations/de/LC_MESSAGES/messages.po
tests/translations/de/LC_MESSAGES/test.mo
tests/translations/de/LC_MESSAGES/test.po
tests/translations_different_domain/myapp.pot
tests/translations_different_domain/de/LC_MESSAGES/myapp.mo
tests/translations_different_domain/de/LC_MESSAGES/myapp.po
\ No newline at end of file \ No newline at end of file
Babel>=2.3
Flask
Jinja2>=2.5
pytz
[dev]
Pallets-Sphinx-Themes
bumpversion
ghp-import
pytest
pytest-mock
sphinx
Copyright (c) 2010 by Armin Ronacher.
Some rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* The names of the contributors may not be used to endorse or
promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
include Makefile LICENSE README.md
recursive-include tests *
recursive-exclude tests *.pyc
recursive-exclude tests *.pyo
recursive-include docs *
recursive-exclude docs *.pyc
recursive-exclude docs *.pyo
prune docs/_build
prune docs/_themes/.git
Metadata-Version: 2.1
Name: Flask-Babel
Version: 2.0.0
Summary: Adds i18n/l10n support to Flask applications
Home-page: http://github.com/python-babel/flask-babel
Author: Armin Ronacher
Author-email: armin.ronacher@active-4.com
Maintainer: Tyler Kennedy
Maintainer-email: tk@tkte.ch
License: BSD
Description: # Flask Babel
![Tests](https://github.com/python-babel/flask-babel/workflows/Tests/badge.svg?branch=master)
[![PyPI](https://img.shields.io/pypi/v/flask-babel.svg?maxAge=2592000)](https://pypi.python.org/pypi/Flask-Babel)
Implements i18n and l10n support for Flask. This is based on the Python
[babel][] module as well as [pytz][] both of which are installed automatically
for you if you install this library.
# Documention
The latest documentation is available [here][docs].
[babel]: https://github.com/python-babel/babel
[pytz]: https://pypi.python.org/pypi/pytz/
[docs]: https://flask-babel.tkte.ch/
[semver]: https://semver.org/
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Web Environment
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Description-Content-Type: text/markdown
Provides-Extra: dev
# Flask Babel
![Tests](https://github.com/python-babel/flask-babel/workflows/Tests/badge.svg?branch=master)
[![PyPI](https://img.shields.io/pypi/v/flask-babel.svg?maxAge=2592000)](https://pypi.python.org/pypi/Flask-Babel)
Implements i18n and l10n support for Flask. This is based on the Python
[babel][] module as well as [pytz][] both of which are installed automatically
for you if you install this library.
# Documention
The latest documentation is available [here][docs].
[babel]: https://github.com/python-babel/babel
[pytz]: https://pypi.python.org/pypi/pytz/
[docs]: https://flask-babel.tkte.ch/
[semver]: https://semver.org/
class LazyString(object):
def __init__(self, func, *args, **kwargs):
self._func = func
self._args = args
self._kwargs = kwargs
def __getattr__(self, attr):
if attr == "__setstate__":
raise AttributeError(attr)
string = str(self)
if hasattr(string, attr):
return getattr(string, attr)
raise AttributeError(attr)
def __repr__(self):
return "l'{0}'".format(str(self))
def __str__(self):
return str(self._func(*self._args, **self._kwargs))
def __len__(self):
return len(str(self))
def __getitem__(self, key):
return str(self)[key]
def __iter__(self):
return iter(str(self))
def __contains__(self, item):
return item in str(self)
def __add__(self, other):
return str(self) + other
def __radd__(self, other):
return other + str(self)
def __mul__(self, other):
return str(self) * other
def __rmul__(self, other):
return other * str(self)
def __lt__(self, other):
return str(self) < other
def __le__(self, other):
return str(self) <= other
def __eq__(self, other):
return str(self) == other
def __ne__(self, other):
return str(self) != other
def __gt__(self, other):
return str(self) > other
def __ge__(self, other):
return str(self) >= other
def __html__(self):
return str(self)
def __hash__(self):
return hash(str(self))
def __mod__(self, other):
return str(self) % other
def __rmod__(self, other):
return other + str(self)
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = .
BUILDDIR = _build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
import:
ghp-import -n -c flask-babel.tkte.ch "$(BUILDDIR)/html"
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
# Configuration file for the Sphinx documentation builder.
#
# This file only contains a selection of the most common options. For a full
# list see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html
# -- Path setup --------------------------------------------------------------
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
# import os
# import sys
# sys.path.insert(0, os.path.abspath('.'))
# -- Project information -----------------------------------------------------
project = 'Flask-Babel'
copyright = '2020, Armin Ronacher'
author = 'Armin Ronacher'
# The full version, including alpha/beta/rc tags
release = '2.0.0'
# -- General configuration ---------------------------------------------------
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.viewcode',
'pallets_sphinx_themes'
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
# -- Options for HTML output -------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'flask'
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
@ECHO OFF
pushd %~dp0
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=.
set BUILDDIR=_build
if "%1" == "" goto help
%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
goto end
:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
:end
popd
class LazyString(object):
def __init__(self, func, *args, **kwargs):
self._func = func
self._args = args
self._kwargs = kwargs
def __getattr__(self, attr):
if attr == "__setstate__":
raise AttributeError(attr)
string = str(self)
if hasattr(string, attr):
return getattr(string, attr)
raise AttributeError(attr)
def __repr__(self):
return "l'{0}'".format(str(self))
def __str__(self):
return str(self._func(*self._args, **self._kwargs))
def __len__(self):
return len(str(self))
def __getitem__(self, key):
return str(self)[key]
def __iter__(self):
return iter(str(self))
def __contains__(self, item):
return item in str(self)
def __add__(self, other):
return str(self) + other
def __radd__(self, other):
return other + str(self)
def __mul__(self, other):
return str(self) * other
def __rmul__(self, other):
return other * str(self)
def __lt__(self, other):
return str(self) < other
def __le__(self, other):
return str(self) <= other
def __eq__(self, other):
return str(self) == other
def __ne__(self, other):
return str(self) != other
def __gt__(self, other):
return str(self) > other
def __ge__(self, other):
return str(self) >= other
def __html__(self):
return str(self)
def __hash__(self):
return hash(str(self))
def __mod__(self, other):
return str(self) % other
def __rmod__(self, other):
return other + str(self)
[egg_info]
tag_build =
tag_date = 0
from setuptools import setup
from os import path
this_directory = path.abspath(path.dirname(__file__))
with open(path.join(this_directory, 'README.md'), 'rb') as f:
long_description = f.read().decode('utf-8')
setup(
name='Flask-Babel',
version='2.0.0',
url='http://github.com/python-babel/flask-babel',
license='BSD',
author='Armin Ronacher',
author_email='armin.ronacher@active-4.com',
maintainer='Tyler Kennedy',
maintainer_email='tk@tkte.ch',
description='Adds i18n/l10n support to Flask applications',
long_description=long_description,
long_description_content_type='text/markdown',
packages=['flask_babel'],
zip_safe=False,
install_requires=[
'pytz',
'Flask',
'Babel>=2.3',
'Jinja2>=2.5'
],
classifiers=[
'Development Status :: 5 - Production/Stable',
'Environment :: Web Environment',
'Intended Audience :: Developers',
'License :: OSI Approved :: BSD License',
'Operating System :: OS Independent',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: PyPy',
'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
'Topic :: Software Development :: Libraries :: Python Modules'
],
extras_require={
'dev': [
'pytest',
'pytest-mock',
'bumpversion',
'ghp-import',
'sphinx',
'Pallets-Sphinx-Themes'
]
}
)
[python: **.py]
[jinja2: **/templates/**.html]
extensions=jinja2.ext.autoescape,jinja2.ext.with_
# German translations for PROJECT.
# Copyright (C) 2010 ORGANIZATION
# This file is distributed under the same license as the PROJECT project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2010.
#
msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2010-05-29 17:00+0200\n"
"PO-Revision-Date: 2010-05-30 12:56+0200\n"
"Last-Translator: Armin Ronacher <armin.ronacher@active-4.com>\n"
"Language-Team: de <LL@li.org>\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 0.9.5\n"
#: tests.py:94
#, python-format
msgid "Hello %(name)s!"
msgstr "Hallo %(name)s!"
#: tests.py:95 tests.py:96
#, python-format
msgid "%(num)s Apple"
msgid_plural "%(num)s Apples"
msgstr[0] "%(num)s Apfel"
msgstr[1] "%(num)s Äpfel"
#: tests.py:119
msgid "Yes"
msgstr "Ja"
# German translations for PROJECT.
# Copyright (C) 2010 ORGANIZATION
# This file is distributed under the same license as the PROJECT project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2010.
#
msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2010-05-29 17:00+0200\n"
"PO-Revision-Date: 2010-05-30 12:56+0200\n"
"Last-Translator: Armin Ronacher <armin.ronacher@active-4.com>\n"
"Language-Team: de <LL@li.org>\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 0.9.5\n"
#: tests.py:94
#, python-format
msgid "Hello %(name)s!"
msgstr "Hallo %(name)s!"
#: tests.py:95 tests.py:96
#, python-format
msgid "%(num)s Apple"
msgid_plural "%(num)s Apples"
msgstr[0] "%(num)s Apfel"
msgstr[1] "%(num)s Äpfel"
#: tests.py:119
msgid "Yes"
msgstr "Ja"
# Translations template for PROJECT.
# Copyright (C) 2010 ORGANIZATION
# This file is distributed under the same license as the PROJECT project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2010.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2010-05-30 12:56+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 0.9.5\n"
#: tests.py:94
#, python-format
msgid "Hello %(name)s!"
msgstr ""
#: tests.py:95 tests.py:96
#, python-format
msgid "%(num)s Apple"
msgid_plural "%(num)s Apples"
msgstr[0] ""
msgstr[1] ""
#: tests.py:119
msgid "Yes"
msgstr ""
# -*- coding: utf-8 -*-
from __future__ import with_statement
from datetime import datetime, timedelta
from threading import Semaphore, Thread
import flask
import flask_babel as babel
def test_basics():
app = flask.Flask(__name__)
babel.Babel(app)
d = datetime(2010, 4, 12, 13, 46)
delta = timedelta(days=6)
with app.test_request_context():
assert babel.format_datetime(d) == 'Apr 12, 2010, 1:46:00 PM'
assert babel.format_date(d) == 'Apr 12, 2010'
assert babel.format_time(d) == '1:46:00 PM'
assert babel.format_timedelta(delta) == '1 week'
assert babel.format_timedelta(delta, threshold=1) == '6 days'
with app.test_request_context():
app.config['BABEL_DEFAULT_TIMEZONE'] = 'Europe/Vienna'
assert babel.format_datetime(d) == 'Apr 12, 2010, 3:46:00 PM'
assert babel.format_date(d) == 'Apr 12, 2010'
assert babel.format_time(d) == '3:46:00 PM'
with app.test_request_context():
app.config['BABEL_DEFAULT_LOCALE'] = 'de_DE'
assert babel.format_datetime(d, 'long') == \
'12. April 2010 um 15:46:00 MESZ'
def test_init_app():
b = babel.Babel()
app = flask.Flask(__name__)
b.init_app(app)
d = datetime(2010, 4, 12, 13, 46)
with app.test_request_context():
assert babel.format_datetime(d) == 'Apr 12, 2010, 1:46:00 PM'
assert babel.format_date(d) == 'Apr 12, 2010'
assert babel.format_time(d) == '1:46:00 PM'
with app.test_request_context():
app.config['BABEL_DEFAULT_TIMEZONE'] = 'Europe/Vienna'
assert babel.format_datetime(d) == 'Apr 12, 2010, 3:46:00 PM'
assert babel.format_date(d) == 'Apr 12, 2010'
assert babel.format_time(d) == '3:46:00 PM'
with app.test_request_context():
app.config['BABEL_DEFAULT_LOCALE'] = 'de_DE'
assert babel.format_datetime(d, 'long') == \
'12. April 2010 um 15:46:00 MESZ'
def test_custom_formats():
app = flask.Flask(__name__)
app.config.update(
BABEL_DEFAULT_LOCALE='en_US',
BABEL_DEFAULT_TIMEZONE='Pacific/Johnston'
)
b = babel.Babel(app)
b.date_formats['datetime'] = 'long'
b.date_formats['datetime.long'] = 'MMMM d, yyyy h:mm:ss a'
d = datetime(2010, 4, 12, 13, 46)
with app.test_request_context():
assert babel.format_datetime(d) == 'April 12, 2010 3:46:00 AM'
def test_custom_locale_selector():
app = flask.Flask(__name__)
b = babel.Babel(app)
d = datetime(2010, 4, 12, 13, 46)
the_timezone = 'UTC'
the_locale = 'en_US'
@b.localeselector
def select_locale():
return the_locale
@b.timezoneselector
def select_timezone():
return the_timezone
with app.test_request_context():
assert babel.format_datetime(d) == 'Apr 12, 2010, 1:46:00 PM'
the_locale = 'de_DE'
the_timezone = 'Europe/Vienna'
with app.test_request_context():
assert babel.format_datetime(d) == '12.04.2010, 15:46:00'
def test_refreshing():
app = flask.Flask(__name__)
babel.Babel(app)
d = datetime(2010, 4, 12, 13, 46)
with app.test_request_context():
assert babel.format_datetime(d) == 'Apr 12, 2010, 1:46:00 PM'
app.config['BABEL_DEFAULT_TIMEZONE'] = 'Europe/Vienna'
babel.refresh()
assert babel.format_datetime(d) == 'Apr 12, 2010, 3:46:00 PM'
def test_force_locale():
app = flask.Flask(__name__)
b = babel.Babel(app)
@b.localeselector
def select_locale():
return 'de_DE'
with app.test_request_context():
assert str(babel.get_locale()) == 'de_DE'
with babel.force_locale('en_US'):
assert str(babel.get_locale()) == 'en_US'
assert str(babel.get_locale()) == 'de_DE'
def test_force_locale_with_threading():
app = flask.Flask(__name__)
b = babel.Babel(app)
@b.localeselector
def select_locale():
return 'de_DE'
semaphore = Semaphore(value=0)
def first_request():
with app.test_request_context():
with babel.force_locale('en_US'):
assert str(babel.get_locale()) == 'en_US'
semaphore.acquire()
thread = Thread(target=first_request)
thread.start()
try:
with app.test_request_context():
assert str(babel.get_locale()) == 'de_DE'
finally:
semaphore.release()
thread.join()
def test_refresh_during_force_locale():
app = flask.Flask(__name__)
b = babel.Babel(app)
@b.localeselector
def select_locale():
return 'de_DE'
with app.test_request_context():
with babel.force_locale('en_US'):
assert str(babel.get_locale()) == 'en_US'
babel.refresh()
assert str(babel.get_locale()) == 'en_US'
# -*- coding: utf-8 -*-
from __future__ import with_statement
import flask
import flask_babel as babel
from flask_babel import gettext, lazy_gettext, lazy_ngettext, ngettext
def test_basics():
app = flask.Flask(__name__)
babel.Babel(app, default_locale='de_DE')
with app.test_request_context():
assert gettext(u'Hello %(name)s!', name='Peter') == 'Hallo Peter!'
assert ngettext(u'%(num)s Apple', u'%(num)s Apples', 3) == \
u'3 Äpfel'
assert ngettext(u'%(num)s Apple', u'%(num)s Apples', 1) == \
u'1 Apfel'
def test_template_basics():
app = flask.Flask(__name__)
babel.Babel(app, default_locale='de_DE')
t = lambda x: flask.render_template_string('{{ %s }}' % x)
with app.test_request_context():
assert t("gettext('Hello %(name)s!', name='Peter')") == \
u'Hallo Peter!'
assert t("ngettext('%(num)s Apple', '%(num)s Apples', 3)") == \
u'3 Äpfel'
assert t("ngettext('%(num)s Apple', '%(num)s Apples', 1)") == \
u'1 Apfel'
assert flask.render_template_string('''
{% trans %}Hello {{ name }}!{% endtrans %}
''', name='Peter').strip() == 'Hallo Peter!'
assert flask.render_template_string('''
{% trans num=3 %}{{ num }} Apple
{%- pluralize %}{{ num }} Apples{% endtrans %}
''', name='Peter').strip() == u'3 Äpfel'
def test_lazy_gettext():
app = flask.Flask(__name__)
babel.Babel(app, default_locale='de_DE')
yes = lazy_gettext(u'Yes')
with app.test_request_context():
assert str(yes) == 'Ja'
assert yes.__html__() == 'Ja'
app.config['BABEL_DEFAULT_LOCALE'] = 'en_US'
with app.test_request_context():
assert str(yes) == 'Yes'
assert yes.__html__() == 'Yes'
def test_lazy_ngettext():
app = flask.Flask(__name__)
babel.Babel(app, default_locale='de_DE')
one_apple = lazy_ngettext(u'%(num)s Apple', u'%(num)s Apples', 1)
with app.test_request_context():
assert str(one_apple) == '1 Apfel'
assert one_apple.__html__() == '1 Apfel'
two_apples = lazy_ngettext(u'%(num)s Apple', u'%(num)s Apples', 2)
with app.test_request_context():
assert str(two_apples) == u'2 Äpfel'
assert two_apples.__html__() == u'2 Äpfel'
def test_lazy_gettext_defaultdomain():
app = flask.Flask(__name__)
b = babel.Babel(app, default_locale='de_DE', default_domain='test')
first = lazy_gettext('first')
with app.test_request_context():
assert str(first) == 'erste'
app.config['BABEL_DEFAULT_LOCALE'] = 'en_US'
with app.test_request_context():
assert str(first) == 'first'
def test_list_translations():
app = flask.Flask(__name__)
b = babel.Babel(app, default_locale='de_DE')
translations = b.list_translations()
assert len(translations) == 1
assert str(translations[0]) == 'de'
def test_no_formatting():
"""
Ensure we don't format strings unless a variable is passed.
"""
app = flask.Flask(__name__)
babel.Babel(app)
with app.test_request_context():
assert gettext(u'Test %s') == u'Test %s'
assert gettext(u'Test %(name)s', name=u'test') == u'Test test'
assert gettext(u'Test %s') % 'test' == u'Test test'
def test_domain():
app = flask.Flask(__name__)
b = babel.Babel(app, default_locale='de_DE')
domain = babel.Domain(domain='test')
with app.test_request_context():
assert domain.gettext('first') == 'erste'
assert babel.gettext('first') == 'first'
def test_as_default():
app = flask.Flask(__name__)
b = babel.Babel(app, default_locale='de_DE')
domain = babel.Domain(domain='test')
with app.test_request_context():
assert babel.gettext('first') == 'first'
domain.as_default()
assert babel.gettext('first') == 'erste'
def test_default_domain():
app = flask.Flask(__name__)
b = babel.Babel(app, default_locale='de_DE', default_domain='test')
with app.test_request_context():
assert babel.gettext('first') == 'erste'
def test_multiple_apps():
app1 = flask.Flask(__name__)
b1 = babel.Babel(app1, default_locale='de_DE')
app2 = flask.Flask(__name__)
b2 = babel.Babel(app2, default_locale='de_DE')
with app1.test_request_context() as ctx:
assert babel.gettext('Yes') == 'Ja'
assert ('de_DE', 'messages') in b1.domain_instance.get_translations_cache(ctx)
with app2.test_request_context() as ctx:
assert 'de_DE', 'messages' not in b2.domain_instance.get_translations_cache(ctx)
def test_cache(mocker):
load_mock = mocker.patch(
"babel.support.Translations.load", side_effect=babel.support.Translations.load
)
app = flask.Flask(__name__)
b = babel.Babel(app, default_locale="de_DE")
@b.localeselector
def select_locale():
return the_locale
# first request, should load en_US
the_locale = "en_US"
with app.test_request_context() as ctx:
assert b.domain_instance.get_translations_cache(ctx) == {}
assert babel.gettext("Yes") == "Yes"
assert load_mock.call_count == 1
# second request, should use en_US from cache
with app.test_request_context() as ctx:
assert set(b.domain_instance.get_translations_cache(ctx)) == {
("en_US", "messages")
}
assert babel.gettext("Yes") == "Yes"
assert load_mock.call_count == 1
# third request, should load de_DE from cache
the_locale = "de_DE"
with app.test_request_context() as ctx:
assert set(b.domain_instance.get_translations_cache(ctx)) == {
("en_US", "messages")
}
assert babel.gettext("Yes") == "Ja"
assert load_mock.call_count == 2
# now everything is cached, so no more loads should happen!
the_locale = "en_US"
with app.test_request_context() as ctx:
assert set(b.domain_instance.get_translations_cache(ctx)) == {
("en_US", "messages"),
("de_DE", "messages"),
}
assert babel.gettext("Yes") == "Yes"
assert load_mock.call_count == 2
the_locale = "de_DE"
with app.test_request_context() as ctx:
assert set(b.domain_instance.get_translations_cache(ctx)) == {
("en_US", "messages"),
("de_DE", "messages"),
}
assert babel.gettext("Yes") == "Ja"
assert load_mock.call_count == 2
# -*- coding: utf-8 -*-
from __future__ import with_statement
import pickle
import flask
from babel.support import NullTranslations
import flask_babel as babel
from flask_babel import get_translations, gettext, lazy_gettext
def test_no_request_context():
b = babel.Babel()
app = flask.Flask(__name__)
b.init_app(app)
with app.app_context():
assert isinstance(get_translations(), NullTranslations)
def test_multiple_directories():
"""
Ensure we can load translations from multiple directories.
"""
b = babel.Babel()
app = flask.Flask(__name__)
app.config.update({
'BABEL_TRANSLATION_DIRECTORIES': ';'.join((
'translations',
'renamed_translations'
)),
'BABEL_DEFAULT_LOCALE': 'de_DE'
})
b.init_app(app)
with app.test_request_context():
translations = b.list_translations()
assert(len(translations) == 2)
assert(str(translations[0]) == 'de')
assert(str(translations[1]) == 'de')
assert gettext(
u'Hello %(name)s!',
name='Peter'
) == 'Hallo Peter!'
def test_multiple_directories_different_domain():
"""
Ensure we can load translations from multiple directories with a
custom domain.
"""
b = babel.Babel()
app = flask.Flask(__name__)
app.config.update({
'BABEL_TRANSLATION_DIRECTORIES': ';'.join((
'translations_different_domain',
'renamed_translations'
)),
'BABEL_DEFAULT_LOCALE': 'de_DE',
'BABEL_DOMAIN': 'myapp'
})
b.init_app(app)
with app.test_request_context():
translations = b.list_translations()
assert(len(translations) == 2)
assert(str(translations[0]) == 'de')
assert(str(translations[1]) == 'de')
assert gettext(
u'Hello %(name)s!',
name='Peter'
) == 'Hallo Peter!'
assert gettext(u'Good bye') == 'Auf Wiedersehen'
def test_different_domain():
"""
Ensure we can load translations from multiple directories.
"""
b = babel.Babel()
app = flask.Flask(__name__)
app.config.update({
'BABEL_TRANSLATION_DIRECTORIES': 'translations_different_domain',
'BABEL_DEFAULT_LOCALE': 'de_DE',
'BABEL_DOMAIN': 'myapp'
})
b.init_app(app)
with app.test_request_context():
translations = b.list_translations()
assert(len(translations) == 1)
assert(str(translations[0]) == 'de')
assert gettext(u'Good bye') == 'Auf Wiedersehen'
def test_lazy_old_style_formatting():
lazy_string = lazy_gettext(u'Hello %(name)s')
assert lazy_string % {u'name': u'test'} == u'Hello test'
lazy_string = lazy_gettext(u'test')
assert u'Hello %s' % lazy_string == u'Hello test'
def test_lazy_pickling():
lazy_string = lazy_gettext(u'Foo')
pickled = pickle.dumps(lazy_string)
unpickled = pickle.loads(pickled)
assert unpickled == lazy_string
# -*- coding: utf-8 -*-
from __future__ import with_statement
from decimal import Decimal
import flask
import flask_babel as babel
def test_basics():
app = flask.Flask(__name__)
babel.Babel(app)
n = 1099
with app.test_request_context():
assert babel.format_number(n) == u'1,099'
assert babel.format_decimal(Decimal('1010.99')) == u'1,010.99'
assert babel.format_currency(n, 'USD') == '$1,099.00'
assert babel.format_percent(0.19) == '19%'
assert babel.format_scientific(10000) == u'1E4'
# German translations for PROJECT.
# Copyright (C) 2010 ORGANIZATION
# This file is distributed under the same license as the PROJECT project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2010.
#
msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2010-05-29 17:00+0200\n"
"PO-Revision-Date: 2010-05-30 12:56+0200\n"
"Last-Translator: Armin Ronacher <armin.ronacher@active-4.com>\n"
"Language-Team: de <LL@li.org>\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 0.9.5\n"
#: tests.py:94
#, python-format
msgid "Hello %(name)s!"
msgstr "Hallo %(name)s!"
#: tests.py:95 tests.py:96
#, python-format
msgid "%(num)s Apple"
msgid_plural "%(num)s Apples"
msgstr[0] "%(num)s Apfel"
msgstr[1] "%(num)s Äpfel"
#: tests.py:119
msgid "Yes"
msgstr "Ja"
# Translations template for PROJECT.
# Copyright (C) 2010 ORGANIZATION
# This file is distributed under the same license as the PROJECT project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2010.
#
msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2010-05-30 12:56+0200\n"
"PO-Revision-Date: 2012-04-11 15:18+0200\n"
"Last-Translator: Serge S. Koval <serge.koval+github@gmail.com>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 0.9.5\n"
#: tests.py:94
#, python-format
msgid "first"
msgstr "erste"
# Translations template for PROJECT.
# Copyright (C) 2010 ORGANIZATION
# This file is distributed under the same license as the PROJECT project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2010.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2010-05-30 12:56+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 0.9.5\n"
#: tests.py:94
#, python-format
msgid "Hello %(name)s!"
msgstr ""
#: tests.py:95 tests.py:96
#, python-format
msgid "%(num)s Apple"
msgid_plural "%(num)s Apples"
msgstr[0] ""
msgstr[1] ""
#: tests.py:119
msgid "Yes"
msgstr ""
# German translations for PROJECT.
# Copyright (C) 2010 ORGANIZATION
# This file is distributed under the same license as the PROJECT project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2010.
#
msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2010-05-29 17:00+0200\n"
"PO-Revision-Date: 2010-05-30 12:56+0200\n"
"Last-Translator: Armin Ronacher <armin.ronacher@active-4.com>\n"
"Language-Team: de <LL@li.org>\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 0.9.5\n"
#: tests.py:94
#, python-format
msgid "Hello %(name)s!"
msgstr "Hallo %(name)s!"
#: tests.py:95 tests.py:96
#, python-format
msgid "%(num)s Apple"
msgid_plural "%(num)s Apples"
msgstr[0] "%(num)s Apfel"
msgstr[1] "%(num)s Äpfel"
#: tests.py:119
msgid "Yes"
msgstr "Ja"
msgid "Good bye"
msgstr "Auf Wiedersehen"
# Translations template for PROJECT.
# Copyright (C) 2010 ORGANIZATION
# This file is distributed under the same license as the PROJECT project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2010.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2010-05-30 12:56+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 0.9.5\n"
#: tests.py:94
#, python-format
msgid "Hello %(name)s!"
msgstr ""
#: tests.py:95 tests.py:96
#, python-format
msgid "%(num)s Apple"
msgid_plural "%(num)s Apples"
msgstr[0] ""
msgstr[1] ""
#: tests.py:119
msgid "Yes"
msgstr ""
msgid "Good bye"
msgstr ""
此文件类型无法预览
==========
Change log
==========
6.1 (14 January 2019)
=====================
- Fix short chunks of data not being optimized to the correct mode.
- Tests fixed for Python 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.
* Avoid unnecessary dependency for non MS platforms, thanks to Noah Vesely.
* Make ``BaseImage.get_image()`` actually work.
5.2 (25 Jan 2016)
=================
* Add ``--error-correction`` option to qr script.
* Fix script piping to stdout in Python 3 and reading non-UTF-8 characters in
Python 3.
* Fix script piping in Windows.
* Add some useful behind-the-curtain methods for tinkerers.
* Fix terminal output when using Python 2.6
* Fix terminal output to display correctly on MS command line.
5.2.1
-----
* Small fix to terminal output in Python 3 (and fix tests)
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.
5.1 (22 Oct 2014)
=================
* Make ``qr`` script work in Windows. Thanks Ionel Cristian Mărieș
* Fixed print_ascii function in Python 3.
* Out-of-bounds code version numbers are handled more consistently with a
ValueError.
* Much better test coverage (now only officially supporting Python 2.6+)
5.0 (17 Jun 2014)
=================
* Speed optimizations.
* Change the output when using the ``qr`` script to use ASCII rather than
just colors, better using the terminal real estate.
* Fix a bug in passing bytecode data directly when in Python 3.
* Substation speed optimizations to best-fit algorithm (thanks Jacob Welsh!).
* Introduce a ``print_ascii`` method and use it as the default for the ``qr``
script rather than ``print_tty``.
5.0.1
-----
* Update version numbers correctly.
4.0 (4 Sep 2013)
================
* Made qrcode work on Python 2.4 - Thanks tcely.
Note: officially, qrcode only supports 2.5+.
* Support pure-python PNG generation (via pymaging) for Python 2.6+ -- thanks
Adam Wisniewski!
* SVG image generation now supports alternate sizing (the default box size of
10 == 1mm per rectangle).
* SVG path image generation allows cleaner SVG output by combining all QR rects
into a single path. Thank you, Viktor Stískala.
* Added some extra simple SVG factories that fill the background white.
4.0.1
-----
* Fix the pymaging backend not able to save the image to a buffer. Thanks ilj!
4.0.2
-----
* Fix incorrect regex causing a comma to be considered part of the alphanumeric
set.
* Switch to using setuptools for setup.py.
4.0.3
-----
* Fix bad QR code generation due to the regex comma fix in version 4.0.2.
4.0.4
-----
* Bad version number for previous hotfix release.
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
(even if others wern't). Also, the two characters ``{`` and ``}`` had snuck
in as valid characters. Thanks to Eran Tromer for the report and fix.
* 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.
3.1.1
-----
* Update change log to contain version 3.1 changes. :P
* Give the ``qr`` script an ``--optimize`` argument to control the chunk
optimization setting.
3.0 (25 Jun 2013)
=================
* Python 3 support.
* Add QRCode.get_matrix, an easy way to get the matrix array of a QR code
including the border. Thanks Hugh Rawlinson.
* Add in a workaround so that Python 2.6 users can use SVG generation (they
must install ``lxml``).
* Some initial tests! And tox support (``pip install tox``) for testing across
Python platforms.
2.7 (5 Mar 2013)
================
* Fix incorrect termination padding.
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.
* Fix strings within 4 bits of the QR version limit being incorrectly
terminated. Thanks to zhjie231 for the report.
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.
2.5.1
-----
* Fix installation error on Windows.
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.
2.4.1
-----
* Fix a packaging issue
2.4.2
-----
* Added a ``show`` method to the PIL image wrapper so the ``run_example``
function actually works.
2.3 (29 Jan 2012)
=================
* When adding data, auto-select the more efficient encoding methods for numbers
and alphanumeric data (KANJI still not supported).
2.3.1
-----
* Encode unicode to utf-8 bytestrings when adding data to a QRCode.
2.2 (18 Jan 2012)
=================
* Fixed tty output to work on both white and black backgrounds.
* Added `border` parameter to allow customizing of the number of boxes used to
create the border of the QR code
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.
Copyright (c) 2011, Lincoln Loop
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the package name nor the names of its contributors may be
used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-------------------------------------------------------------------------------
Original text and license from the pyqrnative package where this was forked
from (http://code.google.com/p/pyqrnative):
#Ported from the Javascript library by Sam Curren
#
#QRCode for Javascript
#http://d-project.googlecode.com/svn/trunk/misc/qrcode/js/qrcode.js
#
#Copyright (c) 2009 Kazuhiko Arase
#
#URL: http://www.d-project.com/
#
#Licensed under the MIT license:
# http://www.opensource.org/licenses/mit-license.php
#
# The word "QR Code" is registered trademark of
# DENSO WAVE INCORPORATED
# http://www.denso-wave.com/qrcode/faqpatent-e.html
include *.rst
include LICENSE
include signing-key.asc
include tox.ini
include doc/qr.1
Packaging quick reminder
========================
Ensure version numbers in ``setup.py`` and ``doc/qr.1`` have been updated.
1. Check twine and wheel are up to date::
pip install --upgrade twine wheel
2. Delete contents of ``dist/``::
rm -r dist
3. Package it up::
python setup.py sdist bdist_wheel
4. Sign it::
gpg --detach-sign -a dist/*.gz
gpg --detach-sign -a dist/*.whl
5. Upload it::
twine upload dist/*
此文件的差异被折叠, 点击展开。
=============================
Pure python QR Code generator
=============================
Generate QR codes.
For a standard install (which will include pillow_ for generating images),
run::
pip install qrcode[pil]
.. _pillow: https://pypi.python.org/pypi/Pillow
What is a QR Code?
==================
A Quick Response code is a two-dimensional pictographic code used for its fast
readability and comparatively large storage capacity. The code consists of
black modules arranged in a square pattern on a white background. The
information encoded can be made up of any kind of data (e.g., binary,
alphanumeric, or Kanji symbols)
Usage
=====
From the command line, use the installed ``qr`` script::
qr "Some text" > test.png
Or in Python, use the ``make`` shortcut function:
.. code:: python
import qrcode
img = qrcode.make('Some data here')
Advanced Usage
--------------
For more control, use the ``QRCode`` class. For example:
.. code:: python
import qrcode
qr = qrcode.QRCode(
version=1,
error_correction=qrcode.constants.ERROR_CORRECT_L,
box_size=10,
border=4,
)
qr.add_data('Some data')
qr.make(fit=True)
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:
``ERROR_CORRECT_L``
About 7% or less errors can be corrected.
``ERROR_CORRECT_M`` (default)
About 15% or less errors can be corrected.
``ERROR_CORRECT_Q``
About 25% or less errors can be corrected.
``ERROR_CORRECT_H``.
About 30% or less errors can be corrected.
The ``box_size`` parameter controls how many pixels each "box" of the QR code
is.
The ``border`` parameter controls how many boxes thick the border should be
(the default is 4, which is the minimum according to the specs).
Other image factories
=====================
You can encode as SVG, or use a new pure Python image processor to encode to
PNG images.
The Python examples below use the ``make`` shortcut. The same ``image_factory``
keyword argument is a valid option for the ``QRCode`` class for more advanced
usage.
SVG
---
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.
From your command line::
qr --factory=svg-path "Some text" > test.svg
qr --factory=svg "Some text" > test.svg
qr --factory=svg-fragment "Some text" > test.svg
Or in Python:
.. code:: python
import qrcode
import qrcode.image.svg
if method == 'basic':
# Simple factory, just a set of rects.
factory = qrcode.image.svg.SvgImage
elif method == 'fragment':
# Fragment factory (also just a set of rects)
factory = qrcode.image.svg.SvgFragmentImage
else:
# Combined path factory, fixes white space that may occur when zooming
factory = qrcode.image.svg.SvgPathImage
img = qrcode.make('Some data here', image_factory=factory)
Two other related factories are available that work the same, but also fill the
background of the SVG with white::
qrcode.image.svg.SvgFillImage
qrcode.image.svg.SvgPathFillImage
Pure Python PNG
---------------
Install the following two packages::
pip install git+git://github.com/ojii/pymaging.git#egg=pymaging
pip install git+git://github.com/ojii/pymaging-png.git#egg=pymaging-png
From your command line::
qr --factory=pymaging "Some text" > test.png
Or in Python:
.. code:: python
import qrcode
from qrcode.image.pure import PymagingImage
img = qrcode.make('Some data here', image_factory=PymagingImage)
Testing
=======
First, install tox into your virtualenv::
pip install --upgrade tox
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``.
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::
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 py36``
# 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]
}
from qrcode.main import QRCode
from qrcode.main import make # noqa
from qrcode.constants import ( # noqa
ERROR_CORRECT_L, ERROR_CORRECT_M, ERROR_CORRECT_Q, ERROR_CORRECT_H)
from qrcode import image # noqa
def run_example(data="http://www.lincolnloop.com", *args, **kwargs):
"""
Build an example QR Code and display it.
There's an even easier way than the code here though: just use the ``make``
shortcut.
"""
qr = QRCode(*args, **kwargs)
qr.add_data(data)
im = qr.make_image()
im.show()
if __name__ == '__main__': # pragma: no cover
import sys
run_example(*sys.argv[1:])
from qrcode import constants
EXP_TABLE = list(range(256))
LOG_TABLE = list(range(256))
for i in range(8):
EXP_TABLE[i] = 1 << i
for i in range(8, 256):
EXP_TABLE[i] = (
EXP_TABLE[i - 4] ^ EXP_TABLE[i - 5] ^ EXP_TABLE[i - 6] ^
EXP_TABLE[i - 8])
for i in range(255):
LOG_TABLE[EXP_TABLE[i]] = i
RS_BLOCK_OFFSET = {
constants.ERROR_CORRECT_L: 0,
constants.ERROR_CORRECT_M: 1,
constants.ERROR_CORRECT_Q: 2,
constants.ERROR_CORRECT_H: 3,
}
RS_BLOCK_TABLE = [
# L
# M
# Q
# H
# 1
[1, 26, 19],
[1, 26, 16],
[1, 26, 13],
[1, 26, 9],
# 2
[1, 44, 34],
[1, 44, 28],
[1, 44, 22],
[1, 44, 16],
# 3
[1, 70, 55],
[1, 70, 44],
[2, 35, 17],
[2, 35, 13],
# 4
[1, 100, 80],
[2, 50, 32],
[2, 50, 24],
[4, 25, 9],
# 5
[1, 134, 108],
[2, 67, 43],
[2, 33, 15, 2, 34, 16],
[2, 33, 11, 2, 34, 12],
# 6
[2, 86, 68],
[4, 43, 27],
[4, 43, 19],
[4, 43, 15],
# 7
[2, 98, 78],
[4, 49, 31],
[2, 32, 14, 4, 33, 15],
[4, 39, 13, 1, 40, 14],
# 8
[2, 121, 97],
[2, 60, 38, 2, 61, 39],
[4, 40, 18, 2, 41, 19],
[4, 40, 14, 2, 41, 15],
# 9
[2, 146, 116],
[3, 58, 36, 2, 59, 37],
[4, 36, 16, 4, 37, 17],
[4, 36, 12, 4, 37, 13],
# 10
[2, 86, 68, 2, 87, 69],
[4, 69, 43, 1, 70, 44],
[6, 43, 19, 2, 44, 20],
[6, 43, 15, 2, 44, 16],
# 11
[4, 101, 81],
[1, 80, 50, 4, 81, 51],
[4, 50, 22, 4, 51, 23],
[3, 36, 12, 8, 37, 13],
# 12
[2, 116, 92, 2, 117, 93],
[6, 58, 36, 2, 59, 37],
[4, 46, 20, 6, 47, 21],
[7, 42, 14, 4, 43, 15],
# 13
[4, 133, 107],
[8, 59, 37, 1, 60, 38],
[8, 44, 20, 4, 45, 21],
[12, 33, 11, 4, 34, 12],
# 14
[3, 145, 115, 1, 146, 116],
[4, 64, 40, 5, 65, 41],
[11, 36, 16, 5, 37, 17],
[11, 36, 12, 5, 37, 13],
# 15
[5, 109, 87, 1, 110, 88],
[5, 65, 41, 5, 66, 42],
[5, 54, 24, 7, 55, 25],
[11, 36, 12, 7, 37, 13],
# 16
[5, 122, 98, 1, 123, 99],
[7, 73, 45, 3, 74, 46],
[15, 43, 19, 2, 44, 20],
[3, 45, 15, 13, 46, 16],
# 17
[1, 135, 107, 5, 136, 108],
[10, 74, 46, 1, 75, 47],
[1, 50, 22, 15, 51, 23],
[2, 42, 14, 17, 43, 15],
# 18
[5, 150, 120, 1, 151, 121],
[9, 69, 43, 4, 70, 44],
[17, 50, 22, 1, 51, 23],
[2, 42, 14, 19, 43, 15],
# 19
[3, 141, 113, 4, 142, 114],
[3, 70, 44, 11, 71, 45],
[17, 47, 21, 4, 48, 22],
[9, 39, 13, 16, 40, 14],
# 20
[3, 135, 107, 5, 136, 108],
[3, 67, 41, 13, 68, 42],
[15, 54, 24, 5, 55, 25],
[15, 43, 15, 10, 44, 16],
# 21
[4, 144, 116, 4, 145, 117],
[17, 68, 42],
[17, 50, 22, 6, 51, 23],
[19, 46, 16, 6, 47, 17],
# 22
[2, 139, 111, 7, 140, 112],
[17, 74, 46],
[7, 54, 24, 16, 55, 25],
[34, 37, 13],
# 23
[4, 151, 121, 5, 152, 122],
[4, 75, 47, 14, 76, 48],
[11, 54, 24, 14, 55, 25],
[16, 45, 15, 14, 46, 16],
# 24
[6, 147, 117, 4, 148, 118],
[6, 73, 45, 14, 74, 46],
[11, 54, 24, 16, 55, 25],
[30, 46, 16, 2, 47, 17],
# 25
[8, 132, 106, 4, 133, 107],
[8, 75, 47, 13, 76, 48],
[7, 54, 24, 22, 55, 25],
[22, 45, 15, 13, 46, 16],
# 26
[10, 142, 114, 2, 143, 115],
[19, 74, 46, 4, 75, 47],
[28, 50, 22, 6, 51, 23],
[33, 46, 16, 4, 47, 17],
# 27
[8, 152, 122, 4, 153, 123],
[22, 73, 45, 3, 74, 46],
[8, 53, 23, 26, 54, 24],
[12, 45, 15, 28, 46, 16],
# 28
[3, 147, 117, 10, 148, 118],
[3, 73, 45, 23, 74, 46],
[4, 54, 24, 31, 55, 25],
[11, 45, 15, 31, 46, 16],
# 29
[7, 146, 116, 7, 147, 117],
[21, 73, 45, 7, 74, 46],
[1, 53, 23, 37, 54, 24],
[19, 45, 15, 26, 46, 16],
# 30
[5, 145, 115, 10, 146, 116],
[19, 75, 47, 10, 76, 48],
[15, 54, 24, 25, 55, 25],
[23, 45, 15, 25, 46, 16],
# 31
[13, 145, 115, 3, 146, 116],
[2, 74, 46, 29, 75, 47],
[42, 54, 24, 1, 55, 25],
[23, 45, 15, 28, 46, 16],
# 32
[17, 145, 115],
[10, 74, 46, 23, 75, 47],
[10, 54, 24, 35, 55, 25],
[19, 45, 15, 35, 46, 16],
# 33
[17, 145, 115, 1, 146, 116],
[14, 74, 46, 21, 75, 47],
[29, 54, 24, 19, 55, 25],
[11, 45, 15, 46, 46, 16],
# 34
[13, 145, 115, 6, 146, 116],
[14, 74, 46, 23, 75, 47],
[44, 54, 24, 7, 55, 25],
[59, 46, 16, 1, 47, 17],
# 35
[12, 151, 121, 7, 152, 122],
[12, 75, 47, 26, 76, 48],
[39, 54, 24, 14, 55, 25],
[22, 45, 15, 41, 46, 16],
# 36
[6, 151, 121, 14, 152, 122],
[6, 75, 47, 34, 76, 48],
[46, 54, 24, 10, 55, 25],
[2, 45, 15, 64, 46, 16],
# 37
[17, 152, 122, 4, 153, 123],
[29, 74, 46, 14, 75, 47],
[49, 54, 24, 10, 55, 25],
[24, 45, 15, 46, 46, 16],
# 38
[4, 152, 122, 18, 153, 123],
[13, 74, 46, 32, 75, 47],
[48, 54, 24, 14, 55, 25],
[42, 45, 15, 32, 46, 16],
# 39
[20, 147, 117, 4, 148, 118],
[40, 75, 47, 7, 76, 48],
[43, 54, 24, 22, 55, 25],
[10, 45, 15, 67, 46, 16],
# 40
[19, 148, 118, 6, 149, 119],
[18, 75, 47, 31, 76, 48],
[34, 54, 24, 34, 55, 25],
[20, 45, 15, 61, 46, 16]
]
def glog(n):
if n < 1: # pragma: no cover
raise ValueError("glog(%s)" % n)
return LOG_TABLE[n]
def gexp(n):
return EXP_TABLE[n % 255]
class Polynomial:
def __init__(self, num, shift):
if not num: # pragma: no cover
raise Exception("%s/%s" % (len(num), shift))
for offset in range(len(num)):
if num[offset] != 0:
break
else:
offset += 1
self.num = num[offset:] + [0] * shift
def __getitem__(self, index):
return self.num[index]
def __iter__(self):
return iter(self.num)
def __len__(self):
return len(self.num)
def __mul__(self, other):
num = [0] * (len(self) + len(other) - 1)
for i, item in enumerate(self):
for j, other_item in enumerate(other):
num[i + j] ^= gexp(glog(item) + glog(other_item))
return Polynomial(num, 0)
def __mod__(self, other):
difference = len(self) - len(other)
if difference < 0:
return self
ratio = glog(self[0]) - glog(other[0])
num = [
item ^ gexp(glog(other_item) + ratio)
for item, other_item in zip(self, other)]
if difference:
num.extend(self[-difference:])
# recursive call
return Polynomial(num, 0) % other
class RSBlock:
def __init__(self, total_count, data_count):
self.total_count = total_count
self.data_count = data_count
def rs_blocks(version, error_correction):
if error_correction not in RS_BLOCK_OFFSET: # pragma: no cover
raise Exception(
"bad rs block @ version: %s / error_correction: %s" %
(version, error_correction))
offset = RS_BLOCK_OFFSET[error_correction]
rs_block = RS_BLOCK_TABLE[(version - 1) * 4 + offset]
blocks = []
for i in range(0, len(rs_block), 3):
count, total_count, data_count = rs_block[i:i + 3]
for j in range(count):
blocks.append(RSBlock(total_count, data_count))
return blocks
#!/usr/bin/env python
"""
qr - Convert stdin (or the first argument) to a QR Code.
When stdout is a tty the QR Code is printed to the terminal and when stdout is
a pipe to a file an image is written. The default image format is PNG.
"""
import sys
import optparse
import os
import qrcode
# The next block is added to get the terminal to display properly on MS platforms
if sys.platform.startswith(('win', 'cygwin')):
import colorama
colorama.init()
default_factories = {
'pil': 'qrcode.image.pil.PilImage',
'pymaging': 'qrcode.image.pure.PymagingImage',
'svg': 'qrcode.image.svg.SvgImage',
'svg-fragment': 'qrcode.image.svg.SvgFragmentImage',
'svg-path': 'qrcode.image.svg.SvgPathImage',
}
error_correction = {
'L': qrcode.ERROR_CORRECT_L,
'M': qrcode.ERROR_CORRECT_M,
'Q': qrcode.ERROR_CORRECT_Q,
'H': qrcode.ERROR_CORRECT_H,
}
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 "
"built-in image factory classes: {0}.".format(
", ".join(sorted(default_factories.keys()))))
parser.add_option(
"--optimize", type=int, help="Optimize the data by looking for chunks "
"of at least this many characters that could use a more efficient "
"encoding method. Use 0 to turn off chunk optimization.")
parser.add_option(
"--error-correction", type='choice',
choices=sorted(error_correction.keys()), default='M',
help="The error correction level to use. Choices are L (7%), "
"M (15%, default), Q (25%), and H (30%).")
opts, args = parser.parse_args(args)
qr = qrcode.QRCode(
error_correction=error_correction[opts.error_correction])
if opts.factory:
module = default_factories.get(opts.factory, opts.factory)
if '.' not in module:
parser.error("The image factory is not a full python path")
module, name = module.rsplit('.', 1)
imp = __import__(module, {}, [], [name])
image_factory = getattr(imp, name)
else:
image_factory = None
if args:
data = args[0]
else:
# Use sys.stdin.buffer if available (Python 3) avoiding
# UnicodeDecodeErrors.
stdin_buffer = getattr(sys.stdin, 'buffer', sys.stdin)
data = stdin_buffer.read()
if opts.optimize is None:
qr.add_data(data)
else:
qr.add_data(data, optimize=opts.optimize)
if image_factory is None and os.isatty(sys.stdout.fileno()):
qr.print_ascii(tty=True)
return
img = qr.make_image(image_factory=image_factory)
sys.stdout.flush()
# Use sys.stdout.buffer if available (Python 3), avoiding
# UnicodeDecodeErrors.
stdout_buffer = getattr(sys.stdout, 'buffer', None)
if not stdout_buffer:
if sys.platform == 'win32': # pragma: no cover
import msvcrt
msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
stdout_buffer = sys.stdout
img.save(stdout_buffer)
if __name__ == "__main__":
main()
# QR error correct levels
ERROR_CORRECT_L = 1
ERROR_CORRECT_M = 0
ERROR_CORRECT_Q = 3
ERROR_CORRECT_H = 2
class DataOverflowError(Exception):
pass
class BaseImage(object):
"""
Base QRCode image output class.
"""
kind = None
allowed_kinds = None
def __init__(self, border, width, box_size, *args, **kwargs):
self.border = border
self.width = width
self.box_size = box_size
self.pixel_size = (self.width + self.border*2) * self.box_size
self._img = self.new_image(**kwargs)
def drawrect(self, row, col):
"""
Draw a single rectangle of the QR code.
"""
raise NotImplementedError("BaseImage.drawrect")
def save(self, stream, kind=None):
"""
Save the image file.
"""
raise NotImplementedError("BaseImage.save")
def pixel_box(self, row, col):
"""
A helper method for pixel-based image generators that specifies the
four pixel coordinates for a single rect.
"""
x = (col + self.border) * self.box_size
y = (row + self.border) * self.box_size
return [(x, y), (x + self.box_size - 1, y + self.box_size - 1)]
def new_image(self, **kwargs): # pragma: no cover
"""
Build the image class. Subclasses should return the class created.
"""
return None
def get_image(self, **kwargs):
"""
Return the image class for further processing.
"""
return self._img
def check_kind(self, kind, transform=None):
"""
Get the image type.
"""
if kind is None:
kind = self.kind
allowed = not self.allowed_kinds or kind in self.allowed_kinds
if transform:
kind = transform(kind)
if not allowed:
allowed = kind in self.allowed_kinds
if not allowed:
raise ValueError(
"Cannot set %s type to %s" % (type(self).__name__, kind))
return kind
# Needed on case-insensitive filesystems
from __future__ import absolute_import
# Try to import PIL in either of the two ways it can be installed.
try:
from PIL import Image, ImageDraw
except ImportError: # pragma: no cover
import Image
import ImageDraw
import qrcode.image.base
class PilImage(qrcode.image.base.BaseImage):
"""
PIL image builder, default format is PNG.
"""
kind = "PNG"
def new_image(self, **kwargs):
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":
mode = "RGBA"
back_color = None
else:
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
self._idr = ImageDraw.Draw(img)
return img
def drawrect(self, row, col):
box = self.pixel_box(row, col)
self._idr.rectangle(box, fill=self.fill_color)
def save(self, stream, format=None, **kwargs):
if format is None:
format = kwargs.get("kind", self.kind)
if "kind" in kwargs:
del kwargs["kind"]
self._img.save(stream, format=format, **kwargs)
def __getattr__(self, name):
return getattr(self._img, name)
from pymaging import Image
from pymaging.colors import RGB
from pymaging.formats import registry
from pymaging.shapes import Line
from pymaging.webcolors import Black, White
from pymaging_png.png import PNG
import qrcode.image.base
class PymagingImage(qrcode.image.base.BaseImage):
"""
pymaging image builder, default format is PNG.
"""
kind = "PNG"
allowed_kinds = ("PNG",)
def __init__(self, *args, **kwargs):
"""
Register PNG with pymaging.
"""
registry.formats = []
registry.names = {}
registry._populate()
registry.register(PNG)
super(PymagingImage, self).__init__(*args, **kwargs)
def new_image(self, **kwargs):
return Image.new(RGB, self.pixel_size, self.pixel_size, White)
def drawrect(self, row, col):
(x, y), (x2, y2) = self.pixel_box(row, col)
for r in range(self.box_size):
line_y = y + r
line = Line(x, line_y, x2, line_y)
self._img.draw(line, Black)
def save(self, stream, kind=None):
self._img.save(stream, self.check_kind(kind))
def check_kind(self, kind, transform=None, **kwargs):
"""
pymaging (pymaging_png at least) uses lower case for the type.
"""
if transform is None:
transform = lambda x: x.lower()
return super(PymagingImage, self).check_kind(
kind, transform=transform, **kwargs)
from decimal import Decimal
# On Python 2.6 must install lxml since the older xml.etree.ElementTree
# version can not be used to create SVG images.
try:
import lxml.etree as ET
except ImportError:
import xml.etree.ElementTree as ET
import qrcode.image.base
class SvgFragmentImage(qrcode.image.base.BaseImage):
"""
SVG image builder
Creates a QR-code image as a SVG document fragment.
"""
_SVG_namespace = "http://www.w3.org/2000/svg"
kind = "SVG"
allowed_kinds = ("SVG",)
def __init__(self, *args, **kwargs):
ET.register_namespace("svg", self._SVG_namespace)
super(SvgFragmentImage, self).__init__(*args, **kwargs)
# Save the unit size, for example the default box_size of 10 is '1mm'.
self.unit_size = self.units(self.box_size)
def drawrect(self, row, col):
self._img.append(self._rect(row, col))
def units(self, pixels, text=True):
"""
A box_size of 10 (default) equals 1mm.
"""
units = Decimal(pixels) / 10
if not text:
return units
return '%smm' % units
def save(self, stream, kind=None):
self.check_kind(kind=kind)
self._write(stream)
def new_image(self, **kwargs):
return self._svg()
def _svg(self, tag=None, version='1.1', **kwargs):
if tag is None:
tag = ET.QName(self._SVG_namespace, "svg")
dimension = self.units(self.pixel_size)
return ET.Element(
tag, width=dimension, height=dimension, version=version,
**kwargs)
def _rect(self, row, col, tag=None):
if tag is None:
tag = ET.QName(self._SVG_namespace, "rect")
x, y = self.pixel_box(row, col)[0]
return ET.Element(
tag, x=self.units(x), y=self.units(y),
width=self.unit_size, height=self.unit_size)
def _write(self, stream):
ET.ElementTree(self._img).write(stream, xml_declaration=False)
class SvgImage(SvgFragmentImage):
"""
Standalone SVG image builder
Creates a QR-code image as a standalone SVG document.
"""
background = None
def _svg(self, tag='svg', **kwargs):
svg = super(SvgImage, self)._svg(tag=tag, **kwargs)
svg.set("xmlns", self._SVG_namespace)
if self.background:
svg.append(
ET.Element(
'rect', fill=self.background, x='0', y='0', width='100%',
height='100%'))
return svg
def _rect(self, row, col):
return super(SvgImage, self)._rect(row, col, tag="rect")
def _write(self, stream):
ET.ElementTree(self._img).write(stream, encoding="UTF-8",
xml_declaration=True)
class SvgPathImage(SvgImage):
"""
SVG image builder with one single <path> element (removes white spaces
between individual QR points).
"""
QR_PATH_STYLE = 'fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none'
def __init__(self, *args, **kwargs):
self._points = set()
super(SvgPathImage, self).__init__(*args, **kwargs)
def _svg(self, viewBox=None, **kwargs):
if viewBox is None:
dimension = self.units(self.pixel_size, text=False)
viewBox = '0 0 %(d)s %(d)s' % {'d': dimension}
return super(SvgPathImage, self)._svg(viewBox=viewBox, **kwargs)
def drawrect(self, row, col):
# (x, y)
self._points.add((col, row))
def _generate_subpaths(self):
"""Generates individual QR points as subpaths"""
rect_size = self.units(self.box_size, text=False)
for point in self._points:
x_base = self.units(
(point[0]+self.border)*self.box_size, text=False)
y_base = self.units(
(point[1]+self.border)*self.box_size, text=False)
yield (
'M %(x0)s %(y0)s L %(x0)s %(y1)s L %(x1)s %(y1)s L %(x1)s '
'%(y0)s z' % dict(
x0=x_base, y0=y_base,
x1=x_base+rect_size, y1=y_base+rect_size,
))
def make_path(self):
subpaths = self._generate_subpaths()
return ET.Element(
ET.QName("path"),
style=self.QR_PATH_STYLE,
d=' '.join(subpaths),
id="qr-path"
)
def _write(self, stream):
self._img.append(self.make_path())
super(SvgPathImage, self)._write(stream)
class SvgFillImage(SvgImage):
"""
An SvgImage that fills the background to white.
"""
background = 'white'
class SvgPathFillImage(SvgPathImage):
"""
An SvgPathImage that fills the background to white.
"""
background = 'white'
"""
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':
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)
from qrcode.image.svg import SvgImage
class SvgImageWhite(SvgImage):
background = 'white'
try:
import unittest2 as unittest
except ImportError:
import unittest
try:
from unittest import mock
except ImportError:
import mock
from qrcode import run_example
class ExampleTest(unittest.TestCase):
@mock.patch('PIL.Image.Image.show')
def runTest(self, mock_show):
run_example()
mock_show.assert_called_with()
import warnings
import six
import sys
import qrcode
import qrcode.util
import qrcode.image.svg
try:
import qrcode.image.pure
import pymaging_png # ensure that PNG support is installed
except ImportError: # pragma: no cover
pymaging_png = None
import qrcode
from qrcode.image.base import BaseImage
from qrcode.exceptions import DataOverflowError
from qrcode.util import (
QRData, MODE_NUMBER, MODE_ALPHA_NUM, MODE_8BIT_BYTE)
from qrcode.tests.svg import SvgImageWhite
try:
import unittest2 as unittest
except ImportError:
import unittest
try:
from unittest import mock
except ImportError:
import mock
UNICODE_TEXT = u'\u03b1\u03b2\u03b3'
class QRCodeTests(unittest.TestCase):
def test_basic(self):
qr = qrcode.QRCode(version=1)
qr.add_data('a')
qr.make(fit=False)
def test_large(self):
qr = qrcode.QRCode(version=27)
qr.add_data('a')
qr.make(fit=False)
def test_invalid_version(self):
qr = qrcode.QRCode(version=41)
self.assertRaises(ValueError, qr.make, fit=False)
def test_overflow(self):
qr = qrcode.QRCode(version=1)
qr.add_data('abcdefghijklmno')
self.assertRaises(DataOverflowError, qr.make, fit=False)
def test_add_qrdata(self):
qr = qrcode.QRCode(version=1)
data = QRData('a')
qr.add_data(data)
qr.make(fit=False)
def test_fit(self):
qr = qrcode.QRCode()
qr.add_data('a')
qr.make()
self.assertEqual(qr.version, 1)
qr.add_data('bcdefghijklmno')
qr.make()
self.assertEqual(qr.version, 2)
def test_mode_number(self):
qr = qrcode.QRCode()
qr.add_data('1234567890123456789012345678901234', optimize=0)
qr.make()
self.assertEqual(qr.version, 1)
self.assertEqual(qr.data_list[0].mode, MODE_NUMBER)
def test_mode_alpha(self):
qr = qrcode.QRCode()
qr.add_data('ABCDEFGHIJ1234567890', optimize=0)
qr.make()
self.assertEqual(qr.version, 1)
self.assertEqual(qr.data_list[0].mode, MODE_ALPHA_NUM)
def test_regression_mode_comma(self):
qr = qrcode.QRCode()
qr.add_data(',', optimize=0)
qr.make()
self.assertEqual(qr.data_list[0].mode, MODE_8BIT_BYTE)
def test_mode_8bit(self):
qr = qrcode.QRCode()
qr.add_data(u'abcABC' + UNICODE_TEXT, optimize=0)
qr.make()
self.assertEqual(qr.version, 1)
self.assertEqual(qr.data_list[0].mode, MODE_8BIT_BYTE)
def test_mode_8bit_newline(self):
qr = qrcode.QRCode()
qr.add_data('ABCDEFGHIJ1234567890\n', optimize=0)
qr.make()
self.assertEqual(qr.data_list[0].mode, MODE_8BIT_BYTE)
def test_render_pil(self):
qr = qrcode.QRCode()
qr.add_data(UNICODE_TEXT)
img = qr.make_image()
img.save(six.BytesIO())
def test_qrcode_bad_factory(self):
self.assertRaises(
TypeError, qrcode.QRCode, image_factory='not_BaseImage')
self.assertRaises(
AssertionError, qrcode.QRCode, image_factory=dict)
def test_qrcode_factory(self):
class MockFactory(BaseImage):
drawrect = mock.Mock()
qr = qrcode.QRCode(image_factory=MockFactory)
qr.add_data(UNICODE_TEXT)
qr.make_image()
self.assertTrue(MockFactory.drawrect.called)
def test_render_svg(self):
qr = qrcode.QRCode()
qr.add_data(UNICODE_TEXT)
img = qr.make_image(image_factory=qrcode.image.svg.SvgImage)
img.save(six.BytesIO())
def test_render_svg_path(self):
qr = qrcode.QRCode()
qr.add_data(UNICODE_TEXT)
img = qr.make_image(image_factory=qrcode.image.svg.SvgPathImage)
img.save(six.BytesIO())
def test_render_svg_fragment(self):
qr = qrcode.QRCode()
qr.add_data(UNICODE_TEXT)
img = qr.make_image(image_factory=qrcode.image.svg.SvgFragmentImage)
img.save(six.BytesIO())
def test_render_svg_with_background(self):
qr = qrcode.QRCode()
qr.add_data(UNICODE_TEXT)
img = qr.make_image(image_factory=SvgImageWhite)
img.save(six.BytesIO())
@unittest.skipIf(not pymaging_png, "Requires pymaging with PNG support")
def test_render_pymaging_png(self):
qr = qrcode.QRCode()
qr.add_data(UNICODE_TEXT)
img = qr.make_image(image_factory=qrcode.image.pure.PymagingImage)
with warnings.catch_warnings():
if six.PY3:
warnings.simplefilter('ignore', DeprecationWarning)
img.save(six.BytesIO())
@unittest.skipIf(not pymaging_png, "Requires pymaging")
def test_render_pymaging_png_bad_kind(self):
qr = qrcode.QRCode()
qr.add_data(UNICODE_TEXT)
img = qr.make_image(image_factory=qrcode.image.pure.PymagingImage)
self.assertRaises(ValueError, img.save, six.BytesIO(), kind='FISH')
def test_optimize(self):
qr = qrcode.QRCode()
text = 'A1abc12345def1HELLOa'
qr.add_data(text, optimize=4)
qr.make()
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_longer_than_data(self):
qr = qrcode.QRCode()
text = 'ABCDEFGHIJK'
qr.add_data(text, optimize=12)
self.assertEqual(len(qr.data_list), 1)
self.assertEqual(qr.data_list[0].mode, MODE_ALPHA_NUM)
def test_optimize_size(self):
text = 'A1abc12345123451234512345def1HELLOHELLOHELLOHELLOa' * 5
qr = qrcode.QRCode()
qr.add_data(text)
qr.make()
self.assertEqual(qr.version, 10)
qr = qrcode.QRCode()
qr.add_data(text, optimize=0)
qr.make()
self.assertEqual(qr.version, 11)
def test_qrdata_repr(self):
data = b'hello'
data_obj = qrcode.util.QRData(data)
self.assertEqual(repr(data_obj), repr(data))
def test_print_ascii_stdout(self):
qr = qrcode.QRCode()
stdout_encoding = sys.stdout.encoding
with mock.patch('sys.stdout') as fake_stdout:
# Python 2.6 needs sys.stdout.encoding to be a real string.
sys.stdout.encoding = stdout_encoding
fake_stdout.isatty.return_value = None
self.assertRaises(OSError, qr.print_ascii, tty=True)
self.assertTrue(fake_stdout.isatty.called)
def test_print_ascii(self):
qr = qrcode.QRCode(border=0)
f = six.StringIO()
qr.print_ascii(out=f)
printed = f.getvalue()
f.close()
expected = u'\u2588\u2580\u2580\u2580\u2580\u2580\u2588'
self.assertEqual(printed[:len(expected)], expected)
f = six.StringIO()
f.isatty = lambda: True
qr.print_ascii(out=f, tty=True)
printed = f.getvalue()
f.close()
expected = (
u'\x1b[48;5;232m\x1b[38;5;255m' +
u'\xa0\u2584\u2584\u2584\u2584\u2584\xa0')
self.assertEqual(printed[:len(expected)], expected)
def test_print_tty_stdout(self):
qr = qrcode.QRCode()
with mock.patch('sys.stdout') as fake_stdout:
fake_stdout.isatty.return_value = None
self.assertRaises(OSError, qr.print_tty)
self.assertTrue(fake_stdout.isatty.called)
def test_print_tty(self):
qr = qrcode.QRCode()
f = six.StringIO()
f.isatty = lambda: True
qr.print_tty(out=f)
printed = f.getvalue()
f.close()
BOLD_WHITE_BG = '\x1b[1;47m'
BLACK_BG = '\x1b[40m'
WHITE_BLOCK = BOLD_WHITE_BG + ' ' + BLACK_BG
EOL = '\x1b[0m\n'
expected = (
BOLD_WHITE_BG + ' '*23 + EOL +
WHITE_BLOCK + ' '*7 + WHITE_BLOCK)
self.assertEqual(printed[:len(expected)], expected)
def test_get_matrix(self):
qr = qrcode.QRCode(border=0)
qr.add_data('1')
self.assertEqual(qr.get_matrix(), qr.modules)
def test_get_matrix_border(self):
qr = qrcode.QRCode(border=1)
qr.add_data('1')
matrix = [row[1:-1] for row in qr.get_matrix()[1:-1]]
self.assertEqual(matrix, qr.modules)
def test_negative_size_at_construction(self):
self.assertRaises(ValueError, qrcode.QRCode, box_size=-1)
def test_negative_size_at_usage(self):
qr = qrcode.QRCode()
qr.box_size = -1
self.assertRaises(ValueError, qr.make_image)
class ShortcutTest(unittest.TestCase):
def runTest(self):
qrcode.make('image')
import sys
import re
import datetime
import unittest
try:
from unittest import mock
except ImportError:
import mock
import six
from qrcode.release import update_manpage
OPEN = '{}.open'.format(six.moves.builtins.__name__)
DATA = 'test\n.TH "date" "version" "description"\nthis'
@unittest.skipIf(
sys.version_info[0] == 3 and sys.version_info[1] < 6,
"mock_file not working on Python 3 when less than 3.6")
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])
import sys
try:
import unittest2 as unittest
except ImportError:
import unittest
try:
from unittest import mock
except ImportError:
import mock
from qrcode.console_scripts import main
def bad_read():
raise UnicodeDecodeError('utf-8', b'0x80', 0, 1, 'invalid start byte')
class ScriptTest(unittest.TestCase):
@mock.patch('os.isatty', lambda *args: True)
@mock.patch('qrcode.main.QRCode.print_ascii')
def test_isatty(self, mock_print_ascii):
main(['testtext'])
mock_print_ascii.assert_called_with(tty=True)
@mock.patch('os.isatty', lambda *args: False)
@mock.patch('sys.stdout')
def test_piped(self, mock_stdout):
main(['testtext'])
@mock.patch('os.isatty', lambda *args: True)
@mock.patch('qrcode.main.QRCode.print_ascii')
def test_stdin(self, mock_print_ascii):
mock_stdin = mock.Mock(sys.stdin)
stdin_buffer = getattr(mock_stdin, 'buffer', mock_stdin)
stdin_buffer.read.return_value = 'testtext'
with mock.patch('sys.stdin', mock_stdin):
main([])
self.assertTrue(stdin_buffer.read.called)
mock_print_ascii.assert_called_with(tty=True)
@unittest.skipIf(sys.version_info[0] < 3, 'Python 3')
@mock.patch('os.isatty', lambda *args: True)
@mock.patch('qrcode.main.QRCode.print_ascii')
def test_stdin_py3_unicodedecodeerror(self, mock_print_ascii):
mock_stdin = mock.Mock(sys.stdin)
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)
@mock.patch('os.isatty', lambda *args: True)
@mock.patch('qrcode.main.QRCode.print_ascii')
def test_optimize(self, mock_print_ascii):
main('testtext --optimize 0'.split())
@mock.patch('sys.stdout')
def test_factory(self, mock_stdout):
main('testtext --factory svg'.split())
@mock.patch('sys.stderr')
def test_bad_factory(self, mock_stderr):
self.assertRaises(SystemExit, main, 'testtext --factory fish'.split())
此文件类型无法预览
.\" Manpage for qr
.TH QR 1 "14 Jan 2019" "6.1" "Python QR tool"
.SH NAME
qr \- script to create QR codes at the command line
.SH SYNOPSIS
qr [\-\-help] [\-\-factory=FACTORY] [\-\-optimize=OPTIMIZE] [\-\-error\-correction=LEVEL] [data]
.SH DESCRIPTION
This script uses the python qrcode module. It can take data from stdin or from the commandline and generate a QR code.
Normally it will output the QR code as ascii art to the terminal. If the output is piped to a file, it will output the image (default type of PNG).
.SH OPTIONS
.PP
\fB\ \-h, \-\-help\fR
.RS 4
Show a help message.
.RE
.PP
\fB\ \-\-factory=FACTORY\fR
.RS 4
Full python path to the image factory class to create the
image with. You can use the following shortcuts to the
built-in image factory classes: pil (default), pymaging,
svg, svg-fragment, svg-path.
.RE
.PP
\fB\ \-\-optimize=OPTIMIZE\fR
.RS 4
Optimize the data by looking for chunks of at least this
many characters that could use a more efficient encoding
method. Use 0 to turn off chunk optimization.
.RE
.PP
\fB\ \-\-error\-correction=LEVEL\fR
.RS 4
The error correction level to use. Choices are L (7%),
M (15%, default), Q (25%), and H (30%).
.RE
.PP
\fB\ data\fR
.RS 4
The data from which the QR code will be generated.
.RE
.SH SEE ALSO
https://github.com/lincolnloop/python-qrcode/
CHANGES.rst
LICENSE
MANIFEST.in
PACKAGING.rst
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/not-zip-safe
qrcode.egg-info/requires.txt
qrcode.egg-info/top_level.txt
qrcode/image/__init__.py
qrcode/image/base.py
qrcode/image/pil.py
qrcode/image/pure.py
qrcode/image/svg.py
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 \ No newline at end of file
[console_scripts]
qr = qrcode.console_scripts:main
six
[:platform_system == "Windows"]
colorama
[dev]
pytest
tox
[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]
}
from qrcode.main import QRCode
from qrcode.main import make # noqa
from qrcode.constants import ( # noqa
ERROR_CORRECT_L, ERROR_CORRECT_M, ERROR_CORRECT_Q, ERROR_CORRECT_H)
from qrcode import image # noqa
def run_example(data="http://www.lincolnloop.com", *args, **kwargs):
"""
Build an example QR Code and display it.
There's an even easier way than the code here though: just use the ``make``
shortcut.
"""
qr = QRCode(*args, **kwargs)
qr.add_data(data)
im = qr.make_image()
im.show()
if __name__ == '__main__': # pragma: no cover
import sys
run_example(*sys.argv[1:])
from qrcode import constants
EXP_TABLE = list(range(256))
LOG_TABLE = list(range(256))
for i in range(8):
EXP_TABLE[i] = 1 << i
for i in range(8, 256):
EXP_TABLE[i] = (
EXP_TABLE[i - 4] ^ EXP_TABLE[i - 5] ^ EXP_TABLE[i - 6] ^
EXP_TABLE[i - 8])
for i in range(255):
LOG_TABLE[EXP_TABLE[i]] = i
RS_BLOCK_OFFSET = {
constants.ERROR_CORRECT_L: 0,
constants.ERROR_CORRECT_M: 1,
constants.ERROR_CORRECT_Q: 2,
constants.ERROR_CORRECT_H: 3,
}
RS_BLOCK_TABLE = [
# L
# M
# Q
# H
# 1
[1, 26, 19],
[1, 26, 16],
[1, 26, 13],
[1, 26, 9],
# 2
[1, 44, 34],
[1, 44, 28],
[1, 44, 22],
[1, 44, 16],
# 3
[1, 70, 55],
[1, 70, 44],
[2, 35, 17],
[2, 35, 13],
# 4
[1, 100, 80],
[2, 50, 32],
[2, 50, 24],
[4, 25, 9],
# 5
[1, 134, 108],
[2, 67, 43],
[2, 33, 15, 2, 34, 16],
[2, 33, 11, 2, 34, 12],
# 6
[2, 86, 68],
[4, 43, 27],
[4, 43, 19],
[4, 43, 15],
# 7
[2, 98, 78],
[4, 49, 31],
[2, 32, 14, 4, 33, 15],
[4, 39, 13, 1, 40, 14],
# 8
[2, 121, 97],
[2, 60, 38, 2, 61, 39],
[4, 40, 18, 2, 41, 19],
[4, 40, 14, 2, 41, 15],
# 9
[2, 146, 116],
[3, 58, 36, 2, 59, 37],
[4, 36, 16, 4, 37, 17],
[4, 36, 12, 4, 37, 13],
# 10
[2, 86, 68, 2, 87, 69],
[4, 69, 43, 1, 70, 44],
[6, 43, 19, 2, 44, 20],
[6, 43, 15, 2, 44, 16],
# 11
[4, 101, 81],
[1, 80, 50, 4, 81, 51],
[4, 50, 22, 4, 51, 23],
[3, 36, 12, 8, 37, 13],
# 12
[2, 116, 92, 2, 117, 93],
[6, 58, 36, 2, 59, 37],
[4, 46, 20, 6, 47, 21],
[7, 42, 14, 4, 43, 15],
# 13
[4, 133, 107],
[8, 59, 37, 1, 60, 38],
[8, 44, 20, 4, 45, 21],
[12, 33, 11, 4, 34, 12],
# 14
[3, 145, 115, 1, 146, 116],
[4, 64, 40, 5, 65, 41],
[11, 36, 16, 5, 37, 17],
[11, 36, 12, 5, 37, 13],
# 15
[5, 109, 87, 1, 110, 88],
[5, 65, 41, 5, 66, 42],
[5, 54, 24, 7, 55, 25],
[11, 36, 12, 7, 37, 13],
# 16
[5, 122, 98, 1, 123, 99],
[7, 73, 45, 3, 74, 46],
[15, 43, 19, 2, 44, 20],
[3, 45, 15, 13, 46, 16],
# 17
[1, 135, 107, 5, 136, 108],
[10, 74, 46, 1, 75, 47],
[1, 50, 22, 15, 51, 23],
[2, 42, 14, 17, 43, 15],
# 18
[5, 150, 120, 1, 151, 121],
[9, 69, 43, 4, 70, 44],
[17, 50, 22, 1, 51, 23],
[2, 42, 14, 19, 43, 15],
# 19
[3, 141, 113, 4, 142, 114],
[3, 70, 44, 11, 71, 45],
[17, 47, 21, 4, 48, 22],
[9, 39, 13, 16, 40, 14],
# 20
[3, 135, 107, 5, 136, 108],
[3, 67, 41, 13, 68, 42],
[15, 54, 24, 5, 55, 25],
[15, 43, 15, 10, 44, 16],
# 21
[4, 144, 116, 4, 145, 117],
[17, 68, 42],
[17, 50, 22, 6, 51, 23],
[19, 46, 16, 6, 47, 17],
# 22
[2, 139, 111, 7, 140, 112],
[17, 74, 46],
[7, 54, 24, 16, 55, 25],
[34, 37, 13],
# 23
[4, 151, 121, 5, 152, 122],
[4, 75, 47, 14, 76, 48],
[11, 54, 24, 14, 55, 25],
[16, 45, 15, 14, 46, 16],
# 24
[6, 147, 117, 4, 148, 118],
[6, 73, 45, 14, 74, 46],
[11, 54, 24, 16, 55, 25],
[30, 46, 16, 2, 47, 17],
# 25
[8, 132, 106, 4, 133, 107],
[8, 75, 47, 13, 76, 48],
[7, 54, 24, 22, 55, 25],
[22, 45, 15, 13, 46, 16],
# 26
[10, 142, 114, 2, 143, 115],
[19, 74, 46, 4, 75, 47],
[28, 50, 22, 6, 51, 23],
[33, 46, 16, 4, 47, 17],
# 27
[8, 152, 122, 4, 153, 123],
[22, 73, 45, 3, 74, 46],
[8, 53, 23, 26, 54, 24],
[12, 45, 15, 28, 46, 16],
# 28
[3, 147, 117, 10, 148, 118],
[3, 73, 45, 23, 74, 46],
[4, 54, 24, 31, 55, 25],
[11, 45, 15, 31, 46, 16],
# 29
[7, 146, 116, 7, 147, 117],
[21, 73, 45, 7, 74, 46],
[1, 53, 23, 37, 54, 24],
[19, 45, 15, 26, 46, 16],
# 30
[5, 145, 115, 10, 146, 116],
[19, 75, 47, 10, 76, 48],
[15, 54, 24, 25, 55, 25],
[23, 45, 15, 25, 46, 16],
# 31
[13, 145, 115, 3, 146, 116],
[2, 74, 46, 29, 75, 47],
[42, 54, 24, 1, 55, 25],
[23, 45, 15, 28, 46, 16],
# 32
[17, 145, 115],
[10, 74, 46, 23, 75, 47],
[10, 54, 24, 35, 55, 25],
[19, 45, 15, 35, 46, 16],
# 33
[17, 145, 115, 1, 146, 116],
[14, 74, 46, 21, 75, 47],
[29, 54, 24, 19, 55, 25],
[11, 45, 15, 46, 46, 16],
# 34
[13, 145, 115, 6, 146, 116],
[14, 74, 46, 23, 75, 47],
[44, 54, 24, 7, 55, 25],
[59, 46, 16, 1, 47, 17],
# 35
[12, 151, 121, 7, 152, 122],
[12, 75, 47, 26, 76, 48],
[39, 54, 24, 14, 55, 25],
[22, 45, 15, 41, 46, 16],
# 36
[6, 151, 121, 14, 152, 122],
[6, 75, 47, 34, 76, 48],
[46, 54, 24, 10, 55, 25],
[2, 45, 15, 64, 46, 16],
# 37
[17, 152, 122, 4, 153, 123],
[29, 74, 46, 14, 75, 47],
[49, 54, 24, 10, 55, 25],
[24, 45, 15, 46, 46, 16],
# 38
[4, 152, 122, 18, 153, 123],
[13, 74, 46, 32, 75, 47],
[48, 54, 24, 14, 55, 25],
[42, 45, 15, 32, 46, 16],
# 39
[20, 147, 117, 4, 148, 118],
[40, 75, 47, 7, 76, 48],
[43, 54, 24, 22, 55, 25],
[10, 45, 15, 67, 46, 16],
# 40
[19, 148, 118, 6, 149, 119],
[18, 75, 47, 31, 76, 48],
[34, 54, 24, 34, 55, 25],
[20, 45, 15, 61, 46, 16]
]
def glog(n):
if n < 1: # pragma: no cover
raise ValueError("glog(%s)" % n)
return LOG_TABLE[n]
def gexp(n):
return EXP_TABLE[n % 255]
class Polynomial:
def __init__(self, num, shift):
if not num: # pragma: no cover
raise Exception("%s/%s" % (len(num), shift))
for offset in range(len(num)):
if num[offset] != 0:
break
else:
offset += 1
self.num = num[offset:] + [0] * shift
def __getitem__(self, index):
return self.num[index]
def __iter__(self):
return iter(self.num)
def __len__(self):
return len(self.num)
def __mul__(self, other):
num = [0] * (len(self) + len(other) - 1)
for i, item in enumerate(self):
for j, other_item in enumerate(other):
num[i + j] ^= gexp(glog(item) + glog(other_item))
return Polynomial(num, 0)
def __mod__(self, other):
difference = len(self) - len(other)
if difference < 0:
return self
ratio = glog(self[0]) - glog(other[0])
num = [
item ^ gexp(glog(other_item) + ratio)
for item, other_item in zip(self, other)]
if difference:
num.extend(self[-difference:])
# recursive call
return Polynomial(num, 0) % other
class RSBlock:
def __init__(self, total_count, data_count):
self.total_count = total_count
self.data_count = data_count
def rs_blocks(version, error_correction):
if error_correction not in RS_BLOCK_OFFSET: # pragma: no cover
raise Exception(
"bad rs block @ version: %s / error_correction: %s" %
(version, error_correction))
offset = RS_BLOCK_OFFSET[error_correction]
rs_block = RS_BLOCK_TABLE[(version - 1) * 4 + offset]
blocks = []
for i in range(0, len(rs_block), 3):
count, total_count, data_count = rs_block[i:i + 3]
for j in range(count):
blocks.append(RSBlock(total_count, data_count))
return blocks
#!/usr/bin/env python
"""
qr - Convert stdin (or the first argument) to a QR Code.
When stdout is a tty the QR Code is printed to the terminal and when stdout is
a pipe to a file an image is written. The default image format is PNG.
"""
import sys
import optparse
import os
import qrcode
# The next block is added to get the terminal to display properly on MS platforms
if sys.platform.startswith(('win', 'cygwin')):
import colorama
colorama.init()
default_factories = {
'pil': 'qrcode.image.pil.PilImage',
'pymaging': 'qrcode.image.pure.PymagingImage',
'svg': 'qrcode.image.svg.SvgImage',
'svg-fragment': 'qrcode.image.svg.SvgFragmentImage',
'svg-path': 'qrcode.image.svg.SvgPathImage',
}
error_correction = {
'L': qrcode.ERROR_CORRECT_L,
'M': qrcode.ERROR_CORRECT_M,
'Q': qrcode.ERROR_CORRECT_Q,
'H': qrcode.ERROR_CORRECT_H,
}
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 "
"built-in image factory classes: {0}.".format(
", ".join(sorted(default_factories.keys()))))
parser.add_option(
"--optimize", type=int, help="Optimize the data by looking for chunks "
"of at least this many characters that could use a more efficient "
"encoding method. Use 0 to turn off chunk optimization.")
parser.add_option(
"--error-correction", type='choice',
choices=sorted(error_correction.keys()), default='M',
help="The error correction level to use. Choices are L (7%), "
"M (15%, default), Q (25%), and H (30%).")
opts, args = parser.parse_args(args)
qr = qrcode.QRCode(
error_correction=error_correction[opts.error_correction])
if opts.factory:
module = default_factories.get(opts.factory, opts.factory)
if '.' not in module:
parser.error("The image factory is not a full python path")
module, name = module.rsplit('.', 1)
imp = __import__(module, {}, [], [name])
image_factory = getattr(imp, name)
else:
image_factory = None
if args:
data = args[0]
else:
# Use sys.stdin.buffer if available (Python 3) avoiding
# UnicodeDecodeErrors.
stdin_buffer = getattr(sys.stdin, 'buffer', sys.stdin)
data = stdin_buffer.read()
if opts.optimize is None:
qr.add_data(data)
else:
qr.add_data(data, optimize=opts.optimize)
if image_factory is None and os.isatty(sys.stdout.fileno()):
qr.print_ascii(tty=True)
return
img = qr.make_image(image_factory=image_factory)
sys.stdout.flush()
# Use sys.stdout.buffer if available (Python 3), avoiding
# UnicodeDecodeErrors.
stdout_buffer = getattr(sys.stdout, 'buffer', None)
if not stdout_buffer:
if sys.platform == 'win32': # pragma: no cover
import msvcrt
msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
stdout_buffer = sys.stdout
img.save(stdout_buffer)
if __name__ == "__main__":
main()
# QR error correct levels
ERROR_CORRECT_L = 1
ERROR_CORRECT_M = 0
ERROR_CORRECT_Q = 3
ERROR_CORRECT_H = 2
class DataOverflowError(Exception):
pass
class BaseImage(object):
"""
Base QRCode image output class.
"""
kind = None
allowed_kinds = None
def __init__(self, border, width, box_size, *args, **kwargs):
self.border = border
self.width = width
self.box_size = box_size
self.pixel_size = (self.width + self.border*2) * self.box_size
self._img = self.new_image(**kwargs)
def drawrect(self, row, col):
"""
Draw a single rectangle of the QR code.
"""
raise NotImplementedError("BaseImage.drawrect")
def save(self, stream, kind=None):
"""
Save the image file.
"""
raise NotImplementedError("BaseImage.save")
def pixel_box(self, row, col):
"""
A helper method for pixel-based image generators that specifies the
four pixel coordinates for a single rect.
"""
x = (col + self.border) * self.box_size
y = (row + self.border) * self.box_size
return [(x, y), (x + self.box_size - 1, y + self.box_size - 1)]
def new_image(self, **kwargs): # pragma: no cover
"""
Build the image class. Subclasses should return the class created.
"""
return None
def get_image(self, **kwargs):
"""
Return the image class for further processing.
"""
return self._img
def check_kind(self, kind, transform=None):
"""
Get the image type.
"""
if kind is None:
kind = self.kind
allowed = not self.allowed_kinds or kind in self.allowed_kinds
if transform:
kind = transform(kind)
if not allowed:
allowed = kind in self.allowed_kinds
if not allowed:
raise ValueError(
"Cannot set %s type to %s" % (type(self).__name__, kind))
return kind
# Needed on case-insensitive filesystems
from __future__ import absolute_import
# Try to import PIL in either of the two ways it can be installed.
try:
from PIL import Image, ImageDraw
except ImportError: # pragma: no cover
import Image
import ImageDraw
import qrcode.image.base
class PilImage(qrcode.image.base.BaseImage):
"""
PIL image builder, default format is PNG.
"""
kind = "PNG"
def new_image(self, **kwargs):
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":
mode = "RGBA"
back_color = None
else:
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
self._idr = ImageDraw.Draw(img)
return img
def drawrect(self, row, col):
box = self.pixel_box(row, col)
self._idr.rectangle(box, fill=self.fill_color)
def save(self, stream, format=None, **kwargs):
if format is None:
format = kwargs.get("kind", self.kind)
if "kind" in kwargs:
del kwargs["kind"]
self._img.save(stream, format=format, **kwargs)
def __getattr__(self, name):
return getattr(self._img, name)
from pymaging import Image
from pymaging.colors import RGB
from pymaging.formats import registry
from pymaging.shapes import Line
from pymaging.webcolors import Black, White
from pymaging_png.png import PNG
import qrcode.image.base
class PymagingImage(qrcode.image.base.BaseImage):
"""
pymaging image builder, default format is PNG.
"""
kind = "PNG"
allowed_kinds = ("PNG",)
def __init__(self, *args, **kwargs):
"""
Register PNG with pymaging.
"""
registry.formats = []
registry.names = {}
registry._populate()
registry.register(PNG)
super(PymagingImage, self).__init__(*args, **kwargs)
def new_image(self, **kwargs):
return Image.new(RGB, self.pixel_size, self.pixel_size, White)
def drawrect(self, row, col):
(x, y), (x2, y2) = self.pixel_box(row, col)
for r in range(self.box_size):
line_y = y + r
line = Line(x, line_y, x2, line_y)
self._img.draw(line, Black)
def save(self, stream, kind=None):
self._img.save(stream, self.check_kind(kind))
def check_kind(self, kind, transform=None, **kwargs):
"""
pymaging (pymaging_png at least) uses lower case for the type.
"""
if transform is None:
transform = lambda x: x.lower()
return super(PymagingImage, self).check_kind(
kind, transform=transform, **kwargs)
from decimal import Decimal
# On Python 2.6 must install lxml since the older xml.etree.ElementTree
# version can not be used to create SVG images.
try:
import lxml.etree as ET
except ImportError:
import xml.etree.ElementTree as ET
import qrcode.image.base
class SvgFragmentImage(qrcode.image.base.BaseImage):
"""
SVG image builder
Creates a QR-code image as a SVG document fragment.
"""
_SVG_namespace = "http://www.w3.org/2000/svg"
kind = "SVG"
allowed_kinds = ("SVG",)
def __init__(self, *args, **kwargs):
ET.register_namespace("svg", self._SVG_namespace)
super(SvgFragmentImage, self).__init__(*args, **kwargs)
# Save the unit size, for example the default box_size of 10 is '1mm'.
self.unit_size = self.units(self.box_size)
def drawrect(self, row, col):
self._img.append(self._rect(row, col))
def units(self, pixels, text=True):
"""
A box_size of 10 (default) equals 1mm.
"""
units = Decimal(pixels) / 10
if not text:
return units
return '%smm' % units
def save(self, stream, kind=None):
self.check_kind(kind=kind)
self._write(stream)
def new_image(self, **kwargs):
return self._svg()
def _svg(self, tag=None, version='1.1', **kwargs):
if tag is None:
tag = ET.QName(self._SVG_namespace, "svg")
dimension = self.units(self.pixel_size)
return ET.Element(
tag, width=dimension, height=dimension, version=version,
**kwargs)
def _rect(self, row, col, tag=None):
if tag is None:
tag = ET.QName(self._SVG_namespace, "rect")
x, y = self.pixel_box(row, col)[0]
return ET.Element(
tag, x=self.units(x), y=self.units(y),
width=self.unit_size, height=self.unit_size)
def _write(self, stream):
ET.ElementTree(self._img).write(stream, xml_declaration=False)
class SvgImage(SvgFragmentImage):
"""
Standalone SVG image builder
Creates a QR-code image as a standalone SVG document.
"""
background = None
def _svg(self, tag='svg', **kwargs):
svg = super(SvgImage, self)._svg(tag=tag, **kwargs)
svg.set("xmlns", self._SVG_namespace)
if self.background:
svg.append(
ET.Element(
'rect', fill=self.background, x='0', y='0', width='100%',
height='100%'))
return svg
def _rect(self, row, col):
return super(SvgImage, self)._rect(row, col, tag="rect")
def _write(self, stream):
ET.ElementTree(self._img).write(stream, encoding="UTF-8",
xml_declaration=True)
class SvgPathImage(SvgImage):
"""
SVG image builder with one single <path> element (removes white spaces
between individual QR points).
"""
QR_PATH_STYLE = 'fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none'
def __init__(self, *args, **kwargs):
self._points = set()
super(SvgPathImage, self).__init__(*args, **kwargs)
def _svg(self, viewBox=None, **kwargs):
if viewBox is None:
dimension = self.units(self.pixel_size, text=False)
viewBox = '0 0 %(d)s %(d)s' % {'d': dimension}
return super(SvgPathImage, self)._svg(viewBox=viewBox, **kwargs)
def drawrect(self, row, col):
# (x, y)
self._points.add((col, row))
def _generate_subpaths(self):
"""Generates individual QR points as subpaths"""
rect_size = self.units(self.box_size, text=False)
for point in self._points:
x_base = self.units(
(point[0]+self.border)*self.box_size, text=False)
y_base = self.units(
(point[1]+self.border)*self.box_size, text=False)
yield (
'M %(x0)s %(y0)s L %(x0)s %(y1)s L %(x1)s %(y1)s L %(x1)s '
'%(y0)s z' % dict(
x0=x_base, y0=y_base,
x1=x_base+rect_size, y1=y_base+rect_size,
))
def make_path(self):
subpaths = self._generate_subpaths()
return ET.Element(
ET.QName("path"),
style=self.QR_PATH_STYLE,
d=' '.join(subpaths),
id="qr-path"
)
def _write(self, stream):
self._img.append(self.make_path())
super(SvgPathImage, self)._write(stream)
class SvgFillImage(SvgImage):
"""
An SvgImage that fills the background to white.
"""
background = 'white'
class SvgPathFillImage(SvgPathImage):
"""
An SvgPathImage that fills the background to white.
"""
background = 'white'
"""
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':
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)
from qrcode.image.svg import SvgImage
class SvgImageWhite(SvgImage):
background = 'white'
try:
import unittest2 as unittest
except ImportError:
import unittest
try:
from unittest import mock
except ImportError:
import mock
from qrcode import run_example
class ExampleTest(unittest.TestCase):
@mock.patch('PIL.Image.Image.show')
def runTest(self, mock_show):
run_example()
mock_show.assert_called_with()
import warnings
import six
import sys
import qrcode
import qrcode.util
import qrcode.image.svg
try:
import qrcode.image.pure
import pymaging_png # ensure that PNG support is installed
except ImportError: # pragma: no cover
pymaging_png = None
import qrcode
from qrcode.image.base import BaseImage
from qrcode.exceptions import DataOverflowError
from qrcode.util import (
QRData, MODE_NUMBER, MODE_ALPHA_NUM, MODE_8BIT_BYTE)
from qrcode.tests.svg import SvgImageWhite
try:
import unittest2 as unittest
except ImportError:
import unittest
try:
from unittest import mock
except ImportError:
import mock
UNICODE_TEXT = u'\u03b1\u03b2\u03b3'
class QRCodeTests(unittest.TestCase):
def test_basic(self):
qr = qrcode.QRCode(version=1)
qr.add_data('a')
qr.make(fit=False)
def test_large(self):
qr = qrcode.QRCode(version=27)
qr.add_data('a')
qr.make(fit=False)
def test_invalid_version(self):
qr = qrcode.QRCode(version=41)
self.assertRaises(ValueError, qr.make, fit=False)
def test_overflow(self):
qr = qrcode.QRCode(version=1)
qr.add_data('abcdefghijklmno')
self.assertRaises(DataOverflowError, qr.make, fit=False)
def test_add_qrdata(self):
qr = qrcode.QRCode(version=1)
data = QRData('a')
qr.add_data(data)
qr.make(fit=False)
def test_fit(self):
qr = qrcode.QRCode()
qr.add_data('a')
qr.make()
self.assertEqual(qr.version, 1)
qr.add_data('bcdefghijklmno')
qr.make()
self.assertEqual(qr.version, 2)
def test_mode_number(self):
qr = qrcode.QRCode()
qr.add_data('1234567890123456789012345678901234', optimize=0)
qr.make()
self.assertEqual(qr.version, 1)
self.assertEqual(qr.data_list[0].mode, MODE_NUMBER)
def test_mode_alpha(self):
qr = qrcode.QRCode()
qr.add_data('ABCDEFGHIJ1234567890', optimize=0)
qr.make()
self.assertEqual(qr.version, 1)
self.assertEqual(qr.data_list[0].mode, MODE_ALPHA_NUM)
def test_regression_mode_comma(self):
qr = qrcode.QRCode()
qr.add_data(',', optimize=0)
qr.make()
self.assertEqual(qr.data_list[0].mode, MODE_8BIT_BYTE)
def test_mode_8bit(self):
qr = qrcode.QRCode()
qr.add_data(u'abcABC' + UNICODE_TEXT, optimize=0)
qr.make()
self.assertEqual(qr.version, 1)
self.assertEqual(qr.data_list[0].mode, MODE_8BIT_BYTE)
def test_mode_8bit_newline(self):
qr = qrcode.QRCode()
qr.add_data('ABCDEFGHIJ1234567890\n', optimize=0)
qr.make()
self.assertEqual(qr.data_list[0].mode, MODE_8BIT_BYTE)
def test_render_pil(self):
qr = qrcode.QRCode()
qr.add_data(UNICODE_TEXT)
img = qr.make_image()
img.save(six.BytesIO())
def test_qrcode_bad_factory(self):
self.assertRaises(
TypeError, qrcode.QRCode, image_factory='not_BaseImage')
self.assertRaises(
AssertionError, qrcode.QRCode, image_factory=dict)
def test_qrcode_factory(self):
class MockFactory(BaseImage):
drawrect = mock.Mock()
qr = qrcode.QRCode(image_factory=MockFactory)
qr.add_data(UNICODE_TEXT)
qr.make_image()
self.assertTrue(MockFactory.drawrect.called)
def test_render_svg(self):
qr = qrcode.QRCode()
qr.add_data(UNICODE_TEXT)
img = qr.make_image(image_factory=qrcode.image.svg.SvgImage)
img.save(six.BytesIO())
def test_render_svg_path(self):
qr = qrcode.QRCode()
qr.add_data(UNICODE_TEXT)
img = qr.make_image(image_factory=qrcode.image.svg.SvgPathImage)
img.save(six.BytesIO())
def test_render_svg_fragment(self):
qr = qrcode.QRCode()
qr.add_data(UNICODE_TEXT)
img = qr.make_image(image_factory=qrcode.image.svg.SvgFragmentImage)
img.save(six.BytesIO())
def test_render_svg_with_background(self):
qr = qrcode.QRCode()
qr.add_data(UNICODE_TEXT)
img = qr.make_image(image_factory=SvgImageWhite)
img.save(six.BytesIO())
@unittest.skipIf(not pymaging_png, "Requires pymaging with PNG support")
def test_render_pymaging_png(self):
qr = qrcode.QRCode()
qr.add_data(UNICODE_TEXT)
img = qr.make_image(image_factory=qrcode.image.pure.PymagingImage)
with warnings.catch_warnings():
if six.PY3:
warnings.simplefilter('ignore', DeprecationWarning)
img.save(six.BytesIO())
@unittest.skipIf(not pymaging_png, "Requires pymaging")
def test_render_pymaging_png_bad_kind(self):
qr = qrcode.QRCode()
qr.add_data(UNICODE_TEXT)
img = qr.make_image(image_factory=qrcode.image.pure.PymagingImage)
self.assertRaises(ValueError, img.save, six.BytesIO(), kind='FISH')
def test_optimize(self):
qr = qrcode.QRCode()
text = 'A1abc12345def1HELLOa'
qr.add_data(text, optimize=4)
qr.make()
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_longer_than_data(self):
qr = qrcode.QRCode()
text = 'ABCDEFGHIJK'
qr.add_data(text, optimize=12)
self.assertEqual(len(qr.data_list), 1)
self.assertEqual(qr.data_list[0].mode, MODE_ALPHA_NUM)
def test_optimize_size(self):
text = 'A1abc12345123451234512345def1HELLOHELLOHELLOHELLOa' * 5
qr = qrcode.QRCode()
qr.add_data(text)
qr.make()
self.assertEqual(qr.version, 10)
qr = qrcode.QRCode()
qr.add_data(text, optimize=0)
qr.make()
self.assertEqual(qr.version, 11)
def test_qrdata_repr(self):
data = b'hello'
data_obj = qrcode.util.QRData(data)
self.assertEqual(repr(data_obj), repr(data))
def test_print_ascii_stdout(self):
qr = qrcode.QRCode()
stdout_encoding = sys.stdout.encoding
with mock.patch('sys.stdout') as fake_stdout:
# Python 2.6 needs sys.stdout.encoding to be a real string.
sys.stdout.encoding = stdout_encoding
fake_stdout.isatty.return_value = None
self.assertRaises(OSError, qr.print_ascii, tty=True)
self.assertTrue(fake_stdout.isatty.called)
def test_print_ascii(self):
qr = qrcode.QRCode(border=0)
f = six.StringIO()
qr.print_ascii(out=f)
printed = f.getvalue()
f.close()
expected = u'\u2588\u2580\u2580\u2580\u2580\u2580\u2588'
self.assertEqual(printed[:len(expected)], expected)
f = six.StringIO()
f.isatty = lambda: True
qr.print_ascii(out=f, tty=True)
printed = f.getvalue()
f.close()
expected = (
u'\x1b[48;5;232m\x1b[38;5;255m' +
u'\xa0\u2584\u2584\u2584\u2584\u2584\xa0')
self.assertEqual(printed[:len(expected)], expected)
def test_print_tty_stdout(self):
qr = qrcode.QRCode()
with mock.patch('sys.stdout') as fake_stdout:
fake_stdout.isatty.return_value = None
self.assertRaises(OSError, qr.print_tty)
self.assertTrue(fake_stdout.isatty.called)
def test_print_tty(self):
qr = qrcode.QRCode()
f = six.StringIO()
f.isatty = lambda: True
qr.print_tty(out=f)
printed = f.getvalue()
f.close()
BOLD_WHITE_BG = '\x1b[1;47m'
BLACK_BG = '\x1b[40m'
WHITE_BLOCK = BOLD_WHITE_BG + ' ' + BLACK_BG
EOL = '\x1b[0m\n'
expected = (
BOLD_WHITE_BG + ' '*23 + EOL +
WHITE_BLOCK + ' '*7 + WHITE_BLOCK)
self.assertEqual(printed[:len(expected)], expected)
def test_get_matrix(self):
qr = qrcode.QRCode(border=0)
qr.add_data('1')
self.assertEqual(qr.get_matrix(), qr.modules)
def test_get_matrix_border(self):
qr = qrcode.QRCode(border=1)
qr.add_data('1')
matrix = [row[1:-1] for row in qr.get_matrix()[1:-1]]
self.assertEqual(matrix, qr.modules)
def test_negative_size_at_construction(self):
self.assertRaises(ValueError, qrcode.QRCode, box_size=-1)
def test_negative_size_at_usage(self):
qr = qrcode.QRCode()
qr.box_size = -1
self.assertRaises(ValueError, qr.make_image)
class ShortcutTest(unittest.TestCase):
def runTest(self):
qrcode.make('image')
import sys
import re
import datetime
import unittest
try:
from unittest import mock
except ImportError:
import mock
import six
from qrcode.release import update_manpage
OPEN = '{}.open'.format(six.moves.builtins.__name__)
DATA = 'test\n.TH "date" "version" "description"\nthis'
@unittest.skipIf(
sys.version_info[0] == 3 and sys.version_info[1] < 6,
"mock_file not working on Python 3 when less than 3.6")
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])
import sys
try:
import unittest2 as unittest
except ImportError:
import unittest
try:
from unittest import mock
except ImportError:
import mock
from qrcode.console_scripts import main
def bad_read():
raise UnicodeDecodeError('utf-8', b'0x80', 0, 1, 'invalid start byte')
class ScriptTest(unittest.TestCase):
@mock.patch('os.isatty', lambda *args: True)
@mock.patch('qrcode.main.QRCode.print_ascii')
def test_isatty(self, mock_print_ascii):
main(['testtext'])
mock_print_ascii.assert_called_with(tty=True)
@mock.patch('os.isatty', lambda *args: False)
@mock.patch('sys.stdout')
def test_piped(self, mock_stdout):
main(['testtext'])
@mock.patch('os.isatty', lambda *args: True)
@mock.patch('qrcode.main.QRCode.print_ascii')
def test_stdin(self, mock_print_ascii):
mock_stdin = mock.Mock(sys.stdin)
stdin_buffer = getattr(mock_stdin, 'buffer', mock_stdin)
stdin_buffer.read.return_value = 'testtext'
with mock.patch('sys.stdin', mock_stdin):
main([])
self.assertTrue(stdin_buffer.read.called)
mock_print_ascii.assert_called_with(tty=True)
@unittest.skipIf(sys.version_info[0] < 3, 'Python 3')
@mock.patch('os.isatty', lambda *args: True)
@mock.patch('qrcode.main.QRCode.print_ascii')
def test_stdin_py3_unicodedecodeerror(self, mock_print_ascii):
mock_stdin = mock.Mock(sys.stdin)
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)
@mock.patch('os.isatty', lambda *args: True)
@mock.patch('qrcode.main.QRCode.print_ascii')
def test_optimize(self, mock_print_ascii):
main('testtext --optimize 0'.split())
@mock.patch('sys.stdout')
def test_factory(self, mock_stdout):
main('testtext --factory svg'.split())
@mock.patch('sys.stderr')
def test_bad_factory(self, mock_stderr):
self.assertRaises(SystemExit, main, 'testtext --factory fish'.split())
[metadata]
name = qrcode
version = 6.1
description = QR Code image generator
long_description = file: README.rst, CHANGES.rst
author = Lincoln Loop
author_email = info@lincolnloop.com
url = https://github.com/lincolnloop/python-qrcode
keywords = qr denso-wave IEC18004
license = BSD
classifiers =
Development Status :: 5 - Production/Stable
License :: OSI Approved :: BSD License
Operating System :: OS Independent
Intended Audience :: Developers
Programming Language :: Python
Programming Language :: Python :: 2.7
Programming Language :: Python :: 3.4
Programming Language :: Python :: 3.5
Programming Language :: Python :: 3.6
Topic :: Multimedia :: Graphics
Topic :: Software Development :: Libraries :: Python Modules
[options]
zip_safe = False
include_package_data = True
packages = find:
install_requires =
six
colorama;platform_system=="Windows"
[options.extras_require]
maintainer =
zest.releaser[recommended]
dev =
tox
pytest
mock;python_version<"3"
test =
pytest
pytest-cov
mock;python_version<"3"
pil =
pillow
[options.entry_points]
console-scripts =
qr = qrcode.console_scripts:main
[bdist_wheel]
universal = 1
[flake8]
exclude =
.tox
.git
__pycache__
build
dist
[coverage:run]
source = qrcode
[zest.releaser]
less-zeros = yes
version-levels = 2
tag-format = v{version}
tag-message = Version {version}
tag-signing = yes
date-format = %%-d %%B %%Y
prereleaser.middle =
qrcode.release.update_manpage
[tool:pytest]
filterwarnings = module
[egg_info]
tag_build =
tag_date = 0
此文件的差异被折叠, 点击展开。
此文件的差异被折叠, 点击展开。
此文件的差异被折叠, 点击展开。
此文件的差异太大,无法显示。
此文件的差异太大,无法显示。
此文件的差异太大,无法显示。
此文件的差异太大,无法显示。
此文件类型无法预览
此文件的差异被折叠, 点击展开。
此文件的差异被折叠, 点击展开。
此文件类型无法预览
此文件的差异太大,无法显示。
支持 Markdown 格式
你添加了 0 到此讨论。请谨慎行事。
Finish editing this message first!