From 8926bcf778dcf4789328618a155cdcbaa8bc2162 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 12 Mar 2017 05:52:25 +0300 Subject: [PATCH 001/509] Fix pip's --install-option: --compile is default and I prefer -O2 [skip ci] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 89214067..220e308c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ ---install-option="--compile --optimize" +--install-option=-O2 FormEncode >= 1.1.1, != 1.3.0; python_version >= '2.6' and python_version < '3.0' FormEncode >= 1.3.1; python_version >= '3.4' From ac3e39da98448311e97d070dce6436d36750bcfd Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 19 Mar 2017 05:02:12 +0300 Subject: [PATCH 002/509] Convert scripts repository to devscripts subdirectory Some of thses scripts are version-dependent so it's better to have them in the main repo. [skip ci] --- devscripts/BRANCH-CHECKLIST | 32 +++++++++++ devscripts/RELEASE-CHECKLIST | 50 +++++++++++++++++ devscripts/add-remotes | 29 ++++++++++ devscripts/branch | 56 +++++++++++++++++++ devscripts/build-all-docs | 15 +++++ devscripts/build-docs | 5 ++ devscripts/cleanup | 5 ++ devscripts/flake8/.gitignore | 5 ++ devscripts/flake8/run | 5 ++ devscripts/flake8/split | 5 ++ devscripts/git-hooks/post-checkout | 22 ++++++++ devscripts/git-hooks/post-merge | 8 +++ devscripts/git-hooks/post-rewrite | 8 +++ .../git-svn/SQLObject-gitignore/.gitignore | 10 ++++ .../SQLObject-gitignore/docs/.gitignore | 3 + devscripts/git-svn/svn2git | 55 ++++++++++++++++++ devscripts/git-svn/svn2git-fullhistory | 33 +++++++++++ devscripts/null-merge | 54 ++++++++++++++++++ devscripts/prerelease | 26 +++++++++ devscripts/prerelease-tag | 17 ++++++ devscripts/publish-docs | 7 +++ devscripts/push-all | 5 ++ devscripts/release | 41 ++++++++++++++ devscripts/replace | 26 +++++++++ devscripts/run-all-tests | 13 +++++ devscripts/run-all-tests-ALL | 4 ++ devscripts/run-all-tests-pgsql | 2 + devscripts/run-all-tests-sqlite | 2 + devscripts/run-tests | 22 ++++++++ devscripts/run-tests-mysql-connector | 5 ++ devscripts/run-tests-mysqlclient | 5 ++ devscripts/run-tests-mysqldb | 5 ++ devscripts/run-tests-oursql | 5 ++ devscripts/run-tests-pg8000 | 5 ++ devscripts/run-tests-pgsql | 5 ++ devscripts/run-tests-pygresql | 5 ++ devscripts/run-tests-pymysql | 5 ++ devscripts/run-tests-pypostgresql | 5 ++ devscripts/run-tests-sqlite | 2 + devscripts/run-tests-sqlite-memory | 2 + devscripts/set-commit-date.py | 46 +++++++++++++++ devscripts/setup | 11 ++++ devscripts/sftp-frs | 2 + devscripts/sftp-web | 2 + devscripts/split.sh | 22 ++++++++ devscripts/test-split.sh | 17 ++++++ devscripts/tox-select-envs | 12 ++++ docs/News.rst | 7 +++ 48 files changed, 733 insertions(+) create mode 100644 devscripts/BRANCH-CHECKLIST create mode 100644 devscripts/RELEASE-CHECKLIST create mode 100755 devscripts/add-remotes create mode 100755 devscripts/branch create mode 100755 devscripts/build-all-docs create mode 100755 devscripts/build-docs create mode 100755 devscripts/cleanup create mode 100644 devscripts/flake8/.gitignore create mode 100755 devscripts/flake8/run create mode 100755 devscripts/flake8/split create mode 100755 devscripts/git-hooks/post-checkout create mode 100755 devscripts/git-hooks/post-merge create mode 100755 devscripts/git-hooks/post-rewrite create mode 100644 devscripts/git-svn/SQLObject-gitignore/.gitignore create mode 100644 devscripts/git-svn/SQLObject-gitignore/docs/.gitignore create mode 100755 devscripts/git-svn/svn2git create mode 100755 devscripts/git-svn/svn2git-fullhistory create mode 100755 devscripts/null-merge create mode 100755 devscripts/prerelease create mode 100755 devscripts/prerelease-tag create mode 100755 devscripts/publish-docs create mode 100755 devscripts/push-all create mode 100755 devscripts/release create mode 100755 devscripts/replace create mode 100755 devscripts/run-all-tests create mode 100755 devscripts/run-all-tests-ALL create mode 100755 devscripts/run-all-tests-pgsql create mode 100755 devscripts/run-all-tests-sqlite create mode 100755 devscripts/run-tests create mode 100755 devscripts/run-tests-mysql-connector create mode 100755 devscripts/run-tests-mysqlclient create mode 100755 devscripts/run-tests-mysqldb create mode 100755 devscripts/run-tests-oursql create mode 100755 devscripts/run-tests-pg8000 create mode 100755 devscripts/run-tests-pgsql create mode 100755 devscripts/run-tests-pygresql create mode 100755 devscripts/run-tests-pymysql create mode 100755 devscripts/run-tests-pypostgresql create mode 100755 devscripts/run-tests-sqlite create mode 100755 devscripts/run-tests-sqlite-memory create mode 100755 devscripts/set-commit-date.py create mode 100755 devscripts/setup create mode 100755 devscripts/sftp-frs create mode 100755 devscripts/sftp-web create mode 100644 devscripts/split.sh create mode 100755 devscripts/test-split.sh create mode 100755 devscripts/tox-select-envs diff --git a/devscripts/BRANCH-CHECKLIST b/devscripts/BRANCH-CHECKLIST new file mode 100644 index 00000000..4e64f48d --- /dev/null +++ b/devscripts/BRANCH-CHECKLIST @@ -0,0 +1,32 @@ +0. Run full test suite in master. Continue if all tests passed. + +1. If the branching point is master run ../branch $NEW_BRANCH. If it's +not master run ../branch $NEW_BRANCH $TREEISH, where $TREEISH is +a branch, a commit id or a tag. + +1a. The script creates a new branch and calls editor; edit README.rst, + __version__.py and News.rst in the branch - set version. In + setup.cfg in the branch edit section [publish] - uncomment doc-dest + for stable branch. In setup.py in the branch edit URL (remove + '/devel') and download URL. In setup.py and DeveloperGuide.rst edit + Travis CI build status image URL (change branch). Commit. + +1b. If the branching point was master the script checks out master and + calls editor again; edit README.rst, __version__.py and News.rst in + master - set version for the next release. Edit branch in + appveyor.yml. In setup.py edit "Development Status" in trove + classifiers. Commit. + +1c. If the branching point was master the script updates versions in + SQLObject-master.rst. If the branching point was not master the + script updates versions in SQLObject-$branch.rst. + +2. To deprecate a version of Python edit files docs/News.rst, + docs/SQLObject.rst, docs/TODO.rst, sqlobject/main.py, README.rst and + setup.py in master. + +3. Do a null-merge from the new branch to the higher branch or the + master. + +4. Run ../push-all to push all branches and tags to the public + repositories. diff --git a/devscripts/RELEASE-CHECKLIST b/devscripts/RELEASE-CHECKLIST new file mode 100644 index 00000000..acfc14f9 --- /dev/null +++ b/devscripts/RELEASE-CHECKLIST @@ -0,0 +1,50 @@ +0. Run full test suite in all branches and in master. Continue if all + tests passed. + +1. Check out the release branch. If it is a stable release - edit + docs/News.rst to set release date. Commit. If it's not master - merge + to all higher branches and master. + +2. If release branch is not master - run ../prerelease $NEW_TAG; if it's + master - run ../prerelease $NEW_TAG master. + +2a. The script checks out the release branch and calls editor; edit + __version__.py and README.rst in the release branch - fix versions. + Edit section [egg_info] in setup.cfg - set if it is a stable or + development release. In setup.py edit "Development Status" in trove + classifiers; edit download URL: if a non-stable version - append + 'dev' and date stamp, for a stable version remove 'dev' and date + stamp). Commit. Verify. + +3. If it's not master - null-merge to the next higher branch. + +4. If release branch is not master - run ../prerelease-tag $NEW_TAG; if + it's master - run ../prerelease-tag $NEW_TAG master. This checks out + the release branch and creates the new tag at the head of the release + branch. + +5. Update version, the list of changes, the list of contributors and + download URL in SQLObject-$branch.rst. + +6. Run ../release. This generates and uploads new archives to PyPI and + if it is a stable release - uploads archives and release announcement + (SQLObject-$branch.rst) to SourceForge. + +7. Hide/show old releases at PyPI and SourceForge. + +8. If it's the first stable release of the branch - edit build-all-docs, + advance stable branch. If it's a stable release edit stable tag at + ReadTheDocs. Generate new docs using ./build-all-docs. Commit generated + docs. Upload docs using ./publish-docs. + +9. Run ../push-all in the development repository to push all branches + and tags to the public repositories. + +10. Announce new release(s) at Twitter (https://twitter.com/SQLObject) and + Wikipedia (https://en.wikipedia.org/wiki/SQLObject). If it is a stable + release - announce it at + https://en.wikipedia.org/wiki/Comparison_of_object-relational_mapping_software. + +11. Send announcement to the SQLObject mailing list. For a stable + release send announcements to python, python-announce and python-db + mailing lists. diff --git a/devscripts/add-remotes b/devscripts/add-remotes new file mode 100755 index 00000000..3b664bd9 --- /dev/null +++ b/devscripts/add-remotes @@ -0,0 +1,29 @@ +#! /bin/sh + +if [ -z "$2" ]; then + echo "Usage: $0 sf-url gl-url gh-url" >&2 + exit 1 +fi + +sf_url="$1" +gl_url="$2" +gh_url="$3" + +if ! echo "$sf_url" | grep -q ^$USER@git\\.code\\.sf\\.net:/p/sqlobject/; then + echo "Usage: $0 SF-URL gl-url gh-url" >&2 + exit 1 +fi + +if ! echo "$gl_url" | grep -q ^git@gitlab.com:sqlobject/; then + echo "Usage: $0 sf-url GL-URL gh-url" >&2 + exit 1 +fi + +if ! echo "$gh_url" | grep -q ^git@github.com:sqlobject/; then + echo "Usage: $0 sf-url gl-url GH-URL" >&2 + exit 1 +fi + + git remote add sf "$sf_url" && + git remote add gl "$gl_url" && +exec git remote add gh "$gh_url" diff --git a/devscripts/branch b/devscripts/branch new file mode 100755 index 00000000..e3d47714 --- /dev/null +++ b/devscripts/branch @@ -0,0 +1,56 @@ +#! /bin/sh + +if [ -z "$1" -o -n "$3" ]; then + echo "Usage: $0 branch [treeish]" >&2 + exit 1 +fi + +branch="$1" +treeish="$2" + +. `dirname $0`/split.sh && +branch="$1" + +if [ -z "$treeish" ]; then + treeish="master" +fi + +split_tag "`git describe --abbrev=0 \"$treeish\"`" +prev_branch="$major.$minor" + +split_tag $branch +next_minor="`expr $minor + 1`" + +git checkout -b "$branch" "$treeish" && +echo " +version = '$major.$minor' +major = $major +minor = $minor +micro = 0 +release_level = 'branch' +serial = 0 +version_info = (major, minor, micro, release_level, serial)" > sqlobject/__version__.py && +`git var GIT_EDITOR` README.rst sqlobject/__version__.py docs/News.rst setup.cfg setup.py docs/DeveloperGuide.rst && +git commit --message="Branch $branch" README.rst sqlobject/__version__.py docs/News.rst setup.cfg setup.py docs/DeveloperGuide.rst && + +if [ "$treeish" = master ]; then + git checkout master && echo " +version = '$major.$next_minor' +major = $major +minor = $next_minor +micro = 0 +release_level = 'trunk' +serial = 0 +version_info = (major, minor, micro, release_level, serial)" > sqlobject/__version__.py && + `git var GIT_EDITOR` README.rst sqlobject/__version__.py docs/News.rst appveyor.yml setup.py && + git commit --message="Next branch will be $major.$next_minor" README.rst sqlobject/__version__.py docs/News.rst setup.py && + + cd .. && + cp -p SQLObject-master.rst SQLObject-"$branch".rst && + exec ./replace "$major\.$minor" "$major.$next_minor" SQLObject-master.rst + +else + cd .. && + cp -p SQLObject-"$prev_branch".rst SQLObject-"$branch".rst && + exec ./replace "$prev_branch" "$major.$next_minor" SQLObject-"$branch".rst +fi diff --git a/devscripts/build-all-docs b/devscripts/build-all-docs new file mode 100755 index 00000000..e16b7263 --- /dev/null +++ b/devscripts/build-all-docs @@ -0,0 +1,15 @@ +#! /bin/sh + +build_docs() { + git checkout "$1" && + ../build-docs && + rsync -ahP --del --exclude=.git --exclude=.gitlab-ci.yml \ + --exclude=.nojekyll docs/html/ ../SQLObject-docs/"$2"/ +} + +cd "`dirname \"$0\"`"/SQLObject && +build_docs 3.2.0 && +build_docs master devel && + +cd ../SQLObject-docs && +exec git status diff --git a/devscripts/build-docs b/devscripts/build-docs new file mode 100755 index 00000000..8f9895bd --- /dev/null +++ b/devscripts/build-docs @@ -0,0 +1,5 @@ +#! /bin/sh + +cd "`dirname \"$0\"`"/SQLObject && +cd docs && +exec ./rebuild diff --git a/devscripts/cleanup b/devscripts/cleanup new file mode 100755 index 00000000..fa38d794 --- /dev/null +++ b/devscripts/cleanup @@ -0,0 +1,5 @@ +#! /bin/sh + +cd "`dirname $0`" && +find . \( -name \*.orig -o -name \*.rej -o -name \*.tmp \) -type f -delete && +exec rm -f /tmp/test-sqlite.sqdb* diff --git a/devscripts/flake8/.gitignore b/devscripts/flake8/.gitignore new file mode 100644 index 00000000..d2eae243 --- /dev/null +++ b/devscripts/flake8/.gitignore @@ -0,0 +1,5 @@ +E* +F* +W* +all-results +sort-by-lines diff --git a/devscripts/flake8/run b/devscripts/flake8/run new file mode 100755 index 00000000..2000dd6d --- /dev/null +++ b/devscripts/flake8/run @@ -0,0 +1,5 @@ +#! /bin/sh + +flake8 ../SQLObject | sort >all-results && +awk '{print $2}' all-results | sort | uniq -c | + sort -k 1,1nr -k 2,2 >sort-by-lines diff --git a/devscripts/flake8/split b/devscripts/flake8/split new file mode 100755 index 00000000..958b7585 --- /dev/null +++ b/devscripts/flake8/split @@ -0,0 +1,5 @@ +#! /bin/sh + +while read _count code; do + grep -F " $code " all-results | sort -t : -k 1,1 -k 2,2nr >"$code" +done &2 + exit 1 +fi + +url="$1" + +if [ ! -f authors.txt ]; then + echo "Run \"get-authors $1\" first" >&2 + exit 2 +fi + +if [ -z "$2" ]; then + dir="`basename $url`" +else + dir="$2" +fi + +if [ -z "$dir" ]; then + echo "Usage: $0 $url dir" >&2 + exit 1 +fi + +# init + fetch +git svn clone "$url" --authors-file=authors.txt --prefix=svn/ --stdlayout "$dir" && +cd "$dir" && + +# Convert tags and branches + +# See http://blog.jessitron.com/2013/08/converting-from-svn-to-git.html + +git for-each-ref --format="%(refname:short)" refs/remotes/svn | + sed 's#svn/##' | grep -v '^tags' | + while read aBranch; do git branch $aBranch svn/$aBranch || exit 1; done + +# See http://thomasrast.ch/git/git-svn-conversion.html + +git for-each-ref --format="%(refname:short)" refs/remotes/svn/tags/ | +while read tag; do + GIT_COMMITTER_DATE="`git log -1 --pretty=format:\"%ad\" \"$tag\"`" \ + GIT_COMMITTER_EMAIL="`git log -1 --pretty=format:\"%ce\" \"$tag\"`" \ + GIT_COMMITTER_NAME="`git log -1 --pretty=format:\"%cn\" \"$tag\"`" \ + git tag -a -m "`git for-each-ref --format=\"%(contents)\" \"$tag\"`" \ + "`echo \"$tag\" | sed 's#svn/tags/##'`" "$tag" || exit 1 +done + +# preserve authors.txt +cp -p ../authors.txt .git/info && +git config --local --path svn.authorsfile .git/info/authors.txt + +git svn gc && +git gc --aggressive && +echo "Cloned from $url using git-svn" >.git/description diff --git a/devscripts/git-svn/svn2git-fullhistory b/devscripts/git-svn/svn2git-fullhistory new file mode 100755 index 00000000..bc74b897 --- /dev/null +++ b/devscripts/git-svn/svn2git-fullhistory @@ -0,0 +1,33 @@ +#! /bin/sh + +"`dirname \"$0\"`"/svn2git \ + http://svn.colorstudy.com/SQLObject SQLObject-fullhistory && + +git init --bare SQLObject.git && +cd SQLObject.git && +echo "Bare SQLObject repository" >description && +git fetch ../SQLObject-fullhistory master:master 1.5:1.5 1.6:1.6 1.7:1.7 tag 1.5.0b1 tag 1.5.0rc1 tag 1.5.0 tag 1.5.1 tag 1.5.2 tag 1.6.0a1 tag 1.6.0b1 tag 1.6.0 tag 1.7.0b1 && + +cd .. && +git clone SQLObject.git SQLObject && rm -rf SQLObject.git && +cd SQLObject && git remote rm origin && rmdir .git/refs/remotes/origin && + +echo "Development SQLObject repository" >.git/description && +git branch --track 1.5 origin/1.5 && +git branch --track 1.6 origin/1.6 && +git branch --track 1.7 origin/1.7 && + +# Null merges +git checkout 1.6 && git merge --no-commit -s ours 1.5 && +git checkout HEAD sqlobject/main.py && git commit && + +git checkout 1.7 && git merge --no-commit -s ours 1.6 && +git checkout HEAD sqlobject/col.py && git commit && + +git checkout master && git merge --no-commit -s ours 1.7 && +git checkout HEAD setup.cfg setup.py \ + sqlobject/__version__.py sqlobject/converters.py \ + sqlobject/tests/test_converters.py sqlobject/tests/test_datetime.py && +git commit && + +exec vim .git/config diff --git a/devscripts/null-merge b/devscripts/null-merge new file mode 100755 index 00000000..036782bf --- /dev/null +++ b/devscripts/null-merge @@ -0,0 +1,54 @@ +#! /bin/sh + +new_branch="" +old_branch="" + +while getopts n:o: opt; do + case $opt in + n ) new_branch="$OPTARG" ;; + o ) old_branch="$OPTARG" ;; + esac +done +shift `expr $OPTIND - 1` + +usage() { + echo "Usage: $0 [-o old_branch] [-n new_branch]|[old_branch new_branch]" >&2 + exit 1 +} + +get_current_branch() { + current_branch="`git branch | grep '^\*' | awk '{print $2}'`" +} + +if [ -n "$new_branch" ]; then + if [ -n "$old_branch" ]; then + if [ -n "$1" ]; then + usage + fi + else + get_current_branch + old_branch="$current_branch" + fi +elif [ -n "$old_branch" ]; then + if [ -n "$1" ]; then + usage + else + get_current_branch + new_branch="$current_branch" + fi +elif [ -n "$1" ]; then + if [ -n "$2" ]; then + if [ -n "$3" ]; then + usage + fi + old_branch="$1" + new_branch="$2" + else + usage + fi +else + usage +fi + +git checkout "$new_branch" && +exec git merge --strategy=ours "$old_branch" diff --git a/devscripts/prerelease b/devscripts/prerelease new file mode 100755 index 00000000..0386c16d --- /dev/null +++ b/devscripts/prerelease @@ -0,0 +1,26 @@ +#! /bin/sh + +if [ -z "$1" -o -n "$3" ]; then + echo "Usage: $0 new_tag [branch]" >&2 + exit 1 +elif [ -z "$2" ]; then + tag="$1" +else + tag="$1" + branch="$2" +fi + +. `dirname $0`/split.sh && +split_tag $tag $branch + +git checkout "$branch" && +echo " +version = '$tag' +major = $major +minor = $minor +micro = $micro +release_level = '$state' +serial = $serial +version_info = (major, minor, micro, release_level, serial)" > sqlobject/__version__.py && +`git var GIT_EDITOR` docs/News.rst sqlobject/__version__.py README.rst setup.cfg setup.py && +exec git commit --message="Release $tag" docs/News.rst sqlobject/__version__.py README.rst setup.cfg setup.py diff --git a/devscripts/prerelease-tag b/devscripts/prerelease-tag new file mode 100755 index 00000000..b7f10175 --- /dev/null +++ b/devscripts/prerelease-tag @@ -0,0 +1,17 @@ +#! /bin/sh + +if [ -z "$1" -o -n "$3" ]; then + echo "Usage: $0 new_tag [branch]" >&2 + exit 1 +elif [ -z "$2" ]; then + tag="$1" +else + tag="$1" + branch="$2" +fi + +. `dirname $0`/split.sh && +split_tag $tag $branch + +git checkout "$branch" && +exec git tag --message="Release $tag" --sign $tag diff --git a/devscripts/publish-docs b/devscripts/publish-docs new file mode 100755 index 00000000..10f75968 --- /dev/null +++ b/devscripts/publish-docs @@ -0,0 +1,7 @@ +#! /bin/sh + +cd "`dirname \"$0\"`"/SQLObject-docs && +../set-commit-date.py && chmod -R u=rwX,go=rX . && +rsync -hlrtP4 --del . web.sourceforge.net:/home/project-web/sqlobject/htdocs/ && +git archive --format=zip -o "$HOME"/tmp/SQLObject-docs.zip master && +git push gl master && exec git push gh master diff --git a/devscripts/push-all b/devscripts/push-all new file mode 100755 index 00000000..7d4020ca --- /dev/null +++ b/devscripts/push-all @@ -0,0 +1,5 @@ +#! /bin/sh + +git push --all sf && git push --tags sf && +git push --all gl && git push --tags gl && +git push --all gh && exec git push --tags gh diff --git a/devscripts/release b/devscripts/release new file mode 100755 index 00000000..8e8d829f --- /dev/null +++ b/devscripts/release @@ -0,0 +1,41 @@ +#! /bin/sh + +cd "`dirname \"$0\"`"/SQLObject && +umask 022 && +chmod -R a+rX . && + +../build-docs && +../set-commit-date.py && + +python setup.py build_py && +python setup.py register sdist upload --sign && + +for py in 6 7; do + find build -name '*.py[co]' -delete && + python2.$py -m compileall build && + python2.$py -O -m compileall build && + python2.$py setup.py bdist_egg upload --sign || exit 1 +done + +version="`python setup.py -V`" && +. `dirname $0`/split.sh && +split_tag $version + +if [ "$major" -ge 3 ]; then + find build -name '*.py[co]' -delete && + python setup.py bdist_wheel --universal upload --sign && + for py in 4 5; do + find build -name '*.py[co]' -delete && + python3.$py -m compileall build && + python3.$py -O -m compileall build && + python3.$py setup.py bdist_egg upload --sign || exit 1 + done +fi + +if [ "$state" = final ]; then + cp -a dist/* "$HOME"/tmp/ && + rsync -ahP4 dist/* frs.sourceforge.net:/home/frs/project/sqlobject/sqlobject/"$version"/ && + rsync -ahP4 ../SQLObject-"$branch".rst frs.sourceforge.net:/home/frs/project/sqlobject/sqlobject/"$version"/README.rst || exit 1 +fi + +exec rm -rf build dist docs/html SQLObject.egg-info diff --git a/devscripts/replace b/devscripts/replace new file mode 100755 index 00000000..8ff7124a --- /dev/null +++ b/devscripts/replace @@ -0,0 +1,26 @@ +#! /usr/bin/env python + +import sys + +if len(sys.argv) < 4: + sys.stderr.write("Usage: %s [-i] from_re to_re file....\n" % sys.argv[0]) + sys.exit(1) + +import re +if sys.argv[1] == '-i': + search = re.compile(sys.argv[2], re.IGNORECASE) + replace = sys.argv[3] + start = 4 +else: + search = re.compile(sys.argv[1]) + replace = sys.argv[2] + start = 3 + +from fileinput import FileInput +files = FileInput(sys.argv[start:], inplace=1) + +for line in files: + line = search.sub(replace, line) + sys.stdout.write(line) + +files.close() diff --git a/devscripts/run-all-tests b/devscripts/run-all-tests new file mode 100755 index 00000000..6c1bae6a --- /dev/null +++ b/devscripts/run-all-tests @@ -0,0 +1,13 @@ +#! /bin/sh + +cd "`dirname \"$0\"`"/SQLObject && +SO_DIR="`dirname $0`" + +for py_ver in 2.6 2.7 3.4 3.5; do + echo "---------- PYTHON $py_ver "$1" ----------" + "$SO_DIR"/cleanup && + PY_VER=$py_ver "$SO_DIR"/run-tests-"$1" \ + sqlobject/tests/test_*.py sqlobject/inheritance/tests/test_*.py \ + sqlobject/versioning/test/test_*.py || exit 1 +done +echo "---------- 'DONE!' ----------" diff --git a/devscripts/run-all-tests-ALL b/devscripts/run-all-tests-ALL new file mode 100755 index 00000000..1d2d813c --- /dev/null +++ b/devscripts/run-all-tests-ALL @@ -0,0 +1,4 @@ +#! /bin/sh + +"`dirname $0`"/run-all-tests-sqlite && +exec "`dirname $0`"/run-all-tests-pgsql diff --git a/devscripts/run-all-tests-pgsql b/devscripts/run-all-tests-pgsql new file mode 100755 index 00000000..283ee0c2 --- /dev/null +++ b/devscripts/run-all-tests-pgsql @@ -0,0 +1,2 @@ +#! /bin/sh +exec "`dirname $0`"/run-all-tests pgsql diff --git a/devscripts/run-all-tests-sqlite b/devscripts/run-all-tests-sqlite new file mode 100755 index 00000000..ffa4ba59 --- /dev/null +++ b/devscripts/run-all-tests-sqlite @@ -0,0 +1,2 @@ +#! /bin/sh +exec "`dirname $0`"/run-all-tests sqlite diff --git a/devscripts/run-tests b/devscripts/run-tests new file mode 100755 index 00000000..b81141da --- /dev/null +++ b/devscripts/run-tests @@ -0,0 +1,22 @@ +#! /bin/sh + +START_DIR="`pwd`" +CWD="$START_DIR" + +while [ ! -f setup.py -a "$CWD" != / ]; do + cd .. && CWD="`pwd`" || exit 1 +done +if [ ! -f setup.py ]; then + echo "Cannot find setup.py, abort" >&2 + exit 1 +fi +SO_DIR="$CWD" + +PYTHONPATH="$CWD" +export PYTHONPATH + +TESTDB_URI="$1" +shift + +cd "$START_DIR" && +exec python"$PY_VER" `which pytest` $PYTEST_OPTIONS -D "$TESTDB_URI" "$@" diff --git a/devscripts/run-tests-mysql-connector b/devscripts/run-tests-mysql-connector new file mode 100755 index 00000000..d9ed8177 --- /dev/null +++ b/devscripts/run-tests-mysql-connector @@ -0,0 +1,5 @@ +#! /bin/sh + +mysql -e 'create database sqlobject_test;' +"`dirname \"$0\"`/run-tests" 'mysql://localhost/sqlobject_test?driver=connector&charset=utf8&debug=1' "$@" +mysql -e 'drop database sqlobject_test;' diff --git a/devscripts/run-tests-mysqlclient b/devscripts/run-tests-mysqlclient new file mode 100755 index 00000000..c99ca61c --- /dev/null +++ b/devscripts/run-tests-mysqlclient @@ -0,0 +1,5 @@ +#! /bin/sh + +mysql -e 'create database sqlobject_test;' +"`dirname \"$0\"`/run-tests" 'mysql://localhost/sqlobject_test?driver=mysqldb&charset=utf8&debug=1' "$@" +mysql -e 'drop database sqlobject_test;' diff --git a/devscripts/run-tests-mysqldb b/devscripts/run-tests-mysqldb new file mode 100755 index 00000000..65b7e7e2 --- /dev/null +++ b/devscripts/run-tests-mysqldb @@ -0,0 +1,5 @@ +#! /bin/sh + +mysql -e 'create database sqlobject_test;' +"`dirname \"$0\"`/run-tests" 'mysql://localhost/sqlobject_test?driver=mysqldb&debug=1' "$@" +mysql -e 'drop database sqlobject_test;' diff --git a/devscripts/run-tests-oursql b/devscripts/run-tests-oursql new file mode 100755 index 00000000..d01dfd61 --- /dev/null +++ b/devscripts/run-tests-oursql @@ -0,0 +1,5 @@ +#! /bin/sh + +mysql -e 'create database sqlobject_test;' +"`dirname \"$0\"`/run-tests" 'mysql://localhost/sqlobject_test?driver=oursql&charset=utf8&debug=1' "$@" +mysql -e 'drop database sqlobject_test;' diff --git a/devscripts/run-tests-pg8000 b/devscripts/run-tests-pg8000 new file mode 100755 index 00000000..751f8981 --- /dev/null +++ b/devscripts/run-tests-pg8000 @@ -0,0 +1,5 @@ +#! /bin/sh + +createdb -E utf-8 -l en_US.UTF-8 -T template0 test && +"`dirname \"$0\"`/run-tests" 'postgres:/var/run/postgresql/.s.PGSQL.5432/test?driver=pg8000&charset=utf-8&debug=1' "$@" +exec dropdb test diff --git a/devscripts/run-tests-pgsql b/devscripts/run-tests-pgsql new file mode 100755 index 00000000..38144bdb --- /dev/null +++ b/devscripts/run-tests-pgsql @@ -0,0 +1,5 @@ +#! /bin/sh + +createdb -E utf-8 -l en_US.UTF-8 -T template0 test && +"`dirname \"$0\"`/run-tests" 'postgres:/test?driver=psycopg&charset=utf-8&debug=1' "$@" +exec dropdb test diff --git a/devscripts/run-tests-pygresql b/devscripts/run-tests-pygresql new file mode 100755 index 00000000..72072e8b --- /dev/null +++ b/devscripts/run-tests-pygresql @@ -0,0 +1,5 @@ +#! /bin/sh + +createdb -E utf-8 -l en_US.UTF-8 -T template0 test && +"`dirname \"$0\"`/run-tests" 'postgres:/var/run/postgresql/test?driver=pygresql&charset=utf-8&debug=1' "$@" +exec dropdb test diff --git a/devscripts/run-tests-pymysql b/devscripts/run-tests-pymysql new file mode 100755 index 00000000..2000db18 --- /dev/null +++ b/devscripts/run-tests-pymysql @@ -0,0 +1,5 @@ +#! /bin/sh + +mysql -e 'create database sqlobject_test;' +"`dirname \"$0\"`/run-tests" 'mysql://localhost/sqlobject_test?driver=pymysql&charset=utf8&debug=1' "$@" +mysql -e 'drop database sqlobject_test;' diff --git a/devscripts/run-tests-pypostgresql b/devscripts/run-tests-pypostgresql new file mode 100755 index 00000000..614950fa --- /dev/null +++ b/devscripts/run-tests-pypostgresql @@ -0,0 +1,5 @@ +#! /bin/sh + +createdb -E utf-8 -l en_US.UTF-8 -T template0 test && +"`dirname \"$0\"`/run-tests" 'postgres:/var/run/postgresql/.s.PGSQL.5432/test?driver=pypostgresql&charset=utf-8&debug=1' "$@" +exec dropdb test diff --git a/devscripts/run-tests-sqlite b/devscripts/run-tests-sqlite new file mode 100755 index 00000000..b200a678 --- /dev/null +++ b/devscripts/run-tests-sqlite @@ -0,0 +1,2 @@ +#! /bin/sh +exec "`dirname \"$0\"`/run-tests" "sqlite:/tmp/test-sqlite.sqdb?debug=1" "$@" diff --git a/devscripts/run-tests-sqlite-memory b/devscripts/run-tests-sqlite-memory new file mode 100755 index 00000000..850229bf --- /dev/null +++ b/devscripts/run-tests-sqlite-memory @@ -0,0 +1,2 @@ +#! /bin/sh +exec "`dirname \"$0\"`/run-tests" 'sqlite:/:memory:?debug=1&check_same_thread=' "$@" diff --git a/devscripts/set-commit-date.py b/devscripts/set-commit-date.py new file mode 100755 index 00000000..c5d49d42 --- /dev/null +++ b/devscripts/set-commit-date.py @@ -0,0 +1,46 @@ +#! /usr/bin/env python + +# Find commit date/time for every commit, list files in the commit +# and set the file's modification time to the date/time of the latest commit. + +# Adapted from https://git.wiki.kernel.org/index.php/ExampleScripts#Setting_the_timestamps_of_the_files_to_the_commit_timestamp_of_the_commit_which_last_touched_them # noqa + +import os +import subprocess + +separator = '----- GIT LOG SEPARATOR -----' + +git_log = subprocess.Popen(['git', 'log', '-m', '--first-parent', + '--name-only', '--no-color', + '--format=%s%%n%%ct' % separator], + stdout=subprocess.PIPE, stderr=subprocess.STDOUT) +filenames = set() +# stages: 1 - start of commit, 2 - timestamp, 3 - empty line, 4 - files +stage = 1 +while True: + line = git_log.stdout.readline() + if not line: # EOF + break + line = line.strip() + if (stage in (1, 4)) and (line == separator): # Start of a commit + stage = 2 + elif stage == 2: + stage = 3 + time = int(line) + elif stage == 3: + if line == separator: # Null-merge (git merge -s ours), no files + stage = 2 + continue + stage = 4 + assert line == '', line + elif stage == 4: + filename = line + if filename not in filenames: + filenames.add(filename) + if os.path.exists(filename): + os.utime(filename, (time, time)) + else: + raise ValueError("stage: %d, line: %s" % (stage, line)) + +git_log.wait() +git_log.stdout.close() diff --git a/devscripts/setup b/devscripts/setup new file mode 100755 index 00000000..8f4d2f5c --- /dev/null +++ b/devscripts/setup @@ -0,0 +1,11 @@ +#! /bin/sh + +umask 002 # -rwxrwxr-x +cd "`dirname \"$0\"`"/SQLObject && + +python2.6 setup.py install -O2 && +for py_ver in 2.7 3.4 3.5; do + python$py_ver -m pip install --install-option=-O2 --upgrade . +done && + +exec rm -rf build dist SQLObject.egg-info MANIFEST *.egg diff --git a/devscripts/sftp-frs b/devscripts/sftp-frs new file mode 100755 index 00000000..f7d664b5 --- /dev/null +++ b/devscripts/sftp-frs @@ -0,0 +1,2 @@ +#! /bin/sh +exec sftp frs.sourceforge.net:/home/frs/project/sqlobject diff --git a/devscripts/sftp-web b/devscripts/sftp-web new file mode 100755 index 00000000..e39ad5b2 --- /dev/null +++ b/devscripts/sftp-web @@ -0,0 +1,2 @@ +#! /bin/sh +exec sftp web.sourceforge.net:/home/project-web/sqlobject diff --git a/devscripts/split.sh b/devscripts/split.sh new file mode 100644 index 00000000..9ae68ab9 --- /dev/null +++ b/devscripts/split.sh @@ -0,0 +1,22 @@ +split_tag() { + branch=$2 + set -- `echo $1 | sed -e 's/\./ /g' -e 's/a/ alpha /' -e 's/b/ beta /' -e 's/c/ rc /'` + major=$1 + minor=$2 + micro=$3 + if [ -n "$4" ]; then + if [ "$4" = rc ]; then + state="release candidate" + else + state=$4 + fi + serial=$5 + else + state=final + serial=0 + fi + + if [ -z "$branch" ]; then + branch=$major.$minor + fi +} diff --git a/devscripts/test-split.sh b/devscripts/test-split.sh new file mode 100755 index 00000000..6919f572 --- /dev/null +++ b/devscripts/test-split.sh @@ -0,0 +1,17 @@ +#! /bin/sh + +. `dirname $0`/split.sh && +split_tag 21.12.42c4 + +test_eq() { + if [ "$1" != "$2" ]; then + echo "$1" != "$2" >&2 + fi +} + +test_eq "$branch" 21.12 +test_eq "$major" 21 +test_eq "$minor" 12 +test_eq "$micro" 42 +test_eq "$state" "release candidate" +test_eq "$serial" 4 diff --git a/devscripts/tox-select-envs b/devscripts/tox-select-envs new file mode 100755 index 00000000..49cf3abf --- /dev/null +++ b/devscripts/tox-select-envs @@ -0,0 +1,12 @@ +#! /bin/sh + +pattern="$1" +shift +envs="`tox --listenvs | grep -F $pattern | sed 's/$/,/'`" + +if [ -n "$envs" ]; then + exec tox -e "$envs" "$@" +else + echo "No environments match $pattern" >&2 + exit 1 +fi diff --git a/docs/News.rst b/docs/News.rst index c2669926..57fa4c08 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -10,6 +10,13 @@ News SQLObject 3.3.0 (master) ======================== +Minor features +-------------- + +* Convert scripts repository to devscripts subdirectory. + Some of thses scripts are version-dependent so it's better to have them + in the main repo. + SQLObject 3.2.0 =============== From 1b2aaadcbbe49a1e5d8cb97937fa27f579a60b99 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 19 Mar 2017 05:28:57 +0300 Subject: [PATCH 003/509] Stop publishing docs at GitHub/GitLab Pages and PyPI [skip ci] --- devscripts/build-all-docs | 3 +-- devscripts/publish-docs | 8 +++----- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/devscripts/build-all-docs b/devscripts/build-all-docs index e16b7263..29fca500 100755 --- a/devscripts/build-all-docs +++ b/devscripts/build-all-docs @@ -3,8 +3,7 @@ build_docs() { git checkout "$1" && ../build-docs && - rsync -ahP --del --exclude=.git --exclude=.gitlab-ci.yml \ - --exclude=.nojekyll docs/html/ ../SQLObject-docs/"$2"/ + rsync -ahP --del docs/html/ ../SQLObject-docs/"$2"/ } cd "`dirname \"$0\"`"/SQLObject && diff --git a/devscripts/publish-docs b/devscripts/publish-docs index 10f75968..37276d7e 100755 --- a/devscripts/publish-docs +++ b/devscripts/publish-docs @@ -1,7 +1,5 @@ #! /bin/sh -cd "`dirname \"$0\"`"/SQLObject-docs && -../set-commit-date.py && chmod -R u=rwX,go=rX . && -rsync -hlrtP4 --del . web.sourceforge.net:/home/project-web/sqlobject/htdocs/ && -git archive --format=zip -o "$HOME"/tmp/SQLObject-docs.zip master && -git push gl master && exec git push gh master +cd "`dirname \"$0\"`"/SQLObject-docs && chmod -R u=rwX,go=rX . && +exec rsync -hlrtP4 --del . \ + web.sourceforge.net:/home/project-web/sqlobject/htdocs/ From 69097bb952e46ec8b767a42e042891dcd734c080 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 19 Mar 2017 05:36:10 +0300 Subject: [PATCH 004/509] Include devscripts into sdist [skip ci] --- MANIFEST.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MANIFEST.in b/MANIFEST.in index f486d465..212861b8 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -2,5 +2,7 @@ global-include *.py *.rst *.txt include LICENSE MANIFEST.in .travis.yml circle.yml tox.ini include debian/* sqlobject/.coveragerc include docs/Makefile docs/genapidocs docs/rebuild +recursive-include devscripts * recursive-include docs *.css *.html *.js *.gif *.png +global-exclude *.py[co] prune docs/_build From 01fee4436e02e1079fe2af3ad2a9433f30c724fb Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 19 Mar 2017 05:54:16 +0300 Subject: [PATCH 005/509] Fix: ../SQLObject-docs no longer is a repo [skip ci] --- devscripts/build-all-docs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/devscripts/build-all-docs b/devscripts/build-all-docs index 29fca500..5e8f2866 100755 --- a/devscripts/build-all-docs +++ b/devscripts/build-all-docs @@ -7,8 +7,4 @@ build_docs() { } cd "`dirname \"$0\"`"/SQLObject && -build_docs 3.2.0 && -build_docs master devel && - -cd ../SQLObject-docs && -exec git status +build_docs 3.2.0 && exec build_docs master devel From aa22d9f6f0c92001ac87d035d5e95d9e310f9946 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 19 Mar 2017 21:26:01 +0300 Subject: [PATCH 006/509] Use travis_retry to retry after a network timeout --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 848791ae..eca24704 100644 --- a/.travis.yml +++ b/.travis.yml @@ -74,7 +74,7 @@ env: - TOXENV=py34-firebirdsql - TOXENV=py35-firebirdsql -install: pip install tox coveralls codecov +install: travis_retry pip install tox coveralls codecov matrix: allow_failures: From 63cdcff9efd3ada1509e8e6f2fd1ce2765c6eae6 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 21 Mar 2017 17:22:04 +0300 Subject: [PATCH 007/509] Add ANNOUNCE.rst for version 3.2.0 Announcements are rather version dependent and should have been under version control from the very beginning. [skip ci] --- ANNOUNCE.rst | 140 +++++++++++++++++++++++++++++++++++ devscripts/BRANCH-CHECKLIST | 4 +- devscripts/RELEASE-CHECKLIST | 10 +-- devscripts/branch | 8 +- devscripts/release | 2 +- 5 files changed, 149 insertions(+), 15 deletions(-) create mode 100644 ANNOUNCE.rst diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst new file mode 100644 index 00000000..d10189d9 --- /dev/null +++ b/ANNOUNCE.rst @@ -0,0 +1,140 @@ +Hello! + +I'm pleased to announce version 3.2.0, the first stable release of branch +3.2 of SQLObject. + + +What's new in SQLObject +======================= + +Contributor for this release is Neil Muller. + +Minor features +-------------- + +* Drop table name from ``VACUUM`` command in SQLiteConnection: SQLite + doesn't vacuum a single table and SQLite 3.15 uses the supplied name as + the name of the attached database to vacuum. + +* Remove ``driver`` keyword from RdbhostConnection as it allows one driver + ``rdbhdb``. + +* Add ``driver`` keyword for FirebirdConnection. Allowed values are 'fdb', + 'kinterbasdb' and 'pyfirebirdsql'. Default is to test 'fdb' and + 'kinterbasdb' in that order. pyfirebirdsql is supported but has problems. + +* Add ``driver`` keyword for MySQLConnection. Allowed values are 'mysqldb', + 'connector', 'oursql' and 'pymysql'. Default is to test for mysqldb only. + +* Add support for `MySQL Connector + `_ (pure python; `binary + packages `_ are not at + PyPI and hence are hard to install and test). + +* Add support for `oursql `_ MySQL + driver (only Python 2.6 and 2.7 until oursql author fixes Python 3 + compatibility). + +* Add support for `PyMySQL `_ - pure + python mysql interface). + +* Add parameter ``timeout`` for MSSQLConnection (usable only with pymssql + driver); timeouts are in seconds. + +* Remove deprecated ez_setup.py. + +Drivers (work in progress) +-------------------------- + +* Extend support for PyGreSQL driver. There are still some problems. + +* Add support for `py-postgresql + `_ PostgreSQL driver. There + are still problems with the driver. + +* Add support for `pyfirebirdsql + `_.There are still problems with + the driver. + +Bug fixes +--------- + +* Fix MSSQLConnection.columnsFromSchema: remove `(` and `)` from default + value. + +* Fix MSSQLConnection and SybaseConnection: insert default values into a table + with just one IDENTITY column. + +* Remove excessive NULLs from ``CREATE TABLE`` for MSSQL/Sybase. + +* Fix concatenation operator for MSSQL/Sybase (it's ``+``, not ``||``). + +* Fix MSSQLConnection.server_version() under Py3 (decode version to str). + +Documentation +------------- + +* The docs are now generated with Sphinx. + +* Move ``docs/LICENSE`` to the top-level directory so that Github + recognizes it. + +Tests +----- + +* Rename ``py.test`` -> ``pytest`` in tests and docs. + +* Great Renaming: fix ``pytest`` warnings by renaming ``TestXXX`` classes + to ``SOTestXXX`` to prevent ``pytest`` to recognize them as test classes. + +* Fix ``pytest`` warnings by converting yield tests to plain calls: yield + tests were deprecated in ``pytest``. + +* Tests are now run at CIs with Python 3.5. + +* Drop ``Circle CI``. + +* Run at Travis CI tests with Firebird backend (server version 2.5; + drivers fdb and firebirdsql). There are problems with tests. + +* Run tests at AppVeyor for windows testing. Run tests with MS SQL, + MySQL, Postgres and SQLite backends; use Python 2.7, 3.4 and 3.5, + x86 and x64. There are problems with MS SQL and MySQL. + +For a more complete list, please see the news: +http://sqlobject.org/News.html + + +What is SQLObject +================= + +SQLObject is an object-relational mapper. Your database tables are described +as classes, and rows are instances of those classes. SQLObject is meant to be +easy to use and quick to get started with. + +SQLObject supports a number of backends: MySQL, PostgreSQL, SQLite, +Firebird, Sybase, MSSQL and MaxDB (also known as SAPDB). + +Python 2.6, 2.7 or 3.4+ is required. + + +Where is SQLObject +================== + +Site: +http://sqlobject.org + +Development: +http://sqlobject.org/devel/ + +Mailing list: +https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss + +Archives: +http://news.gmane.org/gmane.comp.python.sqlobject + +Download: +https://pypi.python.org/pypi/SQLObject/3.2.0 + +News and changes: +http://sqlobject.org/News.html diff --git a/devscripts/BRANCH-CHECKLIST b/devscripts/BRANCH-CHECKLIST index 4e64f48d..61e06be7 100644 --- a/devscripts/BRANCH-CHECKLIST +++ b/devscripts/BRANCH-CHECKLIST @@ -17,9 +17,7 @@ a branch, a commit id or a tag. appveyor.yml. In setup.py edit "Development Status" in trove classifiers. Commit. -1c. If the branching point was master the script updates versions in - SQLObject-master.rst. If the branching point was not master the - script updates versions in SQLObject-$branch.rst. +1c. The script updates versions in ANNOUNCE.rst. 2. To deprecate a version of Python edit files docs/News.rst, docs/SQLObject.rst, docs/TODO.rst, sqlobject/main.py, README.rst and diff --git a/devscripts/RELEASE-CHECKLIST b/devscripts/RELEASE-CHECKLIST index acfc14f9..43e939c7 100644 --- a/devscripts/RELEASE-CHECKLIST +++ b/devscripts/RELEASE-CHECKLIST @@ -18,17 +18,17 @@ 3. If it's not master - null-merge to the next higher branch. -4. If release branch is not master - run ../prerelease-tag $NEW_TAG; if +4. Update version, the list of changes, the list of contributors and + download URL in ANNOUNCE.rst + +5. If release branch is not master - run ../prerelease-tag $NEW_TAG; if it's master - run ../prerelease-tag $NEW_TAG master. This checks out the release branch and creates the new tag at the head of the release branch. -5. Update version, the list of changes, the list of contributors and - download URL in SQLObject-$branch.rst. - 6. Run ../release. This generates and uploads new archives to PyPI and if it is a stable release - uploads archives and release announcement - (SQLObject-$branch.rst) to SourceForge. + (ANNOUNCE.rst) to SourceForge. 7. Hide/show old releases at PyPI and SourceForge. diff --git a/devscripts/branch b/devscripts/branch index e3d47714..38ca214a 100755 --- a/devscripts/branch +++ b/devscripts/branch @@ -45,12 +45,8 @@ version_info = (major, minor, micro, release_level, serial)" > sqlobject/__versi `git var GIT_EDITOR` README.rst sqlobject/__version__.py docs/News.rst appveyor.yml setup.py && git commit --message="Next branch will be $major.$next_minor" README.rst sqlobject/__version__.py docs/News.rst setup.py && - cd .. && - cp -p SQLObject-master.rst SQLObject-"$branch".rst && - exec ./replace "$major\.$minor" "$major.$next_minor" SQLObject-master.rst + exec ./replace "$major\.$minor" "$major.$next_minor" ANNOUNCE.rst else - cd .. && - cp -p SQLObject-"$prev_branch".rst SQLObject-"$branch".rst && - exec ./replace "$prev_branch" "$major.$next_minor" SQLObject-"$branch".rst + exec ./replace "$prev_branch" "$major.$next_minor" ANNOUNCE.rst fi diff --git a/devscripts/release b/devscripts/release index 8e8d829f..21ce6e4f 100755 --- a/devscripts/release +++ b/devscripts/release @@ -35,7 +35,7 @@ fi if [ "$state" = final ]; then cp -a dist/* "$HOME"/tmp/ && rsync -ahP4 dist/* frs.sourceforge.net:/home/frs/project/sqlobject/sqlobject/"$version"/ && - rsync -ahP4 ../SQLObject-"$branch".rst frs.sourceforge.net:/home/frs/project/sqlobject/sqlobject/"$version"/README.rst || exit 1 + rsync -ahP4 ANNOUNCE.rst frs.sourceforge.net:/home/frs/project/sqlobject/sqlobject/"$version"/README.rst || exit 1 fi exec rm -rf build dist docs/html SQLObject.egg-info From 899d057a1a2465c8f2fecd0164306a6f70858c8e Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 21 Mar 2017 17:31:42 +0300 Subject: [PATCH 008/509] The next bugfix version will be 3.2.1 [skip ci] --- ANNOUNCE.rst | 98 ++-------------------------------------------------- 1 file changed, 3 insertions(+), 95 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index d10189d9..1dc2eb2f 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,105 +1,13 @@ Hello! -I'm pleased to announce version 3.2.0, the first stable release of branch +I'm pleased to announce version 3.2.1, the first bugfix release of branch 3.2 of SQLObject. What's new in SQLObject ======================= -Contributor for this release is Neil Muller. - -Minor features --------------- - -* Drop table name from ``VACUUM`` command in SQLiteConnection: SQLite - doesn't vacuum a single table and SQLite 3.15 uses the supplied name as - the name of the attached database to vacuum. - -* Remove ``driver`` keyword from RdbhostConnection as it allows one driver - ``rdbhdb``. - -* Add ``driver`` keyword for FirebirdConnection. Allowed values are 'fdb', - 'kinterbasdb' and 'pyfirebirdsql'. Default is to test 'fdb' and - 'kinterbasdb' in that order. pyfirebirdsql is supported but has problems. - -* Add ``driver`` keyword for MySQLConnection. Allowed values are 'mysqldb', - 'connector', 'oursql' and 'pymysql'. Default is to test for mysqldb only. - -* Add support for `MySQL Connector - `_ (pure python; `binary - packages `_ are not at - PyPI and hence are hard to install and test). - -* Add support for `oursql `_ MySQL - driver (only Python 2.6 and 2.7 until oursql author fixes Python 3 - compatibility). - -* Add support for `PyMySQL `_ - pure - python mysql interface). - -* Add parameter ``timeout`` for MSSQLConnection (usable only with pymssql - driver); timeouts are in seconds. - -* Remove deprecated ez_setup.py. - -Drivers (work in progress) --------------------------- - -* Extend support for PyGreSQL driver. There are still some problems. - -* Add support for `py-postgresql - `_ PostgreSQL driver. There - are still problems with the driver. - -* Add support for `pyfirebirdsql - `_.There are still problems with - the driver. - -Bug fixes ---------- - -* Fix MSSQLConnection.columnsFromSchema: remove `(` and `)` from default - value. - -* Fix MSSQLConnection and SybaseConnection: insert default values into a table - with just one IDENTITY column. - -* Remove excessive NULLs from ``CREATE TABLE`` for MSSQL/Sybase. - -* Fix concatenation operator for MSSQL/Sybase (it's ``+``, not ``||``). - -* Fix MSSQLConnection.server_version() under Py3 (decode version to str). - -Documentation -------------- - -* The docs are now generated with Sphinx. - -* Move ``docs/LICENSE`` to the top-level directory so that Github - recognizes it. - -Tests ------ - -* Rename ``py.test`` -> ``pytest`` in tests and docs. - -* Great Renaming: fix ``pytest`` warnings by renaming ``TestXXX`` classes - to ``SOTestXXX`` to prevent ``pytest`` to recognize them as test classes. - -* Fix ``pytest`` warnings by converting yield tests to plain calls: yield - tests were deprecated in ``pytest``. - -* Tests are now run at CIs with Python 3.5. - -* Drop ``Circle CI``. - -* Run at Travis CI tests with Firebird backend (server version 2.5; - drivers fdb and firebirdsql). There are problems with tests. - -* Run tests at AppVeyor for windows testing. Run tests with MS SQL, - MySQL, Postgres and SQLite backends; use Python 2.7, 3.4 and 3.5, - x86 and x64. There are problems with MS SQL and MySQL. +Contributor for this release is For a more complete list, please see the news: http://sqlobject.org/News.html @@ -134,7 +42,7 @@ Archives: http://news.gmane.org/gmane.comp.python.sqlobject Download: -https://pypi.python.org/pypi/SQLObject/3.2.0 +https://pypi.python.org/pypi/SQLObject/3.2.1a0.dev20170311 News and changes: http://sqlobject.org/News.html From fdf95c96fc2f06719af798c27825d4507f3ab9a8 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 21 Mar 2017 17:32:16 +0300 Subject: [PATCH 009/509] The next minor version will be 3.3. [skip ci] --- ANNOUNCE.rst | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 1dc2eb2f..e636be50 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,12 +1,28 @@ Hello! -I'm pleased to announce version 3.2.1, the first bugfix release of branch +I'm pleased to announce version 3.3.0a1, the first alpha of the upcoming +release of branch 3.2 of SQLObject. + +I'm pleased to announce version 3.3.0a2, the second alpha of the upcoming +release of branch 3.2 of SQLObject. + +I'm pleased to announce version 3.3.0b1, the first beta of the upcoming +release of branch 3.2 of SQLObject. + +I'm pleased to announce version 3.3.0rc1, the first release candidate +of the upcoming release of branch 3.2 of SQLObject. + +I'm pleased to announce version 3.3.0, the first stable release of branch +3.2 of SQLObject. + +I'm pleased to announce version 3.3.1, the first bugfix release of branch 3.2 of SQLObject. What's new in SQLObject ======================= + Contributor for this release is For a more complete list, please see the news: @@ -42,7 +58,7 @@ Archives: http://news.gmane.org/gmane.comp.python.sqlobject Download: -https://pypi.python.org/pypi/SQLObject/3.2.1a0.dev20170311 +https://pypi.python.org/pypi/SQLObject/3.3.0a0.dev20170110 News and changes: http://sqlobject.org/News.html From dd3a93bd6d11a2580789c59f852a9b5f94c1c219 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 23 Mar 2017 02:05:30 +0300 Subject: [PATCH 010/509] Refactor release script [skip ci] --- devscripts/release | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/devscripts/release b/devscripts/release index 21ce6e4f..3043a88d 100755 --- a/devscripts/release +++ b/devscripts/release @@ -10,27 +10,15 @@ chmod -R a+rX . && python setup.py build_py && python setup.py register sdist upload --sign && -for py in 6 7; do +for py in 2.6 2.7 3.4 3.5; do find build -name '*.py[co]' -delete && - python2.$py -m compileall build && - python2.$py -O -m compileall build && - python2.$py setup.py bdist_egg upload --sign || exit 1 + python$py -m compileall build && + python$py -O -m compileall build && + python$py setup.py bdist_egg upload --sign || exit 1 done -version="`python setup.py -V`" && -. `dirname $0`/split.sh && -split_tag $version - -if [ "$major" -ge 3 ]; then - find build -name '*.py[co]' -delete && - python setup.py bdist_wheel --universal upload --sign && - for py in 4 5; do - find build -name '*.py[co]' -delete && - python3.$py -m compileall build && - python3.$py -O -m compileall build && - python3.$py setup.py bdist_egg upload --sign || exit 1 - done -fi +find build -name '*.py[co]' -delete && +python setup.py bdist_wheel --universal upload --sign && if [ "$state" = final ]; then cp -a dist/* "$HOME"/tmp/ && From 6c87d84438b7259af7e8348a16c3831df8abedb7 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 25 Mar 2017 07:15:28 +0300 Subject: [PATCH 011/509] Change release process Edit ANNOUNCE.rst in prerelease script. Edit build-all-docs before merging upward. We stopped using ReadTheDocs. Do not commit docs - we stopped using Github/Gitlab Pages. Announce new releases at Twitter/Wiki after mailing lists. [skip ci] --- devscripts/RELEASE-CHECKLIST | 47 ++++++++++++++++++------------------ devscripts/prerelease | 4 +-- 2 files changed, 25 insertions(+), 26 deletions(-) diff --git a/devscripts/RELEASE-CHECKLIST b/devscripts/RELEASE-CHECKLIST index 43e939c7..cbc08c2e 100644 --- a/devscripts/RELEASE-CHECKLIST +++ b/devscripts/RELEASE-CHECKLIST @@ -2,24 +2,25 @@ tests passed. 1. Check out the release branch. If it is a stable release - edit - docs/News.rst to set release date. Commit. If it's not master - merge - to all higher branches and master. + docs/News.rst to set release date. Commit. -2. If release branch is not master - run ../prerelease $NEW_TAG; if it's - master - run ../prerelease $NEW_TAG master. +2. If it's the first stable release of the branch - edit build-all-docs, + advance stable branch. Commit. If it's not master - merge to all higher + branches and master. -2a. The script checks out the release branch and calls editor; edit - __version__.py and README.rst in the release branch - fix versions. - Edit section [egg_info] in setup.cfg - set if it is a stable or - development release. In setup.py edit "Development Status" in trove - classifiers; edit download URL: if a non-stable version - append - 'dev' and date stamp, for a stable version remove 'dev' and date - stamp). Commit. Verify. +3. If release branch is not master - run ../prerelease $NEW_TAG; if it's + master - run ../prerelease $NEW_TAG master. -3. If it's not master - null-merge to the next higher branch. +3a. The script checks out the release branch and calls editor; update + version, the list of contributors, the list of changes and download + URL in ANNOUNCE.rst; edit __version__.py and README.rst in the release + branch - fix versions. Edit section [egg_info] in setup.cfg - set if + it is a stable or development release. In setup.py edit "Development + Status" in trove classifiers; edit download URL: if a non-stable + version - append 'dev' and date stamp, for a stable version remove + 'dev' and date stamp). Commit. Verify. -4. Update version, the list of changes, the list of contributors and - download URL in ANNOUNCE.rst +4. If it's not master - null-merge to the next higher branch. 5. If release branch is not master - run ../prerelease-tag $NEW_TAG; if it's master - run ../prerelease-tag $NEW_TAG master. This checks out @@ -32,19 +33,17 @@ 7. Hide/show old releases at PyPI and SourceForge. -8. If it's the first stable release of the branch - edit build-all-docs, - advance stable branch. If it's a stable release edit stable tag at - ReadTheDocs. Generate new docs using ./build-all-docs. Commit generated - docs. Upload docs using ./publish-docs. +8. Generate new docs using ./build-all-docs. Upload docs using + ./publish-docs. 9. Run ../push-all in the development repository to push all branches and tags to the public repositories. -10. Announce new release(s) at Twitter (https://twitter.com/SQLObject) and - Wikipedia (https://en.wikipedia.org/wiki/SQLObject). If it is a stable - release - announce it at - https://en.wikipedia.org/wiki/Comparison_of_object-relational_mapping_software. - -11. Send announcement to the SQLObject mailing list. For a stable +10. Send announcement to the SQLObject mailing list. For a stable release send announcements to python, python-announce and python-db mailing lists. + +11. Announce new release(s) at Twitter (https://twitter.com/SQLObject) and + Wikipedia (https://en.wikipedia.org/wiki/SQLObject). If it is a stable + release - announce it at + https://en.wikipedia.org/wiki/Comparison_of_object-relational_mapping_software. diff --git a/devscripts/prerelease b/devscripts/prerelease index 0386c16d..17ed8904 100755 --- a/devscripts/prerelease +++ b/devscripts/prerelease @@ -22,5 +22,5 @@ micro = $micro release_level = '$state' serial = $serial version_info = (major, minor, micro, release_level, serial)" > sqlobject/__version__.py && -`git var GIT_EDITOR` docs/News.rst sqlobject/__version__.py README.rst setup.cfg setup.py && -exec git commit --message="Release $tag" docs/News.rst sqlobject/__version__.py README.rst setup.cfg setup.py +`git var GIT_EDITOR` ANNOUNCE.rst docs/News.rst sqlobject/__version__.py README.rst setup.cfg setup.py && +exec git commit --message="Release $tag" ANNOUNCE.rst docs/News.rst sqlobject/__version__.py README.rst setup.cfg setup.py From 093945bac78e061b5daf58a6dc544597f10b2c53 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 25 Mar 2017 16:21:46 +0300 Subject: [PATCH 012/509] Run tests at Travis CI and AppVeyor with Python 3.6, x86 and x64 --- .travis.yml | 17 +++++++++++++++++ appveyor.yml | 14 ++++++++++++++ docs/News.rst | 5 +++++ setup.py | 1 + tox.ini | 49 +++++++++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 84 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index eca24704..d29b2ba9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,9 @@ sudo: required language: python +python: + - "3.6" + cache: pip addons: @@ -37,42 +40,52 @@ env: - TOXENV=py27-mysqldb - TOXENV=py34-mysqlclient - TOXENV=py35-mysqlclient + - TOXENV=py36-mysqlclient - TOXENV=py26-mysql-connector - TOXENV=py27-mysql-connector - TOXENV=py34-mysql-connector - TOXENV=py35-mysql-connector + - TOXENV=py36-mysql-connector - TOXENV=py26-mysql-oursql - TOXENV=py27-mysql-oursql - TOXENV=py26-pymysql - TOXENV=py27-pymysql - TOXENV=py34-pymysql - TOXENV=py35-pymysql + - TOXENV=py36-pymysql - TOXENV=py26-postgres-psycopg - TOXENV=py27-postgres-psycopg - TOXENV=py34-postgres-psycopg - TOXENV=py35-postgres-psycopg + - TOXENV=py36-postgres-psycopg - TOXENV=py26-postgres-pygresql - TOXENV=py27-postgres-pygresql - TOXENV=py34-postgres-pygresql - TOXENV=py35-postgres-pygresql + - TOXENV=py36-postgres-pygresql - TOXENV=py34-pypostgresql - TOXENV=py35-pypostgresql + - TOXENV=py36-pypostgresql - TOXENV=py26-sqlite - TOXENV=py27-sqlite - TOXENV=py34-sqlite - TOXENV=py35-sqlite + - TOXENV=py36-sqlite - TOXENV=py26-sqlite-memory - TOXENV=py27-sqlite-memory - TOXENV=py34-sqlite-memory - TOXENV=py35-sqlite-memory + - TOXENV=py36-sqlite-memory - TOXENV=py27-flake8 - TOXENV=py34-flake8 - TOXENV=py27-firebird-fdb - TOXENV=py34-firebird-fdb - TOXENV=py35-firebird-fdb + - TOXENV=py36-firebird-fdb - TOXENV=py27-firebirdsql - TOXENV=py34-firebirdsql - TOXENV=py35-firebirdsql + - TOXENV=py36-firebirdsql install: travis_retry pip install tox coveralls codecov @@ -82,14 +95,18 @@ matrix: - env: TOXENV=py27-postgres-pygresql - env: TOXENV=py34-postgres-pygresql - env: TOXENV=py35-postgres-pygresql + - env: TOXENV=py36-postgres-pygresql - env: TOXENV=py34-pypostgresql - env: TOXENV=py35-pypostgresql + - env: TOXENV=py36-pypostgresql - env: TOXENV=py27-firebird-fdb - env: TOXENV=py34-firebird-fdb - env: TOXENV=py35-firebird-fdb + - env: TOXENV=py36-firebird-fdb - env: TOXENV=py27-firebirdsql - env: TOXENV=py34-firebirdsql - env: TOXENV=py35-firebirdsql + - env: TOXENV=py36-firebirdsql fast_finish: true script: tox -e ${TOXENV} diff --git a/appveyor.yml b/appveyor.yml index c7ccf442..ae8b89a3 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -47,6 +47,12 @@ environment: - PYTHON: "C:\\Python35-x64" db: postgresql TOX_ENV: "py35-postgres-psycopg-w32" + - PYTHON: "C:\\Python36" + db: postgresql + TOX_ENV: "py36-postgres-psycopg-w32" + - PYTHON: "C:\\Python36-x64" + db: postgresql + TOX_ENV: "py36-postgres-psycopg-w32" - PYTHON: "C:\\Python27" TOX_ENV: "py27-sqlite-w32" - PYTHON: "C:\\Python27-x64" @@ -59,6 +65,10 @@ environment: TOX_ENV: "py35-sqlite-w32" - PYTHON: "C:\\Python35-x64" TOX_ENV: "py35-sqlite-w32" + - PYTHON: "C:\\Python36" + TOX_ENV: "py36-sqlite-w32" + - PYTHON: "C:\\Python36-x64" + TOX_ENV: "py36-sqlite-w32" - PYTHON: "C:\\Python27" TOX_ENV: "py27-sqlite-memory-w32" - PYTHON: "C:\\Python27-x64" @@ -71,6 +81,10 @@ environment: TOX_ENV: "py35-sqlite-memory-w32" - PYTHON: "C:\\Python35-x64" TOX_ENV: "py35-sqlite-memory-w32" + - PYTHON: "C:\\Python36" + TOX_ENV: "py36-sqlite-memory-w32" + - PYTHON: "C:\\Python36-x64" + TOX_ENV: "py36-sqlite-memory-w32" install: # Ensure we use the right python version diff --git a/docs/News.rst b/docs/News.rst index 57fa4c08..6123ae03 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -17,6 +17,11 @@ Minor features Some of thses scripts are version-dependent so it's better to have them in the main repo. +Tests +----- + +* Run tests at Travis CI and AppVeyor with Python 3.6, x86 and x64. + SQLObject 3.2.0 =============== diff --git a/setup.py b/setup.py index 031c43d9..d4b43245 100755 --- a/setup.py +++ b/setup.py @@ -80,6 +80,7 @@ "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", "Topic :: Database", "Topic :: Database :: Front-Ends", "Topic :: Software Development :: Libraries :: Python Modules", diff --git a/tox.ini b/tox.ini index 3cd16776..38a87781 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 1.8 -envlist = py{26,27}-{mysqldb,mysql-oursql},py{34,35}-{mysqlclient,pypostgresql},py{26,27,34,35}-{mysql-connector,pymysql,postgres-psycopg,postgres-pygresql,sqlite,sqlite-memory},py{27,34,35}-{firebird-fdb,firebirdsql},py{27,34}-flake8,py{27,34,35}-{mssql,mysql-connector,postgres-psycopg,sqlite,sqlite-memory}-w32 +envlist = py{26,27}-{mysqldb,mysql-oursql},py{34,35,36}-{mysqlclient,pypostgresql},py{26,27,34,35,36}-{mysql-connector,pymysql,postgres-psycopg,postgres-pygresql,sqlite,sqlite-memory},py{27,34,35,36}-{firebird-fdb,firebirdsql},py{27,34}-flake8,py{27,34,35,36}-{mssql,mysql-connector,postgres-psycopg,sqlite,sqlite-memory}-w32 # Base test environment settings [testenv] @@ -10,7 +10,7 @@ deps = pytest pytest-cov py{26,27}: FormEncode >= 1.1.1, != 1.3.0 - py{34,35}: FormEncode >= 1.3.1 + py{34,35,36}: FormEncode >= 1.3.1 PyDispatcher>=2.0.4 py{26,27}: egenix-mx-base mysqldb: mysql-python @@ -62,6 +62,9 @@ commands = {[mysqlclient]commands} [testenv:py35-mysqlclient] commands = {[mysqlclient]commands} +[testenv:py36-mysqlclient] +commands = {[mysqlclient]commands} + [mysql-connector] commands = -mysql -e 'drop database sqlobject_test;' @@ -81,6 +84,9 @@ commands = {[mysql-connector]commands} [testenv:py35-mysql-connector] commands = {[mysql-connector]commands} +[testenv:py36-mysql-connector] +commands = {[mysql-connector]commands} + [oursql] commands = -mysql -e 'drop database sqlobject_test;' @@ -113,6 +119,9 @@ commands = {[pymysql]commands} [testenv:py35-pymysql] commands = {[pymysql]commands} +[testenv:py36-pymysql] +commands = {[pymysql]commands} + # PostgreSQL test environments [psycopg] commands = @@ -133,6 +142,9 @@ commands = {[psycopg]commands} [testenv:py35-postgres-psycopg] commands = {[psycopg]commands} +[testenv:py36-postgres-psycopg] +commands = {[psycopg]commands} + [pygresql] commands = -dropdb -U postgres -w sqlobject_test @@ -152,6 +164,9 @@ commands = {[pygresql]commands} [testenv:py35-postgres-pygresql] commands = {[pygresql]commands} +[testenv:py36-postgres-pygresql] +commands = {[pygresql]commands} + [pypostgresql] commands = -dropdb -U postgres -w sqlobject_test @@ -165,6 +180,9 @@ commands = {[pypostgresql]commands} [testenv:py35-pypostgresql] commands = {[pypostgresql]commands} +[testenv:py36-pypostgresql] +commands = {[pypostgresql]commands} + # SQLite test environments [sqlite] commands = @@ -184,6 +202,9 @@ commands = {[sqlite]commands} [testenv:py35-sqlite] commands = {[sqlite]commands} +[testenv:py36-sqlite] +commands = {[sqlite]commands} + [sqlite-memory] commands = pytest --cov=sqlobject -D sqlite:/:memory:?debug=1 @@ -200,6 +221,9 @@ commands = {[sqlite-memory]commands} [testenv:py35-sqlite-memory] commands = {[sqlite-memory]commands} +[testenv:py36-sqlite-memory] +commands = {[sqlite-memory]commands} + # Firebird database test environments [fdb] commands = @@ -217,6 +241,9 @@ commands = {[fdb]commands} [testenv:py35-firebird-fdb] commands = {[fdb]commands} +[testenv:py36-firebird-fdb] +commands = {[fdb]commands} + [firebirdsql] commands = sudo rm -f /tmp/test.fdb @@ -233,6 +260,9 @@ commands = {[firebirdsql]commands} [testenv:py35-firebirdsql] commands = {[firebirdsql]commands} +[testenv:py36-firebirdsql] +commands = {[firebirdsql]commands} + # Special test environments [testenv:py27-flake8] changedir = ./ @@ -263,6 +293,9 @@ commands = {[mssql-w32]commands} [testenv:py35-mssql-w32] commands = {[mssql-w32]commands} +[testenv:py36-mssql-w32] +commands = {[mssql-w32]commands} + [mysql-connector-w32] commands = -mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' @@ -279,6 +312,9 @@ commands = {[mysql-connector-w32]commands} [testenv:py35-mysql-connector-w32] commands = {[mysql-connector-w32]commands} +[testenv:py36-mysql-connector-w32] +commands = {[mysql-connector-w32]commands} + [psycopg-w32] commands = -dropdb -U postgres -w sqlobject_test @@ -295,6 +331,9 @@ commands = {[psycopg-w32]commands} [testenv:py35-postgres-psycopg-w32] commands = {[psycopg-w32]commands} +[testenv:py36-postgres-psycopg-w32] +commands = {[psycopg-w32]commands} + [sqlite-w32] commands = pytest --cov=sqlobject -D sqlite:/C:/projects/sqlobject/sqlobject_test.sqdb?debug=1 @@ -308,6 +347,9 @@ commands = {[sqlite-w32]commands} [testenv:py35-sqlite-w32] commands = {[sqlite-w32]commands} +[testenv:py36-sqlite-w32] +commands = {[sqlite-w32]commands} + [sqlite-memory-w32] commands = pytest --cov=sqlobject -D sqlite:/:memory:?debug=1 @@ -320,3 +362,6 @@ commands = {[sqlite-memory-w32]commands} [testenv:py35-sqlite-memory-w32] commands = {[sqlite-memory-w32]commands} + +[testenv:py36-sqlite-memory-w32] +commands = {[sqlite-memory-w32]commands} From 8d714e82c7fb3618c2a960ef417d799e07932170 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 25 Mar 2017 16:30:29 +0300 Subject: [PATCH 013/509] Refactor .travis.yml: move around some sections --- .travis.yml | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/.travis.yml b/.travis.yml index d29b2ba9..e7773d15 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,23 +18,6 @@ addons: - firebird2.5-super postgresql: "9.4" -before_install: - # Start the firebird database server. - # We use firebird-super, so there's none of the inetd configuration - # required by firebird-classic. - # We also create a test user for the firebird test and - # create a script that can be fed into isql-fb - # to create the test database. - - if [[ $TOXENV = *firebird* ]]; then - sudo sed -i /etc/default/firebird2.5 -e 's/=no/=yes/' && - sudo /etc/init.d/firebird2.5-super start && sleep 5 && - sudo touch /var/lib/firebird/create_test_db && - sudo chmod 666 /var/lib/firebird/create_test_db && - echo "CREATE DATABASE 'localhost:/tmp/test.fdb';" > /var/lib/firebird/create_test_db && - sudo chmod 644 /var/lib/firebird/create_test_db && - sudo gsec -user sysdba -pass masterkey -add test -pw test; - fi - env: - TOXENV=py26-mysqldb - TOXENV=py27-mysqldb @@ -87,8 +70,6 @@ env: - TOXENV=py35-firebirdsql - TOXENV=py36-firebirdsql -install: travis_retry pip install tox coveralls codecov - matrix: allow_failures: - env: TOXENV=py26-postgres-pygresql @@ -109,6 +90,25 @@ matrix: - env: TOXENV=py36-firebirdsql fast_finish: true +before_install: + # Start the firebird database server. + # We use firebird-super, so there's none of the inetd configuration + # required by firebird-classic. + # We also create a test user for the firebird test and + # create a script that can be fed into isql-fb + # to create the test database. + - if [[ $TOXENV = *firebird* ]]; then + sudo sed -i /etc/default/firebird2.5 -e 's/=no/=yes/' && + sudo /etc/init.d/firebird2.5-super start && sleep 5 && + sudo touch /var/lib/firebird/create_test_db && + sudo chmod 666 /var/lib/firebird/create_test_db && + echo "CREATE DATABASE 'localhost:/tmp/test.fdb';" > /var/lib/firebird/create_test_db && + sudo chmod 644 /var/lib/firebird/create_test_db && + sudo gsec -user sysdba -pass masterkey -add test -pw test; + fi + +install: travis_retry pip install tox coveralls codecov + script: tox -e ${TOXENV} after_success: From 0faf96630e54a95b43e5829ac5ab5251136a0975 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 25 Mar 2017 18:27:54 +0300 Subject: [PATCH 014/509] Disable microseconds at AppVeyor for MySQL --- sqlobject/mysql/mysqlconnection.py | 5 +++++ sqlobject/tests/dbtest.py | 6 +++++- tox.ini | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index cffb7d5d..05ef526c 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -1,3 +1,5 @@ +import os + from sqlobject import col, dberrors from sqlobject.compat import PY2 from sqlobject.dbconnection import DBAPI @@ -411,6 +413,9 @@ def server_version(self): def can_use_microseconds(self): if self._can_use_microseconds is not None: return self._can_use_microseconds + if os.environ.get('APPVEYOR'): + self._can_use_microseconds = False + return False server_version = self.server_version() if server_version is None: return None diff --git a/sqlobject/tests/dbtest.py b/sqlobject/tests/dbtest.py index 9102d99f..8ddcaa3b 100644 --- a/sqlobject/tests/dbtest.py +++ b/sqlobject/tests/dbtest.py @@ -120,7 +120,11 @@ def getConnectionURI(): if 'sphinx' not in sys.modules: print("Could not open database: %s" % e, file=sys.stderr) else: - if connection.dbName == 'firebird': + if (connection.dbName == 'firebird') \ + or ( + (connection.dbName == 'mysql') and + (os.environ.get('APPVEYOR')) + ): use_microseconds(False) diff --git a/tox.ini b/tox.ini index 38a87781..58c94986 100644 --- a/tox.ini +++ b/tox.ini @@ -24,7 +24,7 @@ deps = firebird-fdb: fdb firebirdsql: firebirdsql mssql: pymssql -passenv = CI TRAVIS TRAVIS_* PGPASSWORD +passenv = CI TRAVIS TRAVIS_* PGPASSWORD APPVEYOR # Don't fail or warn on uninstalled commands whitelist_externals = mysql From 801dae53ba83aa313b281a1aa5782f84433b79e1 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 25 Mar 2017 22:48:12 +0300 Subject: [PATCH 015/509] Use mysql-connector version <= 2.2.2 mysql-connector >= 2.2.3 requires Protobuf >= 2.6.0. --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 58c94986..edf6e412 100644 --- a/tox.ini +++ b/tox.ini @@ -15,7 +15,7 @@ deps = py{26,27}: egenix-mx-base mysqldb: mysql-python mysqlclient: mysqlclient - mysql-connector: mysql-connector + mysql-connector: mysql-connector <= 2.2.2 mysql-oursql: oursql pymysql: pymysql postgres-psycopg: psycopg2 From ca89f873c3137c2f47e18fbb435ee0c4af3a3a4a Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 25 Mar 2017 23:23:35 +0300 Subject: [PATCH 016/509] Run MySQL tests at AppVeyor with Python 3.5 and 3.6 --- appveyor.yml | 6 ++++++ tox.ini | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index ae8b89a3..5966552a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -29,6 +29,12 @@ environment: - PYTHON: "C:\\Python34" db: mysql TOX_ENV: "py34-mysql-connector-w32" + - PYTHON: "C:\\Python35" + db: mysql + TOX_ENV: "py35-mysql-connector-w32" + - PYTHON: "C:\\Python36" + db: mysql + TOX_ENV: "py36-mysql-connector-w32" - PYTHON: "C:\\Python27" db: postgresql TOX_ENV: "py27-postgres-psycopg-w32" diff --git a/tox.ini b/tox.ini index edf6e412..3d37e1d3 100644 --- a/tox.ini +++ b/tox.ini @@ -300,7 +300,7 @@ commands = {[mssql-w32]commands} commands = -mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' mysql -u root "-pPassword12!" -e 'create database sqlobject_test;' - pytest --cov=sqlobject -D "mysql://root:Password12!@localhost/sqlobject_test?driver=connector&debug=1" + pytest --cov=sqlobject -D "mysql://root:Password12!@localhost/sqlobject_test?driver=connector&charset=utf8&debug=1" mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' [testenv:py27-mysql-connector-w32] From aa993f05dfaa4e12e7c501e14e70e0c2d9861f19 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 26 Mar 2017 01:56:20 +0300 Subject: [PATCH 017/509] Fix tests under Python 3.6 + SQLite memory DB --- sqlobject/tests/dbtest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlobject/tests/dbtest.py b/sqlobject/tests/dbtest.py index 8ddcaa3b..ed1cb487 100644 --- a/sqlobject/tests/dbtest.py +++ b/sqlobject/tests/dbtest.py @@ -101,7 +101,7 @@ def getConnection(**kw): conn.debug = True if conftest.option.show_sql_output: conn.debugOutput = True - if conn.dbName == 'sqlite': + if (conn.dbName == 'sqlite') and not conn._memory: speedupSQLiteConnection(conn) return conn From b6c60444aefc8cb2a8a192ba38f59e61a2505ec8 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 26 Mar 2017 03:40:07 +0300 Subject: [PATCH 018/509] Work with Python 3.6 [skip ci] --- devscripts/release | 2 +- devscripts/run-all-tests | 2 +- devscripts/setup | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/devscripts/release b/devscripts/release index 3043a88d..ee492aae 100755 --- a/devscripts/release +++ b/devscripts/release @@ -10,7 +10,7 @@ chmod -R a+rX . && python setup.py build_py && python setup.py register sdist upload --sign && -for py in 2.6 2.7 3.4 3.5; do +for py in 2.6 2.7 3.4 3.5 3.6; do find build -name '*.py[co]' -delete && python$py -m compileall build && python$py -O -m compileall build && diff --git a/devscripts/run-all-tests b/devscripts/run-all-tests index 6c1bae6a..80b2e1ad 100755 --- a/devscripts/run-all-tests +++ b/devscripts/run-all-tests @@ -3,7 +3,7 @@ cd "`dirname \"$0\"`"/SQLObject && SO_DIR="`dirname $0`" -for py_ver in 2.6 2.7 3.4 3.5; do +for py_ver in 2.6 2.7 3.4 3.5 3.6; do echo "---------- PYTHON $py_ver "$1" ----------" "$SO_DIR"/cleanup && PY_VER=$py_ver "$SO_DIR"/run-tests-"$1" \ diff --git a/devscripts/setup b/devscripts/setup index 8f4d2f5c..315e84ab 100755 --- a/devscripts/setup +++ b/devscripts/setup @@ -4,7 +4,7 @@ umask 002 # -rwxrwxr-x cd "`dirname \"$0\"`"/SQLObject && python2.6 setup.py install -O2 && -for py_ver in 2.7 3.4 3.5; do +for py_ver in 2.7 3.4 3.5 3.6; do python$py_ver -m pip install --install-option=-O2 --upgrade . done && From 6fa36b817c9bc7c7af42647a99cb8a28f48bb726 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 29 Mar 2017 23:59:27 +0300 Subject: [PATCH 019/509] Display pip's version at AppVeyor --- appveyor.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/appveyor.yml b/appveyor.yml index 5966552a..6a7aae7d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -96,6 +96,7 @@ install: # Ensure we use the right python version - "SET PATH=%PYTHON%;%PYTHON%\\Scripts;C:\\Program Files\\MySQL\\MySQL Server 5.7\\bin;C:\\Program Files\\PostgreSQL\\9.5\\bin;%PATH%" - "python --version" + - "pip --version" - "pip install -r requirements.txt" - "pip install tox" # Enable TCP for mssql From b4e68b5bac08d4163f31d65365881511748eb594 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 30 Mar 2017 00:45:25 +0300 Subject: [PATCH 020/509] Do not install requirements - they are installed by tox --- appveyor.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 6a7aae7d..d2ff8abb 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -97,7 +97,6 @@ install: - "SET PATH=%PYTHON%;%PYTHON%\\Scripts;C:\\Program Files\\MySQL\\MySQL Server 5.7\\bin;C:\\Program Files\\PostgreSQL\\9.5\\bin;%PATH%" - "python --version" - "pip --version" - - "pip install -r requirements.txt" - "pip install tox" # Enable TCP for mssql # (from appveyor documentation) From d62190196491847b78f0e0ab953bc2e72f654e6f Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 3 Apr 2017 01:05:21 +0300 Subject: [PATCH 021/509] Add postrelease devscript [skip ci] --- devscripts/RELEASE-CHECKLIST | 11 ++++++++--- devscripts/postrelease | 6 ++++++ 2 files changed, 14 insertions(+), 3 deletions(-) create mode 100755 devscripts/postrelease diff --git a/devscripts/RELEASE-CHECKLIST b/devscripts/RELEASE-CHECKLIST index cbc08c2e..efc9d504 100644 --- a/devscripts/RELEASE-CHECKLIST +++ b/devscripts/RELEASE-CHECKLIST @@ -36,10 +36,15 @@ 8. Generate new docs using ./build-all-docs. Upload docs using ./publish-docs. -9. Run ../push-all in the development repository to push all branches - and tags to the public repositories. +9. Run ../postrelease. The script restores ANNOUNCE.rst from the previous + commit (HEAD~). It calls editor; update next version, remove the list + of contributors and the list of changes, edit download URL in + ANNOUNCE.rst. Edit docs/News.rst - add new version. -10. Send announcement to the SQLObject mailing list. For a stable +10. Run ../push-all in the development repository to push all branches + and tags to the public repositories. + +11. Send announcement to the SQLObject mailing list. For a stable release send announcements to python, python-announce and python-db mailing lists. diff --git a/devscripts/postrelease b/devscripts/postrelease new file mode 100755 index 00000000..bfb03d49 --- /dev/null +++ b/devscripts/postrelease @@ -0,0 +1,6 @@ +#! /bin/sh + +git checkout HEAD~ ANNOUNCE.rst && + +`git var GIT_EDITOR` ANNOUNCE.rst docs/News.rst && +exec git commit --message="Prepare for the next release" ANNOUNCE.rst docs/News.rst From 58925e1a6fdbadd200c9b41c251317c30d34bd9b Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 3 Apr 2017 01:14:40 +0300 Subject: [PATCH 022/509] Update release script Separate build steps from upload. Use twine. [skip ci] --- devscripts/release | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/devscripts/release b/devscripts/release index ee492aae..d04373cc 100755 --- a/devscripts/release +++ b/devscripts/release @@ -8,17 +8,18 @@ chmod -R a+rX . && ../set-commit-date.py && python setup.py build_py && -python setup.py register sdist upload --sign && +python setup.py sdist && for py in 2.6 2.7 3.4 3.5 3.6; do find build -name '*.py[co]' -delete && + python$py setup.py build_py && python$py -m compileall build && python$py -O -m compileall build && - python$py setup.py bdist_egg upload --sign || exit 1 + python$py setup.py bdist_egg || exit 1 done find build -name '*.py[co]' -delete && -python setup.py bdist_wheel --universal upload --sign && +python setup.py bdist_wheel --universal && if [ "$state" = final ]; then cp -a dist/* "$HOME"/tmp/ && @@ -26,4 +27,7 @@ if [ "$state" = final ]; then rsync -ahP4 ANNOUNCE.rst frs.sourceforge.net:/home/frs/project/sqlobject/sqlobject/"$version"/README.rst || exit 1 fi +twine register dist/SQLObject-"`python setup.py --version`".tar.gz && +twine upload --sign dist/* && + exec rm -rf build dist docs/html SQLObject.egg-info From b7e0a90be5c926b1b0478d1b24ccee9aa67ce2cb Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 31 Mar 2017 20:53:43 +0300 Subject: [PATCH 023/509] Add PyODBC driver for PostgreSQL Add run_with_env.cmd from https://github.com/ogrisel/python-appveyor-demo Pass necessary environment variables. --- appveyor.yml | 91 ++++++++++++++++- docs/News.rst | 5 + docs/SQLObject.rst | 11 ++- run_with_env.cmd | 88 +++++++++++++++++ sqlobject/postgres/pgconnection.py | 151 +++++++++++++++++------------ tox.ini | 46 ++++++++- 6 files changed, 322 insertions(+), 70 deletions(-) create mode 100644 run_with_env.cmd diff --git a/appveyor.yml b/appveyor.yml index d2ff8abb..c52e6578 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -15,81 +15,167 @@ environment: PGUSER: "postgres" PGPASSWORD: "Password12!" + global: + # SDK v7.0 MSVC Express 2008's SetEnv.cmd script will fail if the + # /E:ON and /V:ON options are not enabled in the batch script intepreter + # See: http://stackoverflow.com/a/13751649/163740 + CMD_IN_ENV: "cmd /E:ON /V:ON /C .\\run_with_env.cmd" + matrix: # from https://www.appveyor.com/docs/installed-software/#python - PYTHON: "C:\\Python27" + PYTHON_VERSION: "2.7" + PYTHON_ARCH: "32" db: mssql2014 TOX_ENV: "py27-mssql-w32" - PYTHON: "C:\\Python34" + PYTHON_VERSION: "3.4" + PYTHON_ARCH: "32" db: mssql2014 TOX_ENV: "py34-mssql-w32" - PYTHON: "C:\\Python27" + PYTHON_VERSION: "2.7" + PYTHON_ARCH: "32" db: mysql TOX_ENV: "py27-mysql-connector-w32" - PYTHON: "C:\\Python34" + PYTHON_VERSION: "3.4" + PYTHON_ARCH: "32" db: mysql TOX_ENV: "py34-mysql-connector-w32" - PYTHON: "C:\\Python35" + PYTHON_VERSION: "3.5" + PYTHON_ARCH: "32" db: mysql TOX_ENV: "py35-mysql-connector-w32" - PYTHON: "C:\\Python36" + PYTHON_VERSION: "3.6" + PYTHON_ARCH: "32" db: mysql TOX_ENV: "py36-mysql-connector-w32" - PYTHON: "C:\\Python27" + PYTHON_VERSION: "2.7" + PYTHON_ARCH: "32" db: postgresql TOX_ENV: "py27-postgres-psycopg-w32" - PYTHON: "C:\\Python27-x64" + PYTHON_VERSION: "2.7" + PYTHON_ARCH: "64" db: postgresql TOX_ENV: "py27-postgres-psycopg-w32" - PYTHON: "C:\\Python34" + PYTHON_VERSION: "3.4" + PYTHON_ARCH: "32" db: postgresql TOX_ENV: "py34-postgres-psycopg-w32" - PYTHON: "C:\\Python34-x64" + PYTHON_VERSION: "3.4" + PYTHON_ARCH: "64" db: postgresql TOX_ENV: "py34-postgres-psycopg-w32" - PYTHON: "C:\\Python35" + PYTHON_VERSION: "3.5" + PYTHON_ARCH: "32" db: postgresql TOX_ENV: "py35-postgres-psycopg-w32" - PYTHON: "C:\\Python35-x64" + PYTHON_VERSION: "3.5" + PYTHON_ARCH: "64" db: postgresql TOX_ENV: "py35-postgres-psycopg-w32" - PYTHON: "C:\\Python36" + PYTHON_VERSION: "3.6" + PYTHON_ARCH: "32" db: postgresql TOX_ENV: "py36-postgres-psycopg-w32" - PYTHON: "C:\\Python36-x64" + PYTHON_VERSION: "3.6" + PYTHON_ARCH: "64" db: postgresql TOX_ENV: "py36-postgres-psycopg-w32" + - PYTHON: "C:\\Python27-x64" + PYTHON_VERSION: "2.7" + PYTHON_ARCH: "64" + db: postgresql + TOX_ENV: "py27-postgres-odbc-w32" + - PYTHON: "C:\\Python34-x64" + PYTHON_VERSION: "3.4" + PYTHON_ARCH: "64" + db: postgresql + TOX_ENV: "py34-postgres-odbc-w32" + - PYTHON: "C:\\Python35-x64" + PYTHON_VERSION: "3.5" + PYTHON_ARCH: "64" + db: postgresql + TOX_ENV: "py35-postgres-odbc-w32" + - PYTHON: "C:\\Python36-x64" + PYTHON_VERSION: "3.6" + PYTHON_ARCH: "64" + db: postgresql + TOX_ENV: "py36-postgres-odbc-w32" - PYTHON: "C:\\Python27" + PYTHON_VERSION: "2.7" + PYTHON_ARCH: "32" TOX_ENV: "py27-sqlite-w32" - PYTHON: "C:\\Python27-x64" + PYTHON_VERSION: "2.7" + PYTHON_ARCH: "64" TOX_ENV: "py27-sqlite-w32" - PYTHON: "C:\\Python34" + PYTHON_VERSION: "3.4" + PYTHON_ARCH: "32" TOX_ENV: "py34-sqlite-w32" - PYTHON: "C:\\Python34-x64" + PYTHON_VERSION: "3.4" + PYTHON_ARCH: "64" TOX_ENV: "py34-sqlite-w32" - PYTHON: "C:\\Python35" + PYTHON_VERSION: "3.5" + PYTHON_ARCH: "32" TOX_ENV: "py35-sqlite-w32" - PYTHON: "C:\\Python35-x64" + PYTHON_VERSION: "3.5" + PYTHON_ARCH: "64" TOX_ENV: "py35-sqlite-w32" - PYTHON: "C:\\Python36" + PYTHON_VERSION: "3.6" + PYTHON_ARCH: "32" TOX_ENV: "py36-sqlite-w32" - PYTHON: "C:\\Python36-x64" + PYTHON_VERSION: "3.6" + PYTHON_ARCH: "64" TOX_ENV: "py36-sqlite-w32" - PYTHON: "C:\\Python27" + PYTHON_VERSION: "2.7" + PYTHON_ARCH: "32" TOX_ENV: "py27-sqlite-memory-w32" - PYTHON: "C:\\Python27-x64" + PYTHON_VERSION: "2.7" + PYTHON_ARCH: "64" TOX_ENV: "py27-sqlite-memory-w32" - PYTHON: "C:\\Python34" + PYTHON_VERSION: "3.4" + PYTHON_ARCH: "32" TOX_ENV: "py34-sqlite-memory-w32" - PYTHON: "C:\\Python34-x64" + PYTHON_VERSION: "3.4" + PYTHON_ARCH: "64" TOX_ENV: "py34-sqlite-memory-w32" - PYTHON: "C:\\Python35" + PYTHON_VERSION: "3.5" + PYTHON_ARCH: "32" TOX_ENV: "py35-sqlite-memory-w32" - PYTHON: "C:\\Python35-x64" + PYTHON_VERSION: "3.5" + PYTHON_ARCH: "64" TOX_ENV: "py35-sqlite-memory-w32" - PYTHON: "C:\\Python36" + PYTHON_VERSION: "3.6" + PYTHON_ARCH: "32" TOX_ENV: "py36-sqlite-memory-w32" - PYTHON: "C:\\Python36-x64" + PYTHON_VERSION: "3.6" + PYTHON_ARCH: "64" TOX_ENV: "py36-sqlite-memory-w32" install: @@ -98,6 +184,9 @@ install: - "python --version" - "pip --version" - "pip install tox" + # List ODBC drivers + - ps: Get-OdbcDriver -Platform 32-bit | Select-Object -ExpandProperty Name + - ps: Get-OdbcDriver -Platform 64-bit | Select-Object -ExpandProperty Name # Enable TCP for mssql # (from appveyor documentation) - ps: | @@ -119,4 +208,4 @@ install: build: false test_script: - - "tox -e %TOX_ENV%" + - "%CMD_IN_ENV% tox -e %TOX_ENV%" diff --git a/docs/News.rst b/docs/News.rst index 6123ae03..46c6be31 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -17,6 +17,11 @@ Minor features Some of thses scripts are version-dependent so it's better to have them in the main repo. +Drivers (work in progress) +-------------------------- + +* Add support for PyODBC for PostgreSQL. There are some problems. + Tests ----- diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index 003172ed..92809863 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -48,9 +48,9 @@ Requirements Currently SQLObject supports MySQL_ via MySQLdb_ aka MySQL-python (called mysqlclient_ for Python 3), `MySQL Connector`_, oursql_ and PyMySQL_. For -PostgreSQL_ psycopg2_ or psycopg1 are recommended; PyGreSQL_ and py-postgresql_ -are supported but have problems (not all tests passed). SQLite_ has -a built-in driver or PySQLite_. Firebird_ is supported via fdb_ or +PostgreSQL_ psycopg2_ or psycopg1 are recommended; PyGreSQL_, py-postgresql_ +and PyODBC_ are supported but have problems (not all tests passed). SQLite_ +has a built-in driver or PySQLite_. Firebird_ is supported via fdb_ or kinterbasdb_; pyfirebirdsql_ is supported but has problems. `MAX DB`_ (also known as SAP DB) is supported via sapdb_. Sybase via Sybase_. `MSSQL Server`_ via pymssql_ (+ FreeTDS_) or adodbapi_ (Win32). @@ -65,6 +65,7 @@ via pymssql_ (+ FreeTDS_) or adodbapi_ (Win32). .. _psycopg2: http://initd.org/psycopg/ .. _PyGreSQL: http://www.pygresql.org/ .. _py-postgresql: https://pypi.python.org/pypi/py-postgresql +.. _PyODBC: https://pypi.python.org/pypi/pyodbc .. _SQLite: https://sqlite.org/ .. _PySQLite: https://github.com/ghaering/pysqlite .. _Firebird: http://www.firebirdsql.org/en/python-driver/ @@ -1826,8 +1827,8 @@ PostgresConnection supports transactions and all other features. The user can choose a DB API driver for PostgreSQL by using a ``driver`` parameter in DB URI or PostgresConnection that can be a comma-separated list of driver names. Possible drivers are: ``psycopg2``, psycopg1, -``psycopg`` (tries psycopg2 and psycopg1), ``pygresql``, ``pygresql`` -or ``pypostgresql``. Default is ``psycopg``. +``psycopg`` (tries psycopg2 and psycopg1), ``pygresql``, ``pygresql``, +``pypostgresql`` or ``odbc``. Default is ``psycopg``. Connection-specific parameters are: ``sslmode``, ``unicodeCols``, ``schema``, ``charset``. diff --git a/run_with_env.cmd b/run_with_env.cmd new file mode 100644 index 00000000..5da547c4 --- /dev/null +++ b/run_with_env.cmd @@ -0,0 +1,88 @@ +:: To build extensions for 64 bit Python 3, we need to configure environment +:: variables to use the MSVC 2010 C++ compilers from GRMSDKX_EN_DVD.iso of: +:: MS Windows SDK for Windows 7 and .NET Framework 4 (SDK v7.1) +:: +:: To build extensions for 64 bit Python 2, we need to configure environment +:: variables to use the MSVC 2008 C++ compilers from GRMSDKX_EN_DVD.iso of: +:: MS Windows SDK for Windows 7 and .NET Framework 3.5 (SDK v7.0) +:: +:: 32 bit builds, and 64-bit builds for 3.5 and beyond, do not require specific +:: environment configurations. +:: +:: Note: this script needs to be run with the /E:ON and /V:ON flags for the +:: cmd interpreter, at least for (SDK v7.0) +:: +:: More details at: +:: https://github.com/cython/cython/wiki/64BitCythonExtensionsOnWindows +:: http://stackoverflow.com/a/13751649/163740 +:: +:: Author: Olivier Grisel +:: License: CC0 1.0 Universal: http://creativecommons.org/publicdomain/zero/1.0/ +:: +:: Notes about batch files for Python people: +:: +:: Quotes in values are literally part of the values: +:: SET FOO="bar" +:: FOO is now five characters long: " b a r " +:: If you don't want quotes, don't include them on the right-hand side. +:: +:: The CALL lines at the end of this file look redundant, but if you move them +:: outside of the IF clauses, they do not run properly in the SET_SDK_64==Y +:: case, I don't know why. +@ECHO OFF + +SET COMMAND_TO_RUN=%* +SET WIN_SDK_ROOT=C:\Program Files\Microsoft SDKs\Windows +SET WIN_WDK=c:\Program Files (x86)\Windows Kits\10\Include\wdf + +:: Extract the major and minor versions, and allow for the minor version to be +:: more than 9. This requires the version number to have two dots in it. +SET MAJOR_PYTHON_VERSION=%PYTHON_VERSION:~0,1% +IF "%PYTHON_VERSION:~3,1%" == "." ( + SET MINOR_PYTHON_VERSION=%PYTHON_VERSION:~2,1% +) ELSE ( + SET MINOR_PYTHON_VERSION=%PYTHON_VERSION:~2,2% +) + +:: Based on the Python version, determine what SDK version to use, and whether +:: to set the SDK for 64-bit. +IF %MAJOR_PYTHON_VERSION% == 2 ( + SET WINDOWS_SDK_VERSION="v7.0" + SET SET_SDK_64=Y +) ELSE ( + IF %MAJOR_PYTHON_VERSION% == 3 ( + SET WINDOWS_SDK_VERSION="v7.1" + IF %MINOR_PYTHON_VERSION% LEQ 4 ( + SET SET_SDK_64=Y + ) ELSE ( + SET SET_SDK_64=N + IF EXIST "%WIN_WDK%" ( + :: See: https://connect.microsoft.com/VisualStudio/feedback/details/1610302/ + REN "%WIN_WDK%" 0wdf + ) + ) + ) ELSE ( + ECHO Unsupported Python version: "%MAJOR_PYTHON_VERSION%" + EXIT 1 + ) +) + +IF %PYTHON_ARCH% == 64 ( + IF %SET_SDK_64% == Y ( + ECHO Configuring Windows SDK %WINDOWS_SDK_VERSION% for Python %MAJOR_PYTHON_VERSION% on a 64 bit architecture + SET DISTUTILS_USE_SDK=1 + SET MSSdk=1 + "%WIN_SDK_ROOT%\%WINDOWS_SDK_VERSION%\Setup\WindowsSdkVer.exe" -q -version:%WINDOWS_SDK_VERSION% + "%WIN_SDK_ROOT%\%WINDOWS_SDK_VERSION%\Bin\SetEnv.cmd" /x64 /release + ECHO Executing: %COMMAND_TO_RUN% + call %COMMAND_TO_RUN% || EXIT 1 + ) ELSE ( + ECHO Using default MSVC build environment for 64 bit architecture + ECHO Executing: %COMMAND_TO_RUN% + call %COMMAND_TO_RUN% || EXIT 1 + ) +) ELSE ( + ECHO Using default MSVC build environment for 32 bit architecture + ECHO Executing: %COMMAND_TO_RUN% + call %COMMAND_TO_RUN% || EXIT 1 +) diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index 5920cd58..cdb32f2c 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -53,11 +53,14 @@ def __init__(self, dsn=None, host=None, port=None, db=None, elif driver in ('py-postgresql', 'pypostgresql'): from postgresql.driver import dbapi20 self.module = dbapi20 + elif driver in ('odbc', 'pyodbc'): + import pyodbc + self.module = pyodbc else: raise ValueError( 'Unknown PostgreSQL driver "%s", ' 'expected psycopg2, psycopg1, ' - 'pygresql or pypostgresql' % driver) + 'pygresql, pypostgresql or odbc' % driver) except ImportError: pass else: @@ -75,70 +78,84 @@ def __init__(self, dsn=None, host=None, port=None, db=None, registerConverter(type(self.module.Binary(b'')), PostgresBinaryConverter) + self.db = db self.user = user + self.password = password self.host = host self.port = port - self.db = db - self.password = password - self.dsn_dict = dsn_dict = {} - if host: - dsn_dict["host"] = host - if port: - if driver == 'pygresql': - dsn_dict["host"] = "%s:%d" % (host, port) - elif driver.startswith('psycopg') and \ - psycopg.__version__.split('.')[0] == '1': - dsn_dict["port"] = str(port) - else: - dsn_dict["port"] = port - if db: - dsn_dict["database"] = db - if user: - dsn_dict["user"] = user - if password: - dsn_dict["password"] = password - sslmode = kw.pop("sslmode", None) - if sslmode: - dsn_dict["sslmode"] = sslmode - self.use_dsn = dsn is not None - if dsn is None: - if driver == 'pygresql': - dsn = '' - if host: - dsn += host - dsn += ':' - if db: - dsn += db - dsn += ':' - if user: - dsn += user - dsn += ':' - if password: - dsn += password - else: - dsn = [] - if db: - dsn.append('dbname=%s' % db) - if user: - dsn.append('user=%s' % user) - if password: - dsn.append('password=%s' % password) - if host: - dsn.append('host=%s' % host) - if port: - dsn.append('port=%d' % port) - if sslmode: - dsn.append('sslmode=%s' % sslmode) - dsn = ' '.join(dsn) - if driver in ('py-postgresql', 'pypostgresql'): - if host and host.startswith('/'): - dsn_dict["host"] = dsn_dict["port"] = None - dsn_dict["unix"] = host - else: - if "unix" in dsn_dict: - del dsn_dict["unix"] + if driver in ('odbc', 'pyodbc'): + odb_source = kw.pop('odbcdrv', 'PostgreSQL ANSI') + odbc_conn_str = 'Driver={%s};' % odb_source + odbc_conn_str += 'Database=%s;' % db + if user: + odbc_conn_str += 'User ID=%s;' % user + if password: + odbc_conn_str += 'Password=%s;' % password + if host: + odbc_conn_str += 'Host=%s;' % host + if port: + odbc_conn_str += 'Port=%d;' % port + self.odbc_conn_str = odbc_conn_str + else: + self.dsn_dict = dsn_dict = {} + if host: + dsn_dict["host"] = host + if port: + if driver == 'pygresql': + dsn_dict["host"] = "%s:%d" % (host, port) + elif driver.startswith('psycopg') and \ + psycopg.__version__.split('.')[0] == '1': + dsn_dict["port"] = str(port) + else: + dsn_dict["port"] = port + if db: + dsn_dict["database"] = db + if user: + dsn_dict["user"] = user + if password: + dsn_dict["password"] = password + sslmode = kw.pop("sslmode", None) + if sslmode: + dsn_dict["sslmode"] = sslmode + self.use_dsn = dsn is not None + if dsn is None: + if driver == 'pygresql': + dsn = '' + if host: + dsn += host + dsn += ':' + if db: + dsn += db + dsn += ':' + if user: + dsn += user + dsn += ':' + if password: + dsn += password + else: + dsn = [] + if db: + dsn.append('dbname=%s' % db) + if user: + dsn.append('user=%s' % user) + if password: + dsn.append('password=%s' % password) + if host: + dsn.append('host=%s' % host) + if port: + dsn.append('port=%d' % port) + if sslmode: + dsn.append('sslmode=%s' % sslmode) + dsn = ' '.join(dsn) + if driver in ('py-postgresql', 'pypostgresql'): + if host and host.startswith('/'): + dsn_dict["host"] = dsn_dict["port"] = None + dsn_dict["unix"] = host + else: + if "unix" in dsn_dict: + del dsn_dict["unix"] + self.dsn = dsn self.driver = driver - self.dsn = dsn self.unicodeCols = kw.pop('unicodeCols', False) self.schema = kw.pop('schema', None) self.dbEncoding = kw.pop("charset", None) @@ -164,7 +181,9 @@ def _setAutoCommit(self, conn, auto): def makeConnection(self): try: - if self.use_dsn: + if self.driver in ('odbc', 'pyodbc'): + conn = self.module.connect(self.odbc_conn_str) + elif self.use_dsn: conn = self.module.connect(self.dsn) else: conn = self.module.connect(**self.dsn_dict) @@ -182,6 +201,14 @@ def makeConnection(self): self._executeRetry(conn, c, "SET search_path TO " + self.schema) dbEncoding = self.dbEncoding if dbEncoding: + if self.driver in ('odbc', 'pyodbc'): + conn.setdecoding(self.module.SQL_CHAR, encoding=dbEncoding) + conn.setdecoding(self.module.SQL_WCHAR, encoding=dbEncoding) + if PY2: + conn.setencoding(str, encoding=dbEncoding) + conn.setencoding(unicode, encoding=dbEncoding) + else: + conn.setencoding(encoding=dbEncoding) self._executeRetry(conn, c, "SET client_encoding TO '%s'" % dbEncoding) return conn diff --git a/tox.ini b/tox.ini index 3d37e1d3..666677b6 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 1.8 -envlist = py{26,27}-{mysqldb,mysql-oursql},py{34,35,36}-{mysqlclient,pypostgresql},py{26,27,34,35,36}-{mysql-connector,pymysql,postgres-psycopg,postgres-pygresql,sqlite,sqlite-memory},py{27,34,35,36}-{firebird-fdb,firebirdsql},py{27,34}-flake8,py{27,34,35,36}-{mssql,mysql-connector,postgres-psycopg,sqlite,sqlite-memory}-w32 +envlist = py{26,27}-{mysqldb,mysql-oursql},py{34,35,36}-{mysqlclient,pypostgresql},py{26,27,34,35,36}-{mysql-connector,pymysql,postgres-psycopg,postgres-pygresql,postgres-odbc,sqlite,sqlite-memory},py{27,34,35,36}-{firebird-fdb,firebirdsql},py{27,34}-flake8,py{27,34,35,36}-{mssql,mysql-connector,postgres-psycopg,postgres-odbc,sqlite,sqlite-memory}-w32 # Base test environment settings [testenv] @@ -21,10 +21,11 @@ deps = postgres-psycopg: psycopg2 postgres-pygresql: pygresql pypostgresql: py-postgresql + postgres-odbc: pyodbc firebird-fdb: fdb firebirdsql: firebirdsql mssql: pymssql -passenv = CI TRAVIS TRAVIS_* PGPASSWORD APPVEYOR +passenv = CI TRAVIS TRAVIS_* PGPASSWORD APPVEYOR DISTUTILS_USE_SDK MSSdk INCLUDE LIB # Don't fail or warn on uninstalled commands whitelist_externals = mysql @@ -183,6 +184,28 @@ commands = {[pypostgresql]commands} [testenv:py36-pypostgresql] commands = {[pypostgresql]commands} +[odbc] +commands = + -dropdb -U postgres -w sqlobject_test + createdb -U postgres -w sqlobject_test + pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=odbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test + dropdb -U postgres -w sqlobject_test + +[testenv:py26-postgres-odbc] +commands = {[odbc]commands} + +[testenv:py27-postgres-odbc] +commands = {[odbc]commands} + +[testenv:py34-postgres-odbc] +commands = {[odbc]commands} + +[testenv:py35-postgres-odbc] +commands = {[odbc]commands} + +[testenv:py36-postgres-odbc] +commands = {[odbc]commands} + # SQLite test environments [sqlite] commands = @@ -334,6 +357,25 @@ commands = {[psycopg-w32]commands} [testenv:py36-postgres-psycopg-w32] commands = {[psycopg-w32]commands} +[odbc-w32] +commands = + -dropdb -U postgres -w sqlobject_test + createdb -U postgres -w sqlobject_test + pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=odbc&odbcdrv=PostgreSQL%20ANSI%28x64%29&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + dropdb -U postgres -w sqlobject_test + +[testenv:py27-postgres-odbc-w32] +commands = {[odbc-w32]commands} + +[testenv:py34-postgres-odbc-w32] +commands = {[odbc-w32]commands} + +[testenv:py35-postgres-odbc-w32] +commands = {[odbc-w32]commands} + +[testenv:py36-postgres-odbc-w32] +commands = {[odbc-w32]commands} + [sqlite-w32] commands = pytest --cov=sqlobject -D sqlite:/C:/projects/sqlobject/sqlobject_test.sqdb?debug=1 From b654cbf4f45d5e27d52c86dcee64a7d119fb86fc Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 4 Apr 2017 21:52:06 +0300 Subject: [PATCH 024/509] Refactor make_odbc_conn_str --- sqlobject/dbconnection.py | 15 +++++++++++++++ sqlobject/postgres/pgconnection.py | 16 ++++------------ 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/sqlobject/dbconnection.py b/sqlobject/dbconnection.py index f5baaf50..9f3ebfbe 100644 --- a/sqlobject/dbconnection.py +++ b/sqlobject/dbconnection.py @@ -734,6 +734,21 @@ def createEmptyDatabase(self): """ raise NotImplementedError + def make_odbc_conn_str(self, db, host=None, port=None, + user=None, password=None, + default_odbc_driver=None, **kw): + odb_source = kw.pop('odbcdrv', default_odbc_driver) + odbc_conn_parts = ['Driver={%s}' % odb_source, 'Database=%s' % db] + if host: + odbc_conn_parts.append('Server=%s' % host) + if port: + odbc_conn_parts.append('Port=%d' % port) + if user: + odbc_conn_parts.append('UID=%s' % user) + if password: + odbc_conn_parts.append('Password=%s' % password) + self.odbc_conn_str = ';'.join(odbc_conn_parts) + class Iteration(object): diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index cdb32f2c..8e89f687 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -84,18 +84,8 @@ def __init__(self, dsn=None, host=None, port=None, db=None, self.host = host self.port = port if driver in ('odbc', 'pyodbc'): - odb_source = kw.pop('odbcdrv', 'PostgreSQL ANSI') - odbc_conn_str = 'Driver={%s};' % odb_source - odbc_conn_str += 'Database=%s;' % db - if user: - odbc_conn_str += 'User ID=%s;' % user - if password: - odbc_conn_str += 'Password=%s;' % password - if host: - odbc_conn_str += 'Host=%s;' % host - if port: - odbc_conn_str += 'Port=%d;' % port - self.odbc_conn_str = odbc_conn_str + self.make_odbc_conn_str(db, host, port, user, password, + 'PostgreSQL ANSI', **kw) else: self.dsn_dict = dsn_dict = {} if host: @@ -182,6 +172,8 @@ def _setAutoCommit(self, conn, auto): def makeConnection(self): try: if self.driver in ('odbc', 'pyodbc'): + self.debugWriter.write( + "ODBC connect string: " + self.odbc_conn_str) conn = self.module.connect(self.odbc_conn_str) elif self.use_dsn: conn = self.module.connect(self.dsn) From 98ab6094fd6f990ea527d8b2e07bac3d8ca3fba7 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 31 Mar 2017 20:53:43 +0300 Subject: [PATCH 025/509] Add PyPyODBC driver for PostgreSQL Driver `odbc` means try `pyodbc` and `pypyodbc`. --- appveyor.yml | 28 ++++++++-- docs/News.rst | 4 +- docs/SQLObject.rst | 17 +++--- sqlobject/dbconnection.py | 4 +- sqlobject/postgres/pgconnection.py | 22 ++++++-- tox.ini | 88 ++++++++++++++++++++++-------- 6 files changed, 119 insertions(+), 44 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index c52e6578..e6bcb177 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -97,22 +97,42 @@ environment: PYTHON_VERSION: "2.7" PYTHON_ARCH: "64" db: postgresql - TOX_ENV: "py27-postgres-odbc-w32" + TOX_ENV: "py27-postgres-pyodbc-w32" - PYTHON: "C:\\Python34-x64" PYTHON_VERSION: "3.4" PYTHON_ARCH: "64" db: postgresql - TOX_ENV: "py34-postgres-odbc-w32" + TOX_ENV: "py34-postgres-pyodbc-w32" - PYTHON: "C:\\Python35-x64" PYTHON_VERSION: "3.5" PYTHON_ARCH: "64" db: postgresql - TOX_ENV: "py35-postgres-odbc-w32" + TOX_ENV: "py35-postgres-pyodbc-w32" - PYTHON: "C:\\Python36-x64" PYTHON_VERSION: "3.6" PYTHON_ARCH: "64" db: postgresql - TOX_ENV: "py36-postgres-odbc-w32" + TOX_ENV: "py36-postgres-pyodbc-w32" + - PYTHON: "C:\\Python27-x64" + PYTHON_VERSION: "2.7" + PYTHON_ARCH: "64" + db: postgresql + TOX_ENV: "py27-postgres-pypyodbc-w32" + - PYTHON: "C:\\Python34-x64" + PYTHON_VERSION: "3.4" + PYTHON_ARCH: "64" + db: postgresql + TOX_ENV: "py34-postgres-pypyodbc-w32" + - PYTHON: "C:\\Python35-x64" + PYTHON_VERSION: "3.5" + PYTHON_ARCH: "64" + db: postgresql + TOX_ENV: "py35-postgres-pypyodbc-w32" + - PYTHON: "C:\\Python36-x64" + PYTHON_VERSION: "3.6" + PYTHON_ARCH: "64" + db: postgresql + TOX_ENV: "py36-postgres-pypyodbc-w32" - PYTHON: "C:\\Python27" PYTHON_VERSION: "2.7" PYTHON_ARCH: "32" diff --git a/docs/News.rst b/docs/News.rst index 46c6be31..975e1855 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -20,7 +20,9 @@ Minor features Drivers (work in progress) -------------------------- -* Add support for PyODBC for PostgreSQL. There are some problems. +* Add support for PyODBC and PyPyODBC (pure-python ODBC DB API driver) for + PostgreSQL. Driver names are ``pyodbc``, ``pypyodbc`` or ``odbc`` (try + ``pyodbc`` and ``pypyodbc``). There are some problems. Tests ----- diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index 92809863..291092ad 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -48,12 +48,13 @@ Requirements Currently SQLObject supports MySQL_ via MySQLdb_ aka MySQL-python (called mysqlclient_ for Python 3), `MySQL Connector`_, oursql_ and PyMySQL_. For -PostgreSQL_ psycopg2_ or psycopg1 are recommended; PyGreSQL_, py-postgresql_ -and PyODBC_ are supported but have problems (not all tests passed). SQLite_ -has a built-in driver or PySQLite_. Firebird_ is supported via fdb_ or -kinterbasdb_; pyfirebirdsql_ is supported but has problems. `MAX DB`_ (also -known as SAP DB) is supported via sapdb_. Sybase via Sybase_. `MSSQL Server`_ -via pymssql_ (+ FreeTDS_) or adodbapi_ (Win32). +PostgreSQL_ psycopg2_ or psycopg1 are recommended; PyGreSQL_, +py-postgresql_, PyODBC_ and PyPyODBC_ are supported but have problems (not +all tests passed). SQLite_ has a built-in driver or PySQLite_. Firebird_ +is supported via fdb_ or kinterbasdb_; pyfirebirdsql_ is supported but has +problems. `MAX DB`_ (also known as SAP DB) is supported via sapdb_. Sybase +via Sybase_. `MSSQL Server`_ via pymssql_ (+ FreeTDS_) or adodbapi_ +(Win32). .. _MySQL: https://www.mysql.com/ .. _MySQLdb: https://sourceforge.net/projects/mysql-python/ @@ -66,6 +67,7 @@ via pymssql_ (+ FreeTDS_) or adodbapi_ (Win32). .. _PyGreSQL: http://www.pygresql.org/ .. _py-postgresql: https://pypi.python.org/pypi/py-postgresql .. _PyODBC: https://pypi.python.org/pypi/pyodbc +.. _PyPyODBC: https://pypi.python.org/pypi/pypyodbc .. _SQLite: https://sqlite.org/ .. _PySQLite: https://github.com/ghaering/pysqlite .. _Firebird: http://www.firebirdsql.org/en/python-driver/ @@ -1828,7 +1830,8 @@ The user can choose a DB API driver for PostgreSQL by using a ``driver`` parameter in DB URI or PostgresConnection that can be a comma-separated list of driver names. Possible drivers are: ``psycopg2``, psycopg1, ``psycopg`` (tries psycopg2 and psycopg1), ``pygresql``, ``pygresql``, -``pypostgresql`` or ``odbc``. Default is ``psycopg``. +``pypostgresql``, ``pyodbc``, ``pypyodbc`` or ``odbc`` (try ``pyodbc`` and +``pypyodbc``). Default is ``psycopg``. Connection-specific parameters are: ``sslmode``, ``unicodeCols``, ``schema``, ``charset``. diff --git a/sqlobject/dbconnection.py b/sqlobject/dbconnection.py index 9f3ebfbe..4f29eb08 100644 --- a/sqlobject/dbconnection.py +++ b/sqlobject/dbconnection.py @@ -735,9 +735,7 @@ def createEmptyDatabase(self): raise NotImplementedError def make_odbc_conn_str(self, db, host=None, port=None, - user=None, password=None, - default_odbc_driver=None, **kw): - odb_source = kw.pop('odbcdrv', default_odbc_driver) + user=None, password=None, odb_source=None): odbc_conn_parts = ['Driver={%s}' % odb_source, 'Database=%s' % db] if host: odbc_conn_parts.append('Server=%s' % host) diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index 8e89f687..8f44ef81 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -53,14 +53,24 @@ def __init__(self, dsn=None, host=None, port=None, db=None, elif driver in ('py-postgresql', 'pypostgresql'): from postgresql.driver import dbapi20 self.module = dbapi20 - elif driver in ('odbc', 'pyodbc'): + elif driver == 'pyodbc': import pyodbc self.module = pyodbc + elif driver == 'pypyodbc': + import pypyodbc + self.module = pypyodbc + elif driver == 'odbc': + try: + import pyodbc + except ImportError: + import pypyodbc as pyodbc + self.module = pyodbc else: raise ValueError( 'Unknown PostgreSQL driver "%s", ' - 'expected psycopg2, psycopg1, ' - 'pygresql, pypostgresql or odbc' % driver) + 'expected psycopg, psycopg2, psycopg1, ' + 'pygresql, pypostgresql, ' + 'odbc, pyodbc or pypyodbc' % driver) except ImportError: pass else: @@ -83,9 +93,9 @@ def __init__(self, dsn=None, host=None, port=None, db=None, self.password = password self.host = host self.port = port - if driver in ('odbc', 'pyodbc'): + if driver in ('odbc', 'pyodbc', 'pypyodbc'): self.make_odbc_conn_str(db, host, port, user, password, - 'PostgreSQL ANSI', **kw) + kw.pop('odbcdrv', 'PostgreSQL ANSI')) else: self.dsn_dict = dsn_dict = {} if host: @@ -171,7 +181,7 @@ def _setAutoCommit(self, conn, auto): def makeConnection(self): try: - if self.driver in ('odbc', 'pyodbc'): + if self.driver in ('odbc', 'pyodbc', 'pypyodbc'): self.debugWriter.write( "ODBC connect string: " + self.odbc_conn_str) conn = self.module.connect(self.odbc_conn_str) diff --git a/tox.ini b/tox.ini index 666677b6..ba896c68 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 1.8 -envlist = py{26,27}-{mysqldb,mysql-oursql},py{34,35,36}-{mysqlclient,pypostgresql},py{26,27,34,35,36}-{mysql-connector,pymysql,postgres-psycopg,postgres-pygresql,postgres-odbc,sqlite,sqlite-memory},py{27,34,35,36}-{firebird-fdb,firebirdsql},py{27,34}-flake8,py{27,34,35,36}-{mssql,mysql-connector,postgres-psycopg,postgres-odbc,sqlite,sqlite-memory}-w32 +envlist = py{26,27}-{mysqldb,mysql-oursql},py{34,35,36}-{mysqlclient,pypostgresql},py{26,27,34,35,36}-{mysql-connector,pymysql,postgres-psycopg,postgres-pygresql,postgres-pyodbc,postgres-pypyodbc,sqlite,sqlite-memory},py{27,34,35,36}-{firebird-fdb,firebirdsql},py{27,34}-flake8,py{27,34,35,36}-{mssql,mysql-connector,postgres-psycopg,postgres-pyodbc,postgres-pypyodbc,sqlite,sqlite-memory}-w32 # Base test environment settings [testenv] @@ -21,7 +21,8 @@ deps = postgres-psycopg: psycopg2 postgres-pygresql: pygresql pypostgresql: py-postgresql - postgres-odbc: pyodbc + postgres-pyodbc: pyodbc + postgres-pypyodbc: pypyodbc firebird-fdb: fdb firebirdsql: firebirdsql mssql: pymssql @@ -184,27 +185,49 @@ commands = {[pypostgresql]commands} [testenv:py36-pypostgresql] commands = {[pypostgresql]commands} -[odbc] +[pyodbc] commands = -dropdb -U postgres -w sqlobject_test createdb -U postgres -w sqlobject_test - pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=odbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test + pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=pyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test dropdb -U postgres -w sqlobject_test -[testenv:py26-postgres-odbc] -commands = {[odbc]commands} +[testenv:py26-postgres-pyodbc] +commands = {[pyodbc]commands} -[testenv:py27-postgres-odbc] -commands = {[odbc]commands} +[testenv:py27-postgres-pyodbc] +commands = {[pyodbc]commands} -[testenv:py34-postgres-odbc] -commands = {[odbc]commands} +[testenv:py34-postgres-pyodbc] +commands = {[pyodbc]commands} -[testenv:py35-postgres-odbc] -commands = {[odbc]commands} +[testenv:py35-postgres-pyodbc] +commands = {[pyodbc]commands} -[testenv:py36-postgres-odbc] -commands = {[odbc]commands} +[testenv:py36-postgres-pyodbc] +commands = {[pyodbc]commands} + +[pypyodbc] +commands = + -dropdb -U postgres -w sqlobject_test + createdb -U postgres -w sqlobject_test + pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test + dropdb -U postgres -w sqlobject_test + +[testenv:py26-postgres-pypyodbc] +commands = {[pypyodbc]commands} + +[testenv:py27-postgres-pypyodbc] +commands = {[pypyodbc]commands} + +[testenv:py34-postgres-pypyodbc] +commands = {[pypyodbc]commands} + +[testenv:py35-postgres-pypyodbc] +commands = {[pypyodbc]commands} + +[testenv:py36-postgres-pypyodbc] +commands = {[pypyodbc]commands} # SQLite test environments [sqlite] @@ -357,24 +380,43 @@ commands = {[psycopg-w32]commands} [testenv:py36-postgres-psycopg-w32] commands = {[psycopg-w32]commands} -[odbc-w32] +[pyodbc-w32] +commands = + -dropdb -U postgres -w sqlobject_test + createdb -U postgres -w sqlobject_test + pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pyodbc&odbcdrv=PostgreSQL%20ANSI%28x64%29&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + dropdb -U postgres -w sqlobject_test + +[testenv:py27-postgres-pyodbc-w32] +commands = {[pyodbc-w32]commands} + +[testenv:py34-postgres-pyodbc-w32] +commands = {[pyodbc-w32]commands} + +[testenv:py35-postgres-pyodbc-w32] +commands = {[pyodbc-w32]commands} + +[testenv:py36-postgres-pyodbc-w32] +commands = {[pyodbc-w32]commands} + +[pypyodbc-w32] commands = -dropdb -U postgres -w sqlobject_test createdb -U postgres -w sqlobject_test pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=odbc&odbcdrv=PostgreSQL%20ANSI%28x64%29&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb -U postgres -w sqlobject_test -[testenv:py27-postgres-odbc-w32] -commands = {[odbc-w32]commands} +[testenv:py27-postgres-pypyodbc-w32] +commands = {[pypyodbc-w32]commands} -[testenv:py34-postgres-odbc-w32] -commands = {[odbc-w32]commands} +[testenv:py34-postgres-pypyodbc-w32] +commands = {[pypyodbc-w32]commands} -[testenv:py35-postgres-odbc-w32] -commands = {[odbc-w32]commands} +[testenv:py35-postgres-pypyodbc-w32] +commands = {[pypyodbc-w32]commands} -[testenv:py36-postgres-odbc-w32] -commands = {[odbc-w32]commands} +[testenv:py36-postgres-pypyodbc-w32] +commands = {[pypyodbc-w32]commands} [sqlite-w32] commands = From f67f0b550714416a82c03d749aa519e61a752fd5 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 4 Apr 2017 22:44:05 +0300 Subject: [PATCH 026/509] [tox] Pass WINDIR environment variable See http://www.kidstrythisathome.com/2017/02/tox-pyodbc-and-appveyor.html --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index ba896c68..5866fbf5 100644 --- a/tox.ini +++ b/tox.ini @@ -26,7 +26,7 @@ deps = firebird-fdb: fdb firebirdsql: firebirdsql mssql: pymssql -passenv = CI TRAVIS TRAVIS_* PGPASSWORD APPVEYOR DISTUTILS_USE_SDK MSSdk INCLUDE LIB +passenv = CI TRAVIS TRAVIS_* APPVEYOR DISTUTILS_USE_SDK MSSdk INCLUDE LIB PGPASSWORD WINDIR # Don't fail or warn on uninstalled commands whitelist_externals = mysql From d6a1e7537d4e6f954b9a80ec22cab6ae5253ec76 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 5 Apr 2017 02:55:33 +0300 Subject: [PATCH 027/509] [appveyor.yml] Change version format --- appveyor.yml | 2 +- devscripts/BRANCH-CHECKLIST | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index e6bcb177..ce173a4a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,7 +1,7 @@ # Install SQLObject on windows and test against MS SQL server and postgres # Heavily inspired by Oliver Grisel's appveyor-demo (https://github.com/ogrisel/python-appveyor-demo) # and Michael Sverdlik's appveyor-utils (https://github.com/cloudify-cosmo/appveyor-utils) -version: 3.3.{build} +version: '{branch}-{build}' # Match travis clone_depth: 50 diff --git a/devscripts/BRANCH-CHECKLIST b/devscripts/BRANCH-CHECKLIST index 61e06be7..5036e832 100644 --- a/devscripts/BRANCH-CHECKLIST +++ b/devscripts/BRANCH-CHECKLIST @@ -13,9 +13,8 @@ a branch, a commit id or a tag. 1b. If the branching point was master the script checks out master and calls editor again; edit README.rst, __version__.py and News.rst in - master - set version for the next release. Edit branch in - appveyor.yml. In setup.py edit "Development Status" in trove - classifiers. Commit. + master - set version for the next release. In setup.py edit + "Development Status" in trove classifiers. Commit. 1c. The script updates versions in ANNOUNCE.rst. From 380a776fdf43b1edf755a700a1f02b2870d81867 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 5 Apr 2017 02:56:55 +0300 Subject: [PATCH 028/509] [appveyor.yml] Cache pip eggs/wheels --- appveyor.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/appveyor.yml b/appveyor.yml index ce173a4a..98b77fb4 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -3,6 +3,9 @@ # and Michael Sverdlik's appveyor-utils (https://github.com/cloudify-cosmo/appveyor-utils) version: '{branch}-{build}' +cache: + - '%LOCALAPPDATA%\pip\Cache' + # Match travis clone_depth: 50 From 6f641c9e34c5f2ad108ab571f2a5a304c19ee028 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 5 Apr 2017 02:56:55 +0300 Subject: [PATCH 029/509] [appveyor/tox] Print python version and 32/64 bit architecture --- appveyor.yml | 1 + tox.ini | 32 ++++++++++++++++++++++++++++++-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 98b77fb4..cd3b15cc 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -205,6 +205,7 @@ install: # Ensure we use the right python version - "SET PATH=%PYTHON%;%PYTHON%\\Scripts;C:\\Program Files\\MySQL\\MySQL Server 5.7\\bin;C:\\Program Files\\PostgreSQL\\9.5\\bin;%PATH%" - "python --version" + - "python -c \"import struct; print(struct.calcsize('P') * 8)\"" - "pip --version" - "pip install tox" # List ODBC drivers diff --git a/tox.ini b/tox.ini index 5866fbf5..f46ee298 100644 --- a/tox.ini +++ b/tox.ini @@ -6,6 +6,9 @@ envlist = py{26,27}-{mysqldb,mysql-oursql},py{34,35,36}-{mysqlclient,pypostgresq [testenv] # Ensure we cd into sqlobject before running the tests changedir = ./sqlobject/ +commands = + {envpython} --version + {envpython} -c "import struct; print(struct.calcsize('P') * 8)" deps = pytest pytest-cov @@ -40,6 +43,7 @@ whitelist_externals = # MySQL test environments [mysqldb] commands = + {[testenv]commands} -mysql -e 'drop database sqlobject_test;' mysql -e 'create database sqlobject_test;' pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=mysqldb&debug=1 @@ -53,6 +57,7 @@ commands = {[mysqldb]commands} [mysqlclient] commands = + {[testenv]commands} -mysql -e 'drop database sqlobject_test;' mysql -e 'create database sqlobject_test;' pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=mysqldb&charset=utf8&debug=1 @@ -69,6 +74,7 @@ commands = {[mysqlclient]commands} [mysql-connector] commands = + {[testenv]commands} -mysql -e 'drop database sqlobject_test;' mysql -e 'create database sqlobject_test;' pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=connector&charset=utf8&debug=1 @@ -91,6 +97,7 @@ commands = {[mysql-connector]commands} [oursql] commands = + {[testenv]commands} -mysql -e 'drop database sqlobject_test;' mysql -e 'create database sqlobject_test;' pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=oursql&charset=utf8&debug=1 @@ -104,6 +111,7 @@ commands = {[oursql]commands} [pymysql] commands = + {[testenv]commands} -mysql -e 'drop database sqlobject_test;' mysql -e 'create database sqlobject_test;' pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=pymysql&charset=utf8&debug=1 @@ -127,6 +135,7 @@ commands = {[pymysql]commands} # PostgreSQL test environments [psycopg] commands = + {[testenv]commands} -dropdb -U postgres -w sqlobject_test createdb -U postgres -w sqlobject_test pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test @@ -149,6 +158,7 @@ commands = {[psycopg]commands} [pygresql] commands = + {[testenv]commands} -dropdb -U postgres -w sqlobject_test createdb -U postgres -w sqlobject_test pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test @@ -171,6 +181,7 @@ commands = {[pygresql]commands} [pypostgresql] commands = + {[testenv]commands} -dropdb -U postgres -w sqlobject_test createdb -U postgres -w sqlobject_test pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test @@ -187,6 +198,7 @@ commands = {[pypostgresql]commands} [pyodbc] commands = + {[testenv]commands} -dropdb -U postgres -w sqlobject_test createdb -U postgres -w sqlobject_test pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=pyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test @@ -209,6 +221,7 @@ commands = {[pyodbc]commands} [pypyodbc] commands = + {[testenv]commands} -dropdb -U postgres -w sqlobject_test createdb -U postgres -w sqlobject_test pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test @@ -232,6 +245,7 @@ commands = {[pypyodbc]commands} # SQLite test environments [sqlite] commands = + {[testenv]commands} -rm /tmp/sqlobject_test.sqdb pytest --cov=sqlobject -D sqlite:///tmp/sqlobject_test.sqdb?debug=1 rm /tmp/sqlobject_test.sqdb @@ -253,6 +267,7 @@ commands = {[sqlite]commands} [sqlite-memory] commands = + {[testenv]commands} pytest --cov=sqlobject -D sqlite:/:memory:?debug=1 [testenv:py26-sqlite-memory] @@ -273,6 +288,7 @@ commands = {[sqlite-memory]commands} # Firebird database test environments [fdb] commands = + {[testenv]commands} sudo rm -f /tmp/test.fdb isql-fb -u test -p test -i /var/lib/firebird/create_test_db pytest --cov=sqlobject -D 'firebird://test:test@localhost/tmp/test.fdb?debug=1' @@ -292,6 +308,7 @@ commands = {[fdb]commands} [firebirdsql] commands = + {[testenv]commands} sudo rm -f /tmp/test.fdb isql-fb -u test -p test -i /var/lib/firebird/create_test_db pytest --cov=sqlobject -D 'firebird://test:test@localhost:3050/tmp/test.fdb?driver=firebirdsql&charset=utf8&debug=1' @@ -314,17 +331,22 @@ commands = {[firebirdsql]commands} changedir = ./ deps = flake8 -commands = flake8 . +commands = + {[testenv]commands} + flake8 . [testenv:py34-flake8] changedir = ./ deps = flake8 -commands = flake8 . +commands = + {[testenv]commands} + flake8 . # Windows testing [mssql-w32] commands = + {[testenv]commands} -sqlcmd -U sa -P "Password12!" -S .\SQL2014 -Q "DROP DATABASE sqlobject_test" sqlcmd -U sa -P "Password12!" -S .\SQL2014 -Q "CREATE DATABASE sqlobject_test" pytest --cov=sqlobject -D "mssql://sa:Password12!@localhost\SQL2014/sqlobject_test?driver=pymssql&timeout=30&debug=1" @@ -344,6 +366,7 @@ commands = {[mssql-w32]commands} [mysql-connector-w32] commands = + {[testenv]commands} -mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' mysql -u root "-pPassword12!" -e 'create database sqlobject_test;' pytest --cov=sqlobject -D "mysql://root:Password12!@localhost/sqlobject_test?driver=connector&charset=utf8&debug=1" @@ -363,6 +386,7 @@ commands = {[mysql-connector-w32]commands} [psycopg-w32] commands = + {[testenv]commands} -dropdb -U postgres -w sqlobject_test createdb -U postgres -w sqlobject_test pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=psycopg2&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test @@ -382,6 +406,7 @@ commands = {[psycopg-w32]commands} [pyodbc-w32] commands = + {[testenv]commands} -dropdb -U postgres -w sqlobject_test createdb -U postgres -w sqlobject_test pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pyodbc&odbcdrv=PostgreSQL%20ANSI%28x64%29&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test @@ -401,6 +426,7 @@ commands = {[pyodbc-w32]commands} [pypyodbc-w32] commands = + {[testenv]commands} -dropdb -U postgres -w sqlobject_test createdb -U postgres -w sqlobject_test pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=odbc&odbcdrv=PostgreSQL%20ANSI%28x64%29&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test @@ -420,6 +446,7 @@ commands = {[pypyodbc-w32]commands} [sqlite-w32] commands = + {[testenv]commands} pytest --cov=sqlobject -D sqlite:/C:/projects/sqlobject/sqlobject_test.sqdb?debug=1 [testenv:py27-sqlite-w32] @@ -436,6 +463,7 @@ commands = {[sqlite-w32]commands} [sqlite-memory-w32] commands = + {[testenv]commands} pytest --cov=sqlobject -D sqlite:/:memory:?debug=1 [testenv:py27-sqlite-memory-w32] From 47af309433e5dc70eb61f758747e2886cb7fb274 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 5 Apr 2017 04:44:39 +0300 Subject: [PATCH 030/509] [tox] Set basepython to fix 32/64 versions --- appveyor.yml | 79 ++++++++++++++++++++++++++-------------------------- tox.ini | 5 ++++ 2 files changed, 45 insertions(+), 39 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index cd3b15cc..8dda819e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -26,184 +26,185 @@ environment: matrix: # from https://www.appveyor.com/docs/installed-software/#python - - PYTHON: "C:\\Python27" + - PYTHON_HOME: "C:\\Python27" PYTHON_VERSION: "2.7" PYTHON_ARCH: "32" db: mssql2014 TOX_ENV: "py27-mssql-w32" - - PYTHON: "C:\\Python34" + - PYTHON_HOME: "C:\\Python34" PYTHON_VERSION: "3.4" PYTHON_ARCH: "32" db: mssql2014 TOX_ENV: "py34-mssql-w32" - - PYTHON: "C:\\Python27" + - PYTHON_HOME: "C:\\Python27" PYTHON_VERSION: "2.7" PYTHON_ARCH: "32" db: mysql TOX_ENV: "py27-mysql-connector-w32" - - PYTHON: "C:\\Python34" + - PYTHON_HOME: "C:\\Python34" PYTHON_VERSION: "3.4" PYTHON_ARCH: "32" db: mysql TOX_ENV: "py34-mysql-connector-w32" - - PYTHON: "C:\\Python35" + - PYTHON_HOME: "C:\\Python35" PYTHON_VERSION: "3.5" PYTHON_ARCH: "32" db: mysql TOX_ENV: "py35-mysql-connector-w32" - - PYTHON: "C:\\Python36" + - PYTHON_HOME: "C:\\Python36" PYTHON_VERSION: "3.6" PYTHON_ARCH: "32" db: mysql TOX_ENV: "py36-mysql-connector-w32" - - PYTHON: "C:\\Python27" + - PYTHON_HOME: "C:\\Python27" PYTHON_VERSION: "2.7" PYTHON_ARCH: "32" db: postgresql TOX_ENV: "py27-postgres-psycopg-w32" - - PYTHON: "C:\\Python27-x64" + - PYTHON_HOME: "C:\\Python27-x64" PYTHON_VERSION: "2.7" PYTHON_ARCH: "64" db: postgresql TOX_ENV: "py27-postgres-psycopg-w32" - - PYTHON: "C:\\Python34" + - PYTHON_HOME: "C:\\Python34" PYTHON_VERSION: "3.4" PYTHON_ARCH: "32" db: postgresql TOX_ENV: "py34-postgres-psycopg-w32" - - PYTHON: "C:\\Python34-x64" + - PYTHON_HOME: "C:\\Python34-x64" PYTHON_VERSION: "3.4" PYTHON_ARCH: "64" db: postgresql TOX_ENV: "py34-postgres-psycopg-w32" - - PYTHON: "C:\\Python35" + - PYTHON_HOME: "C:\\Python35" PYTHON_VERSION: "3.5" PYTHON_ARCH: "32" db: postgresql TOX_ENV: "py35-postgres-psycopg-w32" - - PYTHON: "C:\\Python35-x64" + - PYTHON_HOME: "C:\\Python35-x64" PYTHON_VERSION: "3.5" PYTHON_ARCH: "64" db: postgresql TOX_ENV: "py35-postgres-psycopg-w32" - - PYTHON: "C:\\Python36" + - PYTHON_HOME: "C:\\Python36" PYTHON_VERSION: "3.6" PYTHON_ARCH: "32" db: postgresql TOX_ENV: "py36-postgres-psycopg-w32" - - PYTHON: "C:\\Python36-x64" + - PYTHON_HOME: "C:\\Python36-x64" PYTHON_VERSION: "3.6" PYTHON_ARCH: "64" db: postgresql TOX_ENV: "py36-postgres-psycopg-w32" - - PYTHON: "C:\\Python27-x64" + - PYTHON_HOME: "C:\\Python27-x64" PYTHON_VERSION: "2.7" PYTHON_ARCH: "64" db: postgresql TOX_ENV: "py27-postgres-pyodbc-w32" - - PYTHON: "C:\\Python34-x64" + - PYTHON_HOME: "C:\\Python34-x64" PYTHON_VERSION: "3.4" PYTHON_ARCH: "64" db: postgresql TOX_ENV: "py34-postgres-pyodbc-w32" - - PYTHON: "C:\\Python35-x64" + - PYTHON_HOME: "C:\\Python35-x64" PYTHON_VERSION: "3.5" PYTHON_ARCH: "64" db: postgresql TOX_ENV: "py35-postgres-pyodbc-w32" - - PYTHON: "C:\\Python36-x64" + - PYTHON_HOME: "C:\\Python36-x64" PYTHON_VERSION: "3.6" PYTHON_ARCH: "64" db: postgresql TOX_ENV: "py36-postgres-pyodbc-w32" - - PYTHON: "C:\\Python27-x64" + - PYTHON_HOME: "C:\\Python27-x64" PYTHON_VERSION: "2.7" PYTHON_ARCH: "64" db: postgresql TOX_ENV: "py27-postgres-pypyodbc-w32" - - PYTHON: "C:\\Python34-x64" + - PYTHON_HOME: "C:\\Python34-x64" PYTHON_VERSION: "3.4" PYTHON_ARCH: "64" db: postgresql TOX_ENV: "py34-postgres-pypyodbc-w32" - - PYTHON: "C:\\Python35-x64" + - PYTHON_HOME: "C:\\Python35-x64" PYTHON_VERSION: "3.5" PYTHON_ARCH: "64" db: postgresql TOX_ENV: "py35-postgres-pypyodbc-w32" - - PYTHON: "C:\\Python36-x64" + - PYTHON_HOME: "C:\\Python36-x64" PYTHON_VERSION: "3.6" PYTHON_ARCH: "64" db: postgresql TOX_ENV: "py36-postgres-pypyodbc-w32" - - PYTHON: "C:\\Python27" + - PYTHON_HOME: "C:\\Python27" PYTHON_VERSION: "2.7" PYTHON_ARCH: "32" TOX_ENV: "py27-sqlite-w32" - - PYTHON: "C:\\Python27-x64" + - PYTHON_HOME: "C:\\Python27-x64" PYTHON_VERSION: "2.7" PYTHON_ARCH: "64" TOX_ENV: "py27-sqlite-w32" - - PYTHON: "C:\\Python34" + - PYTHON_HOME: "C:\\Python34" PYTHON_VERSION: "3.4" PYTHON_ARCH: "32" TOX_ENV: "py34-sqlite-w32" - - PYTHON: "C:\\Python34-x64" + - PYTHON_HOME: "C:\\Python34-x64" PYTHON_VERSION: "3.4" PYTHON_ARCH: "64" TOX_ENV: "py34-sqlite-w32" - - PYTHON: "C:\\Python35" + - PYTHON_HOME: "C:\\Python35" PYTHON_VERSION: "3.5" PYTHON_ARCH: "32" TOX_ENV: "py35-sqlite-w32" - - PYTHON: "C:\\Python35-x64" + - PYTHON_HOME: "C:\\Python35-x64" PYTHON_VERSION: "3.5" PYTHON_ARCH: "64" TOX_ENV: "py35-sqlite-w32" - - PYTHON: "C:\\Python36" + - PYTHON_HOME: "C:\\Python36" PYTHON_VERSION: "3.6" PYTHON_ARCH: "32" TOX_ENV: "py36-sqlite-w32" - - PYTHON: "C:\\Python36-x64" + - PYTHON_HOME: "C:\\Python36-x64" PYTHON_VERSION: "3.6" PYTHON_ARCH: "64" TOX_ENV: "py36-sqlite-w32" - - PYTHON: "C:\\Python27" + - PYTHON_HOME: "C:\\Python27" PYTHON_VERSION: "2.7" PYTHON_ARCH: "32" TOX_ENV: "py27-sqlite-memory-w32" - - PYTHON: "C:\\Python27-x64" + - PYTHON_HOME: "C:\\Python27-x64" PYTHON_VERSION: "2.7" PYTHON_ARCH: "64" TOX_ENV: "py27-sqlite-memory-w32" - - PYTHON: "C:\\Python34" + - PYTHON_HOME: "C:\\Python34" PYTHON_VERSION: "3.4" PYTHON_ARCH: "32" TOX_ENV: "py34-sqlite-memory-w32" - - PYTHON: "C:\\Python34-x64" + - PYTHON_HOME: "C:\\Python34-x64" PYTHON_VERSION: "3.4" PYTHON_ARCH: "64" TOX_ENV: "py34-sqlite-memory-w32" - - PYTHON: "C:\\Python35" + - PYTHON_HOME: "C:\\Python35" PYTHON_VERSION: "3.5" PYTHON_ARCH: "32" TOX_ENV: "py35-sqlite-memory-w32" - - PYTHON: "C:\\Python35-x64" + - PYTHON_HOME: "C:\\Python35-x64" PYTHON_VERSION: "3.5" PYTHON_ARCH: "64" TOX_ENV: "py35-sqlite-memory-w32" - - PYTHON: "C:\\Python36" + - PYTHON_HOME: "C:\\Python36" PYTHON_VERSION: "3.6" PYTHON_ARCH: "32" TOX_ENV: "py36-sqlite-memory-w32" - - PYTHON: "C:\\Python36-x64" + - PYTHON_HOME: "C:\\Python36-x64" PYTHON_VERSION: "3.6" PYTHON_ARCH: "64" TOX_ENV: "py36-sqlite-memory-w32" install: # Ensure we use the right python version - - "SET PATH=%PYTHON%;%PYTHON%\\Scripts;C:\\Program Files\\MySQL\\MySQL Server 5.7\\bin;C:\\Program Files\\PostgreSQL\\9.5\\bin;%PATH%" + - "SET PATH=%PYTHON_HOME%;%PYTHON_HOME%\\Scripts;C:\\Program Files\\MySQL\\MySQL Server 5.7\\bin;C:\\Program Files\\PostgreSQL\\9.5\\bin;%PATH%" + - "SET TOXPYTHON=%PYTHON_HOME%\\python.exe" - "python --version" - "python -c \"import struct; print(struct.calcsize('P') * 8)\"" - "pip --version" diff --git a/tox.ini b/tox.ini index f46ee298..7519d997 100644 --- a/tox.ini +++ b/tox.ini @@ -6,6 +6,11 @@ envlist = py{26,27}-{mysqldb,mysql-oursql},py{34,35,36}-{mysqlclient,pypostgresq [testenv] # Ensure we cd into sqlobject before running the tests changedir = ./sqlobject/ +basepython = + py27: {env:TOXPYTHON:python2.7} + py34: {env:TOXPYTHON:python3.4} + py35: {env:TOXPYTHON:python3.5} + py36: {env:TOXPYTHON:python3.6} commands = {envpython} --version {envpython} -c "import struct; print(struct.calcsize('P') * 8)" From 0fa4628d67982d8fd9e599c5bb68a7af47ba3fad Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 6 Apr 2017 20:29:46 +0300 Subject: [PATCH 031/509] Add sslmode for ODBC connect string for Pg --- sqlobject/postgres/pgconnection.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index 8f44ef81..7792e8b9 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -96,6 +96,9 @@ def __init__(self, dsn=None, host=None, port=None, db=None, if driver in ('odbc', 'pyodbc', 'pypyodbc'): self.make_odbc_conn_str(db, host, port, user, password, kw.pop('odbcdrv', 'PostgreSQL ANSI')) + sslmode = kw.pop("sslmode", None) + if sslmode: + self.odbc_conn_str += ';sslmode=require' else: self.dsn_dict = dsn_dict = {} if host: From 0d02d45489718c709192c53f158ad9242d4bf5ea Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 6 Apr 2017 21:27:43 +0300 Subject: [PATCH 032/509] Add support for PyODBC and PyPyODBC for MySQL --- appveyor.yml | 40 ++++---- docs/News.rst | 4 +- docs/SQLObject.rst | 20 ++-- sqlobject/mysql/mysqlconnection.py | 52 ++++++++-- tox.ini | 148 ++++++++++++++++++++++++----- 5 files changed, 198 insertions(+), 66 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 8dda819e..e7d182c9 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -56,6 +56,26 @@ environment: PYTHON_ARCH: "32" db: mysql TOX_ENV: "py36-mysql-connector-w32" + - PYTHON_HOME: "C:\\Python27-x64" + PYTHON_VERSION: "2.7" + PYTHON_ARCH: "64" + db: mysql + TOX_ENV: "py27-mysql-pyodbc-w32" + - PYTHON_HOME: "C:\\Python34-x64" + PYTHON_VERSION: "3.4" + PYTHON_ARCH: "64" + db: mysql + TOX_ENV: "py34-mysql-pyodbc-w32" + - PYTHON_HOME: "C:\\Python35-x64" + PYTHON_VERSION: "3.5" + PYTHON_ARCH: "64" + db: mysql + TOX_ENV: "py35-mysql-pyodbc-w32" + - PYTHON_HOME: "C:\\Python36-x64" + PYTHON_VERSION: "3.6" + PYTHON_ARCH: "64" + db: mysql + TOX_ENV: "py36-mysql-pyodbc-w32" - PYTHON_HOME: "C:\\Python27" PYTHON_VERSION: "2.7" PYTHON_ARCH: "32" @@ -116,26 +136,6 @@ environment: PYTHON_ARCH: "64" db: postgresql TOX_ENV: "py36-postgres-pyodbc-w32" - - PYTHON_HOME: "C:\\Python27-x64" - PYTHON_VERSION: "2.7" - PYTHON_ARCH: "64" - db: postgresql - TOX_ENV: "py27-postgres-pypyodbc-w32" - - PYTHON_HOME: "C:\\Python34-x64" - PYTHON_VERSION: "3.4" - PYTHON_ARCH: "64" - db: postgresql - TOX_ENV: "py34-postgres-pypyodbc-w32" - - PYTHON_HOME: "C:\\Python35-x64" - PYTHON_VERSION: "3.5" - PYTHON_ARCH: "64" - db: postgresql - TOX_ENV: "py35-postgres-pypyodbc-w32" - - PYTHON_HOME: "C:\\Python36-x64" - PYTHON_VERSION: "3.6" - PYTHON_ARCH: "64" - db: postgresql - TOX_ENV: "py36-postgres-pypyodbc-w32" - PYTHON_HOME: "C:\\Python27" PYTHON_VERSION: "2.7" PYTHON_ARCH: "32" diff --git a/docs/News.rst b/docs/News.rst index 975e1855..e0fea062 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -21,8 +21,8 @@ Drivers (work in progress) -------------------------- * Add support for PyODBC and PyPyODBC (pure-python ODBC DB API driver) for - PostgreSQL. Driver names are ``pyodbc``, ``pypyodbc`` or ``odbc`` (try - ``pyodbc`` and ``pypyodbc``). There are some problems. + MySQL and PostgreSQL. Driver names are ``pyodbc``, ``pypyodbc`` or + ``odbc`` (try ``pyodbc`` and ``pypyodbc``). There are some problems. Tests ----- diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index 291092ad..e1b96223 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -47,14 +47,14 @@ Requirements ============ Currently SQLObject supports MySQL_ via MySQLdb_ aka MySQL-python (called -mysqlclient_ for Python 3), `MySQL Connector`_, oursql_ and PyMySQL_. For -PostgreSQL_ psycopg2_ or psycopg1 are recommended; PyGreSQL_, -py-postgresql_, PyODBC_ and PyPyODBC_ are supported but have problems (not -all tests passed). SQLite_ has a built-in driver or PySQLite_. Firebird_ -is supported via fdb_ or kinterbasdb_; pyfirebirdsql_ is supported but has -problems. `MAX DB`_ (also known as SAP DB) is supported via sapdb_. Sybase -via Sybase_. `MSSQL Server`_ via pymssql_ (+ FreeTDS_) or adodbapi_ -(Win32). +mysqlclient_ for Python 3), `MySQL Connector`_, oursql_, PyMySQL_, PyODBC_ +and PyPyODBC_. For PostgreSQL_ psycopg2_ or psycopg1 are recommended; +PyGreSQL_, py-postgresql_, PyODBC_ and PyPyODBC_ are supported but have +problems (not all tests passed). SQLite_ has a built-in driver or +PySQLite_. Firebird_ is supported via fdb_ or kinterbasdb_; pyfirebirdsql_ +is supported but has problems. `MAX DB`_ (also known as SAP DB) is +supported via sapdb_. Sybase via Sybase_. `MSSQL Server`_ via pymssql_ (+ +FreeTDS_) or adodbapi_ (Win32). .. _MySQL: https://www.mysql.com/ .. _MySQLdb: https://sourceforge.net/projects/mysql-python/ @@ -1785,7 +1785,9 @@ transactions_ when using the InnoDB backend; SQLObject can explicitly define the backend using ``sqlmeta.createSQL``. Supported drivers are ``mysqldb``, ``connector``, ``oursql`` and -``pymysql``; defualt is ``mysqldb``. +``pymysql``, ``pyodbc``, ``pypyodbc`` or ``odbc`` (try ``pyodbc`` and +``pypyodbc``); defualt is ``mysqldb``. + Keyword argument ``conv`` allows to pass a list of custom converters. Example:: diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index 05ef526c..3da502b5 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -8,7 +8,10 @@ class ErrorMessage(str): def __new__(cls, e, append_msg=''): obj = str.__new__(cls, e.args[1] + append_msg) - obj.code = int(e.args[0]) + try: + obj.code = int(e.args[0]) + except ValueError: + obj.code = e.args[0] obj.module = e.__module__ obj.exception = e.__class__.__name__ return obj @@ -67,11 +70,24 @@ def __init__(self, db, user, password='', host='localhost', port=0, **kw): oursql.errnos['CR_SERVER_GONE_ERROR'] self.CR_SERVER_LOST = oursql.errnos['CR_SERVER_LOST'] self.ER_DUP_ENTRY = oursql.errnos['ER_DUP_ENTRY'] + elif driver == 'pyodbc': + import pyodbc + self.module = pyodbc + elif driver == 'pypyodbc': + import pypyodbc + self.module = pypyodbc + elif driver == 'odbc': + try: + import pyodbc + except ImportError: + import pypyodbc as pyodbc + self.module = pyodbc else: raise ValueError( 'Unknown MySQL driver "%s", ' 'expected mysqldb, connector, ' - 'oursql or pymysql' % driver) + 'oursql, pymysql, ' + 'odbc, pyodbc or pypyodbc' % driver) except ImportError: pass else: @@ -104,6 +120,11 @@ def __init__(self, db, user, password='', host='localhost', port=0, **kw): self.dbEncoding = None self.driver = driver + if driver in ('odbc', 'pyodbc', 'pypyodbc'): + self.make_odbc_conn_str(db, host, port, user, password, + kw.pop('odbcdrv', + 'MySQL ODBC 5.3 ANSI Driver')) + global mysql_Bin if not PY2 and mysql_Bin is None: mysql_Bin = self.module.Binary @@ -133,12 +154,17 @@ def character_set_name(self): if self.driver == 'connector': self.kw['consume_results'] = True try: - conn = self.module.connect( - host=self.host, port=self.port, db=self.db, - user=self.user, passwd=self.password, **self.kw) - if self.driver != 'oursql': - # Attempt to reconnect. This setting is persistent. - conn.ping(True) + if self.driver in ('odbc', 'pyodbc', 'pypyodbc'): + self.debugWriter.write( + "ODBC connect string: " + self.odbc_conn_str) + conn = self.module.connect(self.odbc_conn_str) + else: + conn = self.module.connect( + host=self.host, port=self.port, db=self.db, + user=self.user, passwd=self.password, **self.kw) + if self.driver != 'oursql': + # Attempt to reconnect. This setting is persistent. + conn.ping(True) except self.module.OperationalError as e: conninfo = ("; used connection string: " "host=%(host)s, port=%(port)s, " @@ -236,7 +262,13 @@ def _queryInsertID(self, conn, soInstance, id, names, values): try: id = c.lastrowid except AttributeError: - id = c.insert_id() + try: + id = c.insert_id + except AttributeError: + self._executeRetry(conn, c, "SELECT LAST_INSERT_ID();") + id = c.fetchone()[0] + else: + id = c.insert_id() if self.debugOutput: self.printDebug(conn, id, 'QueryIns', 'result') return id @@ -274,7 +306,7 @@ def tableExists(self, tableName): self.query('DESCRIBE %s' % (tableName)) return True except dberrors.ProgrammingError as e: - if e.args[0].code == 1146: # ER_NO_SUCH_TABLE + if e.args[0].code in (1146, '42S02'): # ER_NO_SUCH_TABLE return False raise diff --git a/tox.ini b/tox.ini index 7519d997..0dfb7925 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 1.8 -envlist = py{26,27}-{mysqldb,mysql-oursql},py{34,35,36}-{mysqlclient,pypostgresql},py{26,27,34,35,36}-{mysql-connector,pymysql,postgres-psycopg,postgres-pygresql,postgres-pyodbc,postgres-pypyodbc,sqlite,sqlite-memory},py{27,34,35,36}-{firebird-fdb,firebirdsql},py{27,34}-flake8,py{27,34,35,36}-{mssql,mysql-connector,postgres-psycopg,postgres-pyodbc,postgres-pypyodbc,sqlite,sqlite-memory}-w32 +envlist = py{26,27}-{mysqldb,mysql-oursql},py{34,35,36}-{mysqlclient,pypostgresql},py{26,27,34,35,36}-{mysql-connector,pymysql,mysql-pyodbc,mysql-pypyodbc,postgres-psycopg,postgres-pygresql,postgres-pyodbc,postgres-pypyodbc,sqlite,sqlite-memory},py{27,34,35,36}-{firebird-fdb,firebirdsql},py{27,34}-flake8,py{27,34,35,36}-{mssql,mysql-connector,mysql-pyodbc,mysql-pypyodbc,postgres-psycopg,postgres-pyodbc,postgres-pypyodbc,sqlite,sqlite-memory}-w32 # Base test environment settings [testenv] @@ -29,8 +29,8 @@ deps = postgres-psycopg: psycopg2 postgres-pygresql: pygresql pypostgresql: py-postgresql - postgres-pyodbc: pyodbc - postgres-pypyodbc: pypyodbc + pyodbc: pyodbc + pypyodbc: pypyodbc firebird-fdb: fdb firebirdsql: firebirdsql mssql: pymssql @@ -137,6 +137,53 @@ commands = {[pymysql]commands} [testenv:py36-pymysql] commands = {[pymysql]commands} +[mysql-pyodbc] +commands = + {[testenv]commands} + {envpython} -c "import pyodbc; print(pyodbc.drivers())" + -mysql -e 'drop database sqlobject_test;' + mysql -e 'create database sqlobject_test;' + pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=pyodbc&odbcdrv=MySQL&charset=utf8&debug=1 + mysql -e 'drop database sqlobject_test;' + +[testenv:py26-mysql-pyodbc] +commands = {[mysql-pyodbc]commands} + +[testenv:py27-mysql-pyodbc] +commands = {[mysql-pyodbc]commands} + +[testenv:py34-mysql-pyodbc] +commands = {[mysql-pyodbc]commands} + +[testenv:py35-mysql-pyodbc] +commands = {[mysql-pyodbc]commands} + +[testenv:py36-mysql-pyodbc] +commands = {[mysql-pyodbc]commands} + +[mysql-pypyodbc] +commands = + {[testenv]commands} + -mysql -e 'drop database sqlobject_test;' + mysql -e 'create database sqlobject_test;' + pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=MySQL&charset=utf8&debug=1 + mysql -e 'drop database sqlobject_test;' + +[testenv:py26-mysql-pypyodbc] +commands = {[mysql-pypyodbc]commands} + +[testenv:py27-mysql-pypyodbc] +commands = {[mysql-pypyodbc]commands} + +[testenv:py34-mysql-pypyodbc] +commands = {[mysql-pypyodbc]commands} + +[testenv:py35-mysql-pypyodbc] +commands = {[mysql-pypyodbc]commands} + +[testenv:py36-mysql-pypyodbc] +commands = {[mysql-pypyodbc]commands} + # PostgreSQL test environments [psycopg] commands = @@ -201,30 +248,31 @@ commands = {[pypostgresql]commands} [testenv:py36-pypostgresql] commands = {[pypostgresql]commands} -[pyodbc] +[postgres-pyodbc] commands = {[testenv]commands} + {envpython} -c "import pyodbc; print(pyodbc.drivers())" -dropdb -U postgres -w sqlobject_test createdb -U postgres -w sqlobject_test pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=pyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test dropdb -U postgres -w sqlobject_test [testenv:py26-postgres-pyodbc] -commands = {[pyodbc]commands} +commands = {[postgres-pyodbc]commands} [testenv:py27-postgres-pyodbc] -commands = {[pyodbc]commands} +commands = {[postgres-pyodbc]commands} [testenv:py34-postgres-pyodbc] -commands = {[pyodbc]commands} +commands = {[postgres-pyodbc]commands} [testenv:py35-postgres-pyodbc] -commands = {[pyodbc]commands} +commands = {[postgres-pyodbc]commands} [testenv:py36-postgres-pyodbc] -commands = {[pyodbc]commands} +commands = {[postgres-pyodbc]commands} -[pypyodbc] +[postgres-pypyodbc] commands = {[testenv]commands} -dropdb -U postgres -w sqlobject_test @@ -233,19 +281,19 @@ commands = dropdb -U postgres -w sqlobject_test [testenv:py26-postgres-pypyodbc] -commands = {[pypyodbc]commands} +commands = {[postgres-pypyodbc]commands} [testenv:py27-postgres-pypyodbc] -commands = {[pypyodbc]commands} +commands = {[postgres-pypyodbc]commands} [testenv:py34-postgres-pypyodbc] -commands = {[pypyodbc]commands} +commands = {[postgres-pypyodbc]commands} [testenv:py35-postgres-pypyodbc] -commands = {[pypyodbc]commands} +commands = {[postgres-pypyodbc]commands} [testenv:py36-postgres-pypyodbc] -commands = {[pypyodbc]commands} +commands = {[postgres-pypyodbc]commands} # SQLite test environments [sqlite] @@ -389,6 +437,54 @@ commands = {[mysql-connector-w32]commands} [testenv:py36-mysql-connector-w32] commands = {[mysql-connector-w32]commands} +[mysql-pyodbc-w32] +commands = + {[testenv]commands} + {envpython} -c "import pyodbc; print(pyodbc.drivers())" + -mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' + mysql -u root "-pPassword12!" -e 'create database sqlobject_test;' + pytest --cov=sqlobject -D mysql://root:Password12!@localhost/sqlobject_test?driver=pyodbc&odbcdrv=MySQL%20ODBC%205.3%20ANSI%20Driver&charset=utf8&debug=1 + mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' + +[testenv:py26-mysql-pyodbc-w32] +commands = {[mysql-pyodbc-w32]commands} + +[testenv:py27-mysql-pyodbc-w32] +commands = {[mysql-pyodbc-w32]commands} + +[testenv:py34-mysql-pyodbc-w32] +commands = {[mysql-pyodbc-w32]commands} + +[testenv:py35-mysql-pyodbc-w32] +commands = {[mysql-pyodbc-w32]commands} + +[testenv:py36-mysql-pyodbc-w32] +commands = {[mysql-pyodbc-w32]commands} + +[mysql-pypyodbc-w32] +commands = + {[testenv]commands} + {envpython} -c "import pypyodbc; print(pypyodbc.drivers())" + -mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' + mysql -u root "-pPassword12!" -e 'create database sqlobject_test;' + pytest --cov=sqlobject -D mysql://root:Password12!@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=MySQL%20ODBC%205.3%20ANSI%20Driver&charset=utf8&debug=1 + mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' + +[testenv:py26-mysql-pypyodbc-w32] +commands = {[mysql-pypyodbc-w32]commands} + +[testenv:py27-mysql-pypyodbc-w32] +commands = {[mysql-pypyodbc-w32]commands} + +[testenv:py34-mysql-pypyodbc-w32] +commands = {[mysql-pypyodbc-w32]commands} + +[testenv:py35-mysql-pypyodbc-w32] +commands = {[mysql-pypyodbc-w32]commands} + +[testenv:py36-mysql-pypyodbc-w32] +commands = {[mysql-pypyodbc-w32]commands} + [psycopg-w32] commands = {[testenv]commands} @@ -409,45 +505,47 @@ commands = {[psycopg-w32]commands} [testenv:py36-postgres-psycopg-w32] commands = {[psycopg-w32]commands} -[pyodbc-w32] +[postgres-pyodbc-w32] commands = {[testenv]commands} + {envpython} -c "import pyodbc; print(pyodbc.drivers())" -dropdb -U postgres -w sqlobject_test createdb -U postgres -w sqlobject_test pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pyodbc&odbcdrv=PostgreSQL%20ANSI%28x64%29&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb -U postgres -w sqlobject_test [testenv:py27-postgres-pyodbc-w32] -commands = {[pyodbc-w32]commands} +commands = {[postgres-pyodbc-w32]commands} [testenv:py34-postgres-pyodbc-w32] -commands = {[pyodbc-w32]commands} +commands = {[postgres-pyodbc-w32]commands} [testenv:py35-postgres-pyodbc-w32] -commands = {[pyodbc-w32]commands} +commands = {[postgres-pyodbc-w32]commands} [testenv:py36-postgres-pyodbc-w32] -commands = {[pyodbc-w32]commands} +commands = {[postgres-pyodbc-w32]commands} -[pypyodbc-w32] +[postgres-pypyodbc-w32] commands = {[testenv]commands} + {envpython} -c "import pypyodbc; print(pypyodbc.drivers())" -dropdb -U postgres -w sqlobject_test createdb -U postgres -w sqlobject_test pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=odbc&odbcdrv=PostgreSQL%20ANSI%28x64%29&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb -U postgres -w sqlobject_test [testenv:py27-postgres-pypyodbc-w32] -commands = {[pypyodbc-w32]commands} +commands = {[postgres-pypyodbc-w32]commands} [testenv:py34-postgres-pypyodbc-w32] -commands = {[pypyodbc-w32]commands} +commands = {[postgres-pypyodbc-w32]commands} [testenv:py35-postgres-pypyodbc-w32] -commands = {[pypyodbc-w32]commands} +commands = {[postgres-pypyodbc-w32]commands} [testenv:py36-postgres-pypyodbc-w32] -commands = {[pypyodbc-w32]commands} +commands = {[postgres-pypyodbc-w32]commands} [sqlite-w32] commands = From 3a6f6eda84323d1dca94ec90d3affa111ec5ef90 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 6 Apr 2017 23:36:24 +0300 Subject: [PATCH 033/509] [devscripts] Remove log files from pyodbc [skip ci] --- devscripts/cleanup | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devscripts/cleanup b/devscripts/cleanup index fa38d794..19fdb46f 100755 --- a/devscripts/cleanup +++ b/devscripts/cleanup @@ -1,5 +1,5 @@ #! /bin/sh cd "`dirname $0`" && -find . \( -name \*.orig -o -name \*.rej -o -name \*.tmp \) -type f -delete && +find . \( -name \*.orig -o -name \*.rej -o -name \*.tmp -o -name \*.log \) -type f -delete && exec rm -f /tmp/test-sqlite.sqdb* From d89e61b8dadc60cea619ac089c6fafcf9556a48d Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 7 Apr 2017 06:51:30 +0300 Subject: [PATCH 034/509] Stop running tests at Travis with Python 2.6. --- .travis.yml | 9 --------- docs/News.rst | 2 ++ 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index e7773d15..c56d9ff6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,29 +19,23 @@ addons: postgresql: "9.4" env: - - TOXENV=py26-mysqldb - TOXENV=py27-mysqldb - TOXENV=py34-mysqlclient - TOXENV=py35-mysqlclient - TOXENV=py36-mysqlclient - - TOXENV=py26-mysql-connector - TOXENV=py27-mysql-connector - TOXENV=py34-mysql-connector - TOXENV=py35-mysql-connector - TOXENV=py36-mysql-connector - - TOXENV=py26-mysql-oursql - TOXENV=py27-mysql-oursql - - TOXENV=py26-pymysql - TOXENV=py27-pymysql - TOXENV=py34-pymysql - TOXENV=py35-pymysql - TOXENV=py36-pymysql - - TOXENV=py26-postgres-psycopg - TOXENV=py27-postgres-psycopg - TOXENV=py34-postgres-psycopg - TOXENV=py35-postgres-psycopg - TOXENV=py36-postgres-psycopg - - TOXENV=py26-postgres-pygresql - TOXENV=py27-postgres-pygresql - TOXENV=py34-postgres-pygresql - TOXENV=py35-postgres-pygresql @@ -49,12 +43,10 @@ env: - TOXENV=py34-pypostgresql - TOXENV=py35-pypostgresql - TOXENV=py36-pypostgresql - - TOXENV=py26-sqlite - TOXENV=py27-sqlite - TOXENV=py34-sqlite - TOXENV=py35-sqlite - TOXENV=py36-sqlite - - TOXENV=py26-sqlite-memory - TOXENV=py27-sqlite-memory - TOXENV=py34-sqlite-memory - TOXENV=py35-sqlite-memory @@ -72,7 +64,6 @@ env: matrix: allow_failures: - - env: TOXENV=py26-postgres-pygresql - env: TOXENV=py27-postgres-pygresql - env: TOXENV=py34-postgres-pygresql - env: TOXENV=py35-postgres-pygresql diff --git a/docs/News.rst b/docs/News.rst index e0fea062..f2697d68 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -29,6 +29,8 @@ Tests * Run tests at Travis CI and AppVeyor with Python 3.6, x86 and x64. +* Stop running tests at Travis with Python 2.6. + SQLObject 3.2.0 =============== From f3d1c3641393f098f92c1b3e54504198158c65c8 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 7 Apr 2017 06:53:23 +0300 Subject: [PATCH 035/509] Prevent flake8 to complain about 'unicode' under PY3 --- sqlobject/postgres/pgconnection.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index 7792e8b9..c8d9b35c 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -211,7 +211,7 @@ def makeConnection(self): conn.setdecoding(self.module.SQL_WCHAR, encoding=dbEncoding) if PY2: conn.setencoding(str, encoding=dbEncoding) - conn.setencoding(unicode, encoding=dbEncoding) + conn.setencoding(unicode, encoding=dbEncoding) # noqa else: conn.setencoding(encoding=dbEncoding) self._executeRetry(conn, c, From ed552e3fdf2f2b101c6eba9f83b1e27fe4d2e51b Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 7 Apr 2017 06:56:36 +0300 Subject: [PATCH 036/509] sqlite-memory tests fail at Travis for no apparent reason --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index c56d9ff6..921df72f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -71,6 +71,10 @@ matrix: - env: TOXENV=py34-pypostgresql - env: TOXENV=py35-pypostgresql - env: TOXENV=py36-pypostgresql + - env: TOXENV=py27-sqlite-memory + - env: TOXENV=py34-sqlite-memory + - env: TOXENV=py35-sqlite-memory + - env: TOXENV=py36-sqlite-memory - env: TOXENV=py27-firebird-fdb - env: TOXENV=py34-firebird-fdb - env: TOXENV=py35-firebird-fdb From 4d196203af98b7c418ad8a0ebeba081e1cf76c48 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 7 Apr 2017 07:49:39 +0300 Subject: [PATCH 037/509] Use '/usr/bin/env python' for scripts This allows eggs/wheels to be installed into virtual environments. [skip ci] --- devscripts/release | 2 ++ 1 file changed, 2 insertions(+) diff --git a/devscripts/release b/devscripts/release index d04373cc..3a6fc742 100755 --- a/devscripts/release +++ b/devscripts/release @@ -8,11 +8,13 @@ chmod -R a+rX . && ../set-commit-date.py && python setup.py build_py && +python setup.py build --executable '/usr/bin/env python' && python setup.py sdist && for py in 2.6 2.7 3.4 3.5 3.6; do find build -name '*.py[co]' -delete && python$py setup.py build_py && + python$py setup.py build --executable '/usr/bin/env python' && python$py -m compileall build && python$py -O -m compileall build && python$py setup.py bdist_egg || exit 1 From ab3889be6919f4be63e8c841ff294748935f4499 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 8 Apr 2017 23:00:09 +0300 Subject: [PATCH 038/509] Refactor MANIFEST.in; exclude devscripts from sdist devscripts are not required for installation or development. [skip ci] --- MANIFEST.in | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/MANIFEST.in b/MANIFEST.in index 212861b8..32ac686f 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,8 +1,7 @@ global-include *.py *.rst *.txt +recursive-include docs *.css *.html *.js *.gif *.png include LICENSE MANIFEST.in .travis.yml circle.yml tox.ini include debian/* sqlobject/.coveragerc include docs/Makefile docs/genapidocs docs/rebuild -recursive-include devscripts * -recursive-include docs *.css *.html *.js *.gif *.png -global-exclude *.py[co] -prune docs/_build +recursive-exclude devscripts * +recursive-exclude docs/_build * From e1a698ed6ccef20cd9645d1c88cc2b4f289d2366 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 9 Apr 2017 02:33:30 +0300 Subject: [PATCH 039/509] [devscripts] setup: set umask to 022 -rwxr-xr-x [skip ci] --- devscripts/setup | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devscripts/setup b/devscripts/setup index 315e84ab..946696e8 100755 --- a/devscripts/setup +++ b/devscripts/setup @@ -1,6 +1,6 @@ #! /bin/sh -umask 002 # -rwxrwxr-x +umask 022 # -rwxr-xr-x cd "`dirname \"$0\"`"/SQLObject && python2.6 setup.py install -O2 && From 69d08334b97bb12e89429d5ab0758247ef09a71b Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 9 Apr 2017 18:16:48 +0300 Subject: [PATCH 040/509] [devscripts] Adapt set-commit-date.py to Python 3 Turn on universal_newlines. [skip ci] --- devscripts/set-commit-date.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/devscripts/set-commit-date.py b/devscripts/set-commit-date.py index c5d49d42..dc6a5fb7 100755 --- a/devscripts/set-commit-date.py +++ b/devscripts/set-commit-date.py @@ -13,7 +13,8 @@ git_log = subprocess.Popen(['git', 'log', '-m', '--first-parent', '--name-only', '--no-color', '--format=%s%%n%%ct' % separator], - stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + stdout=subprocess.PIPE, stderr=subprocess.STDOUT, + universal_newlines=True) filenames = set() # stages: 1 - start of commit, 2 - timestamp, 3 - empty line, 4 - files stage = 1 From c322285189d17bc0a9ad10f53ec8864dd9066cff Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 10 Apr 2017 21:28:38 +0300 Subject: [PATCH 041/509] Stop updating http://sqlobject.readthedocs.org/ It's enough to have http://sqlobject.org/ [skip ci] --- docs/News.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/News.rst b/docs/News.rst index f2697d68..0b93b2e7 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -24,6 +24,12 @@ Drivers (work in progress) MySQL and PostgreSQL. Driver names are ``pyodbc``, ``pypyodbc`` or ``odbc`` (try ``pyodbc`` and ``pypyodbc``). There are some problems. +Documentation +------------- + +* Stop updating http://sqlobject.readthedocs.org/ - it's enough to have + http://sqlobject.org/ + Tests ----- From e7608833bcadbcdef50b01321aeae42e76dfdde1 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 10 Apr 2017 21:31:12 +0300 Subject: [PATCH 042/509] Remove gmane [skip ci] --- ANNOUNCE.rst | 3 --- setup.py | 3 --- 2 files changed, 6 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index e636be50..e4759b63 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -54,9 +54,6 @@ http://sqlobject.org/devel/ Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss -Archives: -http://news.gmane.org/gmane.comp.python.sqlobject - Download: https://pypi.python.org/pypi/SQLObject/3.3.0a0.dev20170110 diff --git a/setup.py b/setup.py index d4b43245..ed917f27 100755 --- a/setup.py +++ b/setup.py @@ -173,9 +173,6 @@ Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss -Archives: -http://news.gmane.org/gmane.comp.python.sqlobject - Download: https://pypi.python.org/pypi/SQLObject/@@ From 3fac10b6e2434543ff543b2bdff63907f97298dd Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 15 Apr 2017 20:50:57 +0300 Subject: [PATCH 043/509] [setup.cfg] Remove outdated ez_setup.py [skip ci] --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 4c5fd41a..d0e62d02 100644 --- a/setup.cfg +++ b/setup.cfg @@ -4,7 +4,7 @@ tag_date = 1 tag_svn_revision = 0 [flake8] -exclude = .git,.tox,docs/europython/*.py,ez_setup.py +exclude = .git,.tox,docs/europython/*.py # E305: expected 2 blank lines after class or function definition, found 1 ignore = E305 From 1450275af30b8896373c091e5398fb942c3f1890 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 17 Apr 2017 22:33:54 +0300 Subject: [PATCH 044/509] Fix release script (version) [skip ci] --- devscripts/release | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/devscripts/release b/devscripts/release index 3a6fc742..ee15d01e 100755 --- a/devscripts/release +++ b/devscripts/release @@ -23,13 +23,17 @@ done find build -name '*.py[co]' -delete && python setup.py bdist_wheel --universal && +version=`python setup.py --version` +. `dirname $0`/split.sh && +split_tag $version + if [ "$state" = final ]; then cp -a dist/* "$HOME"/tmp/ && rsync -ahP4 dist/* frs.sourceforge.net:/home/frs/project/sqlobject/sqlobject/"$version"/ && rsync -ahP4 ANNOUNCE.rst frs.sourceforge.net:/home/frs/project/sqlobject/sqlobject/"$version"/README.rst || exit 1 fi -twine register dist/SQLObject-"`python setup.py --version`".tar.gz && +twine register dist/SQLObject-"$version".tar.gz && twine upload --sign dist/* && exec rm -rf build dist docs/html SQLObject.egg-info From ee8c1492c6b80ca971fee2778e2bc781d2e9b84f Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 20 Apr 2017 21:32:23 +0300 Subject: [PATCH 045/509] Document there are many problems with pypyodbc [skip ci] --- docs/News.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/News.rst b/docs/News.rst index 0b93b2e7..dff7e8ea 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -22,7 +22,8 @@ Drivers (work in progress) * Add support for PyODBC and PyPyODBC (pure-python ODBC DB API driver) for MySQL and PostgreSQL. Driver names are ``pyodbc``, ``pypyodbc`` or - ``odbc`` (try ``pyodbc`` and ``pypyodbc``). There are some problems. + ``odbc`` (try ``pyodbc`` and ``pypyodbc``). There are some problems with + pyodbc and many problems with pypyodbc. Documentation ------------- From 5dfacb25fb61bcc6f08aaad2bd3934f2919c92ee Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 20 Apr 2017 22:06:04 +0300 Subject: [PATCH 046/509] Add support for PyODBC and PyPyODBC for MS SQL Run tests at AppVeyor. --- appveyor.yml | 24 +++++++++++++-- docs/News.rst | 6 ++-- sqlobject/mssql/mssqlconnection.py | 47 +++++++++++++++++++++--------- tox.ini | 42 +++++++++++++++++++------- 4 files changed, 90 insertions(+), 29 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index e7d182c9..2b459a2c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -30,12 +30,32 @@ environment: PYTHON_VERSION: "2.7" PYTHON_ARCH: "32" db: mssql2014 - TOX_ENV: "py27-mssql-w32" + TOX_ENV: "py27-pymssql-w32" - PYTHON_HOME: "C:\\Python34" PYTHON_VERSION: "3.4" PYTHON_ARCH: "32" db: mssql2014 - TOX_ENV: "py34-mssql-w32" + TOX_ENV: "py34-pymssql-w32" + - PYTHON_HOME: "C:\\Python27" + PYTHON_VERSION: "2.7" + PYTHON_ARCH: "32" + db: mssql2014 + TOX_ENV: "py27-mssql-pyodbc-w32" + - PYTHON_HOME: "C:\\Python34" + PYTHON_VERSION: "3.4" + PYTHON_ARCH: "32" + db: mssql2014 + TOX_ENV: "py34-mssql-pyodbc-w32" + - PYTHON_HOME: "C:\\Python35" + PYTHON_VERSION: "3.5" + PYTHON_ARCH: "32" + db: mssql2014 + TOX_ENV: "py35-mssql-pyodbc-w32" + - PYTHON_HOME: "C:\\Python36" + PYTHON_VERSION: "3.6" + PYTHON_ARCH: "32" + db: mssql2014 + TOX_ENV: "py36-mssql-pyodbc-w32" - PYTHON_HOME: "C:\\Python27" PYTHON_VERSION: "2.7" PYTHON_ARCH: "32" diff --git a/docs/News.rst b/docs/News.rst index dff7e8ea..d9d5307d 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -21,9 +21,9 @@ Drivers (work in progress) -------------------------- * Add support for PyODBC and PyPyODBC (pure-python ODBC DB API driver) for - MySQL and PostgreSQL. Driver names are ``pyodbc``, ``pypyodbc`` or - ``odbc`` (try ``pyodbc`` and ``pypyodbc``). There are some problems with - pyodbc and many problems with pypyodbc. + MySQL, PostgreSQL and MS SQL. Driver names are ``pyodbc``, ``pypyodbc`` + or ``odbc`` (try ``pyodbc`` and ``pypyodbc``). There are some problems + with pyodbc and many problems with pypyodbc. Documentation ------------- diff --git a/sqlobject/mssql/mssqlconnection.py b/sqlobject/mssql/mssqlconnection.py index 1350514f..c154dd49 100644 --- a/sqlobject/mssql/mssqlconnection.py +++ b/sqlobject/mssql/mssqlconnection.py @@ -24,10 +24,23 @@ def __init__(self, db, user, password='', host='localhost', port=None, import adodbapi as sqlmodule elif driver == 'pymssql': import pymssql as sqlmodule + elif driver == 'pyodbc': + import pyodbc + self.module = pyodbc + elif driver == 'pypyodbc': + import pypyodbc + self.module = pypyodbc + elif driver == 'odbc': + try: + import pyodbc + except ImportError: + import pypyodbc as pyodbc + self.module = pyodbc else: raise ValueError( 'Unknown MSSQL driver "%s", ' - 'expected adodb or pymssql' % driver) + 'expected adodb, pymssql, ' + 'odbc, pyodbc or pypyodbc' % driver) except ImportError: pass else: @@ -35,9 +48,13 @@ def __init__(self, db, user, password='', host='localhost', port=None, else: raise ImportError( 'Cannot find an MSSQL driver, tried %s' % drivers) - self.module = sqlmodule - if sqlmodule.__name__ == 'adodbapi': + if driver in ('odbc', 'pyodbc', 'pypyodbc'): + self.make_odbc_conn_str(db, host, port, user, password, + kw.pop('odbcdrv', 'SQL Server')) + + elif driver in ('adodb', 'adodbapi'): + self.module = sqlmodule self.dbconnection = sqlmodule.connect # ADO uses unicode only (AFAIK) self.usingUnicodeStrings = True @@ -64,7 +81,8 @@ def __init__(self, db, user, password='', host='localhost', port=None, kw.pop("ncli", None) kw.pop("sspi", None) - else: # pymssql + elif driver == 'pymssql': + self.module = sqlmodule self.dbconnection = sqlmodule.connect sqlmodule.Binary = lambda st: str(st) # don't know whether pymssql uses unicode @@ -89,6 +107,7 @@ def _make_conn_str(keys): keys_dict[attr] = value return keys_dict self.make_conn_str = _make_conn_str + self.driver = driver self.autoCommit = int(autoCommit) self.user = user @@ -118,17 +137,22 @@ def insert_id(self, conn): return c.fetchone()[0] def makeConnection(self): - conn_descr = self.make_conn_str(self) - if isinstance(conn_descr, dict): - con = self.dbconnection(**conn_descr) + if self.driver in ('odbc', 'pyodbc', 'pypyodbc'): + self.debugWriter.write( + "ODBC connect string: " + self.odbc_conn_str) + conn = self.module.connect(self.odbc_conn_str) else: - con = self.dbconnection(conn_descr) - cur = con.cursor() + conn_descr = self.make_conn_str(self) + if isinstance(conn_descr, dict): + conn = self.dbconnection(**conn_descr) + else: + conn = self.dbconnection(conn_descr) + cur = conn.cursor() cur.execute('SET ANSI_NULLS ON') cur.execute("SELECT CAST('12345.21' AS DECIMAL(10, 2))") self.decimalSeparator = str(cur.fetchone()[0])[-3] cur.close() - return con + return conn HAS_IDENTITY = """ select 1 @@ -302,9 +326,6 @@ def _setAutoCommit(self, conn, auto): option = "OFF" c = conn.cursor() c.execute("SET AUTOCOMMIT " + option) - # from mx.ODBC.Windows import SQL - # connection.setconnectoption( - # SQL.AUTOCOMMIT, SQL.AUTOCOMMIT_ON if auto else SQL.AUTOCOMMIT_OFF) # precision and scale is needed for decimal columns def guessClass(self, t, size, precision, scale): diff --git a/tox.ini b/tox.ini index 0dfb7925..02d2d4d1 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 1.8 -envlist = py{26,27}-{mysqldb,mysql-oursql},py{34,35,36}-{mysqlclient,pypostgresql},py{26,27,34,35,36}-{mysql-connector,pymysql,mysql-pyodbc,mysql-pypyodbc,postgres-psycopg,postgres-pygresql,postgres-pyodbc,postgres-pypyodbc,sqlite,sqlite-memory},py{27,34,35,36}-{firebird-fdb,firebirdsql},py{27,34}-flake8,py{27,34,35,36}-{mssql,mysql-connector,mysql-pyodbc,mysql-pypyodbc,postgres-psycopg,postgres-pyodbc,postgres-pypyodbc,sqlite,sqlite-memory}-w32 +envlist = py{26,27}-{mysqldb,mysql-oursql},py{34,35,36}-{mysqlclient,pypostgresql},py{26,27,34,35,36}-{mysql-connector,pymysql,mysql-pyodbc,mysql-pypyodbc,postgres-psycopg,postgres-pygresql,postgres-pyodbc,postgres-pypyodbc,sqlite,sqlite-memory},py{27,34,35,36}-{firebird-fdb,firebirdsql},py{27,34}-flake8,py{27,34,35,36}-{pymssql,mssql-pyodbc,mysql-connector,mysql-pyodbc,mysql-pypyodbc,postgres-psycopg,postgres-pyodbc,postgres-pypyodbc,sqlite,sqlite-memory}-w32 # Base test environment settings [testenv] @@ -33,7 +33,7 @@ deps = pypyodbc: pypyodbc firebird-fdb: fdb firebirdsql: firebirdsql - mssql: pymssql + pymssql: pymssql passenv = CI TRAVIS TRAVIS_* APPVEYOR DISTUTILS_USE_SDK MSSdk INCLUDE LIB PGPASSWORD WINDIR # Don't fail or warn on uninstalled commands whitelist_externals = @@ -397,7 +397,7 @@ commands = flake8 . # Windows testing -[mssql-w32] +[pymssql-w32] commands = {[testenv]commands} -sqlcmd -U sa -P "Password12!" -S .\SQL2014 -Q "DROP DATABASE sqlobject_test" @@ -405,17 +405,37 @@ commands = pytest --cov=sqlobject -D "mssql://sa:Password12!@localhost\SQL2014/sqlobject_test?driver=pymssql&timeout=30&debug=1" sqlcmd -U sa -P "Password12!" -S .\SQL2014 -Q "DROP DATABASE sqlobject_test" -[testenv:py27-mssql-w32] -commands = {[mssql-w32]commands} +[testenv:py27-pymssql-w32] +commands = {[pymssql-w32]commands} -[testenv:py34-mssql-w32] -commands = {[mssql-w32]commands} +[testenv:py34-pymssql-w32] +commands = {[pymssql-w32]commands} -[testenv:py35-mssql-w32] -commands = {[mssql-w32]commands} +[testenv:py35-pymssql-w32] +commands = {[pymssql-w32]commands} -[testenv:py36-mssql-w32] -commands = {[mssql-w32]commands} +[testenv:py36-pymssql-w32] +commands = {[pymssql-w32]commands} + +[mssql-pyodbc-w32] +commands = + {envpython} -c "import pyodbc; print(pyodbc.drivers())" + -sqlcmd -U sa -P "Password12!" -S .\SQL2014 -Q "DROP DATABASE sqlobject_test" + sqlcmd -U sa -P "Password12!" -S .\SQL2014 -Q "CREATE DATABASE sqlobject_test" + pytest --cov=sqlobject -D "mssql://sa:Password12!@localhost\SQL2014/sqlobject_test?driver=pyodbc&odbcdrv=SQL%20Server&debug=1" + sqlcmd -U sa -P "Password12!" -S .\SQL2014 -Q "DROP DATABASE sqlobject_test" + +[testenv:py27-mssql-pyodbc-w32] +commands = {[mssql-pyodbc-w32]commands} + +[testenv:py34-mssql-pyodbc-w32] +commands = {[mssql-pyodbc-w32]commands} + +[testenv:py35-mssql-pyodbc-w32] +commands = {[mssql-pyodbc-w32]commands} + +[testenv:py36-mssql-pyodbc-w32] +commands = {[mssql-pyodbc-w32]commands} [mysql-connector-w32] commands = From aea36335819e189316cffc84705dc464f4ff8120 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 20 Apr 2017 21:36:31 +0300 Subject: [PATCH 047/509] Stop running tests at AppVeyor with pymssql Too many timeouts and problems. --- appveyor.yml | 12 ------------ docs/News.rst | 3 +++ tox.ini | 23 +---------------------- 3 files changed, 4 insertions(+), 34 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 2b459a2c..46c89c07 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -25,17 +25,6 @@ environment: CMD_IN_ENV: "cmd /E:ON /V:ON /C .\\run_with_env.cmd" matrix: - # from https://www.appveyor.com/docs/installed-software/#python - - PYTHON_HOME: "C:\\Python27" - PYTHON_VERSION: "2.7" - PYTHON_ARCH: "32" - db: mssql2014 - TOX_ENV: "py27-pymssql-w32" - - PYTHON_HOME: "C:\\Python34" - PYTHON_VERSION: "3.4" - PYTHON_ARCH: "32" - db: mssql2014 - TOX_ENV: "py34-pymssql-w32" - PYTHON_HOME: "C:\\Python27" PYTHON_VERSION: "2.7" PYTHON_ARCH: "32" @@ -233,7 +222,6 @@ install: - ps: Get-OdbcDriver -Platform 32-bit | Select-Object -ExpandProperty Name - ps: Get-OdbcDriver -Platform 64-bit | Select-Object -ExpandProperty Name # Enable TCP for mssql - # (from appveyor documentation) - ps: | [reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo") | Out-Null [reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.SqlWmiManagement") | Out-Null diff --git a/docs/News.rst b/docs/News.rst index d9d5307d..54ee2f1d 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -38,6 +38,9 @@ Tests * Stop running tests at Travis with Python 2.6. +* Stop running tests at AppVeyor with pymssql - too many timeouts and + problems. + SQLObject 3.2.0 =============== diff --git a/tox.ini b/tox.ini index 02d2d4d1..e6812ea7 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 1.8 -envlist = py{26,27}-{mysqldb,mysql-oursql},py{34,35,36}-{mysqlclient,pypostgresql},py{26,27,34,35,36}-{mysql-connector,pymysql,mysql-pyodbc,mysql-pypyodbc,postgres-psycopg,postgres-pygresql,postgres-pyodbc,postgres-pypyodbc,sqlite,sqlite-memory},py{27,34,35,36}-{firebird-fdb,firebirdsql},py{27,34}-flake8,py{27,34,35,36}-{pymssql,mssql-pyodbc,mysql-connector,mysql-pyodbc,mysql-pypyodbc,postgres-psycopg,postgres-pyodbc,postgres-pypyodbc,sqlite,sqlite-memory}-w32 +envlist = py{26,27}-{mysqldb,mysql-oursql},py{34,35,36}-{mysqlclient,pypostgresql},py{26,27,34,35,36}-{mysql-connector,pymysql,mysql-pyodbc,mysql-pypyodbc,postgres-psycopg,postgres-pygresql,postgres-pyodbc,postgres-pypyodbc,sqlite,sqlite-memory},py{27,34,35,36}-{firebird-fdb,firebirdsql},py{27,34}-flake8,py{27,34,35,36}-{mssql-pyodbc,mysql-connector,mysql-pyodbc,mysql-pypyodbc,postgres-psycopg,postgres-pyodbc,postgres-pypyodbc,sqlite,sqlite-memory}-w32 # Base test environment settings [testenv] @@ -33,7 +33,6 @@ deps = pypyodbc: pypyodbc firebird-fdb: fdb firebirdsql: firebirdsql - pymssql: pymssql passenv = CI TRAVIS TRAVIS_* APPVEYOR DISTUTILS_USE_SDK MSSdk INCLUDE LIB PGPASSWORD WINDIR # Don't fail or warn on uninstalled commands whitelist_externals = @@ -397,26 +396,6 @@ commands = flake8 . # Windows testing -[pymssql-w32] -commands = - {[testenv]commands} - -sqlcmd -U sa -P "Password12!" -S .\SQL2014 -Q "DROP DATABASE sqlobject_test" - sqlcmd -U sa -P "Password12!" -S .\SQL2014 -Q "CREATE DATABASE sqlobject_test" - pytest --cov=sqlobject -D "mssql://sa:Password12!@localhost\SQL2014/sqlobject_test?driver=pymssql&timeout=30&debug=1" - sqlcmd -U sa -P "Password12!" -S .\SQL2014 -Q "DROP DATABASE sqlobject_test" - -[testenv:py27-pymssql-w32] -commands = {[pymssql-w32]commands} - -[testenv:py34-pymssql-w32] -commands = {[pymssql-w32]commands} - -[testenv:py35-pymssql-w32] -commands = {[pymssql-w32]commands} - -[testenv:py36-pymssql-w32] -commands = {[pymssql-w32]commands} - [mssql-pyodbc-w32] commands = {envpython} -c "import pyodbc; print(pyodbc.drivers())" From 67d58541fc48c0e1358e1b6ecc2b26a816d5a8c0 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 24 Apr 2017 01:26:24 +0300 Subject: [PATCH 048/509] Remove set-commit-date.py [skip ci] --- devscripts/release | 2 +- devscripts/set-commit-date.py | 47 ----------------------------------- 2 files changed, 1 insertion(+), 48 deletions(-) delete mode 100755 devscripts/set-commit-date.py diff --git a/devscripts/release b/devscripts/release index ee15d01e..0e24a8ae 100755 --- a/devscripts/release +++ b/devscripts/release @@ -4,8 +4,8 @@ cd "`dirname \"$0\"`"/SQLObject && umask 022 && chmod -R a+rX . && +set-commit-date.py && ../build-docs && -../set-commit-date.py && python setup.py build_py && python setup.py build --executable '/usr/bin/env python' && diff --git a/devscripts/set-commit-date.py b/devscripts/set-commit-date.py deleted file mode 100755 index dc6a5fb7..00000000 --- a/devscripts/set-commit-date.py +++ /dev/null @@ -1,47 +0,0 @@ -#! /usr/bin/env python - -# Find commit date/time for every commit, list files in the commit -# and set the file's modification time to the date/time of the latest commit. - -# Adapted from https://git.wiki.kernel.org/index.php/ExampleScripts#Setting_the_timestamps_of_the_files_to_the_commit_timestamp_of_the_commit_which_last_touched_them # noqa - -import os -import subprocess - -separator = '----- GIT LOG SEPARATOR -----' - -git_log = subprocess.Popen(['git', 'log', '-m', '--first-parent', - '--name-only', '--no-color', - '--format=%s%%n%%ct' % separator], - stdout=subprocess.PIPE, stderr=subprocess.STDOUT, - universal_newlines=True) -filenames = set() -# stages: 1 - start of commit, 2 - timestamp, 3 - empty line, 4 - files -stage = 1 -while True: - line = git_log.stdout.readline() - if not line: # EOF - break - line = line.strip() - if (stage in (1, 4)) and (line == separator): # Start of a commit - stage = 2 - elif stage == 2: - stage = 3 - time = int(line) - elif stage == 3: - if line == separator: # Null-merge (git merge -s ours), no files - stage = 2 - continue - stage = 4 - assert line == '', line - elif stage == 4: - filename = line - if filename not in filenames: - filenames.add(filename) - if os.path.exists(filename): - os.utime(filename, (time, time)) - else: - raise ValueError("stage: %d, line: %s" % (stage, line)) - -git_log.wait() -git_log.stdout.close() From f1ffdf88ce7f477ec55eb73a7b0f7bcf15c81fbc Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 27 Apr 2017 23:20:14 +0300 Subject: [PATCH 049/509] build-all-docs: avoid overriding robots.txt and generate sitemap.xml [skip ci] --- devscripts/build-all-docs | 14 ++++++++++--- devscripts/sqlobject.org-sitemapconfig.xml | 24 ++++++++++++++++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 devscripts/sqlobject.org-sitemapconfig.xml diff --git a/devscripts/build-all-docs b/devscripts/build-all-docs index 5e8f2866..e6597824 100755 --- a/devscripts/build-all-docs +++ b/devscripts/build-all-docs @@ -3,8 +3,16 @@ build_docs() { git checkout "$1" && ../build-docs && - rsync -ahP --del docs/html/ ../SQLObject-docs/"$2"/ + rsync -ahP --del --exclude=/robots.txt docs/html/ ../SQLObject-docs/"$2"/ } -cd "`dirname \"$0\"`"/SQLObject && -build_docs 3.2.0 && exec build_docs master devel +PROG_DIR="`dirname \"$0\"`" && +cd "$PROG_DIR" && +PROG_DIR="`pwd`" && + +cd "$PROG_DIR"/SQLObject && +build_docs 3.2.0 && +build_docs master devel && + +cd ../SQLObject-docs && +exec sitemap_gen.py --config="$PROG_DIR"/sqlobject.org-sitemapconfig.xml diff --git a/devscripts/sqlobject.org-sitemapconfig.xml b/devscripts/sqlobject.org-sitemapconfig.xml new file mode 100644 index 00000000..dc370559 --- /dev/null +++ b/devscripts/sqlobject.org-sitemapconfig.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + From f53f3383be434b1d0f10e2e8bc05973872dd3101 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 28 Apr 2017 06:15:55 +0300 Subject: [PATCH 050/509] Only test master and pull requests; skip tags --- .travis.yml | 6 ++++++ appveyor.yml | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/.travis.yml b/.travis.yml index 921df72f..87812e20 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,9 @@ +# Only test master and pull requests; skip tags. +# Other branches can allow themselves. +branches: + only: + - master + # Prefer docker container with setuid/sudo sudo: required diff --git a/appveyor.yml b/appveyor.yml index 46c89c07..a4499b5a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -3,6 +3,14 @@ # and Michael Sverdlik's appveyor-utils (https://github.com/cloudify-cosmo/appveyor-utils) version: '{branch}-{build}' +# Only test master and pull requests; skip tags. +# Other branches can allow themselves. +branches: + only: + - master +skip_branch_with_pr: false +skip_tags: true + cache: - '%LOCALAPPDATA%\pip\Cache' From f09ab7a6c734672d50df14e8d3f364c458eb3ce5 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 2 May 2017 22:11:15 +0300 Subject: [PATCH 051/509] Fix split.sh: recognize both 'c' and 'rc' [skip ci] --- devscripts/split.sh | 2 +- devscripts/test-split.sh | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/devscripts/split.sh b/devscripts/split.sh index 9ae68ab9..ce5c3c5e 100644 --- a/devscripts/split.sh +++ b/devscripts/split.sh @@ -1,6 +1,6 @@ split_tag() { branch=$2 - set -- `echo $1 | sed -e 's/\./ /g' -e 's/a/ alpha /' -e 's/b/ beta /' -e 's/c/ rc /'` + set -- `echo $1 | sed -e 's/\./ /g' -e 's/a/ alpha /' -e 's/b/ beta /' -e 's/rc/ rc /' -e 's/\([0-9]\)c/\1 rc /'` major=$1 minor=$2 micro=$3 diff --git a/devscripts/test-split.sh b/devscripts/test-split.sh index 6919f572..a5f17495 100755 --- a/devscripts/test-split.sh +++ b/devscripts/test-split.sh @@ -1,7 +1,6 @@ #! /bin/sh . `dirname $0`/split.sh && -split_tag 21.12.42c4 test_eq() { if [ "$1" != "$2" ]; then @@ -9,6 +8,15 @@ test_eq() { fi } +split_tag 21.12.42c4 +test_eq "$branch" 21.12 +test_eq "$major" 21 +test_eq "$minor" 12 +test_eq "$micro" 42 +test_eq "$state" "release candidate" +test_eq "$serial" 4 + +split_tag 21.12.42rc4 test_eq "$branch" 21.12 test_eq "$major" 21 test_eq "$minor" 12 From 2ca0972c0579284abea98f5c1d69fa37df718c1c Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 4 May 2017 18:44:35 +0300 Subject: [PATCH 052/509] Refactor make_odbc_conn_str() to use DB-specific ODBC keywords --- sqlobject/dbconnection.py | 18 +++++++----------- sqlobject/mssql/mssqlconnection.py | 7 +++++-- sqlobject/mysql/mysqlconnection.py | 9 ++++++--- sqlobject/postgres/pgconnection.py | 7 +++++-- 4 files changed, 23 insertions(+), 18 deletions(-) diff --git a/sqlobject/dbconnection.py b/sqlobject/dbconnection.py index 4f29eb08..89f4382b 100644 --- a/sqlobject/dbconnection.py +++ b/sqlobject/dbconnection.py @@ -734,17 +734,13 @@ def createEmptyDatabase(self): """ raise NotImplementedError - def make_odbc_conn_str(self, db, host=None, port=None, - user=None, password=None, odb_source=None): - odbc_conn_parts = ['Driver={%s}' % odb_source, 'Database=%s' % db] - if host: - odbc_conn_parts.append('Server=%s' % host) - if port: - odbc_conn_parts.append('Port=%d' % port) - if user: - odbc_conn_parts.append('UID=%s' % user) - if password: - odbc_conn_parts.append('Password=%s' % password) + def make_odbc_conn_str(self, odb_source, db, host=None, port=None, + user=None, password=None): + odbc_conn_parts = ['Driver={%s}' % odb_source] + for odbc_keyword, value in \ + zip(self.odbc_keywords, (host, port, user, password, db)): + if value is not None: + odbc_conn_parts.append('%s=%s' % (odbc_keyword, value)) self.odbc_conn_str = ';'.join(odbc_conn_parts) diff --git a/sqlobject/mssql/mssqlconnection.py b/sqlobject/mssql/mssqlconnection.py index c154dd49..811dcd81 100644 --- a/sqlobject/mssql/mssqlconnection.py +++ b/sqlobject/mssql/mssqlconnection.py @@ -12,6 +12,8 @@ class MSSQLConnection(DBAPI): limit_re = re.compile('^\s*(select )(.*)', re.IGNORECASE) + odbc_keywords = ('Server', 'Port', 'User Id', 'Password', 'Database') + def __init__(self, db, user, password='', host='localhost', port=None, autoCommit=0, **kw): drivers = kw.pop('driver', None) or 'adodb,pymssql' @@ -50,8 +52,9 @@ def __init__(self, db, user, password='', host='localhost', port=None, 'Cannot find an MSSQL driver, tried %s' % drivers) if driver in ('odbc', 'pyodbc', 'pypyodbc'): - self.make_odbc_conn_str(db, host, port, user, password, - kw.pop('odbcdrv', 'SQL Server')) + self.make_odbc_conn_str(kw.pop('odbcdrv', 'SQL Server'), + db, host, port, user, password + ) elif driver in ('adodb', 'adodbapi'): self.module = sqlmodule diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index 3da502b5..bf6c48cc 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -25,6 +25,8 @@ class MySQLConnection(DBAPI): dbName = 'mysql' schemes = [dbName] + odbc_keywords = ('Server', 'Port', 'UID', 'Password', 'Database') + def __init__(self, db, user, password='', host='localhost', port=0, **kw): drivers = kw.pop('driver', None) or 'mysqldb' for driver in drivers.split(','): @@ -121,9 +123,10 @@ def __init__(self, db, user, password='', host='localhost', port=0, **kw): self.driver = driver if driver in ('odbc', 'pyodbc', 'pypyodbc'): - self.make_odbc_conn_str(db, host, port, user, password, - kw.pop('odbcdrv', - 'MySQL ODBC 5.3 ANSI Driver')) + self.make_odbc_conn_str(kw.pop('odbcdrv', + 'MySQL ODBC 5.3 ANSI Driver'), + db, host, port, user, password + ) global mysql_Bin if not PY2 and mysql_Bin is None: diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index c8d9b35c..420c157b 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -27,6 +27,8 @@ class PostgresConnection(DBAPI): dbName = 'postgres' schemes = [dbName, 'postgresql'] + odbc_keywords = ('Server', 'Port', 'UID', 'Password', 'Database') + def __init__(self, dsn=None, host=None, port=None, db=None, user=None, password=None, **kw): drivers = kw.pop('driver', None) or 'psycopg' @@ -94,8 +96,9 @@ def __init__(self, dsn=None, host=None, port=None, db=None, self.host = host self.port = port if driver in ('odbc', 'pyodbc', 'pypyodbc'): - self.make_odbc_conn_str(db, host, port, user, password, - kw.pop('odbcdrv', 'PostgreSQL ANSI')) + self.make_odbc_conn_str(kw.pop('odbcdrv', 'PostgreSQL ANSI'), + db, host, port, user, password + ) sslmode = kw.pop("sslmode", None) if sslmode: self.odbc_conn_str += ';sslmode=require' From 34e2ab6bcd3291db200bee40c4e8dbad9ff814f7 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 4 May 2017 19:29:15 +0300 Subject: [PATCH 053/509] tox.ini: set timeout for mssql-pyodbc tests --- tox.ini | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index e6812ea7..6f27b6ad 100644 --- a/tox.ini +++ b/tox.ini @@ -21,6 +21,7 @@ deps = py{34,35,36}: FormEncode >= 1.3.1 PyDispatcher>=2.0.4 py{26,27}: egenix-mx-base + mssql-pyodbc: pytest-timeout mysqldb: mysql-python mysqlclient: mysqlclient mysql-connector: mysql-connector <= 2.2.2 @@ -401,7 +402,7 @@ commands = {envpython} -c "import pyodbc; print(pyodbc.drivers())" -sqlcmd -U sa -P "Password12!" -S .\SQL2014 -Q "DROP DATABASE sqlobject_test" sqlcmd -U sa -P "Password12!" -S .\SQL2014 -Q "CREATE DATABASE sqlobject_test" - pytest --cov=sqlobject -D "mssql://sa:Password12!@localhost\SQL2014/sqlobject_test?driver=pyodbc&odbcdrv=SQL%20Server&debug=1" + pytest --cov=sqlobject -D "mssql://sa:Password12!@localhost\SQL2014/sqlobject_test?driver=pyodbc&odbcdrv=SQL%20Server&debug=1" --timeout=30 sqlcmd -U sa -P "Password12!" -S .\SQL2014 -Q "DROP DATABASE sqlobject_test" [testenv:py27-mssql-pyodbc-w32] From 70388fa6e6d14c7f9cfca8b642787ff4b1619105 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 4 May 2017 20:46:11 +0300 Subject: [PATCH 054/509] Set encoding for ODBC connections for MySQL --- sqlobject/mysql/mysqlconnection.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index bf6c48cc..fe2eace0 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -177,7 +177,15 @@ def character_set_name(self): self._setAutoCommit(conn, bool(self.autoCommit)) if dbEncoding: - if hasattr(conn, 'set_character_set'): + if self.driver in ('odbc', 'pyodbc'): + conn.setdecoding(self.module.SQL_CHAR, encoding=dbEncoding) + conn.setdecoding(self.module.SQL_WCHAR, encoding=dbEncoding) + if PY2: + conn.setencoding(str, encoding=dbEncoding) + conn.setencoding(unicode, encoding=dbEncoding) # noqa + else: + conn.setencoding(encoding=dbEncoding) + elif hasattr(conn, 'set_character_set'): conn.set_character_set(dbEncoding) elif self.driver == 'oursql': conn.charset = dbEncoding From 3077facd828aebea8b68c5824997a41e4f4df2f3 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 4 May 2017 21:04:57 +0300 Subject: [PATCH 055/509] Add missing error codes for ODBC drivers --- sqlobject/mysql/mysqlconnection.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index fe2eace0..c49e2e7e 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -127,6 +127,9 @@ def __init__(self, db, user, password='', host='localhost', port=0, **kw): 'MySQL ODBC 5.3 ANSI Driver'), db, host, port, user, password ) + self.CR_SERVER_GONE_ERROR = 2006 + self.CR_SERVER_LOST = 2013 + self.ER_DUP_ENTRY = 1062 global mysql_Bin if not PY2 and mysql_Bin is None: From 732a6e21bae84733dd58f43e05a22931c04b2c67 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 4 May 2017 20:51:15 +0300 Subject: [PATCH 056/509] appveyor.yml: add 64-bit tests for mssql-pyodbc --- appveyor.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/appveyor.yml b/appveyor.yml index a4499b5a..eff46149 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -38,21 +38,41 @@ environment: PYTHON_ARCH: "32" db: mssql2014 TOX_ENV: "py27-mssql-pyodbc-w32" + - PYTHON_HOME: "C:\\Python27-x64" + PYTHON_VERSION: "2.7" + PYTHON_ARCH: "64" + db: mssql2014 + TOX_ENV: "py27-mssql-pyodbc-w32" - PYTHON_HOME: "C:\\Python34" PYTHON_VERSION: "3.4" PYTHON_ARCH: "32" db: mssql2014 TOX_ENV: "py34-mssql-pyodbc-w32" + - PYTHON_HOME: "C:\\Python34-x64" + PYTHON_VERSION: "3.4" + PYTHON_ARCH: "64" + db: mssql2014 + TOX_ENV: "py34-mssql-pyodbc-w32" - PYTHON_HOME: "C:\\Python35" PYTHON_VERSION: "3.5" PYTHON_ARCH: "32" db: mssql2014 TOX_ENV: "py35-mssql-pyodbc-w32" + - PYTHON_HOME: "C:\\Python35-x64" + PYTHON_VERSION: "3.5" + PYTHON_ARCH: "64" + db: mssql2014 + TOX_ENV: "py35-mssql-pyodbc-w32" - PYTHON_HOME: "C:\\Python36" PYTHON_VERSION: "3.6" PYTHON_ARCH: "32" db: mssql2014 TOX_ENV: "py36-mssql-pyodbc-w32" + - PYTHON_HOME: "C:\\Python36-x64" + PYTHON_VERSION: "3.6" + PYTHON_ARCH: "64" + db: mssql2014 + TOX_ENV: "py36-mssql-pyodbc-w32" - PYTHON_HOME: "C:\\Python27" PYTHON_VERSION: "2.7" PYTHON_ARCH: "32" From d1ff60d0580650455dc4494ba01ef1f59d8bdf17 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 4 May 2017 22:31:27 +0300 Subject: [PATCH 057/509] Test for __nonzero__ under Python 2, __bool__ under Python 3 in BoolCol --- docs/DeveloperGuide.rst | 12 ++++++------ docs/News.rst | 2 ++ sqlobject/col.py | 3 ++- sqlobject/sqlbuilder.py | 1 + sqlobject/tests/test_validation.py | 1 + 5 files changed, 12 insertions(+), 7 deletions(-) diff --git a/docs/DeveloperGuide.rst b/docs/DeveloperGuide.rst index 69699782..5e889c8e 100644 --- a/docs/DeveloperGuide.rst +++ b/docs/DeveloperGuide.rst @@ -92,12 +92,12 @@ have any code. ``SOBoolCol`` has a method to create ``BoolValidator`` and methods to create backend-specific column type. ``BoolValidator`` has identical methods ``from_python`` and ``to_python``; the method passes ``None``, ``SQLExpression`` and bool values unchanged; int and -objects that have method ``__nonzero__`` are converted to bool; other -objects trigger validation error. Bool values that are returned by call -to ``from_python`` will be converted to SQL strings by -``BoolConverter``; bool values from ``to_python`` (is is supposed they -are originated from the backend via DB API driver) are passed to the -application. +objects that have method ``__nonzero__`` (``__bool__`` in Python 3) are +converted to bool; other objects trigger validation error. Bool values +that are returned by call to ``from_python`` will be converted to SQL +strings by ``BoolConverter``; bool values from ``to_python`` (is is +supposed they are originated from the backend via DB API driver) are +passed to the application. Objects that are returned from ``from_python`` must be registered with converters. Another approach for ``from_python`` is to return an object diff --git a/docs/News.rst b/docs/News.rst index 54ee2f1d..cb22978d 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -17,6 +17,8 @@ Minor features Some of thses scripts are version-dependent so it's better to have them in the main repo. +* Test for __nonzero__ under Python 2, __bool__ under Python 3 in BoolCol. + Drivers (work in progress) -------------------------- diff --git a/sqlobject/col.py b/sqlobject/col.py index 26c9a513..2937a238 100644 --- a/sqlobject/col.py +++ b/sqlobject/col.py @@ -789,7 +789,8 @@ def to_python(self, value, state): return None if isinstance(value, (bool, sqlbuilder.SQLExpression)): return value - if isinstance(value, (int, long)) or hasattr(value, '__nonzero__'): + if PY2 and hasattr(value, '__nonzero__') \ + or not PY2 and hasattr(value, '__bool__'): return bool(value) raise validators.Invalid( "expected a bool or an int in the BoolCol '%s', " diff --git a/sqlobject/sqlbuilder.py b/sqlobject/sqlbuilder.py index 2b4cdc79..e87ba701 100644 --- a/sqlobject/sqlbuilder.py +++ b/sqlobject/sqlbuilder.py @@ -1510,6 +1510,7 @@ def __init__(self, clsName, registry=None): def __nonzero__(self): return True + __bool__ = __nonzero__ def __getattr__(self, attr): if self.soClass is None: diff --git a/sqlobject/tests/test_validation.py b/sqlobject/tests/test_validation.py index 86f1a10a..7a068002 100644 --- a/sqlobject/tests/test_validation.py +++ b/sqlobject/tests/test_validation.py @@ -63,6 +63,7 @@ def __int__(self): class SOValidationTestBool(SOValidationTest): def __nonzero__(self): return self.value + __bool__ = __nonzero__ class SOValidationTestFloat(SOValidationTest): From e506c2c62b3b34e820a30e0b669c197edc4bc392 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 4 May 2017 22:41:40 +0300 Subject: [PATCH 058/509] Convert '0'/'1' (from ODBC) to bool in BoolCol --- sqlobject/col.py | 9 +++++++++ sqlobject/tests/test_validation.py | 4 +++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/sqlobject/col.py b/sqlobject/col.py index 2937a238..4c06489f 100644 --- a/sqlobject/col.py +++ b/sqlobject/col.py @@ -792,6 +792,15 @@ def to_python(self, value, state): if PY2 and hasattr(value, '__nonzero__') \ or not PY2 and hasattr(value, '__bool__'): return bool(value) + try: + connection = state.connection or state.soObject._connection + except AttributeError: + pass + else: + if connection.dbName == 'postgres' and \ + connection.driver in ('odbc', 'pyodbc', 'pypyodbc') and \ + isinstance(value, string_type): + return bool(int(value)) raise validators.Invalid( "expected a bool or an int in the BoolCol '%s', " "got %s %r instead" % ( diff --git a/sqlobject/tests/test_validation.py b/sqlobject/tests/test_validation.py index 7a068002..ae62f3c5 100644 --- a/sqlobject/tests/test_validation.py +++ b/sqlobject/tests/test_validation.py @@ -87,7 +87,9 @@ def test_confirmType(self): raises(validators.Invalid, setattr, t, 'name2', 1) raises(validators.Invalid, setattr, t, 'name3', '1') raises(validators.Invalid, setattr, t, 'name4', '1') - raises(validators.Invalid, setattr, t, 'name6', '1') + if t._connection.dbName != 'postgres' or \ + t._connection.driver not in ('odbc', 'pyodbc', 'pypyodbc'): + raises(validators.Invalid, setattr, t, 'name6', '1') raises(validators.Invalid, setattr, t, 'name7', 1) t.name2 = 'you' assert t.name2 == 'you' From ba4e8909593ed546de04544cf1d38f87d5287fea Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 4 May 2017 23:02:45 +0300 Subject: [PATCH 059/509] Check error codes from ODBC drivers for DuplicateError Check error codes for DuplicateError from MySQL and Postgres ODBC drivers. --- sqlobject/mysql/mysqlconnection.py | 2 +- sqlobject/postgres/pgconnection.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index c49e2e7e..225a02f6 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -129,7 +129,7 @@ def __init__(self, db, user, password='', host='localhost', port=0, **kw): ) self.CR_SERVER_GONE_ERROR = 2006 self.CR_SERVER_LOST = 2013 - self.ER_DUP_ENTRY = 1062 + self.ER_DUP_ENTRY = '23000' global mysql_Bin if not PY2 and mysql_Bin is None: diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index 420c157b..63bd17a3 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -232,7 +232,8 @@ def _executeRetry(self, conn, cursor, query): msg = ErrorMessage(e) if getattr(e, 'code', -1) == '23505' or \ getattr(e, 'pgcode', -1) == '23505' or \ - getattr(e, 'sqlstate', -1) == '23505': + getattr(e, 'sqlstate', -1) == '23505' or \ + e.args[0] == '23505': raise dberrors.DuplicateEntryError(msg) else: raise dberrors.IntegrityError(msg) From d8c2122546da28fc7bbdde857a845f2c1533d29a Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 5 May 2017 01:43:00 +0300 Subject: [PATCH 060/509] Fix JsonbCol: undump a string returned by ODBC driver --- sqlobject/col.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sqlobject/col.py b/sqlobject/col.py index 4c06489f..e5f53018 100644 --- a/sqlobject/col.py +++ b/sqlobject/col.py @@ -1942,6 +1942,8 @@ class UuidCol(Col): class JsonbValidator(SOValidator): def to_python(self, value, state): + if isinstance(value, string_type): + return json.loads(value) return value def from_python(self, value, state): From f7db6df022e81621afc1182f2e5e6ef3bfbe50cc Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 5 May 2017 22:31:12 +0300 Subject: [PATCH 061/509] TODO: PyPy [skip ci] --- docs/TODO.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/TODO.rst b/docs/TODO.rst index b2d3f9de..2ae19ac1 100644 --- a/docs/TODO.rst +++ b/docs/TODO.rst @@ -1,6 +1,8 @@ TODO ---- +* PyPy. + * Quote table/column names that are reserved keywords (order => "order", values => `values` for MySQL). From 38ba2a690d6114cd9df5808272117d6fe7dcb546 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 7 May 2017 13:00:08 +0300 Subject: [PATCH 062/509] Fix tox.ini: Add py26 basepython [skip ci] --- tox.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/tox.ini b/tox.ini index 6f27b6ad..36a54225 100644 --- a/tox.ini +++ b/tox.ini @@ -7,6 +7,7 @@ envlist = py{26,27}-{mysqldb,mysql-oursql},py{34,35,36}-{mysqlclient,pypostgresq # Ensure we cd into sqlobject before running the tests changedir = ./sqlobject/ basepython = + py26: {env:TOXPYTHON:python2.6} py27: {env:TOXPYTHON:python2.7} py34: {env:TOXPYTHON:python3.4} py35: {env:TOXPYTHON:python3.5} From 83dc573193f5f18e5229a1290e3d9a14ed27654b Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 7 May 2017 15:46:24 +0300 Subject: [PATCH 063/509] Support for Python 2.6 is declared obsolete [skip ci] --- devscripts/BRANCH-CHECKLIST | 7 ++++--- docs/News.rst | 6 ++++++ docs/TODO.rst | 2 ++ sqlobject/main.py | 6 +++--- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/devscripts/BRANCH-CHECKLIST b/devscripts/BRANCH-CHECKLIST index 5036e832..2b51cb09 100644 --- a/devscripts/BRANCH-CHECKLIST +++ b/devscripts/BRANCH-CHECKLIST @@ -18,9 +18,10 @@ a branch, a commit id or a tag. 1c. The script updates versions in ANNOUNCE.rst. -2. To deprecate a version of Python edit files docs/News.rst, - docs/SQLObject.rst, docs/TODO.rst, sqlobject/main.py, README.rst and - setup.py in master. +2. To deprecate a version of Python edit files ANNOUNCE.rst, README.rst, + devscripts/release, devscripts/setup, docs/News.rst, docs/SQLObject.rst, + docs/TODO.rst, requirements.txt, setup.py, sqlobject/main.py, + tox.ini in master. 3. Do a null-merge from the new branch to the higher branch or the master. diff --git a/docs/News.rst b/docs/News.rst index cb22978d..1b574757 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -10,6 +10,12 @@ News SQLObject 3.3.0 (master) ======================== +Features +-------- + +* Support for Python 2.6 is declared obsolete and will be removed + in the next release. + Minor features -------------- diff --git a/docs/TODO.rst b/docs/TODO.rst index 2ae19ac1..3bf6a663 100644 --- a/docs/TODO.rst +++ b/docs/TODO.rst @@ -1,6 +1,8 @@ TODO ---- +* Stop supporting Python 2.6. Fix dbconnection.py and joins.py. + * PyPy. * Quote table/column names that are reserved keywords (order => "order", diff --git a/sqlobject/main.py b/sqlobject/main.py index 0ac510c7..cb262ad0 100644 --- a/sqlobject/main.py +++ b/sqlobject/main.py @@ -693,9 +693,9 @@ def deprecated(message, level=1, stacklevel=2): if warnings_level is not None and warnings_level <= level: warnings.warn(message, DeprecationWarning, stacklevel=stacklevel) -# if sys.version_info[:2] < (2, 6): -# deprecated("Support for Python 2.5 has been declared obsolete " -# "and will be removed in the next release of SQLObject") +if sys.version_info[:2] < (2, 7): + deprecated("Support for Python 2.6 has been declared obsolete " + "and will be removed in the next release of SQLObject") def setDeprecationLevel(warning=1, exception=None): From 2085abe0a7b63ab9f4e7bbc802b4239ccdbb3d7d Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 7 May 2017 16:07:16 +0300 Subject: [PATCH 064/509] Release 3.3.0 --- ANNOUNCE.rst | 53 +++++++++++++++++++++++++++------------ README.rst | 4 +-- devscripts/build-all-docs | 2 +- docs/News.rst | 6 +++-- setup.cfg | 4 +-- setup.py | 4 +-- sqlobject/__version__.py | 2 +- 7 files changed, 49 insertions(+), 26 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index e4759b63..fb7e39e9 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,29 +1,50 @@ Hello! -I'm pleased to announce version 3.3.0a1, the first alpha of the upcoming -release of branch 3.2 of SQLObject. +I'm pleased to announce version 3.3.0, the first stable release of branch +3.3 of SQLObject. -I'm pleased to announce version 3.3.0a2, the second alpha of the upcoming -release of branch 3.2 of SQLObject. -I'm pleased to announce version 3.3.0b1, the first beta of the upcoming -release of branch 3.2 of SQLObject. +What's new in SQLObject +======================= -I'm pleased to announce version 3.3.0rc1, the first release candidate -of the upcoming release of branch 3.2 of SQLObject. +Features +-------- -I'm pleased to announce version 3.3.0, the first stable release of branch -3.2 of SQLObject. +* Support for Python 2.6 is declared obsolete and will be removed + in the next release. -I'm pleased to announce version 3.3.1, the first bugfix release of branch -3.2 of SQLObject. +Minor features +-------------- +* Convert scripts repository to devscripts subdirectory. + Some of thses scripts are version-dependent so it's better to have them + in the main repo. -What's new in SQLObject -======================= +* Test for __nonzero__ under Python 2, __bool__ under Python 3 in BoolCol. + +Drivers (work in progress) +-------------------------- + +* Add support for PyODBC and PyPyODBC (pure-python ODBC DB API driver) for + MySQL, PostgreSQL and MS SQL. Driver names are ``pyodbc``, ``pypyodbc`` + or ``odbc`` (try ``pyodbc`` and ``pypyodbc``). There are some problems + with pyodbc and many problems with pypyodbc. + +Documentation +------------- + +* Stop updating http://sqlobject.readthedocs.org/ - it's enough to have + http://sqlobject.org/ + +Tests +----- + +* Run tests at Travis CI and AppVeyor with Python 3.6, x86 and x64. +* Stop running tests at Travis with Python 2.6. -Contributor for this release is +* Stop running tests at AppVeyor with pymssql - too many timeouts and + problems. For a more complete list, please see the news: http://sqlobject.org/News.html @@ -55,7 +76,7 @@ Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Download: -https://pypi.python.org/pypi/SQLObject/3.3.0a0.dev20170110 +https://pypi.python.org/pypi/SQLObject/3.3.0 News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 173a5def..0ba13413 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.3.0a0 -================= +SQLObject 3.3.0 +=============== Thanks for looking at SQLObject. SQLObject is an object-relational mapper, i.e., a library that will wrap your database tables in Python diff --git a/devscripts/build-all-docs b/devscripts/build-all-docs index e6597824..47071df9 100755 --- a/devscripts/build-all-docs +++ b/devscripts/build-all-docs @@ -11,7 +11,7 @@ cd "$PROG_DIR" && PROG_DIR="`pwd`" && cd "$PROG_DIR"/SQLObject && -build_docs 3.2.0 && +build_docs 3.3.0 && build_docs master devel && cd ../SQLObject-docs && diff --git a/docs/News.rst b/docs/News.rst index 1b574757..d6bafeb5 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -7,8 +7,10 @@ News .. _start: -SQLObject 3.3.0 (master) -======================== +SQLObject 3.3.0 +=============== + +Released 7 May 2017. Features -------- diff --git a/setup.cfg b/setup.cfg index d0e62d02..a4729793 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [egg_info] -tag_build = dev -tag_date = 1 +tag_build = +tag_date = 0 tag_svn_revision = 0 [flake8] diff --git a/setup.py b/setup.py index ed917f27..640ab22d 100755 --- a/setup.py +++ b/setup.py @@ -69,7 +69,7 @@ :target: https://travis-ci.org/sqlobject/sqlobject """, classifiers=[ - "Development Status :: 3 - Alpha", + "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: " "GNU Library or Lesser General Public License (LGPL)", @@ -89,7 +89,7 @@ author_email="ianb@colorstudy.com", maintainer="Oleg Broytman", maintainer_email="phd@phdru.name", - url="http://sqlobject.org/devel/", + url="http://sqlobject.org/", download_url="https://pypi.python.org/pypi/SQLObject/%s" % version, license="LGPL", packages=["sqlobject"] + diff --git a/sqlobject/__version__.py b/sqlobject/__version__.py index cc4f6fb7..cc88e83d 100644 --- a/sqlobject/__version__.py +++ b/sqlobject/__version__.py @@ -3,6 +3,6 @@ major = 3 minor = 3 micro = 0 -release_level = 'alpha' +release_level = 'final' serial = 0 version_info = (major, minor, micro, release_level, serial) From 1ba596182f377939a9b907d262d6ea9a40c1ea76 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 7 May 2017 17:14:24 +0300 Subject: [PATCH 065/509] Prepare for the next release [skip ci] --- ANNOUNCE.rst | 54 +++++++++++++++------------------------------------ docs/News.rst | 3 +++ 2 files changed, 19 insertions(+), 38 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index fb7e39e9..46dc308b 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,50 +1,28 @@ Hello! -I'm pleased to announce version 3.3.0, the first stable release of branch -3.3 of SQLObject. +I'm pleased to announce version 3.4.0a1, the first alpha of the upcoming +release of branch 3.4 of SQLObject. +I'm pleased to announce version 3.4.0a2, the second alpha of the upcoming +release of branch 3.4 of SQLObject. -What's new in SQLObject -======================= - -Features --------- - -* Support for Python 2.6 is declared obsolete and will be removed - in the next release. - -Minor features --------------- - -* Convert scripts repository to devscripts subdirectory. - Some of thses scripts are version-dependent so it's better to have them - in the main repo. +I'm pleased to announce version 3.4.0b1, the first beta of the upcoming +release of branch 3.4 of SQLObject. -* Test for __nonzero__ under Python 2, __bool__ under Python 3 in BoolCol. +I'm pleased to announce version 3.4.0rc1, the first release candidate +of the upcoming release of branch 3.4 of SQLObject. -Drivers (work in progress) --------------------------- +I'm pleased to announce version 3.4.0, the first stable release of branch +3.4 of SQLObject. -* Add support for PyODBC and PyPyODBC (pure-python ODBC DB API driver) for - MySQL, PostgreSQL and MS SQL. Driver names are ``pyodbc``, ``pypyodbc`` - or ``odbc`` (try ``pyodbc`` and ``pypyodbc``). There are some problems - with pyodbc and many problems with pypyodbc. +I'm pleased to announce version 3.4.1, the first bugfix release of branch +3.4 of SQLObject. -Documentation -------------- -* Stop updating http://sqlobject.readthedocs.org/ - it's enough to have - http://sqlobject.org/ - -Tests ------ - -* Run tests at Travis CI and AppVeyor with Python 3.6, x86 and x64. - -* Stop running tests at Travis with Python 2.6. +What's new in SQLObject +======================= -* Stop running tests at AppVeyor with pymssql - too many timeouts and - problems. +Contributor for this release is For a more complete list, please see the news: http://sqlobject.org/News.html @@ -76,7 +54,7 @@ Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Download: -https://pypi.python.org/pypi/SQLObject/3.3.0 +https://pypi.python.org/pypi/SQLObject/3.4.0a0.dev20170507 News and changes: http://sqlobject.org/News.html diff --git a/docs/News.rst b/docs/News.rst index d6bafeb5..b307bee7 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -7,6 +7,9 @@ News .. _start: +SQLObject 3.4.0 (master) +======================== + SQLObject 3.3.0 =============== From 3d2bf5ad78eb1c58c8648f2d483377a6946d22cf Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 7 May 2017 17:43:42 +0300 Subject: [PATCH 066/509] Stop supporting Python 2.6 --- ANNOUNCE.rst | 2 +- README.rst | 6 ++--- devscripts/release | 2 +- devscripts/run-all-tests | 2 +- devscripts/setup | 1 - docs/News.rst | 3 +++ docs/SQLObject.rst | 2 +- docs/TODO.rst | 2 -- requirements.txt | 2 +- setup.py | 9 ++++--- sqlobject/dbconnection.py | 6 ----- sqlobject/joins.py | 3 +-- sqlobject/main.py | 10 ++++---- tox.ini | 49 +++------------------------------------ 14 files changed, 24 insertions(+), 75 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 46dc308b..2bf49279 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -38,7 +38,7 @@ easy to use and quick to get started with. SQLObject supports a number of backends: MySQL, PostgreSQL, SQLite, Firebird, Sybase, MSSQL and MaxDB (also known as SAPDB). -Python 2.6, 2.7 or 3.4+ is required. +Python 2.7 or 3.4+ is required. Where is SQLObject diff --git a/README.rst b/README.rst index 0ba13413..43c457d6 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.3.0 -=============== +SQLObject 3.4.0a0 +================= Thanks for looking at SQLObject. SQLObject is an object-relational mapper, i.e., a library that will wrap your database tables in Python @@ -7,7 +7,7 @@ classes, and your rows in Python instances. It currently supports MySQL through the `MySQLdb` package, PostgreSQL through the `psycopg` package, SQLite, Firebird, MaxDB (SAP DB), MS SQL, -Sybase and Rdbhost. Python 2.6, 2.7 or 3.4+ is required. +Sybase and Rdbhost. Python 2.7 or 3.4+ is required. For more information please see the documentation in ``_, or online at http://sqlobject.org/ diff --git a/devscripts/release b/devscripts/release index 0e24a8ae..6c92d3a1 100755 --- a/devscripts/release +++ b/devscripts/release @@ -11,7 +11,7 @@ python setup.py build_py && python setup.py build --executable '/usr/bin/env python' && python setup.py sdist && -for py in 2.6 2.7 3.4 3.5 3.6; do +for py in 2.7 3.4 3.5 3.6; do find build -name '*.py[co]' -delete && python$py setup.py build_py && python$py setup.py build --executable '/usr/bin/env python' && diff --git a/devscripts/run-all-tests b/devscripts/run-all-tests index 80b2e1ad..da6dbe4c 100755 --- a/devscripts/run-all-tests +++ b/devscripts/run-all-tests @@ -3,7 +3,7 @@ cd "`dirname \"$0\"`"/SQLObject && SO_DIR="`dirname $0`" -for py_ver in 2.6 2.7 3.4 3.5 3.6; do +for py_ver in 2.7 3.4 3.5 3.6; do echo "---------- PYTHON $py_ver "$1" ----------" "$SO_DIR"/cleanup && PY_VER=$py_ver "$SO_DIR"/run-tests-"$1" \ diff --git a/devscripts/setup b/devscripts/setup index 946696e8..4edd6797 100755 --- a/devscripts/setup +++ b/devscripts/setup @@ -3,7 +3,6 @@ umask 022 # -rwxr-xr-x cd "`dirname \"$0\"`"/SQLObject && -python2.6 setup.py install -O2 && for py_ver in 2.7 3.4 3.5 3.6; do python$py_ver -m pip install --install-option=-O2 --upgrade . done && diff --git a/docs/News.rst b/docs/News.rst index b307bee7..8ac2a861 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -10,6 +10,9 @@ News SQLObject 3.4.0 (master) ======================== +* Python 2.6 is no longer supported. The minimal supported version is + Python 2.7. + SQLObject 3.3.0 =============== diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index e1b96223..e1f9b43c 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -82,7 +82,7 @@ FreeTDS_) or adodbapi_ (Win32). .. _FreeTDS: http://www.freetds.org/ .. _adodbapi: http://adodbapi.sourceforge.net/ -Python 2.6, 2.7 or 3.4+ is required. +Python 2.7 or 3.4+ is required. Compared To Other Database Wrappers =================================== diff --git a/docs/TODO.rst b/docs/TODO.rst index 3bf6a663..2ae19ac1 100644 --- a/docs/TODO.rst +++ b/docs/TODO.rst @@ -1,8 +1,6 @@ TODO ---- -* Stop supporting Python 2.6. Fix dbconnection.py and joins.py. - * PyPy. * Quote table/column names that are reserved keywords (order => "order", diff --git a/requirements.txt b/requirements.txt index 220e308c..b8113c5c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ --install-option=-O2 -FormEncode >= 1.1.1, != 1.3.0; python_version >= '2.6' and python_version < '3.0' +FormEncode >= 1.1.1, != 1.3.0; python_version >= '2.7' and python_version < '3.0' FormEncode >= 1.3.1; python_version >= '3.4' PyDispatcher >= 2.0.4 diff --git a/setup.py b/setup.py index 640ab22d..ad3814c4 100755 --- a/setup.py +++ b/setup.py @@ -28,12 +28,12 @@ main = sqlobject.wsgi_middleware:make_middleware """ install_requires = [] - if (sys.version_info[0] == 2) and (sys.version_info[:2] >= (2, 6)): + if (sys.version_info[:2] == (2, 7)): install_requires.append("FormEncode>=1.1.1,!=1.3.0") elif (sys.version_info[0] == 3) and (sys.version_info[:2] >= (3, 4)): install_requires.append("FormEncode>=1.3.1") else: - raise ImportError("SQLObject requires Python 2.6, 2.7 or 3.4+") + raise ImportError("SQLObject requires Python 2.7 or 3.4+") install_requires.append("PyDispatcher>=2.0.4") kw['install_requires'] = install_requires kw['extras_require'] = { @@ -59,7 +59,7 @@ applications. Supports MySQL, PostgreSQL, SQLite, Firebird, Sybase, MSSQL and MaxDB (SAPDB). -Python 2.6, 2.7 or 3.4+ is required. +Python 2.7 or 3.4+ is required. For development see the projects at `SourceForge `_ @@ -75,7 +75,6 @@ "GNU Library or Lesser General Public License (LGPL)", "Programming Language :: Python", "Programming Language :: Python :: 2", - "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.4", @@ -161,7 +160,7 @@ It currently supports MySQL through the `MySQLdb` package, PostgreSQL through the `psycopg` package, SQLite, Firebird, MaxDB (SAP DB), MS SQL -Sybase and Rdbhost. Python 2.6, 2.7 or 3.4+ is required. +Sybase and Rdbhost. Python 2.7 or 3.4+ is required. Where is SQLObject diff --git a/sqlobject/dbconnection.py b/sqlobject/dbconnection.py index 89f4382b..ff905f64 100644 --- a/sqlobject/dbconnection.py +++ b/sqlobject/dbconnection.py @@ -210,12 +210,6 @@ def _parseOldURI(uri): @staticmethod def _parseURI(uri): parsed = urlparse(uri) - if sys.version_info[0:2] == (2, 6): - # In python 2.6, urlparse only parses the uri completely - # for certain schemes, so we force the scheme to - # something that will be parsed correctly - scheme = parsed.scheme - parsed = urlparse(uri.replace(scheme, 'http', 1)) host, path = parsed.hostname, parsed.path user, password, port = None, None, None if parsed.username: diff --git a/sqlobject/joins.py b/sqlobject/joins.py index 675beb70..c847e21b 100644 --- a/sqlobject/joins.py +++ b/sqlobject/joins.py @@ -102,8 +102,7 @@ def _applyOrderBy(self, results, defaultSortClass): class MinType(object): """Sort less than everything, for handling None's in the results""" - # functools.total_ordering would simplify this, but isn't available - # for python 2.6 + # functools.total_ordering would simplify this def __lt__(self, other): if self is other: diff --git a/sqlobject/main.py b/sqlobject/main.py index cb262ad0..88b3c0c1 100644 --- a/sqlobject/main.py +++ b/sqlobject/main.py @@ -43,9 +43,9 @@ from .util.threadinglocal import local from sqlobject.compat import PY2, with_metaclass, string_type, unicode_type -if ((sys.version_info[0] == 2) and (sys.version_info[:2] < (2, 6))) or \ +if ((sys.version_info[0] == 2) and (sys.version_info[:2] < (2, 7))) or \ ((sys.version_info[0] == 3) and (sys.version_info[:2] < (3, 4))): - raise ImportError("SQLObject requires Python 2.6, 2.7 or 3.4+") + raise ImportError("SQLObject requires Python 2.7 or 3.4+") if not PY2: # alias for python 3 compatability @@ -693,9 +693,9 @@ def deprecated(message, level=1, stacklevel=2): if warnings_level is not None and warnings_level <= level: warnings.warn(message, DeprecationWarning, stacklevel=stacklevel) -if sys.version_info[:2] < (2, 7): - deprecated("Support for Python 2.6 has been declared obsolete " - "and will be removed in the next release of SQLObject") +# if sys.version_info[:2] < (2, 7): +# deprecated("Support for Python 2.6 has been declared obsolete " +# "and will be removed in the next release of SQLObject") def setDeprecationLevel(warning=1, exception=None): diff --git a/tox.ini b/tox.ini index 36a54225..792dde20 100644 --- a/tox.ini +++ b/tox.ini @@ -1,13 +1,12 @@ [tox] minversion = 1.8 -envlist = py{26,27}-{mysqldb,mysql-oursql},py{34,35,36}-{mysqlclient,pypostgresql},py{26,27,34,35,36}-{mysql-connector,pymysql,mysql-pyodbc,mysql-pypyodbc,postgres-psycopg,postgres-pygresql,postgres-pyodbc,postgres-pypyodbc,sqlite,sqlite-memory},py{27,34,35,36}-{firebird-fdb,firebirdsql},py{27,34}-flake8,py{27,34,35,36}-{mssql-pyodbc,mysql-connector,mysql-pyodbc,mysql-pypyodbc,postgres-psycopg,postgres-pyodbc,postgres-pypyodbc,sqlite,sqlite-memory}-w32 +envlist = py27-{mysqldb,mysql-oursql},py{34,35,36}-{mysqlclient,pypostgresql},py{27,34,35,36}-{mysql-connector,pymysql,mysql-pyodbc,mysql-pypyodbc,postgres-psycopg,postgres-pygresql,postgres-pyodbc,postgres-pypyodbc,sqlite,sqlite-memory},py{27,34,35,36}-{firebird-fdb,firebirdsql},py{27,34}-flake8,py{27,34,35,36}-{mssql-pyodbc,mysql-connector,mysql-pyodbc,mysql-pypyodbc,postgres-psycopg,postgres-pyodbc,postgres-pypyodbc,sqlite,sqlite-memory}-w32 # Base test environment settings [testenv] # Ensure we cd into sqlobject before running the tests changedir = ./sqlobject/ basepython = - py26: {env:TOXPYTHON:python2.6} py27: {env:TOXPYTHON:python2.7} py34: {env:TOXPYTHON:python3.4} py35: {env:TOXPYTHON:python3.5} @@ -18,10 +17,10 @@ commands = deps = pytest pytest-cov - py{26,27}: FormEncode >= 1.1.1, != 1.3.0 + py27: FormEncode >= 1.1.1, != 1.3.0 py{34,35,36}: FormEncode >= 1.3.1 PyDispatcher>=2.0.4 - py{26,27}: egenix-mx-base + py27: egenix-mx-base mssql-pyodbc: pytest-timeout mysqldb: mysql-python mysqlclient: mysqlclient @@ -55,9 +54,6 @@ commands = pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=mysqldb&debug=1 mysql -e 'drop database sqlobject_test;' -[testenv:py26-mysqldb] -commands = {[mysqldb]commands} - [testenv:py27-mysqldb] commands = {[mysqldb]commands} @@ -86,9 +82,6 @@ commands = pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=connector&charset=utf8&debug=1 mysql -e 'drop database sqlobject_test;' -[testenv:py26-mysql-connector] -commands = {[mysql-connector]commands} - [testenv:py27-mysql-connector] commands = {[mysql-connector]commands} @@ -109,9 +102,6 @@ commands = pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=oursql&charset=utf8&debug=1 mysql -e 'drop database sqlobject_test;' -[testenv:py26-mysql-oursql] -commands = {[oursql]commands} - [testenv:py27-mysql-oursql] commands = {[oursql]commands} @@ -123,9 +113,6 @@ commands = pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=pymysql&charset=utf8&debug=1 mysql -e 'drop database sqlobject_test;' -[testenv:py26-pymysql] -commands = {[pymysql]commands} - [testenv:py27-pymysql] commands = {[pymysql]commands} @@ -147,9 +134,6 @@ commands = pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=pyodbc&odbcdrv=MySQL&charset=utf8&debug=1 mysql -e 'drop database sqlobject_test;' -[testenv:py26-mysql-pyodbc] -commands = {[mysql-pyodbc]commands} - [testenv:py27-mysql-pyodbc] commands = {[mysql-pyodbc]commands} @@ -170,9 +154,6 @@ commands = pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=MySQL&charset=utf8&debug=1 mysql -e 'drop database sqlobject_test;' -[testenv:py26-mysql-pypyodbc] -commands = {[mysql-pypyodbc]commands} - [testenv:py27-mysql-pypyodbc] commands = {[mysql-pypyodbc]commands} @@ -194,9 +175,6 @@ commands = pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test dropdb -U postgres -w sqlobject_test -[testenv:py26-postgres-psycopg] -commands = {[psycopg]commands} - [testenv:py27-postgres-psycopg] commands = {[psycopg]commands} @@ -217,9 +195,6 @@ commands = pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test dropdb -U postgres -w sqlobject_test -[testenv:py26-postgres-pygresql] -commands = {[pygresql]commands} - [testenv:py27-postgres-pygresql] commands = {[pygresql]commands} @@ -258,9 +233,6 @@ commands = pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=pyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test dropdb -U postgres -w sqlobject_test -[testenv:py26-postgres-pyodbc] -commands = {[postgres-pyodbc]commands} - [testenv:py27-postgres-pyodbc] commands = {[postgres-pyodbc]commands} @@ -281,9 +253,6 @@ commands = pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test dropdb -U postgres -w sqlobject_test -[testenv:py26-postgres-pypyodbc] -commands = {[postgres-pypyodbc]commands} - [testenv:py27-postgres-pypyodbc] commands = {[postgres-pypyodbc]commands} @@ -304,9 +273,6 @@ commands = pytest --cov=sqlobject -D sqlite:///tmp/sqlobject_test.sqdb?debug=1 rm /tmp/sqlobject_test.sqdb -[testenv:py26-sqlite] -commands = {[sqlite]commands} - [testenv:py27-sqlite] commands = {[sqlite]commands} @@ -324,9 +290,6 @@ commands = {[testenv]commands} pytest --cov=sqlobject -D sqlite:/:memory:?debug=1 -[testenv:py26-sqlite-memory] -commands = {[sqlite-memory]commands} - [testenv:py27-sqlite-memory] commands = {[sqlite-memory]commands} @@ -447,9 +410,6 @@ commands = pytest --cov=sqlobject -D mysql://root:Password12!@localhost/sqlobject_test?driver=pyodbc&odbcdrv=MySQL%20ODBC%205.3%20ANSI%20Driver&charset=utf8&debug=1 mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' -[testenv:py26-mysql-pyodbc-w32] -commands = {[mysql-pyodbc-w32]commands} - [testenv:py27-mysql-pyodbc-w32] commands = {[mysql-pyodbc-w32]commands} @@ -471,9 +431,6 @@ commands = pytest --cov=sqlobject -D mysql://root:Password12!@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=MySQL%20ODBC%205.3%20ANSI%20Driver&charset=utf8&debug=1 mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' -[testenv:py26-mysql-pypyodbc-w32] -commands = {[mysql-pypyodbc-w32]commands} - [testenv:py27-mysql-pypyodbc-w32] commands = {[mysql-pypyodbc-w32]commands} From bd45fb11ae33d224ef0eda473c63fcf064bce0d4 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 7 May 2017 14:42:47 +0300 Subject: [PATCH 067/509] Move requirements.txt to devscripts/ Rename requirements_dev.txt to requirements_test.txt. Split requirements_test.txt intto requirements_tox.txt. [skip ci] --- requirements.txt => devscripts/requirements/requirements.txt | 0 .../requirements/requirements_docs.txt | 0 .../requirements/requirements_tests.txt | 1 - devscripts/requirements/requirements_tox.txt | 1 + 4 files changed, 1 insertion(+), 1 deletion(-) rename requirements.txt => devscripts/requirements/requirements.txt (100%) rename requirements_docs.txt => devscripts/requirements/requirements_docs.txt (100%) rename requirements_dev.txt => devscripts/requirements/requirements_tests.txt (78%) create mode 100644 devscripts/requirements/requirements_tox.txt diff --git a/requirements.txt b/devscripts/requirements/requirements.txt similarity index 100% rename from requirements.txt rename to devscripts/requirements/requirements.txt diff --git a/requirements_docs.txt b/devscripts/requirements/requirements_docs.txt similarity index 100% rename from requirements_docs.txt rename to devscripts/requirements/requirements_docs.txt diff --git a/requirements_dev.txt b/devscripts/requirements/requirements_tests.txt similarity index 78% rename from requirements_dev.txt rename to devscripts/requirements/requirements_tests.txt index ca2ff5d6..8e890d81 100644 --- a/requirements_dev.txt +++ b/devscripts/requirements/requirements_tests.txt @@ -2,4 +2,3 @@ pytest pytest-cov -tox >= 1.8 diff --git a/devscripts/requirements/requirements_tox.txt b/devscripts/requirements/requirements_tox.txt new file mode 100644 index 00000000..9927ea49 --- /dev/null +++ b/devscripts/requirements/requirements_tox.txt @@ -0,0 +1 @@ +tox >= 1.8 From 96bf0e6bfb88a71fe818ee6e27ea8c8f584c20d8 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 7 May 2017 14:53:05 +0300 Subject: [PATCH 068/509] Move hard requirements from tox.ini to requirements.txt Move test requirements to requirements_tests.txt. --- tox.ini | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tox.ini b/tox.ini index 792dde20..6cf2dead 100644 --- a/tox.ini +++ b/tox.ini @@ -15,11 +15,7 @@ commands = {envpython} --version {envpython} -c "import struct; print(struct.calcsize('P') * 8)" deps = - pytest - pytest-cov - py27: FormEncode >= 1.1.1, != 1.3.0 - py{34,35,36}: FormEncode >= 1.3.1 - PyDispatcher>=2.0.4 + -rdevscripts/requirements/requirements_tests.txt py27: egenix-mx-base mssql-pyodbc: pytest-timeout mysqldb: mysql-python From c825a7874ed6f2506193f593fb09dc87cb55d5bd Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 16 May 2017 00:26:09 +0300 Subject: [PATCH 069/509] Fix: Do not register PostgresBinaryConverter for bytes and unicode Avoid recursion in sqlrepr(Binary(value), 'postgres'). --- sqlobject/postgres/pgconnection.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index 63bd17a3..bf22a9ce 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -2,7 +2,7 @@ from sqlobject import col from sqlobject import dberrors from sqlobject import sqlbuilder -from sqlobject.compat import PY2 +from sqlobject.compat import PY2, unicode_type from sqlobject.converters import registerConverter, sqlrepr from sqlobject.dbconnection import DBAPI @@ -85,7 +85,9 @@ def __init__(self, dsn=None, host=None, port=None, db=None, # Register a converter for psycopg Binary type. registerConverter(type(self.module.Binary('')), PsycoBinaryConverter) - elif type(self.module.Binary) in (type, type(PostgresBinaryConverter)): + elif type(self.module.Binary) in ( + type, type(PostgresBinaryConverter)) and \ + type(self.module.Binary(b'')) not in (bytes, unicode_type): # Register a converter for Binary type. registerConverter(type(self.module.Binary(b'')), PostgresBinaryConverter) From 7570514647628f6663e6fb35d8b1fa1b9f8cb2bd Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 16 May 2017 23:28:11 +0300 Subject: [PATCH 070/509] Micro refactoring in BinaryValidator.to_python --- sqlobject/col.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sqlobject/col.py b/sqlobject/col.py index e5f53018..0f358628 100644 --- a/sqlobject/col.py +++ b/sqlobject/col.py @@ -1768,12 +1768,12 @@ def to_python(self, value, state): dbName = connection.dbName binaryType = connection._binaryType if isinstance(value, str): + if not PY2 and dbName == "mysql": + value = value.encode('ascii', errors='surrogateescape') if dbName == "sqlite": if not PY2: value = bytes(value, 'ascii') value = connection.module.decode(value) - if dbName == "mysql" and not PY2: - value = value.encode('ascii', errors='surrogateescape') return value if isinstance(value, bytes): return value From 4c812a1f79509ff84d254d253aabdac7747d4c1b Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 16 May 2017 23:28:45 +0300 Subject: [PATCH 071/509] Encode/decode binary values for PyGreSQL driver --- docs/News.rst | 2 ++ sqlobject/col.py | 3 +++ sqlobject/postgres/pgconnection.py | 4 ++++ 3 files changed, 9 insertions(+) diff --git a/docs/News.rst b/docs/News.rst index 8ac2a861..0c10a220 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -13,6 +13,8 @@ SQLObject 3.4.0 (master) * Python 2.6 is no longer supported. The minimal supported version is Python 2.7. +* Encode/decode binary values for PyGreSQL driver. + SQLObject 3.3.0 =============== diff --git a/sqlobject/col.py b/sqlobject/col.py index 0f358628..6ee5e98b 100644 --- a/sqlobject/col.py +++ b/sqlobject/col.py @@ -1770,6 +1770,9 @@ def to_python(self, value, state): if isinstance(value, str): if not PY2 and dbName == "mysql": value = value.encode('ascii', errors='surrogateescape') + if dbName == "postgres" and connection.driver == 'pygresql': + from pg import unescape_bytea + value = unescape_bytea(value) if dbName == "sqlite": if not PY2: value = bytes(value, 'ascii') diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index bf22a9ce..855a5cf5 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -85,6 +85,10 @@ def __init__(self, dsn=None, host=None, port=None, db=None, # Register a converter for psycopg Binary type. registerConverter(type(self.module.Binary('')), PsycoBinaryConverter) + elif driver == 'pygresql': + from pg import escape_bytea + self.createBinary = \ + lambda value, escape_bytea=escape_bytea: escape_bytea(value) elif type(self.module.Binary) in ( type, type(PostgresBinaryConverter)) and \ type(self.module.Binary(b'')) not in (bytes, unicode_type): From d1177e2f2833a0a5d5f389a25ee7f9af020a9069 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 20 May 2017 16:19:29 +0300 Subject: [PATCH 072/509] Feat(devscripts): Use sed --in-place instead of replace [skip ci] --- devscripts/branch | 4 ++-- devscripts/replace | 26 -------------------------- 2 files changed, 2 insertions(+), 28 deletions(-) delete mode 100755 devscripts/replace diff --git a/devscripts/branch b/devscripts/branch index 38ca214a..908e5fb3 100755 --- a/devscripts/branch +++ b/devscripts/branch @@ -45,8 +45,8 @@ version_info = (major, minor, micro, release_level, serial)" > sqlobject/__versi `git var GIT_EDITOR` README.rst sqlobject/__version__.py docs/News.rst appveyor.yml setup.py && git commit --message="Next branch will be $major.$next_minor" README.rst sqlobject/__version__.py docs/News.rst setup.py && - exec ./replace "$major\.$minor" "$major.$next_minor" ANNOUNCE.rst + exec sed -i /"$major\.$minor"/"$major.$next_minor"/ ANNOUNCE.rst else - exec ./replace "$prev_branch" "$major.$next_minor" ANNOUNCE.rst + exec sed -i /"$prev_branch"/"$major.$next_minor"/ ANNOUNCE.rst fi diff --git a/devscripts/replace b/devscripts/replace deleted file mode 100755 index 8ff7124a..00000000 --- a/devscripts/replace +++ /dev/null @@ -1,26 +0,0 @@ -#! /usr/bin/env python - -import sys - -if len(sys.argv) < 4: - sys.stderr.write("Usage: %s [-i] from_re to_re file....\n" % sys.argv[0]) - sys.exit(1) - -import re -if sys.argv[1] == '-i': - search = re.compile(sys.argv[2], re.IGNORECASE) - replace = sys.argv[3] - start = 4 -else: - search = re.compile(sys.argv[1]) - replace = sys.argv[2] - start = 3 - -from fileinput import FileInput -files = FileInput(sys.argv[start:], inplace=1) - -for line in files: - line = search.sub(replace, line) - sys.stdout.write(line) - -files.close() From e70c2760b962d00fc468afcd7c8224057d9c6b00 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 23 May 2017 23:49:11 +0300 Subject: [PATCH 073/509] Add example to ANNOUNCE.rst [skip ci] --- ANNOUNCE.rst | 40 ++++++++++++++++++++++++++++++++++++++++ docs/index.rst | 8 ++++++++ 2 files changed, 48 insertions(+) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 2bf49279..3d68fe49 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -58,3 +58,43 @@ https://pypi.python.org/pypi/SQLObject/3.4.0a0.dev20170507 News and changes: http://sqlobject.org/News.html + + +Example +======= + +Create a simple class that wraps a table:: + + >>> from sqlobject import * + >>> + >>> sqlhub.processConnection = connectionForURI('sqlite:/:memory:') + >>> + >>> class Person(SQLObject): + ... fname = StringCol() + ... mi = StringCol(length=1, default=None) + ... lname = StringCol() + ... + >>> Person.createTable() + +Use the object:: + + >>> p = Person(fname="John", lname="Doe") + >>> p + + >>> p.fname + 'John' + >>> p.mi = 'Q' + >>> p2 = Person.get(1) + >>> p2 + + >>> p is p2 + True + +Queries:: + + >>> p3 = Person.selectBy(lname="Doe")[0] + >>> p3 + + >>> pc = Person.select(Person.q.lname=="Doe").count() + >>> pc + 1 diff --git a/docs/index.rst b/docs/index.rst index 25c07dd2..f1f1ecee 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -68,6 +68,14 @@ Here's how you'd use the object:: >>> p is p2 True +Queries:: + + >>> p3 = Person.selectBy(lname="Doe")[0] + >>> p3 + + >>> pc = Person.select(Person.q.lname=="Doe").count() + >>> pc + 1 Indices and tables ================== From 96ddc26c7744a6998bfdffe14d214a5d7d0a2159 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 29 May 2017 23:07:18 +0300 Subject: [PATCH 074/509] List all drivers in extras_require in setup.py --- docs/News.rst | 3 +++ setup.py | 50 ++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index 0c10a220..c16216e2 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -15,6 +15,9 @@ SQLObject 3.4.0 (master) * Encode/decode binary values for PyGreSQL driver. +* List all drivers in extras_require in setup.py. + + SQLObject 3.3.0 =============== diff --git a/setup.py b/setup.py index ad3814c4..2e22194e 100755 --- a/setup.py +++ b/setup.py @@ -27,24 +27,54 @@ [paste.filter_app_factory] main = sqlobject.wsgi_middleware:make_middleware """ - install_requires = [] if (sys.version_info[:2] == (2, 7)): - install_requires.append("FormEncode>=1.1.1,!=1.3.0") + PY2 = True elif (sys.version_info[0] == 3) and (sys.version_info[:2] >= (3, 4)): - install_requires.append("FormEncode>=1.3.1") + PY2 = False else: raise ImportError("SQLObject requires Python 2.7 or 3.4+") + + kw['install_requires'] = install_requires = [] + if PY2: + install_requires.append("FormEncode>=1.1.1,!=1.3.0") + else: + install_requires.append("FormEncode>=1.3.1") install_requires.append("PyDispatcher>=2.0.4") - kw['install_requires'] = install_requires - kw['extras_require'] = { - 'mysql': ['MySQLdb'], - 'postgresql': ['psycopg'], # or pgdb from PyGreSQL + + kw['extras_require'] = extras_require = { + # Firebird/Interbase + 'fdb': ['fdb'], + 'firebirdsql': ['firebirdsql'], + 'kinterbasdb': ['kinterbasdb'], + # MS SQL + 'adodbapi': ['adodbapi'], + 'pymssql': ['pymssql'], + # MySQL + 'mysql-connector': ['mysql-connector'], + 'pymysql': ['pymysql'], + # ODBC + 'odbc': ['pyodbc'], + 'pyodbc': ['pyodbc'], + 'pypyodbc': ['pypyodbc'], + # PostgreSQL + 'psycopg1': ['psycopg1'], + 'psycopg2': ['psycopg2'], + 'psycopg': ['psycopg2'], + 'postgres': ['psycopg2'], + 'postgresql': ['psycopg2'], + 'pygresql': ['pygresql'], + 'pypostgresql': ['py-postgresql'], + 'py-postgresql': ['py-postgresql'], + # + 'sapdb': ['sapdb'], 'sqlite': ['pysqlite'], - 'firebird': ['fdb'], # or kinterbasdb 'sybase': ['Sybase'], - 'mssql': ['adodbapi'], # or pymssql - 'sapdb': ['sapdb'], } + if PY2: + extras_require['mysql'] = ['MySQLdb'] + extras_require['oursql'] = ['oursql'] + else: + extras_require['mysql'] = ['mysqlclient'] setup(name="SQLObject", version=version, From 15a61fb807aed1a78775da70fec3b57ed0260339 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 29 May 2017 22:42:29 +0300 Subject: [PATCH 075/509] Use b64encode/b64decode instead of deprecated encodestring/decodestring --- docs/News.rst | 2 ++ sqlobject/sqlite/sqliteconnection.py | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index c16216e2..451c9ba4 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -17,6 +17,8 @@ SQLObject 3.4.0 (master) * List all drivers in extras_require in setup.py. +* Use base64.b64encode/b64decode instead of deprecated + encodestring/decodestring. SQLObject 3.3.0 =============== diff --git a/sqlobject/sqlite/sqliteconnection.py b/sqlobject/sqlite/sqliteconnection.py index 70fae634..93ad429c 100644 --- a/sqlobject/sqlite/sqliteconnection.py +++ b/sqlobject/sqlite/sqliteconnection.py @@ -59,8 +59,8 @@ def __init__(self, filename, autoCommit=1, **kw): raise ImportError( 'Cannot find an SQLite driver, tried %s' % drivers) if self.using_sqlite2: - sqlite.encode = base64.encodestring - sqlite.decode = base64.decodestring + sqlite.encode = base64.b64encode + sqlite.decode = base64.b64decode self.module = sqlite self.filename = filename # full path to sqlite-db-file self._memory = filename == ':memory:' From ecccd99cbf60031312e48ebd6736bf8235dca042 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 29 May 2017 22:20:06 +0300 Subject: [PATCH 076/509] Encode binary values for py-postgresql driver --- .travis.yml | 3 --- docs/News.rst | 3 +++ sqlobject/postgres/pgconnection.py | 31 +++++++++++++++--------------- 3 files changed, 18 insertions(+), 19 deletions(-) diff --git a/.travis.yml b/.travis.yml index 87812e20..bf94aa4e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -74,9 +74,6 @@ matrix: - env: TOXENV=py34-postgres-pygresql - env: TOXENV=py35-postgres-pygresql - env: TOXENV=py36-postgres-pygresql - - env: TOXENV=py34-pypostgresql - - env: TOXENV=py35-pypostgresql - - env: TOXENV=py36-pypostgresql - env: TOXENV=py27-sqlite-memory - env: TOXENV=py34-sqlite-memory - env: TOXENV=py35-sqlite-memory diff --git a/docs/News.rst b/docs/News.rst index 451c9ba4..c14515a5 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -13,6 +13,9 @@ SQLObject 3.4.0 (master) * Python 2.6 is no longer supported. The minimal supported version is Python 2.7. +* Encode binary values for py-postgresql driver. This fixes the + last remaining problems with the driver. + * Encode/decode binary values for PyGreSQL driver. * List all drivers in extras_require in setup.py. diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index 855a5cf5..76a809bc 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -2,7 +2,7 @@ from sqlobject import col from sqlobject import dberrors from sqlobject import sqlbuilder -from sqlobject.compat import PY2, unicode_type +from sqlobject.compat import PY2 from sqlobject.converters import registerConverter, sqlrepr from sqlobject.dbconnection import DBAPI @@ -86,15 +86,13 @@ def __init__(self, dsn=None, host=None, port=None, db=None, registerConverter(type(self.module.Binary('')), PsycoBinaryConverter) elif driver == 'pygresql': - from pg import escape_bytea + from pg import escape_bytea as pg_escape_bytea self.createBinary = \ - lambda value, escape_bytea=escape_bytea: escape_bytea(value) - elif type(self.module.Binary) in ( - type, type(PostgresBinaryConverter)) and \ - type(self.module.Binary(b'')) not in (bytes, unicode_type): - # Register a converter for Binary type. + lambda value, pg_escape_bytea=pg_escape_bytea: \ + pg_escape_bytea(value) + elif driver in ('py-postgresql', 'pypostgresql'): registerConverter(type(self.module.Binary(b'')), - PostgresBinaryConverter) + PypostgresBinaryConverter) self.db = db self.user = user @@ -541,11 +539,12 @@ def PsycoBinaryConverter(value, db): return str(value) -if PY2: - def PostgresBinaryConverter(value, db): - assert db == 'postgres' - return sqlrepr(bytes(value), db) -else: - def PostgresBinaryConverter(value, db): - assert db == 'postgres' - return sqlrepr(value.decode('latin1'), db) +def escape_bytea(value): + return ''.join( + ['\\' + (x[2:].rjust(3, '0')) for x in (oct(ord(c)) for c in value)] + ) + + +def PypostgresBinaryConverter(value, db): + assert db == 'postgres' + return sqlrepr(escape_bytea(value.decode('latin1')), db) From be2c6ade34e0227f664685a3462b3ee905dff167 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 29 May 2017 22:46:33 +0300 Subject: [PATCH 077/509] Change binary encoding for ODBC drivers --- sqlobject/postgres/pgconnection.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index 76a809bc..4e331855 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -93,6 +93,8 @@ def __init__(self, dsn=None, host=None, port=None, db=None, elif driver in ('py-postgresql', 'pypostgresql'): registerConverter(type(self.module.Binary(b'')), PypostgresBinaryConverter) + elif driver in ('odbc', 'pyodbc', 'pypyodbc'): + registerConverter(bytearray, OdbcBinaryConverter) self.db = db self.user = user @@ -548,3 +550,11 @@ def escape_bytea(value): def PypostgresBinaryConverter(value, db): assert db == 'postgres' return sqlrepr(escape_bytea(value.decode('latin1')), db) + + +def OdbcBinaryConverter(value, db): + assert db == 'postgres' + value = bytes(value) + if not PY2: + value = value.decode('latin1') + return value From e5be8841dad1fbad22e3169ecaaf4a6a8b5dcd89 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 30 May 2017 00:28:02 +0300 Subject: [PATCH 078/509] Tests for sqlite-memory at Travis somehow work now --- .travis.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index bf94aa4e..aa7286ad 100644 --- a/.travis.yml +++ b/.travis.yml @@ -74,10 +74,6 @@ matrix: - env: TOXENV=py34-postgres-pygresql - env: TOXENV=py35-postgres-pygresql - env: TOXENV=py36-postgres-pygresql - - env: TOXENV=py27-sqlite-memory - - env: TOXENV=py34-sqlite-memory - - env: TOXENV=py35-sqlite-memory - - env: TOXENV=py36-sqlite-memory - env: TOXENV=py27-firebird-fdb - env: TOXENV=py34-firebird-fdb - env: TOXENV=py35-firebird-fdb From 53a22ac8a7222a86f4638cc00f24d19169838233 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 7 Jun 2017 01:00:17 +0300 Subject: [PATCH 079/509] Docs: I started to answer questions on StackOverflow [skip ci] --- ANNOUNCE.rst | 3 +++ docs/community.rst | 3 +++ 2 files changed, 6 insertions(+) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 3d68fe49..9fd03d32 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -59,6 +59,9 @@ https://pypi.python.org/pypi/SQLObject/3.4.0a0.dev20170507 News and changes: http://sqlobject.org/News.html +StackOverflow: +https://stackoverflow.com/questions/tagged/sqlobject + Example ======= diff --git a/docs/community.rst b/docs/community.rst index 91c0ae0c..c3123857 100644 --- a/docs/community.rst +++ b/docs/community.rst @@ -22,6 +22,9 @@ contributing you should read the `Developer Guide `_. The `Author List `_ tries to list all the major contributors. +Questions can also be asked and answered on `StackOverflow +`_. + One can also contribute to `community-editable recipe/documentation site `_. From 2a85338c232bda8c4c0ecb50266491c5a04d414c Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 17 Jun 2017 20:27:52 +0300 Subject: [PATCH 080/509] Use ppu to cleanup pip cache Use remove-old-files.py from ppu to cleanup pip cache at Travis and AppVeyor. --- .travis.yml | 5 ++++- appveyor.yml | 5 ++++- docs/News.rst | 19 +++++++++++++++++-- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index aa7286ad..95b88830 100644 --- a/.travis.yml +++ b/.travis.yml @@ -101,7 +101,7 @@ before_install: sudo gsec -user sysdba -pass masterkey -add test -pw test; fi -install: travis_retry pip install tox coveralls codecov +install: travis_retry pip install tox coveralls codecov ppu script: tox -e ${TOXENV} @@ -109,3 +109,6 @@ after_success: - cd sqlobject - coveralls - codecov + +before_cache: + - remove-old-files.py -o 180 ~/.cache/pip diff --git a/appveyor.yml b/appveyor.yml index eff46149..ea3779b1 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -245,7 +245,7 @@ install: - "python --version" - "python -c \"import struct; print(struct.calcsize('P') * 8)\"" - "pip --version" - - "pip install tox" + - "pip install tox ppu" # List ODBC drivers - ps: Get-OdbcDriver -Platform 32-bit | Select-Object -ExpandProperty Name - ps: Get-OdbcDriver -Platform 64-bit | Select-Object -ExpandProperty Name @@ -270,3 +270,6 @@ build: false test_script: - "%CMD_IN_ENV% tox -e %TOX_ENV%" + +after_test: + - "remove-old-files.py -o 180 %LOCALAPPDATA%\\pip\\Cache" diff --git a/docs/News.rst b/docs/News.rst index c14515a5..3810aa8c 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -10,9 +10,21 @@ News SQLObject 3.4.0 (master) ======================== +Features +-------- + * Python 2.6 is no longer supported. The minimal supported version is Python 2.7. +Minor features +-------------- + +* Use base64.b64encode/b64decode instead of deprecated + encodestring/decodestring. + +Drivers (work in progress) +-------------------------- + * Encode binary values for py-postgresql driver. This fixes the last remaining problems with the driver. @@ -20,8 +32,11 @@ SQLObject 3.4.0 (master) * List all drivers in extras_require in setup.py. -* Use base64.b64encode/b64decode instead of deprecated - encodestring/decodestring. +Tests +----- + +* Use remove-old-files.py from ppu to cleanup pip cache + at Travis and AppVeyor. SQLObject 3.3.0 =============== From a5531c8d0b499b82ed714aa4971b14b41ae7610c Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 29 Jun 2017 01:09:54 +0300 Subject: [PATCH 081/509] Add test_csvimport.py --- docs/News.rst | 3 +++ sqlobject/tests/test_csvimport.py | 21 +++++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 sqlobject/tests/test_csvimport.py diff --git a/docs/News.rst b/docs/News.rst index 3810aa8c..e2a430ce 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -38,6 +38,9 @@ Tests * Use remove-old-files.py from ppu to cleanup pip cache at Travis and AppVeyor. +* Add test_csvimport.py more as an example how to use load_csv + from sqlobject.util.csvimport. + SQLObject 3.3.0 =============== diff --git a/sqlobject/tests/test_csvimport.py b/sqlobject/tests/test_csvimport.py new file mode 100644 index 00000000..990f4509 --- /dev/null +++ b/sqlobject/tests/test_csvimport.py @@ -0,0 +1,21 @@ +import csv +from datetime import datetime +from sqlobject.util.csvimport import load_csv + +csv_data = """\ +name:str,age:datetime,value:int +Test,2000-01-01 21:44:33,42""" + + +def test_load_csv(): + loaded = load_csv(csv.reader(csv_data.split('\n')), + default_class='SQLObject') + assert loaded == { + 'SQLObject': [ + { + 'age': datetime(2000, 1, 1, 21, 44, 33), + 'name': 'Test', + 'value': 42 + } + ] + } From 78f1bc56ba2f32c28af86611ceb5a0e991544f26 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 5 Jul 2017 12:00:52 +0300 Subject: [PATCH 082/509] Add requirements_dev.txt [skip ci] --- devscripts/requirements/requirements_dev.txt | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 devscripts/requirements/requirements_dev.txt diff --git a/devscripts/requirements/requirements_dev.txt b/devscripts/requirements/requirements_dev.txt new file mode 100644 index 00000000..c7dc3125 --- /dev/null +++ b/devscripts/requirements/requirements_dev.txt @@ -0,0 +1,4 @@ +-r requirements.txt + +wheel +twine From acb369a2f85b1329aa72ff902341cda96dbdb0e4 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 23 Jul 2017 00:34:10 +0300 Subject: [PATCH 083/509] Fix(CI): Force user root for mysql at Travis --- tox.ini | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/tox.ini b/tox.ini index 6cf2dead..c2e9c604 100644 --- a/tox.ini +++ b/tox.ini @@ -45,10 +45,10 @@ whitelist_externals = [mysqldb] commands = {[testenv]commands} - -mysql -e 'drop database sqlobject_test;' - mysql -e 'create database sqlobject_test;' + -mysql -uroot -e 'drop database sqlobject_test;' + mysql -uroot -e 'create database sqlobject_test;' pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=mysqldb&debug=1 - mysql -e 'drop database sqlobject_test;' + mysql -uroot -e 'drop database sqlobject_test;' [testenv:py27-mysqldb] commands = {[mysqldb]commands} @@ -56,10 +56,10 @@ commands = {[mysqldb]commands} [mysqlclient] commands = {[testenv]commands} - -mysql -e 'drop database sqlobject_test;' - mysql -e 'create database sqlobject_test;' + -mysql -uroot -e 'drop database sqlobject_test;' + mysql -uroot -e 'create database sqlobject_test;' pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=mysqldb&charset=utf8&debug=1 - mysql -e 'drop database sqlobject_test;' + mysql -uroot -e 'drop database sqlobject_test;' [testenv:py34-mysqlclient] commands = {[mysqlclient]commands} @@ -73,10 +73,10 @@ commands = {[mysqlclient]commands} [mysql-connector] commands = {[testenv]commands} - -mysql -e 'drop database sqlobject_test;' - mysql -e 'create database sqlobject_test;' + -mysql -uroot -e 'drop database sqlobject_test;' + mysql -uroot -e 'create database sqlobject_test;' pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=connector&charset=utf8&debug=1 - mysql -e 'drop database sqlobject_test;' + mysql -uroot -e 'drop database sqlobject_test;' [testenv:py27-mysql-connector] commands = {[mysql-connector]commands} @@ -93,10 +93,10 @@ commands = {[mysql-connector]commands} [oursql] commands = {[testenv]commands} - -mysql -e 'drop database sqlobject_test;' - mysql -e 'create database sqlobject_test;' + -mysql -uroot -e 'drop database sqlobject_test;' + mysql -uroot -e 'create database sqlobject_test;' pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=oursql&charset=utf8&debug=1 - mysql -e 'drop database sqlobject_test;' + mysql -uroot -e 'drop database sqlobject_test;' [testenv:py27-mysql-oursql] commands = {[oursql]commands} @@ -104,10 +104,10 @@ commands = {[oursql]commands} [pymysql] commands = {[testenv]commands} - -mysql -e 'drop database sqlobject_test;' - mysql -e 'create database sqlobject_test;' + -mysql -uroot -e 'drop database sqlobject_test;' + mysql -uroot -e 'create database sqlobject_test;' pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=pymysql&charset=utf8&debug=1 - mysql -e 'drop database sqlobject_test;' + mysql -uroot -e 'drop database sqlobject_test;' [testenv:py27-pymysql] commands = {[pymysql]commands} @@ -125,10 +125,10 @@ commands = {[pymysql]commands} commands = {[testenv]commands} {envpython} -c "import pyodbc; print(pyodbc.drivers())" - -mysql -e 'drop database sqlobject_test;' - mysql -e 'create database sqlobject_test;' + -mysql -uroot -e 'drop database sqlobject_test;' + mysql -uroot -e 'create database sqlobject_test;' pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=pyodbc&odbcdrv=MySQL&charset=utf8&debug=1 - mysql -e 'drop database sqlobject_test;' + mysql -uroot -e 'drop database sqlobject_test;' [testenv:py27-mysql-pyodbc] commands = {[mysql-pyodbc]commands} @@ -145,10 +145,10 @@ commands = {[mysql-pyodbc]commands} [mysql-pypyodbc] commands = {[testenv]commands} - -mysql -e 'drop database sqlobject_test;' - mysql -e 'create database sqlobject_test;' + -mysql -uroot -e 'drop database sqlobject_test;' + mysql -uroot -e 'create database sqlobject_test;' pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=MySQL&charset=utf8&debug=1 - mysql -e 'drop database sqlobject_test;' + mysql -uroot -e 'drop database sqlobject_test;' [testenv:py27-mysql-pypyodbc] commands = {[mysql-pypyodbc]commands} From 57316afcfd523c8308f0e348f3e17b09973f551e Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 23 Jul 2017 01:10:48 +0300 Subject: [PATCH 084/509] Fix(CI): Disable microseconds for MySQL at Travis --- sqlobject/mysql/mysqlconnection.py | 2 +- sqlobject/tests/dbtest.py | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index 225a02f6..eb56223b 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -459,7 +459,7 @@ def server_version(self): def can_use_microseconds(self): if self._can_use_microseconds is not None: return self._can_use_microseconds - if os.environ.get('APPVEYOR'): + if os.environ.get('APPVEYOR') or os.environ.get('TRAVIS'): self._can_use_microseconds = False return False server_version = self.server_version() diff --git a/sqlobject/tests/dbtest.py b/sqlobject/tests/dbtest.py index ed1cb487..545c3859 100644 --- a/sqlobject/tests/dbtest.py +++ b/sqlobject/tests/dbtest.py @@ -123,7 +123,10 @@ def getConnectionURI(): if (connection.dbName == 'firebird') \ or ( (connection.dbName == 'mysql') and - (os.environ.get('APPVEYOR')) + ( + (os.environ.get('APPVEYOR')) or + (os.environ.get('TRAVIS')) + ) ): use_microseconds(False) From d1876c15115cc13b60a317fb55c564f39270d89a Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 23 Jul 2017 19:45:43 +0300 Subject: [PATCH 085/509] Fix(CI): Fix Firebird setup --- .travis.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 95b88830..79032aa4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -91,14 +91,15 @@ before_install: # We also create a test user for the firebird test and # create a script that can be fed into isql-fb # to create the test database. + # Copied password initializtion from + # https://github.com/xdenser/node-firebird-libfbclient/blob/master/.travis.yml - if [[ $TOXENV = *firebird* ]]; then sudo sed -i /etc/default/firebird2.5 -e 's/=no/=yes/' && sudo /etc/init.d/firebird2.5-super start && sleep 5 && - sudo touch /var/lib/firebird/create_test_db && - sudo chmod 666 /var/lib/firebird/create_test_db && - echo "CREATE DATABASE 'localhost:/tmp/test.fdb';" > /var/lib/firebird/create_test_db && - sudo chmod 644 /var/lib/firebird/create_test_db && - sudo gsec -user sysdba -pass masterkey -add test -pw test; + sudo /bin/bash -c '(export FB_VER="2.5"; export FB_FLAVOUR="super";source /usr/share/firebird2.5-common/functions.sh; writeNewPassword masterkey)' && + sudo gsec -user sysdba -pass masterkey -add test -pw test && + sudo /bin/bash -c "echo \"CREATE DATABASE 'localhost:/tmp/test.fdb';\" > /var/lib/firebird/create_test_db" && + sudo chmod 644 /var/lib/firebird/create_test_db; fi install: travis_retry pip install tox coveralls codecov ppu From 044e33067682d9fb96345fde28f2761a85005b14 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 30 Jul 2017 19:43:09 +0300 Subject: [PATCH 086/509] Fix(pg): Encode binary values for PyGreSQL driver Encode binary values for PyGreSQL driver using the same encoding as for py-postgresql driver. This fixes the last remaining problems with the driver. --- .travis.yml | 4 ---- docs/News.rst | 11 ++++++++++- docs/SQLObject.rst | 6 +++--- sqlobject/col.py | 3 --- sqlobject/postgres/pgconnection.py | 29 ++++++++++++++++------------- 5 files changed, 29 insertions(+), 24 deletions(-) diff --git a/.travis.yml b/.travis.yml index 79032aa4..ddb1252a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -70,10 +70,6 @@ env: matrix: allow_failures: - - env: TOXENV=py27-postgres-pygresql - - env: TOXENV=py34-postgres-pygresql - - env: TOXENV=py35-postgres-pygresql - - env: TOXENV=py36-postgres-pygresql - env: TOXENV=py27-firebird-fdb - env: TOXENV=py34-firebird-fdb - env: TOXENV=py35-firebird-fdb diff --git a/docs/News.rst b/docs/News.rst index e2a430ce..540b47df 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -28,7 +28,16 @@ Drivers (work in progress) * Encode binary values for py-postgresql driver. This fixes the last remaining problems with the driver. -* Encode/decode binary values for PyGreSQL driver. +* Encode binary values for PyGreSQL driver using the same encoding as for + py-postgresql driver. This fixes the last remaining problems with the driver. + + Our own encoding is needed because unescape_bytea(escape_bytea()) is not + idempotent. See the comment for PQunescapeBytea at + https://www.postgresql.org/docs/9.6/static/libpq-exec.html: + + This conversion is not exactly the inverse of PQescapeBytea, because the + string is not expected to be "escaped" when received from PQgetvalue. In + particular this means there is no need for string quoting considerations. * List all drivers in extras_require in setup.py. diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index e1f9b43c..9a3121fb 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -1831,9 +1831,9 @@ PostgresConnection supports transactions and all other features. The user can choose a DB API driver for PostgreSQL by using a ``driver`` parameter in DB URI or PostgresConnection that can be a comma-separated list of driver names. Possible drivers are: ``psycopg2``, psycopg1, -``psycopg`` (tries psycopg2 and psycopg1), ``pygresql``, ``pygresql``, -``pypostgresql``, ``pyodbc``, ``pypyodbc`` or ``odbc`` (try ``pyodbc`` and -``pypyodbc``). Default is ``psycopg``. +``psycopg`` (tries psycopg2 and psycopg1), ``pygresql``, ``pypostgresql``, +``pyodbc``, ``pypyodbc`` or ``odbc`` (try ``pyodbc`` and ``pypyodbc``). +Default is ``psycopg``. Connection-specific parameters are: ``sslmode``, ``unicodeCols``, ``schema``, ``charset``. diff --git a/sqlobject/col.py b/sqlobject/col.py index 6ee5e98b..0f358628 100644 --- a/sqlobject/col.py +++ b/sqlobject/col.py @@ -1770,9 +1770,6 @@ def to_python(self, value, state): if isinstance(value, str): if not PY2 and dbName == "mysql": value = value.encode('ascii', errors='surrogateescape') - if dbName == "postgres" and connection.driver == 'pygresql': - from pg import unescape_bytea - value = unescape_bytea(value) if dbName == "sqlite": if not PY2: value = bytes(value, 'ascii') diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index 4e331855..494ff092 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -85,14 +85,9 @@ def __init__(self, dsn=None, host=None, port=None, db=None, # Register a converter for psycopg Binary type. registerConverter(type(self.module.Binary('')), PsycoBinaryConverter) - elif driver == 'pygresql': - from pg import escape_bytea as pg_escape_bytea - self.createBinary = \ - lambda value, pg_escape_bytea=pg_escape_bytea: \ - pg_escape_bytea(value) - elif driver in ('py-postgresql', 'pypostgresql'): + elif driver in ('pygresql', 'py-postgresql', 'pypostgresql'): registerConverter(type(self.module.Binary(b'')), - PypostgresBinaryConverter) + PostgresBinaryConverter) elif driver in ('odbc', 'pyodbc', 'pypyodbc'): registerConverter(bytearray, OdbcBinaryConverter) @@ -541,15 +536,23 @@ def PsycoBinaryConverter(value, db): return str(value) -def escape_bytea(value): - return ''.join( - ['\\' + (x[2:].rjust(3, '0')) for x in (oct(ord(c)) for c in value)] - ) +if PY2: + def escape_bytea(value): + return ''.join( + ['\\' + (x[1:].rjust(3, '0')) + for x in (oct(ord(c)) for c in value)] + ) +else: + def escape_bytea(value): + return ''.join( + ['\\' + (x[2:].rjust(3, '0')) + for x in (oct(ord(c)) for c in value.decode('latin1'))] + ) -def PypostgresBinaryConverter(value, db): +def PostgresBinaryConverter(value, db): assert db == 'postgres' - return sqlrepr(escape_bytea(value.decode('latin1')), db) + return sqlrepr(escape_bytea(value), db) def OdbcBinaryConverter(value, db): From 48ddb3a762f62b03843db11a9d3fc878ef2038fd Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 2 Aug 2017 01:32:11 +0300 Subject: [PATCH 087/509] Tests: Fix a bug with sqlite-memory Rollback transaction and close connection. --- ANNOUNCE.rst | 2 +- docs/News.rst | 3 +++ sqlobject/tests/test_transactions.py | 9 ++++++--- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 9fd03d32..f11cfefa 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -22,7 +22,7 @@ I'm pleased to announce version 3.4.1, the first bugfix release of branch What's new in SQLObject ======================= -Contributor for this release is +Contributor for this release is Dr. Neil Muller. For a more complete list, please see the news: http://sqlobject.org/News.html diff --git a/docs/News.rst b/docs/News.rst index 540b47df..16bc6e08 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -44,6 +44,9 @@ Drivers (work in progress) Tests ----- +* Fix a bug with sqlite-memory: rollback transaction and close connection. + The solution was found by Dr. Neil Muller. + * Use remove-old-files.py from ppu to cleanup pip cache at Travis and AppVeyor. diff --git a/sqlobject/tests/test_transactions.py b/sqlobject/tests/test_transactions.py index 0fbac423..b52ad52f 100644 --- a/sqlobject/tests/test_transactions.py +++ b/sqlobject/tests/test_transactions.py @@ -50,7 +50,8 @@ def test_transaction(): def test_transaction_commit_sync(): setupClass(SOTestSOTrans) - trans = SOTestSOTrans._connection.transaction() + connection = SOTestSOTrans._connection + trans = connection.transaction() try: SOTestSOTrans(name='bob') bOut = SOTestSOTrans.byName('bob') @@ -60,14 +61,16 @@ def test_transaction_commit_sync(): trans.commit() assert bOut.name == 'robert' finally: - SOTestSOTrans._connection.autoCommit = True + trans.rollback() + connection.autoCommit = True + connection.close() def test_transaction_delete(close=False): setupClass(SOTestSOTrans) connection = SOTestSOTrans._connection if (connection.dbName == 'sqlite') and connection._memory: - pytest.skip("The following test requires a different connection") + pytest.skip("The test doesn't work with sqlite memory connection") trans = connection.transaction() try: SOTestSOTrans(name='bob') From 623a5802b03273b2ef8aa57e6d13dc312f232033 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 5 Aug 2017 19:30:51 +0300 Subject: [PATCH 088/509] Release 3.4.0 --- ANNOUNCE.rst | 60 +++++++++++++++++++++++++++++----------- README.rst | 4 +-- docs/News.rst | 18 ++++++------ sqlobject/__version__.py | 4 +-- 4 files changed, 58 insertions(+), 28 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index f11cfefa..944a3dfe 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,29 +1,57 @@ Hello! -I'm pleased to announce version 3.4.0a1, the first alpha of the upcoming -release of branch 3.4 of SQLObject. - -I'm pleased to announce version 3.4.0a2, the second alpha of the upcoming -release of branch 3.4 of SQLObject. - -I'm pleased to announce version 3.4.0b1, the first beta of the upcoming -release of branch 3.4 of SQLObject. - -I'm pleased to announce version 3.4.0rc1, the first release candidate -of the upcoming release of branch 3.4 of SQLObject. - I'm pleased to announce version 3.4.0, the first stable release of branch 3.4 of SQLObject. -I'm pleased to announce version 3.4.1, the first bugfix release of branch -3.4 of SQLObject. - What's new in SQLObject ======================= Contributor for this release is Dr. Neil Muller. +Features +-------- + +* Python 2.6 is no longer supported. The minimal supported version is + Python 2.7. + +Drivers (work in progress) +-------------------------- + +* Encode binary values for py-postgresql driver. This fixes the + last remaining problems with the driver. + +* Encode binary values for PyGreSQL driver using the same encoding as for + py-postgresql driver. This fixes the last remaining problems with the driver. + + Our own encoding is needed because unescape_bytea(escape_bytea()) is not + idempotent. See the comment for PQunescapeBytea at + https://www.postgresql.org/docs/9.6/static/libpq-exec.html: + + This conversion is not exactly the inverse of PQescapeBytea, because the + string is not expected to be "escaped" when received from PQgetvalue. In + particular this means there is no need for string quoting considerations. + +* List all drivers in extras_require in setup.py. + +Minor features +-------------- + +* Use base64.b64encode/b64decode instead of deprecated + encodestring/decodestring. + +Tests +----- + +* Fix a bug with sqlite-memory: rollback transaction and close connection. + The solution was found by Dr. Neil Muller. + +* Use remove-old-files.py from ppu to cleanup pip cache + at Travis and AppVeyor. + +* Add test_csvimport.py more as an example how to use load_csv + from sqlobject.util.csvimport. + For a more complete list, please see the news: http://sqlobject.org/News.html @@ -54,7 +82,7 @@ Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Download: -https://pypi.python.org/pypi/SQLObject/3.4.0a0.dev20170507 +https://pypi.python.org/pypi/SQLObject/3.4.0 News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 43c457d6..8f49176c 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.4.0a0 -================= +SQLObject 3.4.0 +=============== Thanks for looking at SQLObject. SQLObject is an object-relational mapper, i.e., a library that will wrap your database tables in Python diff --git a/docs/News.rst b/docs/News.rst index 16bc6e08..50edaac4 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -7,8 +7,10 @@ News .. _start: -SQLObject 3.4.0 (master) -======================== +SQLObject 3.4.0 +=============== + +Released 5 Aug 2017. Features -------- @@ -16,12 +18,6 @@ Features * Python 2.6 is no longer supported. The minimal supported version is Python 2.7. -Minor features --------------- - -* Use base64.b64encode/b64decode instead of deprecated - encodestring/decodestring. - Drivers (work in progress) -------------------------- @@ -41,6 +37,12 @@ Drivers (work in progress) * List all drivers in extras_require in setup.py. +Minor features +-------------- + +* Use base64.b64encode/b64decode instead of deprecated + encodestring/decodestring. + Tests ----- diff --git a/sqlobject/__version__.py b/sqlobject/__version__.py index cc88e83d..b86d42e4 100644 --- a/sqlobject/__version__.py +++ b/sqlobject/__version__.py @@ -1,7 +1,7 @@ -version = '3.3.0' +version = '3.4.0' major = 3 -minor = 3 +minor = 4 micro = 0 release_level = 'final' serial = 0 From e200b0a68d73fc6ed9fa3d114a453399554f9455 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 5 Aug 2017 19:42:40 +0300 Subject: [PATCH 089/509] Prepare for the next release [skip ci] --- ANNOUNCE.rst | 60 ++++++++++++++------------------------------------- docs/News.rst | 3 +++ 2 files changed, 19 insertions(+), 44 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 944a3dfe..893d3972 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,56 +1,28 @@ Hello! -I'm pleased to announce version 3.4.0, the first stable release of branch -3.4 of SQLObject. - - -What's new in SQLObject -======================= - -Contributor for this release is Dr. Neil Muller. - -Features --------- - -* Python 2.6 is no longer supported. The minimal supported version is - Python 2.7. +I'm pleased to announce version 3.4.1a1, the first alpha of the upcoming +release of branch 3.4 of SQLObject. -Drivers (work in progress) --------------------------- +I'm pleased to announce version 3.4.1a2, the second alpha of the upcoming +release of branch 3.4 of SQLObject. -* Encode binary values for py-postgresql driver. This fixes the - last remaining problems with the driver. +I'm pleased to announce version 3.4.1b1, the first beta of the upcoming +release of branch 3.4 of SQLObject. -* Encode binary values for PyGreSQL driver using the same encoding as for - py-postgresql driver. This fixes the last remaining problems with the driver. +I'm pleased to announce version 3.4.1rc1, the first release candidate +of the upcoming release of branch 3.4 of SQLObject. - Our own encoding is needed because unescape_bytea(escape_bytea()) is not - idempotent. See the comment for PQunescapeBytea at - https://www.postgresql.org/docs/9.6/static/libpq-exec.html: - - This conversion is not exactly the inverse of PQescapeBytea, because the - string is not expected to be "escaped" when received from PQgetvalue. In - particular this means there is no need for string quoting considerations. - -* List all drivers in extras_require in setup.py. - -Minor features --------------- - -* Use base64.b64encode/b64decode instead of deprecated - encodestring/decodestring. +I'm pleased to announce version 3.4.0, the first stable release of branch +3.4 of SQLObject. -Tests ------ +I'm pleased to announce version 3.4.1, the first bugfix release of branch +3.4 of SQLObject. -* Fix a bug with sqlite-memory: rollback transaction and close connection. - The solution was found by Dr. Neil Muller. -* Use remove-old-files.py from ppu to cleanup pip cache - at Travis and AppVeyor. +What's new in SQLObject +======================= -* Add test_csvimport.py more as an example how to use load_csv - from sqlobject.util.csvimport. +Contributor for this release is For a more complete list, please see the news: http://sqlobject.org/News.html @@ -82,7 +54,7 @@ Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Download: -https://pypi.python.org/pypi/SQLObject/3.4.0 +https://pypi.python.org/pypi/SQLObject/3.4.1a0.dev20170805 News and changes: http://sqlobject.org/News.html diff --git a/docs/News.rst b/docs/News.rst index 50edaac4..76a85db1 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -7,6 +7,9 @@ News .. _start: +SQLObject 3.5.0 (master) +======================== + SQLObject 3.4.0 =============== From 79c3d71c70294faa6dc7181480e9cf9869d02f98 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 5 Aug 2017 19:42:55 +0300 Subject: [PATCH 090/509] Feat(devscripts): build_docs for 3.4.0 [skip ci] --- devscripts/build-all-docs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devscripts/build-all-docs b/devscripts/build-all-docs index 47071df9..9149597c 100755 --- a/devscripts/build-all-docs +++ b/devscripts/build-all-docs @@ -11,7 +11,7 @@ cd "$PROG_DIR" && PROG_DIR="`pwd`" && cd "$PROG_DIR"/SQLObject && -build_docs 3.3.0 && +build_docs 3.4.0 && build_docs master devel && cd ../SQLObject-docs && From 02ef060eccd973fde1c11706580675a11c6b8fff Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 5 Aug 2017 19:42:55 +0300 Subject: [PATCH 091/509] Feat(devscripts): remove html directory after building all docs [skip ci] --- devscripts/build-all-docs | 1 + 1 file changed, 1 insertion(+) diff --git a/devscripts/build-all-docs b/devscripts/build-all-docs index 9149597c..885a0179 100755 --- a/devscripts/build-all-docs +++ b/devscripts/build-all-docs @@ -13,6 +13,7 @@ PROG_DIR="`pwd`" && cd "$PROG_DIR"/SQLObject && build_docs 3.4.0 && build_docs master devel && +rm -rf docs/html && cd ../SQLObject-docs && exec sitemap_gen.py --config="$PROG_DIR"/sqlobject.org-sitemapconfig.xml From 89720cf3f65af7555f2fcebed0ba0d1abc97a674 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 5 Aug 2017 19:42:55 +0300 Subject: [PATCH 092/509] Feat(devscripts): Hide old releases at SF Run sftp-frs for stable release. [skip ci] --- devscripts/release | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/devscripts/release b/devscripts/release index 6c92d3a1..fba62a3f 100755 --- a/devscripts/release +++ b/devscripts/release @@ -31,7 +31,8 @@ if [ "$state" = final ]; then cp -a dist/* "$HOME"/tmp/ && rsync -ahP4 dist/* frs.sourceforge.net:/home/frs/project/sqlobject/sqlobject/"$version"/ && rsync -ahP4 ANNOUNCE.rst frs.sourceforge.net:/home/frs/project/sqlobject/sqlobject/"$version"/README.rst || exit 1 -fi + ../sftp-frs +fi && twine register dist/SQLObject-"$version".tar.gz && twine upload --sign dist/* && From 4bf401075edc7addd6a89d1c10d1179c77a3325e Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 5 Aug 2017 19:42:55 +0300 Subject: [PATCH 093/509] Feat(devscripts): Remove `twine register` from release process There is no longer necessary to pre-register packages before uploading. [skip ci] --- devscripts/release | 2 -- 1 file changed, 2 deletions(-) diff --git a/devscripts/release b/devscripts/release index fba62a3f..1de12856 100755 --- a/devscripts/release +++ b/devscripts/release @@ -34,7 +34,5 @@ if [ "$state" = final ]; then ../sftp-frs fi && -twine register dist/SQLObject-"$version".tar.gz && twine upload --sign dist/* && - exec rm -rf build dist docs/html SQLObject.egg-info From 4ae096a649a465d08a1b65a2164a086bfafa95ad Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 15 Aug 2017 05:21:09 +0300 Subject: [PATCH 094/509] Feat(CI): Remove some less interesting tests Remove some tests for PyODBC and sqlite-memory. --- appveyor.yml | 66 ---------------------------------------------------- 1 file changed, 66 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index ea3779b1..be36b493 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -38,41 +38,11 @@ environment: PYTHON_ARCH: "32" db: mssql2014 TOX_ENV: "py27-mssql-pyodbc-w32" - - PYTHON_HOME: "C:\\Python27-x64" - PYTHON_VERSION: "2.7" - PYTHON_ARCH: "64" - db: mssql2014 - TOX_ENV: "py27-mssql-pyodbc-w32" - - PYTHON_HOME: "C:\\Python34" - PYTHON_VERSION: "3.4" - PYTHON_ARCH: "32" - db: mssql2014 - TOX_ENV: "py34-mssql-pyodbc-w32" - PYTHON_HOME: "C:\\Python34-x64" PYTHON_VERSION: "3.4" PYTHON_ARCH: "64" db: mssql2014 TOX_ENV: "py34-mssql-pyodbc-w32" - - PYTHON_HOME: "C:\\Python35" - PYTHON_VERSION: "3.5" - PYTHON_ARCH: "32" - db: mssql2014 - TOX_ENV: "py35-mssql-pyodbc-w32" - - PYTHON_HOME: "C:\\Python35-x64" - PYTHON_VERSION: "3.5" - PYTHON_ARCH: "64" - db: mssql2014 - TOX_ENV: "py35-mssql-pyodbc-w32" - - PYTHON_HOME: "C:\\Python36" - PYTHON_VERSION: "3.6" - PYTHON_ARCH: "32" - db: mssql2014 - TOX_ENV: "py36-mssql-pyodbc-w32" - - PYTHON_HOME: "C:\\Python36-x64" - PYTHON_VERSION: "3.6" - PYTHON_ARCH: "64" - db: mssql2014 - TOX_ENV: "py36-mssql-pyodbc-w32" - PYTHON_HOME: "C:\\Python27" PYTHON_VERSION: "2.7" PYTHON_ARCH: "32" @@ -103,16 +73,6 @@ environment: PYTHON_ARCH: "64" db: mysql TOX_ENV: "py34-mysql-pyodbc-w32" - - PYTHON_HOME: "C:\\Python35-x64" - PYTHON_VERSION: "3.5" - PYTHON_ARCH: "64" - db: mysql - TOX_ENV: "py35-mysql-pyodbc-w32" - - PYTHON_HOME: "C:\\Python36-x64" - PYTHON_VERSION: "3.6" - PYTHON_ARCH: "64" - db: mysql - TOX_ENV: "py36-mysql-pyodbc-w32" - PYTHON_HOME: "C:\\Python27" PYTHON_VERSION: "2.7" PYTHON_ARCH: "32" @@ -163,16 +123,6 @@ environment: PYTHON_ARCH: "64" db: postgresql TOX_ENV: "py34-postgres-pyodbc-w32" - - PYTHON_HOME: "C:\\Python35-x64" - PYTHON_VERSION: "3.5" - PYTHON_ARCH: "64" - db: postgresql - TOX_ENV: "py35-postgres-pyodbc-w32" - - PYTHON_HOME: "C:\\Python36-x64" - PYTHON_VERSION: "3.6" - PYTHON_ARCH: "64" - db: postgresql - TOX_ENV: "py36-postgres-pyodbc-w32" - PYTHON_HOME: "C:\\Python27" PYTHON_VERSION: "2.7" PYTHON_ARCH: "32" @@ -209,14 +159,6 @@ environment: PYTHON_VERSION: "2.7" PYTHON_ARCH: "32" TOX_ENV: "py27-sqlite-memory-w32" - - PYTHON_HOME: "C:\\Python27-x64" - PYTHON_VERSION: "2.7" - PYTHON_ARCH: "64" - TOX_ENV: "py27-sqlite-memory-w32" - - PYTHON_HOME: "C:\\Python34" - PYTHON_VERSION: "3.4" - PYTHON_ARCH: "32" - TOX_ENV: "py34-sqlite-memory-w32" - PYTHON_HOME: "C:\\Python34-x64" PYTHON_VERSION: "3.4" PYTHON_ARCH: "64" @@ -225,14 +167,6 @@ environment: PYTHON_VERSION: "3.5" PYTHON_ARCH: "32" TOX_ENV: "py35-sqlite-memory-w32" - - PYTHON_HOME: "C:\\Python35-x64" - PYTHON_VERSION: "3.5" - PYTHON_ARCH: "64" - TOX_ENV: "py35-sqlite-memory-w32" - - PYTHON_HOME: "C:\\Python36" - PYTHON_VERSION: "3.6" - PYTHON_ARCH: "32" - TOX_ENV: "py36-sqlite-memory-w32" - PYTHON_HOME: "C:\\Python36-x64" PYTHON_VERSION: "3.6" PYTHON_ARCH: "64" From e6241109b11e9018ae801e02a7893b6f206c8fb1 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 14 Aug 2017 23:27:59 +0300 Subject: [PATCH 095/509] Feat(pg): Restore pg8000 driver This reverts commit aca6f12710642610c0711e5446efb21a6df09f3c. --- .travis.yml | 5 +++++ docs/News.rst | 6 ++++++ docs/SQLObject.rst | 21 +++++++++++---------- setup.py | 1 + sqlobject/postgres/pgconnection.py | 14 ++++++++++++-- tox.ini | 24 +++++++++++++++++++++++- 6 files changed, 58 insertions(+), 13 deletions(-) diff --git a/.travis.yml b/.travis.yml index ddb1252a..3b18a1ce 100644 --- a/.travis.yml +++ b/.travis.yml @@ -49,6 +49,10 @@ env: - TOXENV=py34-pypostgresql - TOXENV=py35-pypostgresql - TOXENV=py36-pypostgresql + - TOXENV=py27-postgres-pg8000 + - TOXENV=py34-postgres-pg8000 + - TOXENV=py35-postgres-pg8000 + - TOXENV=py36-postgres-pg8000 - TOXENV=py27-sqlite - TOXENV=py34-sqlite - TOXENV=py35-sqlite @@ -70,6 +74,7 @@ env: matrix: allow_failures: + - env: TOXENV=py27-postgres-pg8000 - env: TOXENV=py27-firebird-fdb - env: TOXENV=py34-firebird-fdb - env: TOXENV=py35-firebird-fdb diff --git a/docs/News.rst b/docs/News.rst index 76a85db1..6316b544 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -10,6 +10,12 @@ News SQLObject 3.5.0 (master) ======================== +Drivers +------- + +* Add support for `pg8000 `_ + PostgreSQL driver (from git). There is a minor problem with Python 2.7. + SQLObject 3.4.0 =============== diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index 9a3121fb..98367ae9 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -49,12 +49,12 @@ Requirements Currently SQLObject supports MySQL_ via MySQLdb_ aka MySQL-python (called mysqlclient_ for Python 3), `MySQL Connector`_, oursql_, PyMySQL_, PyODBC_ and PyPyODBC_. For PostgreSQL_ psycopg2_ or psycopg1 are recommended; -PyGreSQL_, py-postgresql_, PyODBC_ and PyPyODBC_ are supported but have -problems (not all tests passed). SQLite_ has a built-in driver or -PySQLite_. Firebird_ is supported via fdb_ or kinterbasdb_; pyfirebirdsql_ -is supported but has problems. `MAX DB`_ (also known as SAP DB) is -supported via sapdb_. Sybase via Sybase_. `MSSQL Server`_ via pymssql_ (+ -FreeTDS_) or adodbapi_ (Win32). +PyGreSQL_, py-postgresql_ and pg8000_ are supported; SQLite_ has a +built-in driver or PySQLite_. Firebird_ is supported via fdb_ or +kinterbasdb_; pyfirebirdsql_ is supported but has problems. `MAX DB`_ +(also known as SAP DB) is supported via sapdb_. Sybase via Sybase_. `MSSQL +Server`_ via pymssql_ (+ FreeTDS_) or adodbapi_ (Win32). PyODBC_ and +PyPyODBC_ are supported but have problems (not all tests passed). .. _MySQL: https://www.mysql.com/ .. _MySQLdb: https://sourceforge.net/projects/mysql-python/ @@ -66,8 +66,7 @@ FreeTDS_) or adodbapi_ (Win32). .. _psycopg2: http://initd.org/psycopg/ .. _PyGreSQL: http://www.pygresql.org/ .. _py-postgresql: https://pypi.python.org/pypi/py-postgresql -.. _PyODBC: https://pypi.python.org/pypi/pyodbc -.. _PyPyODBC: https://pypi.python.org/pypi/pypyodbc +.. _pg8000: https://pypi.python.org/pypi/pg8000 .. _SQLite: https://sqlite.org/ .. _PySQLite: https://github.com/ghaering/pysqlite .. _Firebird: http://www.firebirdsql.org/en/python-driver/ @@ -81,6 +80,8 @@ FreeTDS_) or adodbapi_ (Win32). .. _pymssql: http://www.pymssql.org/en/latest/index.html .. _FreeTDS: http://www.freetds.org/ .. _adodbapi: http://adodbapi.sourceforge.net/ +.. _PyODBC: https://pypi.python.org/pypi/pyodbc +.. _PyPyODBC: https://pypi.python.org/pypi/pypyodbc Python 2.7 or 3.4+ is required. @@ -1832,8 +1833,8 @@ The user can choose a DB API driver for PostgreSQL by using a ``driver`` parameter in DB URI or PostgresConnection that can be a comma-separated list of driver names. Possible drivers are: ``psycopg2``, psycopg1, ``psycopg`` (tries psycopg2 and psycopg1), ``pygresql``, ``pypostgresql``, -``pyodbc``, ``pypyodbc`` or ``odbc`` (try ``pyodbc`` and ``pypyodbc``). -Default is ``psycopg``. +``pg8000``, ``pyodbc``, ``pypyodbc`` or ``odbc`` (try ``pyodbc`` and +``pypyodbc``). Default is ``psycopg``. Connection-specific parameters are: ``sslmode``, ``unicodeCols``, ``schema``, ``charset``. diff --git a/setup.py b/setup.py index 2e22194e..f9fe8029 100755 --- a/setup.py +++ b/setup.py @@ -65,6 +65,7 @@ 'pygresql': ['pygresql'], 'pypostgresql': ['py-postgresql'], 'py-postgresql': ['py-postgresql'], + 'pg8000': ['pg8000'], # 'sapdb': ['sapdb'], 'sqlite': ['pysqlite'], diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index 494ff092..f17b7e0d 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -1,3 +1,4 @@ +from getpass import getuser import re from sqlobject import col from sqlobject import dberrors @@ -55,6 +56,9 @@ def __init__(self, dsn=None, host=None, port=None, db=None, elif driver in ('py-postgresql', 'pypostgresql'): from postgresql.driver import dbapi20 self.module = dbapi20 + elif driver == 'pg8000': + import pg8000 + self.module = pg8000 elif driver == 'pyodbc': import pyodbc self.module = pyodbc @@ -71,7 +75,7 @@ def __init__(self, dsn=None, host=None, port=None, db=None, raise ValueError( 'Unknown PostgreSQL driver "%s", ' 'expected psycopg, psycopg2, psycopg1, ' - 'pygresql, pypostgresql, ' + 'pygresql, pypostgresql, pg8000, ' 'odbc, pyodbc or pypyodbc' % driver) except ImportError: pass @@ -85,7 +89,7 @@ def __init__(self, dsn=None, host=None, port=None, db=None, # Register a converter for psycopg Binary type. registerConverter(type(self.module.Binary('')), PsycoBinaryConverter) - elif driver in ('pygresql', 'py-postgresql', 'pypostgresql'): + elif driver in ('pygresql', 'py-postgresql', 'pypostgresql', 'pg8000'): registerConverter(type(self.module.Binary(b'')), PostgresBinaryConverter) elif driver in ('odbc', 'pyodbc', 'pypyodbc'): @@ -161,6 +165,12 @@ def __init__(self, dsn=None, host=None, port=None, db=None, else: if "unix" in dsn_dict: del dsn_dict["unix"] + if driver == 'pg8000': + if host and host.startswith('/'): + dsn_dict["host"] = None + dsn_dict["unix_sock"] = host + if user is None: + dsn_dict["user"] = getuser() self.dsn = dsn self.driver = driver self.unicodeCols = kw.pop('unicodeCols', False) diff --git a/tox.ini b/tox.ini index c2e9c604..76320425 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 1.8 -envlist = py27-{mysqldb,mysql-oursql},py{34,35,36}-{mysqlclient,pypostgresql},py{27,34,35,36}-{mysql-connector,pymysql,mysql-pyodbc,mysql-pypyodbc,postgres-psycopg,postgres-pygresql,postgres-pyodbc,postgres-pypyodbc,sqlite,sqlite-memory},py{27,34,35,36}-{firebird-fdb,firebirdsql},py{27,34}-flake8,py{27,34,35,36}-{mssql-pyodbc,mysql-connector,mysql-pyodbc,mysql-pypyodbc,postgres-psycopg,postgres-pyodbc,postgres-pypyodbc,sqlite,sqlite-memory}-w32 +envlist = py27-{mysqldb,mysql-oursql},py{34,35,36}-{mysqlclient,pypostgresql},py{27,34,35,36}-{mysql-connector,pymysql,mysql-pyodbc,mysql-pypyodbc,postgres-psycopg,postgres-pygresql,postgres-pg8000,postgres-pyodbc,postgres-pypyodbc,sqlite,sqlite-memory},py{27,34,35,36}-{firebird-fdb,firebirdsql},py{27,34}-flake8,py{27,34,35,36}-{mssql-pyodbc,mysql-connector,mysql-pyodbc,mysql-pypyodbc,postgres-psycopg,postgres-pyodbc,postgres-pypyodbc,sqlite,sqlite-memory}-w32 # Base test environment settings [testenv] @@ -26,6 +26,7 @@ deps = postgres-psycopg: psycopg2 postgres-pygresql: pygresql pypostgresql: py-postgresql + postgres-pg8000: git+https://github.com/mfenniak/pg8000.git#egg=pg8000 pyodbc: pyodbc pypyodbc: pypyodbc firebird-fdb: fdb @@ -220,6 +221,26 @@ commands = {[pypostgresql]commands} [testenv:py36-pypostgresql] commands = {[pypostgresql]commands} +[pg8000] +commands = + {[testenv]commands} + -dropdb -U postgres -w sqlobject_test + createdb -U postgres -w sqlobject_test + pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=pg8000&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test + dropdb -U postgres -w sqlobject_test + +[testenv:py27-postgres-pg8000] +commands = {[pg8000]commands} + +[testenv:py34-postgres-pg8000] +commands = {[pg8000]commands} + +[testenv:py35-postgres-pg8000] +commands = {[pg8000]commands} + +[testenv:py36-postgres-pg8000] +commands = {[pg8000]commands} + [postgres-pyodbc] commands = {[testenv]commands} @@ -261,6 +282,7 @@ commands = {[postgres-pypyodbc]commands} [testenv:py36-postgres-pypyodbc] commands = {[postgres-pypyodbc]commands} + # SQLite test environments [sqlite] commands = From 4446696f44d1172ede047a11d89f94c8672c3e25 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 15 Aug 2017 05:42:43 +0300 Subject: [PATCH 096/509] Feat(CI): Add tests for PyGreSQL, py-postgresql and pg8000 at AppVeyor --- appveyor.yml | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++ docs/News.rst | 5 +++ tox.ini | 59 ++++++++++++++++++++++++++- 3 files changed, 173 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index be36b493..6573e069 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -113,6 +113,116 @@ environment: PYTHON_ARCH: "64" db: postgresql TOX_ENV: "py36-postgres-psycopg-w32" + - PYTHON_HOME: "C:\\Python27" + PYTHON_VERSION: "2.7" + PYTHON_ARCH: "32" + db: postgresql + TOX_ENV: "py27-postgres-pygresql-w32" + - PYTHON_HOME: "C:\\Python27-x64" + PYTHON_VERSION: "2.7" + PYTHON_ARCH: "64" + db: postgresql + TOX_ENV: "py27-postgres-pygresql-w32" + - PYTHON_HOME: "C:\\Python34" + PYTHON_VERSION: "3.4" + PYTHON_ARCH: "32" + db: postgresql + TOX_ENV: "py34-postgres-pygresql-w32" + - PYTHON_HOME: "C:\\Python34-x64" + PYTHON_VERSION: "3.4" + PYTHON_ARCH: "64" + db: postgresql + TOX_ENV: "py34-postgres-pygresql-w32" + - PYTHON_HOME: "C:\\Python35" + PYTHON_VERSION: "3.5" + PYTHON_ARCH: "32" + db: postgresql + TOX_ENV: "py35-postgres-pygresql-w32" + - PYTHON_HOME: "C:\\Python35-x64" + PYTHON_VERSION: "3.5" + PYTHON_ARCH: "64" + db: postgresql + TOX_ENV: "py35-postgres-pygresql-w32" + - PYTHON_HOME: "C:\\Python36" + PYTHON_VERSION: "3.6" + PYTHON_ARCH: "32" + db: postgresql + TOX_ENV: "py36-postgres-pygresql-w32" + - PYTHON_HOME: "C:\\Python36-x64" + PYTHON_VERSION: "3.6" + PYTHON_ARCH: "64" + db: postgresql + TOX_ENV: "py36-postgres-pygresql-w32" + - PYTHON_HOME: "C:\\Python34" + PYTHON_VERSION: "3.4" + PYTHON_ARCH: "32" + db: postgresql + TOX_ENV: "py34-pypostgresql-w32" + - PYTHON_HOME: "C:\\Python34-x64" + PYTHON_VERSION: "3.4" + PYTHON_ARCH: "64" + db: postgresql + TOX_ENV: "py34-pypostgresql-w32" + - PYTHON_HOME: "C:\\Python35" + PYTHON_VERSION: "3.5" + PYTHON_ARCH: "32" + db: postgresql + TOX_ENV: "py35-pypostgresql-w32" + - PYTHON_HOME: "C:\\Python35-x64" + PYTHON_VERSION: "3.5" + PYTHON_ARCH: "64" + db: postgresql + TOX_ENV: "py35-pypostgresql-w32" + - PYTHON_HOME: "C:\\Python36" + PYTHON_VERSION: "3.6" + PYTHON_ARCH: "32" + db: postgresql + TOX_ENV: "py36-pypostgresql-w32" + - PYTHON_HOME: "C:\\Python36-x64" + PYTHON_VERSION: "3.6" + PYTHON_ARCH: "64" + db: postgresql + TOX_ENV: "py36-pypostgresql-w32" + - PYTHON_HOME: "C:\\Python27" + PYTHON_VERSION: "2.7" + PYTHON_ARCH: "32" + db: postgresql + TOX_ENV: "py27-postgres-pg8000-w32" + - PYTHON_HOME: "C:\\Python27-x64" + PYTHON_VERSION: "2.7" + PYTHON_ARCH: "64" + db: postgresql + TOX_ENV: "py27-postgres-pg8000-w32" + - PYTHON_HOME: "C:\\Python34" + PYTHON_VERSION: "3.4" + PYTHON_ARCH: "32" + db: postgresql + TOX_ENV: "py34-postgres-pg8000-w32" + - PYTHON_HOME: "C:\\Python34-x64" + PYTHON_VERSION: "3.4" + PYTHON_ARCH: "64" + db: postgresql + TOX_ENV: "py34-postgres-pg8000-w32" + - PYTHON_HOME: "C:\\Python35" + PYTHON_VERSION: "3.5" + PYTHON_ARCH: "32" + db: postgresql + TOX_ENV: "py35-postgres-pg8000-w32" + - PYTHON_HOME: "C:\\Python35-x64" + PYTHON_VERSION: "3.5" + PYTHON_ARCH: "64" + db: postgresql + TOX_ENV: "py35-postgres-pg8000-w32" + - PYTHON_HOME: "C:\\Python36" + PYTHON_VERSION: "3.6" + PYTHON_ARCH: "32" + db: postgresql + TOX_ENV: "py36-postgres-pg8000-w32" + - PYTHON_HOME: "C:\\Python36-x64" + PYTHON_VERSION: "3.6" + PYTHON_ARCH: "64" + db: postgresql + TOX_ENV: "py36-postgres-pg8000-w32" - PYTHON_HOME: "C:\\Python27-x64" PYTHON_VERSION: "2.7" PYTHON_ARCH: "64" diff --git a/docs/News.rst b/docs/News.rst index 6316b544..863d4bee 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -16,6 +16,11 @@ Drivers * Add support for `pg8000 `_ PostgreSQL driver (from git). There is a minor problem with Python 2.7. +Tests +----- + +* Add tests for PyGreSQL, py-postgresql and pg8000 at AppVeyor. + SQLObject 3.4.0 =============== diff --git a/tox.ini b/tox.ini index 76320425..7c5d0ee2 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 1.8 -envlist = py27-{mysqldb,mysql-oursql},py{34,35,36}-{mysqlclient,pypostgresql},py{27,34,35,36}-{mysql-connector,pymysql,mysql-pyodbc,mysql-pypyodbc,postgres-psycopg,postgres-pygresql,postgres-pg8000,postgres-pyodbc,postgres-pypyodbc,sqlite,sqlite-memory},py{27,34,35,36}-{firebird-fdb,firebirdsql},py{27,34}-flake8,py{27,34,35,36}-{mssql-pyodbc,mysql-connector,mysql-pyodbc,mysql-pypyodbc,postgres-psycopg,postgres-pyodbc,postgres-pypyodbc,sqlite,sqlite-memory}-w32 +envlist = py27-{mysqldb,mysql-oursql},py{34,35,36}-{mysqlclient,pypostgresql},py{27,34,35,36}-{mysql-connector,pymysql,mysql-pyodbc,mysql-pypyodbc,postgres-psycopg,postgres-pygresql,postgres-pg8000,postgres-pyodbc,postgres-pypyodbc,sqlite,sqlite-memory},py{27,34,35,36}-{firebird-fdb,firebirdsql},py{27,34}-flake8,py{27,34,35,36}-{mssql-pyodbc,mysql-connector,mysql-pyodbc,mysql-pypyodbc,postgres-psycopg,postgres-pygresql,postgres-pg800,postgres-pyodbc,postgres-pypyodbc,sqlite,sqlite-memory}-w32,py{34,35,36}-pypostgresql-w32 # Base test environment settings [testenv] @@ -481,6 +481,63 @@ commands = {[psycopg-w32]commands} [testenv:py36-postgres-psycopg-w32] commands = {[psycopg-w32]commands} +[pygresql-w32] +commands = + {[testenv]commands} + -dropdb -U postgres -w sqlobject_test + createdb -U postgres -w sqlobject_test + pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + dropdb -U postgres -w sqlobject_test + +[testenv:py27-postgres-pygresql-w32] +commands = {[pygresql-w32]commands} + +[testenv:py34-postgres-pygresql-w32] +commands = {[pygresql-w32]commands} + +[testenv:py35-postgres-pygresql-w32] +commands = {[pygresql-w32]commands} + +[testenv:py36-postgres-pygresql-w32] +commands = {[pygresql-w32]commands} + +[pypostgresql-w32] +commands = + {[testenv]commands} + -dropdb -U postgres -w sqlobject_test + createdb -U postgres -w sqlobject_test + pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + dropdb -U postgres -w sqlobject_test + +[testenv:py34-pypostgresql-w32] +commands = {[pypostgresql-w32]commands} + +[testenv:py35-pypostgresql-w32] +commands = {[pypostgresql-w32]commands} + +[testenv:py36-pypostgresql-w32] +commands = {[pypostgresql-w32]commands} + +[pg8000-w32] +commands = + {[testenv]commands} + -dropdb -U postgres -w sqlobject_test + createdb -U postgres -w sqlobject_test + pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pg8000&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + dropdb -U postgres -w sqlobject_test + +[testenv:py27-postgres-pg8000-w32] +commands = {[pg8000-w32]commands} + +[testenv:py34-postgres-pg8000-w32] +commands = {[pg8000-w32]commands} + +[testenv:py35-postgres-pg8000-w32] +commands = {[pg8000-w32]commands} + +[testenv:py36-postgres-pg8000-w32] +commands = {[pg8000-w32]commands} + [postgres-pyodbc-w32] commands = {[testenv]commands} From 81c84618c9342f1119e97e83cd046446a7de568c Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 18 Aug 2017 22:59:16 +0300 Subject: [PATCH 097/509] Tests(CI): Reorder env vars in appveyor.yml Reorder environment variables in appveyor.yml to make them more visible in the web interface. --- appveyor.yml | 304 +++++++++++++++++++++++++-------------------------- 1 file changed, 152 insertions(+), 152 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 6573e069..0b761950 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -33,254 +33,254 @@ environment: CMD_IN_ENV: "cmd /E:ON /V:ON /C .\\run_with_env.cmd" matrix: - - PYTHON_HOME: "C:\\Python27" - PYTHON_VERSION: "2.7" + - TOX_ENV: "py27-mssql-pyodbc-w32" PYTHON_ARCH: "32" + PYTHON_VERSION: "2.7" + PYTHON_HOME: "C:\\Python27" db: mssql2014 - TOX_ENV: "py27-mssql-pyodbc-w32" - - PYTHON_HOME: "C:\\Python34-x64" - PYTHON_VERSION: "3.4" + - TOX_ENV: "py34-mssql-pyodbc-w32" PYTHON_ARCH: "64" + PYTHON_VERSION: "3.4" + PYTHON_HOME: "C:\\Python34-x64" db: mssql2014 - TOX_ENV: "py34-mssql-pyodbc-w32" - - PYTHON_HOME: "C:\\Python27" - PYTHON_VERSION: "2.7" + - TOX_ENV: "py27-mysql-connector-w32" PYTHON_ARCH: "32" + PYTHON_VERSION: "2.7" + PYTHON_HOME: "C:\\Python27" db: mysql - TOX_ENV: "py27-mysql-connector-w32" - - PYTHON_HOME: "C:\\Python34" - PYTHON_VERSION: "3.4" + - TOX_ENV: "py34-mysql-connector-w32" PYTHON_ARCH: "32" + PYTHON_VERSION: "3.4" + PYTHON_HOME: "C:\\Python34" db: mysql - TOX_ENV: "py34-mysql-connector-w32" - - PYTHON_HOME: "C:\\Python35" - PYTHON_VERSION: "3.5" + - TOX_ENV: "py35-mysql-connector-w32" PYTHON_ARCH: "32" + PYTHON_VERSION: "3.5" + PYTHON_HOME: "C:\\Python35" db: mysql - TOX_ENV: "py35-mysql-connector-w32" - - PYTHON_HOME: "C:\\Python36" - PYTHON_VERSION: "3.6" + - TOX_ENV: "py36-mysql-connector-w32" PYTHON_ARCH: "32" + PYTHON_VERSION: "3.6" + PYTHON_HOME: "C:\\Python36" db: mysql - TOX_ENV: "py36-mysql-connector-w32" - - PYTHON_HOME: "C:\\Python27-x64" - PYTHON_VERSION: "2.7" + - TOX_ENV: "py27-mysql-pyodbc-w32" PYTHON_ARCH: "64" + PYTHON_VERSION: "2.7" + PYTHON_HOME: "C:\\Python27-x64" db: mysql - TOX_ENV: "py27-mysql-pyodbc-w32" - - PYTHON_HOME: "C:\\Python34-x64" - PYTHON_VERSION: "3.4" + - TOX_ENV: "py34-mysql-pyodbc-w32" PYTHON_ARCH: "64" + PYTHON_VERSION: "3.4" + PYTHON_HOME: "C:\\Python34-x64" db: mysql - TOX_ENV: "py34-mysql-pyodbc-w32" - - PYTHON_HOME: "C:\\Python27" - PYTHON_VERSION: "2.7" + - TOX_ENV: "py27-postgres-psycopg-w32" PYTHON_ARCH: "32" - db: postgresql - TOX_ENV: "py27-postgres-psycopg-w32" - - PYTHON_HOME: "C:\\Python27-x64" PYTHON_VERSION: "2.7" + PYTHON_HOME: "C:\\Python27" + db: postgresql + - TOX_ENV: "py27-postgres-psycopg-w32" PYTHON_ARCH: "64" + PYTHON_VERSION: "2.7" + PYTHON_HOME: "C:\\Python27-x64" db: postgresql - TOX_ENV: "py27-postgres-psycopg-w32" - - PYTHON_HOME: "C:\\Python34" - PYTHON_VERSION: "3.4" + - TOX_ENV: "py34-postgres-psycopg-w32" PYTHON_ARCH: "32" - db: postgresql - TOX_ENV: "py34-postgres-psycopg-w32" - - PYTHON_HOME: "C:\\Python34-x64" PYTHON_VERSION: "3.4" + PYTHON_HOME: "C:\\Python34" + db: postgresql + - TOX_ENV: "py34-postgres-psycopg-w32" PYTHON_ARCH: "64" + PYTHON_VERSION: "3.4" + PYTHON_HOME: "C:\\Python34-x64" db: postgresql - TOX_ENV: "py34-postgres-psycopg-w32" - - PYTHON_HOME: "C:\\Python35" - PYTHON_VERSION: "3.5" + - TOX_ENV: "py35-postgres-psycopg-w32" PYTHON_ARCH: "32" - db: postgresql - TOX_ENV: "py35-postgres-psycopg-w32" - - PYTHON_HOME: "C:\\Python35-x64" PYTHON_VERSION: "3.5" + PYTHON_HOME: "C:\\Python35" + db: postgresql + - TOX_ENV: "py35-postgres-psycopg-w32" PYTHON_ARCH: "64" + PYTHON_VERSION: "3.5" + PYTHON_HOME: "C:\\Python35-x64" db: postgresql - TOX_ENV: "py35-postgres-psycopg-w32" - - PYTHON_HOME: "C:\\Python36" - PYTHON_VERSION: "3.6" + - TOX_ENV: "py36-postgres-psycopg-w32" PYTHON_ARCH: "32" - db: postgresql - TOX_ENV: "py36-postgres-psycopg-w32" - - PYTHON_HOME: "C:\\Python36-x64" PYTHON_VERSION: "3.6" + PYTHON_HOME: "C:\\Python36" + db: postgresql + - TOX_ENV: "py36-postgres-psycopg-w32" PYTHON_ARCH: "64" + PYTHON_VERSION: "3.6" + PYTHON_HOME: "C:\\Python36-x64" db: postgresql - TOX_ENV: "py36-postgres-psycopg-w32" - - PYTHON_HOME: "C:\\Python27" - PYTHON_VERSION: "2.7" + - TOX_ENV: "py27-postgres-pygresql-w32" PYTHON_ARCH: "32" - db: postgresql - TOX_ENV: "py27-postgres-pygresql-w32" - - PYTHON_HOME: "C:\\Python27-x64" PYTHON_VERSION: "2.7" + PYTHON_HOME: "C:\\Python27" + db: postgresql + - TOX_ENV: "py27-postgres-pygresql-w32" PYTHON_ARCH: "64" + PYTHON_VERSION: "2.7" + PYTHON_HOME: "C:\\Python27-x64" db: postgresql - TOX_ENV: "py27-postgres-pygresql-w32" - - PYTHON_HOME: "C:\\Python34" - PYTHON_VERSION: "3.4" + - TOX_ENV: "py34-postgres-pygresql-w32" PYTHON_ARCH: "32" - db: postgresql - TOX_ENV: "py34-postgres-pygresql-w32" - - PYTHON_HOME: "C:\\Python34-x64" PYTHON_VERSION: "3.4" + PYTHON_HOME: "C:\\Python34" + db: postgresql + - TOX_ENV: "py34-postgres-pygresql-w32" PYTHON_ARCH: "64" + PYTHON_VERSION: "3.4" + PYTHON_HOME: "C:\\Python34-x64" db: postgresql - TOX_ENV: "py34-postgres-pygresql-w32" - - PYTHON_HOME: "C:\\Python35" - PYTHON_VERSION: "3.5" + - TOX_ENV: "py35-postgres-pygresql-w32" PYTHON_ARCH: "32" - db: postgresql - TOX_ENV: "py35-postgres-pygresql-w32" - - PYTHON_HOME: "C:\\Python35-x64" PYTHON_VERSION: "3.5" + PYTHON_HOME: "C:\\Python35" + db: postgresql + - TOX_ENV: "py35-postgres-pygresql-w32" PYTHON_ARCH: "64" + PYTHON_VERSION: "3.5" + PYTHON_HOME: "C:\\Python35-x64" db: postgresql - TOX_ENV: "py35-postgres-pygresql-w32" - - PYTHON_HOME: "C:\\Python36" - PYTHON_VERSION: "3.6" + - TOX_ENV: "py36-postgres-pygresql-w32" PYTHON_ARCH: "32" - db: postgresql - TOX_ENV: "py36-postgres-pygresql-w32" - - PYTHON_HOME: "C:\\Python36-x64" PYTHON_VERSION: "3.6" + PYTHON_HOME: "C:\\Python36" + db: postgresql + - TOX_ENV: "py36-postgres-pygresql-w32" PYTHON_ARCH: "64" + PYTHON_VERSION: "3.6" + PYTHON_HOME: "C:\\Python36-x64" db: postgresql - TOX_ENV: "py36-postgres-pygresql-w32" - - PYTHON_HOME: "C:\\Python34" - PYTHON_VERSION: "3.4" + - TOX_ENV: "py34-pypostgresql-w32" PYTHON_ARCH: "32" - db: postgresql - TOX_ENV: "py34-pypostgresql-w32" - - PYTHON_HOME: "C:\\Python34-x64" PYTHON_VERSION: "3.4" + PYTHON_HOME: "C:\\Python34" + db: postgresql + - TOX_ENV: "py34-pypostgresql-w32" PYTHON_ARCH: "64" + PYTHON_VERSION: "3.4" + PYTHON_HOME: "C:\\Python34-x64" db: postgresql - TOX_ENV: "py34-pypostgresql-w32" - - PYTHON_HOME: "C:\\Python35" - PYTHON_VERSION: "3.5" + - TOX_ENV: "py35-pypostgresql-w32" PYTHON_ARCH: "32" - db: postgresql - TOX_ENV: "py35-pypostgresql-w32" - - PYTHON_HOME: "C:\\Python35-x64" PYTHON_VERSION: "3.5" + PYTHON_HOME: "C:\\Python35" + db: postgresql + - TOX_ENV: "py35-pypostgresql-w32" PYTHON_ARCH: "64" + PYTHON_VERSION: "3.5" + PYTHON_HOME: "C:\\Python35-x64" db: postgresql - TOX_ENV: "py35-pypostgresql-w32" - - PYTHON_HOME: "C:\\Python36" - PYTHON_VERSION: "3.6" + - TOX_ENV: "py36-pypostgresql-w32" PYTHON_ARCH: "32" - db: postgresql - TOX_ENV: "py36-pypostgresql-w32" - - PYTHON_HOME: "C:\\Python36-x64" PYTHON_VERSION: "3.6" + PYTHON_HOME: "C:\\Python36" + db: postgresql + - TOX_ENV: "py36-pypostgresql-w32" PYTHON_ARCH: "64" + PYTHON_VERSION: "3.6" + PYTHON_HOME: "C:\\Python36-x64" db: postgresql - TOX_ENV: "py36-pypostgresql-w32" - - PYTHON_HOME: "C:\\Python27" - PYTHON_VERSION: "2.7" + - TOX_ENV: "py27-postgres-pg8000-w32" PYTHON_ARCH: "32" - db: postgresql - TOX_ENV: "py27-postgres-pg8000-w32" - - PYTHON_HOME: "C:\\Python27-x64" PYTHON_VERSION: "2.7" + PYTHON_HOME: "C:\\Python27" + db: postgresql + - TOX_ENV: "py27-postgres-pg8000-w32" PYTHON_ARCH: "64" + PYTHON_VERSION: "2.7" + PYTHON_HOME: "C:\\Python27-x64" db: postgresql - TOX_ENV: "py27-postgres-pg8000-w32" - - PYTHON_HOME: "C:\\Python34" - PYTHON_VERSION: "3.4" + - TOX_ENV: "py34-postgres-pg8000-w32" PYTHON_ARCH: "32" - db: postgresql - TOX_ENV: "py34-postgres-pg8000-w32" - - PYTHON_HOME: "C:\\Python34-x64" PYTHON_VERSION: "3.4" + PYTHON_HOME: "C:\\Python34" + db: postgresql + - TOX_ENV: "py34-postgres-pg8000-w32" PYTHON_ARCH: "64" + PYTHON_VERSION: "3.4" + PYTHON_HOME: "C:\\Python34-x64" db: postgresql - TOX_ENV: "py34-postgres-pg8000-w32" - - PYTHON_HOME: "C:\\Python35" - PYTHON_VERSION: "3.5" + - TOX_ENV: "py35-postgres-pg8000-w32" PYTHON_ARCH: "32" - db: postgresql - TOX_ENV: "py35-postgres-pg8000-w32" - - PYTHON_HOME: "C:\\Python35-x64" PYTHON_VERSION: "3.5" + PYTHON_HOME: "C:\\Python35" + db: postgresql + - TOX_ENV: "py35-postgres-pg8000-w32" PYTHON_ARCH: "64" + PYTHON_VERSION: "3.5" + PYTHON_HOME: "C:\\Python35-x64" db: postgresql - TOX_ENV: "py35-postgres-pg8000-w32" - - PYTHON_HOME: "C:\\Python36" - PYTHON_VERSION: "3.6" + - TOX_ENV: "py36-postgres-pg8000-w32" PYTHON_ARCH: "32" - db: postgresql - TOX_ENV: "py36-postgres-pg8000-w32" - - PYTHON_HOME: "C:\\Python36-x64" PYTHON_VERSION: "3.6" + PYTHON_HOME: "C:\\Python36" + db: postgresql + - TOX_ENV: "py36-postgres-pg8000-w32" PYTHON_ARCH: "64" + PYTHON_VERSION: "3.6" + PYTHON_HOME: "C:\\Python36-x64" db: postgresql - TOX_ENV: "py36-postgres-pg8000-w32" - - PYTHON_HOME: "C:\\Python27-x64" - PYTHON_VERSION: "2.7" + - TOX_ENV: "py27-postgres-pyodbc-w32" PYTHON_ARCH: "64" + PYTHON_VERSION: "2.7" + PYTHON_HOME: "C:\\Python27-x64" db: postgresql - TOX_ENV: "py27-postgres-pyodbc-w32" - - PYTHON_HOME: "C:\\Python34-x64" - PYTHON_VERSION: "3.4" + - TOX_ENV: "py34-postgres-pyodbc-w32" PYTHON_ARCH: "64" + PYTHON_VERSION: "3.4" + PYTHON_HOME: "C:\\Python34-x64" db: postgresql - TOX_ENV: "py34-postgres-pyodbc-w32" - - PYTHON_HOME: "C:\\Python27" - PYTHON_VERSION: "2.7" + - TOX_ENV: "py27-sqlite-w32" PYTHON_ARCH: "32" - TOX_ENV: "py27-sqlite-w32" - - PYTHON_HOME: "C:\\Python27-x64" PYTHON_VERSION: "2.7" + PYTHON_HOME: "C:\\Python27" + - TOX_ENV: "py27-sqlite-w32" PYTHON_ARCH: "64" - TOX_ENV: "py27-sqlite-w32" - - PYTHON_HOME: "C:\\Python34" - PYTHON_VERSION: "3.4" + PYTHON_VERSION: "2.7" + PYTHON_HOME: "C:\\Python27-x64" + - TOX_ENV: "py34-sqlite-w32" PYTHON_ARCH: "32" - TOX_ENV: "py34-sqlite-w32" - - PYTHON_HOME: "C:\\Python34-x64" PYTHON_VERSION: "3.4" + PYTHON_HOME: "C:\\Python34" + - TOX_ENV: "py34-sqlite-w32" PYTHON_ARCH: "64" - TOX_ENV: "py34-sqlite-w32" - - PYTHON_HOME: "C:\\Python35" - PYTHON_VERSION: "3.5" + PYTHON_VERSION: "3.4" + PYTHON_HOME: "C:\\Python34-x64" + - TOX_ENV: "py35-sqlite-w32" PYTHON_ARCH: "32" - TOX_ENV: "py35-sqlite-w32" - - PYTHON_HOME: "C:\\Python35-x64" PYTHON_VERSION: "3.5" + PYTHON_HOME: "C:\\Python35" + - TOX_ENV: "py35-sqlite-w32" PYTHON_ARCH: "64" - TOX_ENV: "py35-sqlite-w32" - - PYTHON_HOME: "C:\\Python36" - PYTHON_VERSION: "3.6" + PYTHON_VERSION: "3.5" + PYTHON_HOME: "C:\\Python35-x64" + - TOX_ENV: "py36-sqlite-w32" PYTHON_ARCH: "32" - TOX_ENV: "py36-sqlite-w32" - - PYTHON_HOME: "C:\\Python36-x64" PYTHON_VERSION: "3.6" + PYTHON_HOME: "C:\\Python36" + - TOX_ENV: "py36-sqlite-w32" PYTHON_ARCH: "64" - TOX_ENV: "py36-sqlite-w32" - - PYTHON_HOME: "C:\\Python27" - PYTHON_VERSION: "2.7" + PYTHON_VERSION: "3.6" + PYTHON_HOME: "C:\\Python36-x64" + - TOX_ENV: "py27-sqlite-memory-w32" PYTHON_ARCH: "32" - TOX_ENV: "py27-sqlite-memory-w32" - - PYTHON_HOME: "C:\\Python34-x64" - PYTHON_VERSION: "3.4" + PYTHON_VERSION: "2.7" + PYTHON_HOME: "C:\\Python27" + - TOX_ENV: "py34-sqlite-memory-w32" PYTHON_ARCH: "64" - TOX_ENV: "py34-sqlite-memory-w32" - - PYTHON_HOME: "C:\\Python35" - PYTHON_VERSION: "3.5" + PYTHON_VERSION: "3.4" + PYTHON_HOME: "C:\\Python34-x64" + - TOX_ENV: "py35-sqlite-memory-w32" PYTHON_ARCH: "32" - TOX_ENV: "py35-sqlite-memory-w32" - - PYTHON_HOME: "C:\\Python36-x64" - PYTHON_VERSION: "3.6" + PYTHON_VERSION: "3.5" + PYTHON_HOME: "C:\\Python35" + - TOX_ENV: "py36-sqlite-memory-w32" PYTHON_ARCH: "64" - TOX_ENV: "py36-sqlite-memory-w32" + PYTHON_VERSION: "3.6" + PYTHON_HOME: "C:\\Python36-x64" install: # Ensure we use the right python version From b06e2072ce95012ed04810ae951b08be19115aaa Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 18 Aug 2017 22:59:16 +0300 Subject: [PATCH 098/509] Tests(CI): Remove PyGreSQL tests with 32-bit Python 32-bit PyGreSQL requires 32-bit libraries for PostgreSQL, but AppVeyor has only 64-bit Pg preinstalled. --- appveyor.yml | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 0b761950..12ae77d8 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -113,41 +113,21 @@ environment: PYTHON_VERSION: "3.6" PYTHON_HOME: "C:\\Python36-x64" db: postgresql - - TOX_ENV: "py27-postgres-pygresql-w32" - PYTHON_ARCH: "32" - PYTHON_VERSION: "2.7" - PYTHON_HOME: "C:\\Python27" - db: postgresql - TOX_ENV: "py27-postgres-pygresql-w32" PYTHON_ARCH: "64" PYTHON_VERSION: "2.7" PYTHON_HOME: "C:\\Python27-x64" db: postgresql - - TOX_ENV: "py34-postgres-pygresql-w32" - PYTHON_ARCH: "32" - PYTHON_VERSION: "3.4" - PYTHON_HOME: "C:\\Python34" - db: postgresql - TOX_ENV: "py34-postgres-pygresql-w32" PYTHON_ARCH: "64" PYTHON_VERSION: "3.4" PYTHON_HOME: "C:\\Python34-x64" db: postgresql - - TOX_ENV: "py35-postgres-pygresql-w32" - PYTHON_ARCH: "32" - PYTHON_VERSION: "3.5" - PYTHON_HOME: "C:\\Python35" - db: postgresql - TOX_ENV: "py35-postgres-pygresql-w32" PYTHON_ARCH: "64" PYTHON_VERSION: "3.5" PYTHON_HOME: "C:\\Python35-x64" db: postgresql - - TOX_ENV: "py36-postgres-pygresql-w32" - PYTHON_ARCH: "32" - PYTHON_VERSION: "3.6" - PYTHON_HOME: "C:\\Python36" - db: postgresql - TOX_ENV: "py36-postgres-pygresql-w32" PYTHON_ARCH: "64" PYTHON_VERSION: "3.6" From ea7d88912f90a2bfc23d444554c968bc8515e944 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 19 Aug 2017 03:33:36 +0300 Subject: [PATCH 099/509] Feat(setup): Add keywords and platforms --- setup.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup.py b/setup.py index f9fe8029..cba0bf3d 100755 --- a/setup.py +++ b/setup.py @@ -121,7 +121,9 @@ maintainer_email="phd@phdru.name", url="http://sqlobject.org/", download_url="https://pypi.python.org/pypi/SQLObject/%s" % version, + keywords=["sql", "orm", "object-relational mapper"], license="LGPL", + platforms="Any", packages=["sqlobject"] + ['sqlobject.%s' % package for package in subpackages], scripts=["scripts/sqlobject-admin", "scripts/sqlobject-convertOldURI"], From ec4889a8c1b02cddc90cd62b6ead36e87d4222b0 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 23 Aug 2017 09:46:12 +0300 Subject: [PATCH 100/509] Tests(CI): Fix bugs in py-postgresql at AppVeyor --- docs/News.rst | 3 +++ tox.ini | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/News.rst b/docs/News.rst index 863d4bee..22094c40 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -21,6 +21,9 @@ Tests * Add tests for PyGreSQL, py-postgresql and pg8000 at AppVeyor. +* Fixed bugs in py-postgresql at AppVeyor. SQLObject requires + the latest version of the driver from git. + SQLObject 3.4.0 =============== diff --git a/tox.ini b/tox.ini index 7c5d0ee2..51231c35 100644 --- a/tox.ini +++ b/tox.ini @@ -25,7 +25,7 @@ deps = pymysql: pymysql postgres-psycopg: psycopg2 postgres-pygresql: pygresql - pypostgresql: py-postgresql + pypostgresql: git+https://github.com/sqlobject/py-postgresql.git@fix_w32#egg=pypostgresql postgres-pg8000: git+https://github.com/mfenniak/pg8000.git#egg=pg8000 pyodbc: pyodbc pypyodbc: pypyodbc From e3e522ec5fb30e4dde949828ba233bfe45144171 Mon Sep 17 00:00:00 2001 From: Shailesh Mungikar Date: Sat, 23 Sep 2017 16:40:54 +0530 Subject: [PATCH 101/509] Fix for #139: autoreconnect does not work with pymysql driver --- ANNOUNCE.rst | 2 +- docs/Authors.rst | 1 + docs/News.rst | 2 ++ sqlobject/mysql/mysqlconnection.py | 11 +++++++++++ 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 893d3972..31ffed8a 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -22,7 +22,7 @@ I'm pleased to announce version 3.4.1, the first bugfix release of branch What's new in SQLObject ======================= -Contributor for this release is +Contributor for this release is Shailesh Mungikar. For a more complete list, please see the news: http://sqlobject.org/News.html diff --git a/docs/Authors.rst b/docs/Authors.rst index cf35dfc1..1d0a0638 100644 --- a/docs/Authors.rst +++ b/docs/Authors.rst @@ -34,6 +34,7 @@ Contributions have been made by: * Gregor Horvath * Nathan Edwards * Lutz Steinborn +* Shailesh Mungikar * Oleg Broytman .. image:: https://sourceforge.net/sflogo.php?group_id=74338&type=10 diff --git a/docs/News.rst b/docs/News.rst index 22094c40..a2e2b259 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -16,6 +16,8 @@ Drivers * Add support for `pg8000 `_ PostgreSQL driver (from git). There is a minor problem with Python 2.7. +* Fix autoreconnect with pymysql driver. Contributed by Shailesh Mungikar. + Tests ----- diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index eb56223b..bcda0544 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -206,6 +206,13 @@ def _setAutoCommit(self, conn, auto): # mysql-connector has autocommit as a property conn.autocommit = auto + def _force_reconnect(self, conn): + if self.driver.lower() == 'pymysql': + conn.ping(True) + self._setAutoCommit(conn, bool(self.autoCommit)) + if self.dbEncoding: + conn.query("SET NAMES %s" % self.dbEncoding) + def _executeRetry(self, conn, cursor, query): if self.debug: self.printDebug(conn, query, 'QueryR') @@ -225,6 +232,8 @@ def _executeRetry(self, conn, cursor, query): # reconnect flag must be set when making the connection to indicate # that autoreconnecting is desired. In MySQLdb 1.2.2 or newer this is # done by calling ping(True) on the connection. + # PyMySQL needs explicit reconnect + # each time we detect connection timeout. for count in range(3): try: return cursor.execute(query) @@ -235,6 +244,8 @@ def _executeRetry(self, conn, cursor, query): raise dberrors.OperationalError(ErrorMessage(e)) if self.debug: self.printDebug(conn, str(e), 'ERROR') + if self.driver.lower() == 'pymysql': + self._force_reconnect(conn) else: raise dberrors.OperationalError(ErrorMessage(e)) except self.module.IntegrityError as e: From 8fb6fd7e3dbc0073665929f59fd4230c9af296f3 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 3 Oct 2017 23:00:30 +0300 Subject: [PATCH 102/509] Tests(CI): Explicitly list python versions --- .travis.yml | 145 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 96 insertions(+), 49 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3b18a1ce..60548f8b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ sudo: required language: python python: - - "3.6" + - "2.7" cache: pip @@ -24,55 +24,101 @@ addons: - firebird2.5-super postgresql: "9.4" -env: - - TOXENV=py27-mysqldb - - TOXENV=py34-mysqlclient - - TOXENV=py35-mysqlclient - - TOXENV=py36-mysqlclient - - TOXENV=py27-mysql-connector - - TOXENV=py34-mysql-connector - - TOXENV=py35-mysql-connector - - TOXENV=py36-mysql-connector - - TOXENV=py27-mysql-oursql - - TOXENV=py27-pymysql - - TOXENV=py34-pymysql - - TOXENV=py35-pymysql - - TOXENV=py36-pymysql - - TOXENV=py27-postgres-psycopg - - TOXENV=py34-postgres-psycopg - - TOXENV=py35-postgres-psycopg - - TOXENV=py36-postgres-psycopg - - TOXENV=py27-postgres-pygresql - - TOXENV=py34-postgres-pygresql - - TOXENV=py35-postgres-pygresql - - TOXENV=py36-postgres-pygresql - - TOXENV=py34-pypostgresql - - TOXENV=py35-pypostgresql - - TOXENV=py36-pypostgresql - - TOXENV=py27-postgres-pg8000 - - TOXENV=py34-postgres-pg8000 - - TOXENV=py35-postgres-pg8000 - - TOXENV=py36-postgres-pg8000 - - TOXENV=py27-sqlite - - TOXENV=py34-sqlite - - TOXENV=py35-sqlite - - TOXENV=py36-sqlite - - TOXENV=py27-sqlite-memory - - TOXENV=py34-sqlite-memory - - TOXENV=py35-sqlite-memory - - TOXENV=py36-sqlite-memory - - TOXENV=py27-flake8 - - TOXENV=py34-flake8 - - TOXENV=py27-firebird-fdb - - TOXENV=py34-firebird-fdb - - TOXENV=py35-firebird-fdb - - TOXENV=py36-firebird-fdb - - TOXENV=py27-firebirdsql - - TOXENV=py34-firebirdsql - - TOXENV=py35-firebirdsql - - TOXENV=py36-firebirdsql - matrix: + include: + - python: "2.7" + env: TOXENV=py27-mysqldb + - python: "3.4" + env: TOXENV=py34-mysqlclient + - python: "3.5" + env: TOXENV=py35-mysqlclient + - python: "3.6" + env: TOXENV=py36-mysqlclient + - python: "2.7" + env: TOXENV=py27-mysql-connector + - python: "3.4" + env: TOXENV=py34-mysql-connector + - python: "3.5" + env: TOXENV=py35-mysql-connector + - python: "3.6" + env: TOXENV=py36-mysql-connector + - python: "2.7" + env: TOXENV=py27-mysql-oursql + - python: "2.7" + env: TOXENV=py27-pymysql + - python: "3.4" + env: TOXENV=py34-pymysql + - python: "3.5" + env: TOXENV=py35-pymysql + - python: "3.6" + env: TOXENV=py36-pymysql + - python: "2.7" + env: TOXENV=py27-postgres-psycopg + - python: "3.4" + env: TOXENV=py34-postgres-psycopg + - python: "3.5" + env: TOXENV=py35-postgres-psycopg + - python: "3.6" + env: TOXENV=py36-postgres-psycopg + - python: "2.7" + env: TOXENV=py27-postgres-pygresql + - python: "3.4" + env: TOXENV=py34-postgres-pygresql + - python: "3.5" + env: TOXENV=py35-postgres-pygresql + - python: "3.6" + env: TOXENV=py36-postgres-pygresql + - python: "3.4" + env: TOXENV=py34-pypostgresql + - python: "3.5" + env: TOXENV=py35-pypostgresql + - python: "3.6" + env: TOXENV=py36-pypostgresql + - python: "2.7" + env: TOXENV=py27-postgres-pg8000 + - python: "3.4" + env: TOXENV=py34-postgres-pg8000 + - python: "3.5" + env: TOXENV=py35-postgres-pg8000 + - python: "3.6" + env: TOXENV=py36-postgres-pg8000 + - python: "2.7" + env: TOXENV=py27-sqlite + - python: "3.4" + env: TOXENV=py34-sqlite + - python: "3.5" + env: TOXENV=py35-sqlite + - python: "3.6" + env: TOXENV=py36-sqlite + - python: "2.7" + env: TOXENV=py27-sqlite-memory + - python: "3.4" + env: TOXENV=py34-sqlite-memory + - python: "3.5" + env: TOXENV=py35-sqlite-memory + - python: "3.6" + env: TOXENV=py36-sqlite-memory + - python: "2.7" + env: TOXENV=py27-flake8 + - python: "3.4" + env: TOXENV=py34-flake8 + - python: "2.7" + env: TOXENV=py27-firebird-fdb + - python: "3.4" + env: TOXENV=py34-firebird-fdb + - python: "3.5" + env: TOXENV=py35-firebird-fdb + - python: "3.6" + env: TOXENV=py36-firebird-fdb + - python: "2.7" + env: TOXENV=py27-firebirdsql + - python: "3.4" + env: TOXENV=py34-firebirdsql + - python: "3.5" + env: TOXENV=py35-firebirdsql + - python: "3.6" + env: TOXENV=py36-firebirdsql + allow_failures: - env: TOXENV=py27-postgres-pg8000 - env: TOXENV=py27-firebird-fdb @@ -83,6 +129,7 @@ matrix: - env: TOXENV=py34-firebirdsql - env: TOXENV=py35-firebirdsql - env: TOXENV=py36-firebirdsql + fast_finish: true before_install: From 1a508237f38b2995eee7637924316ba85875ea22 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 5 Oct 2017 19:46:17 +0300 Subject: [PATCH 103/509] Drivers(SapDB): Update download URLs [skip ci] --- sqlobject/maxdb/readme.txt | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/sqlobject/maxdb/readme.txt b/sqlobject/maxdb/readme.txt index 3984fbd8..03fd001d 100644 --- a/sqlobject/maxdb/readme.txt +++ b/sqlobject/maxdb/readme.txt @@ -7,24 +7,21 @@ Author: Edigram SA - Paris France Tel:0144779400 -SAPDBAPI installation +SAPDBAPI installation --------------------- + The sapdb module can be downloaded from: Win32 -------- - -ftp://ftp.sap.com/pub/sapdb/bin/win/sapdb-python-win32-7.4.03.31a.zip - - -Linux ------- - -ftp://ftp.sap.com/pub/sapdb/bin/linux/sapdb-python-linux-i386-7.4.03.31a.tgz +----- +ftp://ftp.sap.com/pub/sapdb/bin/win/sapdb-python-win32-7.4.03.33a.zip -uncompress the archive and add the sapdb directory path to your PYTHONPATH. +Linux +----- +ftp://ftp.sap.com/pub/sapdb/bin/linux/sapdb-python-linux-i386-7.4.03.33a.tgz +Uncompress the archive and add the sapdb directory path to your PYTHONPATH. From be6d94db711c29c09a945a1d3294dba7d5fdbb25 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 5 Oct 2017 19:46:17 +0300 Subject: [PATCH 104/509] Drivers(SapDB): Convert readme.txt to Unix EOL format (LF) [skip ci] --- sqlobject/maxdb/readme.txt | 54 +++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/sqlobject/maxdb/readme.txt b/sqlobject/maxdb/readme.txt index 03fd001d..e1129834 100644 --- a/sqlobject/maxdb/readme.txt +++ b/sqlobject/maxdb/readme.txt @@ -1,27 +1,27 @@ -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -Author: -Edigram SA - Paris France -Tel:0144779400 - -SAPDBAPI installation ---------------------- - -The sapdb module can be downloaded from: - -Win32 ------ - -ftp://ftp.sap.com/pub/sapdb/bin/win/sapdb-python-win32-7.4.03.33a.zip - - -Linux ------ - -ftp://ftp.sap.com/pub/sapdb/bin/linux/sapdb-python-linux-i386-7.4.03.33a.tgz - - -Uncompress the archive and add the sapdb directory path to your PYTHONPATH. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +Author: +Edigram SA - Paris France +Tel:0144779400 + +SAPDBAPI installation +--------------------- + +The sapdb module can be downloaded from: + +Win32 +----- + +ftp://ftp.sap.com/pub/sapdb/bin/win/sapdb-python-win32-7.4.03.33a.zip + + +Linux +----- + +ftp://ftp.sap.com/pub/sapdb/bin/linux/sapdb-python-linux-i386-7.4.03.33a.tgz + + +Uncompress the archive and add the sapdb directory path to your PYTHONPATH. From 28c2a5de93940dd7ea540a372d35dd7fa8153267 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 20 Oct 2017 22:36:26 +0300 Subject: [PATCH 105/509] Tests(tox): Use our fork of pg8000 --- docs/News.rst | 3 ++- tox.ini | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index a2e2b259..978572be 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -14,7 +14,8 @@ Drivers ------- * Add support for `pg8000 `_ - PostgreSQL driver (from git). There is a minor problem with Python 2.7. + PostgreSQL driver (from our fork). There is a minor problem + with Python 2.7. * Fix autoreconnect with pymysql driver. Contributed by Shailesh Mungikar. diff --git a/tox.ini b/tox.ini index 51231c35..828dff1c 100644 --- a/tox.ini +++ b/tox.ini @@ -26,7 +26,7 @@ deps = postgres-psycopg: psycopg2 postgres-pygresql: pygresql pypostgresql: git+https://github.com/sqlobject/py-postgresql.git@fix_w32#egg=pypostgresql - postgres-pg8000: git+https://github.com/mfenniak/pg8000.git#egg=pg8000 + postgres-pg8000: git+https://github.com/sqlobject/pg8000.git@getuser#egg=pg8000 pyodbc: pyodbc pypyodbc: pypyodbc firebird-fdb: fdb From df609592bd34c6c7a496ee636ca4d0fe398d3782 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 22 Oct 2017 01:14:09 +0300 Subject: [PATCH 106/509] Fix(devscripts): Remove circle.yml from MANIFEST.in We've stopped using Circle CI. [skip ci] --- MANIFEST.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MANIFEST.in b/MANIFEST.in index 32ac686f..cb6c6a70 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,6 +1,6 @@ global-include *.py *.rst *.txt recursive-include docs *.css *.html *.js *.gif *.png -include LICENSE MANIFEST.in .travis.yml circle.yml tox.ini +include LICENSE MANIFEST.in .travis.yml tox.ini include debian/* sqlobject/.coveragerc include docs/Makefile docs/genapidocs docs/rebuild recursive-exclude devscripts * From a270c35db17fc66f414a526b0fba549b0e83706c Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 24 Oct 2017 00:14:06 +0300 Subject: [PATCH 107/509] Cleanup: Fix flake8 E722 do not use bare except --- sqlobject/col.py | 14 +++++++------- sqlobject/dbconnection.py | 2 +- sqlobject/inheritance/__init__.py | 2 +- sqlobject/inheritance/tests/test_inheritance.py | 2 +- sqlobject/manager/command.py | 2 +- sqlobject/mssql/mssqlconnection.py | 2 +- sqlobject/mysql/mysqlconnection.py | 2 +- sqlobject/tests/test_auto.py | 2 +- 8 files changed, 14 insertions(+), 14 deletions(-) diff --git a/sqlobject/col.py b/sqlobject/col.py index 0f358628..67719461 100644 --- a/sqlobject/col.py +++ b/sqlobject/col.py @@ -701,7 +701,7 @@ def to_python(self, value, state): if hasattr(value, attr_name): try: return converter(value) - except: + except Exception: break raise validators.Invalid( "expected an int in the IntCol '%s', got %s %r instead" % ( @@ -855,7 +855,7 @@ def to_python(self, value, state): if hasattr(value, attr_name): try: return converter(value) - except: + except Exception: break raise validators.Invalid( "expected a float in the FloatCol '%s', got %s %r instead" % ( @@ -1213,7 +1213,7 @@ def from_python(self, value, state): value = (value,) try: return ",".join(value) - except: + except Exception: raise validators.Invalid( "expected a string or a sequence of strings " "in the SetCol '%s', got %s %r instead" % ( @@ -1284,7 +1284,7 @@ def to_python(self, value, state): else: value += '.0' return datetime.datetime.strptime(value, self.format) - except: + except Exception: raise validators.Invalid( "expected a date/time string of the '%s' format " "in the DateTimeCol '%s', got %s %r instead" % ( @@ -1345,7 +1345,7 @@ def to_python(self, value, state): return DateTime.DateTime(value.year, value.month, value.day, value.hour, value.minute, value.second) - except: + except Exception: raise validators.Invalid( "expected a date/time string of the '%s' format " "in the DateTimeCol '%s', got %s %r instead" % ( @@ -1625,7 +1625,7 @@ def to_python(self, value, state): value = value.replace(connection.decimalSeparator, ".") try: return Decimal(value) - except: + except Exception: raise validators.Invalid( "expected a Decimal in the DecimalCol '%s', " "got %s %r instead" % ( @@ -1646,7 +1646,7 @@ def from_python(self, value, state): value = value.replace(connection.decimalSeparator, ".") try: return Decimal(value) - except: + except Exception: raise validators.Invalid( "can not parse Decimal value '%s' " "in the DecimalCol from '%s'" % ( diff --git a/sqlobject/dbconnection.py b/sqlobject/dbconnection.py index ff905f64..41e9b6a0 100644 --- a/sqlobject/dbconnection.py +++ b/sqlobject/dbconnection.py @@ -1006,7 +1006,7 @@ def doInTransaction(self, func, *args, **kw): try: try: value = func(*args, **kw) - except: + except Exception: conn.rollback() raise else: diff --git a/sqlobject/inheritance/__init__.py b/sqlobject/inheritance/__init__.py index a1340d4a..f340e790 100644 --- a/sqlobject/inheritance/__init__.py +++ b/sqlobject/inheritance/__init__.py @@ -411,7 +411,7 @@ def _create(self, id, **kw): # TC: the parent if the child can not be created. try: super(InheritableSQLObject, self)._create(id, **kw) - except: + except Exception: # If we are outside a transaction and this is a child, # destroy the parent connection = self._connection diff --git a/sqlobject/inheritance/tests/test_inheritance.py b/sqlobject/inheritance/tests/test_inheritance.py index e1d51fa9..2f5930ed 100644 --- a/sqlobject/inheritance/tests/test_inheritance.py +++ b/sqlobject/inheritance/tests/test_inheritance.py @@ -79,7 +79,7 @@ def test_inheritance_select(): try: person = InheritablePerson.byLastName("Oneof") - except: + except Exception: pass else: raise RuntimeError("unknown person %s" % person) diff --git a/sqlobject/manager/command.py b/sqlobject/manager/command.py index 2b7bc21d..e79053fb 100755 --- a/sqlobject/manager/command.py +++ b/sqlobject/manager/command.py @@ -1227,7 +1227,7 @@ def command(self): if not sim: try: conn.query(sql) - except: + except Exception: print("Error in script: %s" % upgrader) raise self.update_db(next_version, conn) diff --git a/sqlobject/mssql/mssqlconnection.py b/sqlobject/mssql/mssqlconnection.py index 811dcd81..0201031d 100644 --- a/sqlobject/mssql/mssqlconnection.py +++ b/sqlobject/mssql/mssqlconnection.py @@ -376,7 +376,7 @@ def server_version(self): server_version = server_version.decode('ascii') server_version = server_version.split('.')[0] server_version = int(server_version) - except: + except Exception: server_version = None # unknown self._server_version = server_version return server_version diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index bcda0544..ba7e7264 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -462,7 +462,7 @@ def server_version(self): server_version = server_version[0] server_version = tuple(int(v) for v in server_version.split('.')) server_version = (server_version, db_tag) - except: + except Exception: server_version = None # unknown self._server_version = server_version return server_version diff --git a/sqlobject/tests/test_auto.py b/sqlobject/tests/test_auto.py index e58ab1ae..8a576949 100644 --- a/sqlobject/tests/test_auto.py +++ b/sqlobject/tests/test_auto.py @@ -193,7 +193,7 @@ def teardown_method(self, meth): if dropper: try: conn.query(dropper) - except: # Perhaps we don't have DROP permission + except Exception: # Perhaps we don't have DROP permission pass def test_classCreate(self): From 1ded887f420a85eb243f6e9db76e3c70f8934e8d Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 24 Oct 2017 00:24:21 +0300 Subject: [PATCH 108/509] Cleanup: Fix flake8 E741 ambiguous variable name 'l' --- sqlobject/tests/test_auto.py | 6 +++--- sqlobject/tests/test_enum.py | 34 +++++++++++++++++----------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/sqlobject/tests/test_auto.py b/sqlobject/tests/test_auto.py index 8a576949..a97e1a8d 100644 --- a/sqlobject/tests/test_auto.py +++ b/sqlobject/tests/test_auto.py @@ -62,9 +62,9 @@ def test_dynamicJoin(self): phone.person = Person.selectBy(name='tim')[0] else: phone.person = Person.selectBy(name='bob')[0] - l = [p.phone for p in Person.selectBy(name='tim')[0].phones] - l.sort() - assert l == ['555-394-2930', '555-555-5555'] + _l = [p.phone for p in Person.selectBy(name='tim')[0].phones] + _l.sort() + assert _l == ['555-394-2930', '555-555-5555'] Phone.sqlmeta.delColumn(col, changeSchema=True) Person.sqlmeta.delJoin(join) diff --git a/sqlobject/tests/test_enum.py b/sqlobject/tests/test_enum.py index d5cba13c..bf2078e4 100644 --- a/sqlobject/tests/test_enum.py +++ b/sqlobject/tests/test_enum.py @@ -10,66 +10,66 @@ class Enum1(SQLObject): - l = EnumCol(enumValues=['a', 'bcd', 'e']) + cl = EnumCol(enumValues=['a', 'bcd', 'e']) def testBad(): setupClass(Enum1) - for l in ['a', 'bcd', 'a', 'e']: - Enum1(l=l) + for _l in ['a', 'bcd', 'a', 'e']: + Enum1(cl=_l) raises( (Enum1._connection.module.IntegrityError, Enum1._connection.module.ProgrammingError, validators.Invalid), - Enum1, l='b') + Enum1, cl='b') class EnumWithNone(SQLObject): - l = EnumCol(enumValues=['a', 'bcd', 'e', None]) + cl = EnumCol(enumValues=['a', 'bcd', 'e', None]) def testNone(): setupClass(EnumWithNone) - for l in [None, 'a', 'bcd', 'a', 'e', None]: - e = EnumWithNone(l=l) - assert e.l == l + for _l in [None, 'a', 'bcd', 'a', 'e', None]: + e = EnumWithNone(cl=_l) + assert e.cl == _l class EnumWithDefaultNone(SQLObject): - l = EnumCol(enumValues=['a', 'bcd', 'e', None], default=None) + cl = EnumCol(enumValues=['a', 'bcd', 'e', None], default=None) def testDefaultNone(): setupClass(EnumWithDefaultNone) e = EnumWithDefaultNone() - assert e.l is None + assert e.cl is None class EnumWithDefaultOther(SQLObject): - l = EnumCol(enumValues=['a', 'bcd', 'e', None], default='a') + cl = EnumCol(enumValues=['a', 'bcd', 'e', None], default='a') def testDefaultOther(): setupClass(EnumWithDefaultOther) e = EnumWithDefaultOther() - assert e.l == 'a' + assert e.cl == 'a' class EnumUnicode(SQLObject): n = UnicodeCol() - l = EnumCol(enumValues=['a', 'b']) + cl = EnumCol(enumValues=['a', 'b']) def testUnicode(): setupClass(EnumUnicode) - EnumUnicode(n=u'a', l='a') - EnumUnicode(n=u'b', l=u'b') - EnumUnicode(n=u'\u201c', l='a') - EnumUnicode(n=u'\u201c', l=u'b') + EnumUnicode(n=u'a', cl='a') + EnumUnicode(n=u'b', cl=u'b') + EnumUnicode(n=u'\u201c', cl='a') + EnumUnicode(n=u'\u201c', cl=u'b') From c230e9e8959da4447a578b6cfdb427eb17d43b5f Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 24 Oct 2017 23:56:19 +0300 Subject: [PATCH 109/509] Docs: Remove generated HTML from eggs/wheels Generated docs are still included in source distribution. --- docs/News.rst | 6 ++++++ setup.py | 36 +++--------------------------------- 2 files changed, 9 insertions(+), 33 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index 978572be..b925c448 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -19,6 +19,12 @@ Drivers * Fix autoreconnect with pymysql driver. Contributed by Shailesh Mungikar. +Documentation +------------- + +* Remove generated HTML from eggs/wheels (docs are installed into wrong + place). Generated docs are still included in source distribution. + Tests ----- diff --git a/setup.py b/setup.py index cba0bf3d..8c2d6e30 100755 --- a/setup.py +++ b/setup.py @@ -127,39 +127,9 @@ packages=["sqlobject"] + ['sqlobject.%s' % package for package in subpackages], scripts=["scripts/sqlobject-admin", "scripts/sqlobject-convertOldURI"], - package_data={"sqlobject": - [ - "../LICENSE", - "../docs/*.rst", - "../docs/html/*", - "../docs/html/_sources/*", - "../docs/html/_sources/api/*", - "../docs/html/_modules/*", - "../docs/html/_modules/sqlobject/*", - "../docs/html/_modules/sqlobject/mysql/*", - "../docs/html/_modules/sqlobject/postgres/*", - "../docs/html/_modules/sqlobject/manager/*", - "../docs/html/_modules/sqlobject/inheritance/*", - "../docs/html/_modules/sqlobject/inheritance/tests/*", - "../docs/html/_modules/sqlobject/mssql/*", - "../docs/html/_modules/sqlobject/tests/*", - "../docs/html/_modules/sqlobject/rdbhost/*", - "../docs/html/_modules/sqlobject/versioning/*", - "../docs/html/_modules/sqlobject/versioning/test/*", - "../docs/html/_modules/sqlobject/util/*", - "../docs/html/_modules/sqlobject/maxdb/*", - "../docs/html/_modules/sqlobject/firebird/*", - "../docs/html/_modules/sqlobject/sybase/*", - "../docs/html/_modules/sqlobject/sqlite/*", - "../docs/html/_modules/sqlobject/include/*", - "../docs/html/_modules/sqlobject/include/tests/*", - "../docs/html/_modules/pydispatch/*", - "../docs/html/_modules/_pytest/*", - "../docs/html/api/*", - "../docs/html/_static/*", - ], - "sqlobject.maxdb": ["readme.txt"], - }, + package_data={ + "sqlobject.maxdb": ["readme.txt"], + }, requires=['FormEncode', 'PyDispatcher'], **kw ) From 898ea2a2482a7cab8ab1d835eaf797d33ea6fdd9 Mon Sep 17 00:00:00 2001 From: "Michael S. Root" Date: Mon, 30 Oct 2017 12:00:11 -0700 Subject: [PATCH 110/509] Add Python3 special methods for division to SQLExpression Adds __truediv__ and __floordiv__ (and reciprocals) to better support using SQLExpression objects in Pythonn3. Note that __floordiv__ is NOT equivalent to SQL's 'DIV' operator, so the SQL FLOOR function is used in combination with the / operator. Should be backwards-compatible with Python2. --- sqlobject/sqlbuilder.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sqlobject/sqlbuilder.py b/sqlobject/sqlbuilder.py index e87ba701..5178c73d 100644 --- a/sqlobject/sqlbuilder.py +++ b/sqlobject/sqlbuilder.py @@ -137,6 +137,18 @@ def __div__(self, other): def __rdiv__(self, other): return SQLOp("/", other, self) + def __truediv__(self, other): + return SQLOp("/", self, other) + + def __rtruediv__(self, other): + return SQLOp("/", other, self) + + def __floordiv__(self, other): + return SQLConstant("FLOOR")(SQLOp("/", self, other)) + + def __rfloordiv__(self, other): + return SQLConstant("FLOOR")(SQLOp("/", other, self)) + def __pos__(self): return SQLPrefix("+", self) From e4c5c2867187f6ab729b3f4fb503424e578a7f89 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 31 Oct 2017 20:23:19 +0300 Subject: [PATCH 111/509] Fix(pg800): Fix encoding problem under Python 2.7 --- .travis.yml | 1 - docs/News.rst | 3 +-- sqlobject/postgres/pgconnection.py | 4 ++++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 60548f8b..be4d42e9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -120,7 +120,6 @@ matrix: env: TOXENV=py36-firebirdsql allow_failures: - - env: TOXENV=py27-postgres-pg8000 - env: TOXENV=py27-firebird-fdb - env: TOXENV=py34-firebird-fdb - env: TOXENV=py35-firebird-fdb diff --git a/docs/News.rst b/docs/News.rst index b925c448..51ad44ee 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -14,8 +14,7 @@ Drivers ------- * Add support for `pg8000 `_ - PostgreSQL driver (from our fork). There is a minor problem - with Python 2.7. + PostgreSQL driver (from our fork). * Fix autoreconnect with pymysql driver. Contributed by Shailesh Mungikar. diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index f17b7e0d..c48e43fc 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -235,6 +235,10 @@ def makeConnection(self): def _executeRetry(self, conn, cursor, query): if self.debug: self.printDebug(conn, query, 'QueryR') + dbEncoding = self.dbEncoding + if dbEncoding and isinstance(query, bytes) and ( + self.driver == 'pg8000'): + query = query.decode(dbEncoding) try: return cursor.execute(query) except self.module.OperationalError as e: From e624f5bea851154b7c76ff004dd961506e0d3efd Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 31 Oct 2017 20:30:42 +0300 Subject: [PATCH 112/509] Fix(pg800): Recognize ('ERROR', 'ERROR', '23505') as DuplicateEntryError --- sqlobject/postgres/pgconnection.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index c48e43fc..a3068665 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -256,7 +256,10 @@ def _executeRetry(self, conn, cursor, query): raise dberrors.InternalError(ErrorMessage(e)) except self.module.ProgrammingError as e: msg = ErrorMessage(e) - if (len(e.args) >= 2) and e.args[1] == '23505': + if ( + (len(e.args) > 2) and (e.args[1] == 'ERROR') and + (e.args[2] == '23505')) \ + or ((len(e.args) >= 2) and (e.args[1] == '23505')): raise dberrors.DuplicateEntryError(msg) else: raise dberrors.ProgrammingError(msg) From 6b80a2d7bc86f07314fbe666abbed49b777056e2 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 31 Oct 2017 20:32:50 +0300 Subject: [PATCH 113/509] Tests(AppVeyor): Stop all MS SQL tests: too many timeouts --- appveyor.yml | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 12ae77d8..a18c941f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -33,16 +33,6 @@ environment: CMD_IN_ENV: "cmd /E:ON /V:ON /C .\\run_with_env.cmd" matrix: - - TOX_ENV: "py27-mssql-pyodbc-w32" - PYTHON_ARCH: "32" - PYTHON_VERSION: "2.7" - PYTHON_HOME: "C:\\Python27" - db: mssql2014 - - TOX_ENV: "py34-mssql-pyodbc-w32" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.4" - PYTHON_HOME: "C:\\Python34-x64" - db: mssql2014 - TOX_ENV: "py27-mysql-connector-w32" PYTHON_ARCH: "32" PYTHON_VERSION: "2.7" @@ -273,21 +263,6 @@ install: # List ODBC drivers - ps: Get-OdbcDriver -Platform 32-bit | Select-Object -ExpandProperty Name - ps: Get-OdbcDriver -Platform 64-bit | Select-Object -ExpandProperty Name - # Enable TCP for mssql - - ps: | - [reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo") | Out-Null - [reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.SqlWmiManagement") | Out-Null - $serverName = $env:COMPUTERNAME - $instanceName = 'SQL2014' - $smo = 'Microsoft.SqlServer.Management.Smo.' - $wmi = new-object ($smo + 'Wmi.ManagedComputer') - $uri = "ManagedComputer[@Name='$serverName']/ServerInstance[@Name='$instanceName']/ServerProtocol[@Name='Tcp']" - $Tcp = $wmi.GetSmoObject($uri) - $Tcp.IsEnabled = $true - $TCP.alter() - Set-Service SQLBrowser -StartupType Manual - Start-Service SQLBrowser - Start-Service "MSSQL`$$instanceName" # Not a C project, so no build step build: false From 0a6f19d2d975fc5ac7a5d25259add57bee7f6cfe Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 31 Oct 2017 20:48:40 +0300 Subject: [PATCH 114/509] Docs: Update news --- docs/News.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index 51ad44ee..8bc7582d 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -22,7 +22,7 @@ Documentation ------------- * Remove generated HTML from eggs/wheels (docs are installed into wrong - place). Generated docs are still included in source distribution. + place). Generated docs are still included in the source distribution. Tests ----- @@ -30,7 +30,7 @@ Tests * Add tests for PyGreSQL, py-postgresql and pg8000 at AppVeyor. * Fixed bugs in py-postgresql at AppVeyor. SQLObject requires - the latest version of the driver from git. + the latest version of the driver from our fork. SQLObject 3.4.0 =============== From ebcecd543fe7a98f2dd66c7af4c10ee877960527 Mon Sep 17 00:00:00 2001 From: "Michael S. Root" Date: Tue, 7 Nov 2017 17:32:36 -0800 Subject: [PATCH 115/509] Added minimal unit tests for __truediv__ and __floordiv__ --- sqlobject/tests/test_sqlbuilder.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sqlobject/tests/test_sqlbuilder.py b/sqlobject/tests/test_sqlbuilder.py index 9a3b6e30..1d2c8501 100644 --- a/sqlobject/tests/test_sqlbuilder.py +++ b/sqlobject/tests/test_sqlbuilder.py @@ -57,6 +57,14 @@ def test_modulo(): "(((so_test_sql_builder.so_value) % (2)) = (0))" +def test_division(): + SOTestSQLBuilder(name='test', so_value=-11) + assert sqlrepr(SOTestSQLBuilder.q.so_value / 4 == -2.75, 'mysql') == \ + "(((so_test_sql_builder.so_value) / (4)) = (-2.75))" + assert sqlrepr(SOTestSQLBuilder.q.so_value // 4 == -3, 'mysql') == \ + "((FLOOR(((so_test_sql_builder.so_value) / (4)))) = (-3))" + + def test_str_or_sqlrepr(): select = Select(['id', 'name'], staticTables=['employees'], where='value>0', orderBy='id') From 5d316860a1259d7acbccc4d11166c27329336fb0 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 8 Nov 2017 08:25:34 +0300 Subject: [PATCH 116/509] Docs: Merged a pull request by Michael S. Root [skip ci] --- ANNOUNCE.rst | 2 +- docs/Authors.rst | 1 + docs/News.rst | 6 ++++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 31ffed8a..bf5903c5 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -22,7 +22,7 @@ I'm pleased to announce version 3.4.1, the first bugfix release of branch What's new in SQLObject ======================= -Contributor for this release is Shailesh Mungikar. +Contributors for this release are Shailesh Mungikar, Michael S. Root. For a more complete list, please see the news: http://sqlobject.org/News.html diff --git a/docs/Authors.rst b/docs/Authors.rst index 1d0a0638..3f3d55ba 100644 --- a/docs/Authors.rst +++ b/docs/Authors.rst @@ -35,6 +35,7 @@ Contributions have been made by: * Nathan Edwards * Lutz Steinborn * Shailesh Mungikar +* Michael S. Root * Oleg Broytman .. image:: https://sourceforge.net/sflogo.php?group_id=74338&type=10 diff --git a/docs/News.rst b/docs/News.rst index 8bc7582d..ae62e53e 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -10,6 +10,12 @@ News SQLObject 3.5.0 (master) ======================== +Features +-------- + +* Add Python3 special methods for division to SQLExpression. + Pull request by Michael S. Root. + Drivers ------- From ae482753099d74cdb16f83d1124a77acaa3856d7 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 8 Nov 2017 08:52:00 +0300 Subject: [PATCH 117/509] Tests: Add a test for truediv on SQLite --- sqlobject/tests/test_sqlite.py | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/sqlobject/tests/test_sqlite.py b/sqlobject/tests/test_sqlite.py index 442ecf3c..4e9611a8 100644 --- a/sqlobject/tests/test_sqlite.py +++ b/sqlobject/tests/test_sqlite.py @@ -1,7 +1,9 @@ +import math import threading import pytest -from sqlobject import SQLObject, StringCol +from sqlobject import SQLObject, StringCol, FloatCol from sqlobject.compat import string_type +from sqlobject.sqlbuilder import Select from sqlobject.tests.dbtest import getConnection, setupClass, supports from sqlobject.tests.dbtest import setSQLiteConnectionFactory from .test_basic import SOTestSO1 @@ -144,3 +146,29 @@ def test_list_databases(): def test_list_tables(): setupClass(SOTestSO1) assert SOTestSO1.sqlmeta.table in connection.listTables() + + +class SQLiteTruedivTest(SQLObject): + value = FloatCol() + + +def test_truediv(): + setupClass(SQLiteTruedivTest) + + if SQLiteTruedivTest._connection.dbName == "sqlite": + if not SQLiteTruedivTest._connection.using_sqlite2: + pytest.skip("These tests require SQLite v2+") + + def SQLiteConnectionFactory(sqlite): + class MyConnection(sqlite.Connection): + def __init__(self, *args, **kwargs): + super(MyConnection, self).__init__(*args, **kwargs) + self.create_function("floor", 1, math.floor) + return MyConnection + + setSQLiteConnectionFactory(SQLiteTruedivTest, SQLiteConnectionFactory) + + SQLiteTruedivTest(value=-5.0) + assert SQLiteTruedivTest._connection.queryAll( + SQLiteTruedivTest._connection.sqlrepr( + Select(SQLiteTruedivTest.q.value // 4)))[0][0] == -2 From 0684a9b3e4250690cf5ff9ce6753c6735dbd27d0 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 15 Nov 2017 16:47:04 +0300 Subject: [PATCH 118/509] SQLObject 3.5.0 released 15 Nov 2017 --- ANNOUNCE.rst | 45 +++++++++++++++++++++++++-------------- README.rst | 2 +- devscripts/build-all-docs | 2 +- docs/News.rst | 12 ++++++----- sqlobject/__version__.py | 4 ++-- 5 files changed, 40 insertions(+), 25 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index bf5903c5..15fd72c1 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,28 +1,41 @@ Hello! -I'm pleased to announce version 3.4.1a1, the first alpha of the upcoming -release of branch 3.4 of SQLObject. +I'm pleased to announce version 3.5.0, the first stable release of branch +3.5 of SQLObject. -I'm pleased to announce version 3.4.1a2, the second alpha of the upcoming -release of branch 3.4 of SQLObject. -I'm pleased to announce version 3.4.1b1, the first beta of the upcoming -release of branch 3.4 of SQLObject. +What's new in SQLObject +======================= -I'm pleased to announce version 3.4.1rc1, the first release candidate -of the upcoming release of branch 3.4 of SQLObject. +Contributors for this release are Shailesh Mungikar and Michael S. Root. -I'm pleased to announce version 3.4.0, the first stable release of branch -3.4 of SQLObject. +Minor features +-------------- -I'm pleased to announce version 3.4.1, the first bugfix release of branch -3.4 of SQLObject. +* Add Python3 special methods for division to SQLExpression. + Pull request by Michael S. Root. +Drivers +------- -What's new in SQLObject -======================= +* Add support for `pg8000 `_ + PostgreSQL driver. + +* Fix autoreconnect with pymysql driver. Contributed by Shailesh Mungikar. + +Documentation +------------- + +* Remove generated HTML from eggs/wheels (docs are installed into wrong + place). Generated docs are still included in the source distribution. + +Tests +----- + +* Add tests for PyGreSQL, py-postgresql and pg8000 at AppVeyor. -Contributors for this release are Shailesh Mungikar, Michael S. Root. +* Fixed bugs in py-postgresql at AppVeyor. SQLObject requires + the latest version of the driver from our fork. For a more complete list, please see the news: http://sqlobject.org/News.html @@ -54,7 +67,7 @@ Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Download: -https://pypi.python.org/pypi/SQLObject/3.4.1a0.dev20170805 +https://pypi.python.org/pypi/SQLObject/3.5.0 News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 8f49176c..d32d4120 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,4 @@ -SQLObject 3.4.0 +SQLObject 3.5.0 =============== Thanks for looking at SQLObject. SQLObject is an object-relational diff --git a/devscripts/build-all-docs b/devscripts/build-all-docs index 885a0179..5fd0c945 100755 --- a/devscripts/build-all-docs +++ b/devscripts/build-all-docs @@ -11,7 +11,7 @@ cd "$PROG_DIR" && PROG_DIR="`pwd`" && cd "$PROG_DIR"/SQLObject && -build_docs 3.4.0 && +build_docs 3.5.0 && build_docs master devel && rm -rf docs/html && diff --git a/docs/News.rst b/docs/News.rst index ae62e53e..afc6164a 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -7,11 +7,13 @@ News .. _start: -SQLObject 3.5.0 (master) -======================== +SQLObject 3.5.0 +=============== -Features --------- +Released 15 Nov 2017. + +Minor features +-------------- * Add Python3 special methods for division to SQLExpression. Pull request by Michael S. Root. @@ -20,7 +22,7 @@ Drivers ------- * Add support for `pg8000 `_ - PostgreSQL driver (from our fork). + PostgreSQL driver. * Fix autoreconnect with pymysql driver. Contributed by Shailesh Mungikar. diff --git a/sqlobject/__version__.py b/sqlobject/__version__.py index b86d42e4..88c8ca08 100644 --- a/sqlobject/__version__.py +++ b/sqlobject/__version__.py @@ -1,7 +1,7 @@ -version = '3.4.0' +version = '3.5.0' major = 3 -minor = 4 +minor = 5 micro = 0 release_level = 'final' serial = 0 From 2ce592300bdd0cfcb444b24cdfd4b2e412fd7bda Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 15 Nov 2017 17:04:21 +0300 Subject: [PATCH 119/509] Prepare for the next release [skip ci] --- ANNOUNCE.rst | 45 ++++++++++++++++----------------------------- docs/News.rst | 3 +++ 2 files changed, 19 insertions(+), 29 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 15fd72c1..2f45be41 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,41 +1,28 @@ Hello! -I'm pleased to announce version 3.5.0, the first stable release of branch -3.5 of SQLObject. +I'm pleased to announce version 3.6.1a1, the first alpha of the upcoming +release of branch 3.6 of SQLObject. +I'm pleased to announce version 3.6.1a2, the second alpha of the upcoming +release of branch 3.6 of SQLObject. -What's new in SQLObject -======================= - -Contributors for this release are Shailesh Mungikar and Michael S. Root. - -Minor features --------------- - -* Add Python3 special methods for division to SQLExpression. - Pull request by Michael S. Root. +I'm pleased to announce version 3.6.1b1, the first beta of the upcoming +release of branch 3.6 of SQLObject. -Drivers -------- +I'm pleased to announce version 3.6.1rc1, the first release candidate +of the upcoming release of branch 3.6 of SQLObject. -* Add support for `pg8000 `_ - PostgreSQL driver. +I'm pleased to announce version 3.6.0, the first stable release of branch +3.6 of SQLObject. -* Fix autoreconnect with pymysql driver. Contributed by Shailesh Mungikar. +I'm pleased to announce version 3.6.1, the first bugfix release of branch +3.6 of SQLObject. -Documentation -------------- -* Remove generated HTML from eggs/wheels (docs are installed into wrong - place). Generated docs are still included in the source distribution. - -Tests ------ - -* Add tests for PyGreSQL, py-postgresql and pg8000 at AppVeyor. +What's new in SQLObject +======================= -* Fixed bugs in py-postgresql at AppVeyor. SQLObject requires - the latest version of the driver from our fork. +Contributors for this release are For a more complete list, please see the news: http://sqlobject.org/News.html @@ -67,7 +54,7 @@ Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Download: -https://pypi.python.org/pypi/SQLObject/3.5.0 +https://pypi.python.org/pypi/SQLObject/3.6.0a0.dev20171115 News and changes: http://sqlobject.org/News.html diff --git a/docs/News.rst b/docs/News.rst index afc6164a..bb0d044c 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -7,6 +7,9 @@ News .. _start: +SQLObject 3.6.0 (master) +======================== + SQLObject 3.5.0 =============== From 76b658299f6eb4b1abc63fac228bd9b5d28cd594 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 15 Nov 2017 17:37:31 +0300 Subject: [PATCH 120/509] Docs(RELEASE-CHECKLIST): Reorder some items [skip ci] --- devscripts/RELEASE-CHECKLIST | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/devscripts/RELEASE-CHECKLIST b/devscripts/RELEASE-CHECKLIST index efc9d504..c1607770 100644 --- a/devscripts/RELEASE-CHECKLIST +++ b/devscripts/RELEASE-CHECKLIST @@ -33,16 +33,16 @@ 7. Hide/show old releases at PyPI and SourceForge. -8. Generate new docs using ./build-all-docs. Upload docs using - ./publish-docs. +8. Run ../push-all in the development repository to push all branches + and tags to the public repositories. 9. Run ../postrelease. The script restores ANNOUNCE.rst from the previous commit (HEAD~). It calls editor; update next version, remove the list of contributors and the list of changes, edit download URL in ANNOUNCE.rst. Edit docs/News.rst - add new version. -10. Run ../push-all in the development repository to push all branches - and tags to the public repositories. +10. Generate new docs using ./build-all-docs. Upload docs using + ./publish-docs. 11. Send announcement to the SQLObject mailing list. For a stable release send announcements to python, python-announce and python-db From 3db1182c8c02635ad5b6e4c950f63ceb21120e2d Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 10 Dec 2017 13:55:44 +0300 Subject: [PATCH 121/509] Build(setup.py): Use python_version environment marker Use ``python_version`` environment marker in ``setup.py`` to make ``install_requires`` and ``extras_require`` declarative. This makes the universal wheel truly universal. --- docs/News.rst | 7 +++++++ setup.py | 31 ++++++++++--------------------- 2 files changed, 17 insertions(+), 21 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index bb0d044c..3a80743e 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -10,6 +10,13 @@ News SQLObject 3.6.0 (master) ======================== +Build +===== + +* Use ``python_version`` environment marker in ``setup.py`` to make + ``install_requires`` and ``extras_require`` declarative. This makes + the universal wheel truly universal. + SQLObject 3.5.0 =============== diff --git a/setup.py b/setup.py index 8c2d6e30..66fdb236 100755 --- a/setup.py +++ b/setup.py @@ -1,6 +1,5 @@ #!/usr/bin/env python -import sys from imp import load_source from os.path import abspath, dirname, join @@ -27,21 +26,13 @@ [paste.filter_app_factory] main = sqlobject.wsgi_middleware:make_middleware """ - if (sys.version_info[:2] == (2, 7)): - PY2 = True - elif (sys.version_info[0] == 3) and (sys.version_info[:2] >= (3, 4)): - PY2 = False - else: - raise ImportError("SQLObject requires Python 2.7 or 3.4+") - - kw['install_requires'] = install_requires = [] - if PY2: - install_requires.append("FormEncode>=1.1.1,!=1.3.0") - else: - install_requires.append("FormEncode>=1.3.1") - install_requires.append("PyDispatcher>=2.0.4") - - kw['extras_require'] = extras_require = { + kw['install_requires'] = [ + "FormEncode>=1.1.1,!=1.3.0; python_version=='2.7'", + "FormEncode>=1.3.1; python_version>='3.4'", + "PyDispatcher>=2.0.4", + ] + + kw['extras_require'] = { # Firebird/Interbase 'fdb': ['fdb'], 'firebirdsql': ['firebirdsql'], @@ -50,7 +41,10 @@ 'adodbapi': ['adodbapi'], 'pymssql': ['pymssql'], # MySQL + 'mysql:python_version=="2.7"': ['MySQL-python'], + 'mysql:python_version>="3.4"': ['mysqlclient'], 'mysql-connector': ['mysql-connector'], + 'oursql:python_version=="2.7"': ['oursql'], 'pymysql': ['pymysql'], # ODBC 'odbc': ['pyodbc'], @@ -71,11 +65,6 @@ 'sqlite': ['pysqlite'], 'sybase': ['Sybase'], } - if PY2: - extras_require['mysql'] = ['MySQLdb'] - extras_require['oursql'] = ['oursql'] - else: - extras_require['mysql'] = ['mysqlclient'] setup(name="SQLObject", version=version, From 7453dbc816d194e7ed3336ef5123aa4b05d39126 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 10 Dec 2017 14:02:07 +0300 Subject: [PATCH 122/509] Build(setup.py): Use python_requires keyword --- docs/News.rst | 2 ++ setup.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/docs/News.rst b/docs/News.rst index 3a80743e..312aba02 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -17,6 +17,8 @@ Build ``install_requires`` and ``extras_require`` declarative. This makes the universal wheel truly universal. +* Use ``python_requires`` keyword in ``setup.py``. + SQLObject 3.5.0 =============== diff --git a/setup.py b/setup.py index 66fdb236..2adc4ab9 100755 --- a/setup.py +++ b/setup.py @@ -66,6 +66,8 @@ 'sybase': ['Sybase'], } + kw['python_requires'] = '>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*' + setup(name="SQLObject", version=version, description="Object-Relational Manager, aka database wrapper", From 520518ce50c7f0df6e4212b55e5a12009c6e2844 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 10 Dec 2017 15:53:25 +0300 Subject: [PATCH 123/509] CI: Upgrade pip and setuptools --- .travis.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index be4d42e9..17191639 100644 --- a/.travis.yml +++ b/.travis.yml @@ -149,7 +149,7 @@ before_install: sudo chmod 644 /var/lib/firebird/create_test_db; fi -install: travis_retry pip install tox coveralls codecov ppu +install: travis_retry pip install --upgrade pip setuptools tox coveralls codecov ppu script: tox -e ${TOXENV} diff --git a/appveyor.yml b/appveyor.yml index a18c941f..6e6512f9 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -259,7 +259,7 @@ install: - "python --version" - "python -c \"import struct; print(struct.calcsize('P') * 8)\"" - "pip --version" - - "pip install tox ppu" + - "pip install --upgrade pip setuptools tox ppu" # List ODBC drivers - ps: Get-OdbcDriver -Platform 32-bit | Select-Object -ExpandProperty Name - ps: Get-OdbcDriver -Platform 64-bit | Select-Object -ExpandProperty Name From fdc40081eb3e12591e5d6603204854512e1a4ca8 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 11 Dec 2017 20:54:27 +0300 Subject: [PATCH 124/509] CI: Rename TOX_ENV -> TOXENV; execute tox (no need to pass TOXENV) --- .travis.yml | 2 +- appveyor.yml | 94 ++++++++++++++++++++++++++-------------------------- 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/.travis.yml b/.travis.yml index 17191639..72148bb9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -151,7 +151,7 @@ before_install: install: travis_retry pip install --upgrade pip setuptools tox coveralls codecov ppu -script: tox -e ${TOXENV} +script: tox after_success: - cd sqlobject diff --git a/appveyor.yml b/appveyor.yml index 6e6512f9..c6641fca 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -33,221 +33,221 @@ environment: CMD_IN_ENV: "cmd /E:ON /V:ON /C .\\run_with_env.cmd" matrix: - - TOX_ENV: "py27-mysql-connector-w32" + - TOXENV: "py27-mysql-connector-w32" PYTHON_ARCH: "32" PYTHON_VERSION: "2.7" PYTHON_HOME: "C:\\Python27" db: mysql - - TOX_ENV: "py34-mysql-connector-w32" + - TOXENV: "py34-mysql-connector-w32" PYTHON_ARCH: "32" PYTHON_VERSION: "3.4" PYTHON_HOME: "C:\\Python34" db: mysql - - TOX_ENV: "py35-mysql-connector-w32" + - TOXENV: "py35-mysql-connector-w32" PYTHON_ARCH: "32" PYTHON_VERSION: "3.5" PYTHON_HOME: "C:\\Python35" db: mysql - - TOX_ENV: "py36-mysql-connector-w32" + - TOXENV: "py36-mysql-connector-w32" PYTHON_ARCH: "32" PYTHON_VERSION: "3.6" PYTHON_HOME: "C:\\Python36" db: mysql - - TOX_ENV: "py27-mysql-pyodbc-w32" + - TOXENV: "py27-mysql-pyodbc-w32" PYTHON_ARCH: "64" PYTHON_VERSION: "2.7" PYTHON_HOME: "C:\\Python27-x64" db: mysql - - TOX_ENV: "py34-mysql-pyodbc-w32" + - TOXENV: "py34-mysql-pyodbc-w32" PYTHON_ARCH: "64" PYTHON_VERSION: "3.4" PYTHON_HOME: "C:\\Python34-x64" db: mysql - - TOX_ENV: "py27-postgres-psycopg-w32" + - TOXENV: "py27-postgres-psycopg-w32" PYTHON_ARCH: "32" PYTHON_VERSION: "2.7" PYTHON_HOME: "C:\\Python27" db: postgresql - - TOX_ENV: "py27-postgres-psycopg-w32" + - TOXENV: "py27-postgres-psycopg-w32" PYTHON_ARCH: "64" PYTHON_VERSION: "2.7" PYTHON_HOME: "C:\\Python27-x64" db: postgresql - - TOX_ENV: "py34-postgres-psycopg-w32" + - TOXENV: "py34-postgres-psycopg-w32" PYTHON_ARCH: "32" PYTHON_VERSION: "3.4" PYTHON_HOME: "C:\\Python34" db: postgresql - - TOX_ENV: "py34-postgres-psycopg-w32" + - TOXENV: "py34-postgres-psycopg-w32" PYTHON_ARCH: "64" PYTHON_VERSION: "3.4" PYTHON_HOME: "C:\\Python34-x64" db: postgresql - - TOX_ENV: "py35-postgres-psycopg-w32" + - TOXENV: "py35-postgres-psycopg-w32" PYTHON_ARCH: "32" PYTHON_VERSION: "3.5" PYTHON_HOME: "C:\\Python35" db: postgresql - - TOX_ENV: "py35-postgres-psycopg-w32" + - TOXENV: "py35-postgres-psycopg-w32" PYTHON_ARCH: "64" PYTHON_VERSION: "3.5" PYTHON_HOME: "C:\\Python35-x64" db: postgresql - - TOX_ENV: "py36-postgres-psycopg-w32" + - TOXENV: "py36-postgres-psycopg-w32" PYTHON_ARCH: "32" PYTHON_VERSION: "3.6" PYTHON_HOME: "C:\\Python36" db: postgresql - - TOX_ENV: "py36-postgres-psycopg-w32" + - TOXENV: "py36-postgres-psycopg-w32" PYTHON_ARCH: "64" PYTHON_VERSION: "3.6" PYTHON_HOME: "C:\\Python36-x64" db: postgresql - - TOX_ENV: "py27-postgres-pygresql-w32" + - TOXENV: "py27-postgres-pygresql-w32" PYTHON_ARCH: "64" PYTHON_VERSION: "2.7" PYTHON_HOME: "C:\\Python27-x64" db: postgresql - - TOX_ENV: "py34-postgres-pygresql-w32" + - TOXENV: "py34-postgres-pygresql-w32" PYTHON_ARCH: "64" PYTHON_VERSION: "3.4" PYTHON_HOME: "C:\\Python34-x64" db: postgresql - - TOX_ENV: "py35-postgres-pygresql-w32" + - TOXENV: "py35-postgres-pygresql-w32" PYTHON_ARCH: "64" PYTHON_VERSION: "3.5" PYTHON_HOME: "C:\\Python35-x64" db: postgresql - - TOX_ENV: "py36-postgres-pygresql-w32" + - TOXENV: "py36-postgres-pygresql-w32" PYTHON_ARCH: "64" PYTHON_VERSION: "3.6" PYTHON_HOME: "C:\\Python36-x64" db: postgresql - - TOX_ENV: "py34-pypostgresql-w32" + - TOXENV: "py34-pypostgresql-w32" PYTHON_ARCH: "32" PYTHON_VERSION: "3.4" PYTHON_HOME: "C:\\Python34" db: postgresql - - TOX_ENV: "py34-pypostgresql-w32" + - TOXENV: "py34-pypostgresql-w32" PYTHON_ARCH: "64" PYTHON_VERSION: "3.4" PYTHON_HOME: "C:\\Python34-x64" db: postgresql - - TOX_ENV: "py35-pypostgresql-w32" + - TOXENV: "py35-pypostgresql-w32" PYTHON_ARCH: "32" PYTHON_VERSION: "3.5" PYTHON_HOME: "C:\\Python35" db: postgresql - - TOX_ENV: "py35-pypostgresql-w32" + - TOXENV: "py35-pypostgresql-w32" PYTHON_ARCH: "64" PYTHON_VERSION: "3.5" PYTHON_HOME: "C:\\Python35-x64" db: postgresql - - TOX_ENV: "py36-pypostgresql-w32" + - TOXENV: "py36-pypostgresql-w32" PYTHON_ARCH: "32" PYTHON_VERSION: "3.6" PYTHON_HOME: "C:\\Python36" db: postgresql - - TOX_ENV: "py36-pypostgresql-w32" + - TOXENV: "py36-pypostgresql-w32" PYTHON_ARCH: "64" PYTHON_VERSION: "3.6" PYTHON_HOME: "C:\\Python36-x64" db: postgresql - - TOX_ENV: "py27-postgres-pg8000-w32" + - TOXENV: "py27-postgres-pg8000-w32" PYTHON_ARCH: "32" PYTHON_VERSION: "2.7" PYTHON_HOME: "C:\\Python27" db: postgresql - - TOX_ENV: "py27-postgres-pg8000-w32" + - TOXENV: "py27-postgres-pg8000-w32" PYTHON_ARCH: "64" PYTHON_VERSION: "2.7" PYTHON_HOME: "C:\\Python27-x64" db: postgresql - - TOX_ENV: "py34-postgres-pg8000-w32" + - TOXENV: "py34-postgres-pg8000-w32" PYTHON_ARCH: "32" PYTHON_VERSION: "3.4" PYTHON_HOME: "C:\\Python34" db: postgresql - - TOX_ENV: "py34-postgres-pg8000-w32" + - TOXENV: "py34-postgres-pg8000-w32" PYTHON_ARCH: "64" PYTHON_VERSION: "3.4" PYTHON_HOME: "C:\\Python34-x64" db: postgresql - - TOX_ENV: "py35-postgres-pg8000-w32" + - TOXENV: "py35-postgres-pg8000-w32" PYTHON_ARCH: "32" PYTHON_VERSION: "3.5" PYTHON_HOME: "C:\\Python35" db: postgresql - - TOX_ENV: "py35-postgres-pg8000-w32" + - TOXENV: "py35-postgres-pg8000-w32" PYTHON_ARCH: "64" PYTHON_VERSION: "3.5" PYTHON_HOME: "C:\\Python35-x64" db: postgresql - - TOX_ENV: "py36-postgres-pg8000-w32" + - TOXENV: "py36-postgres-pg8000-w32" PYTHON_ARCH: "32" PYTHON_VERSION: "3.6" PYTHON_HOME: "C:\\Python36" db: postgresql - - TOX_ENV: "py36-postgres-pg8000-w32" + - TOXENV: "py36-postgres-pg8000-w32" PYTHON_ARCH: "64" PYTHON_VERSION: "3.6" PYTHON_HOME: "C:\\Python36-x64" db: postgresql - - TOX_ENV: "py27-postgres-pyodbc-w32" + - TOXENV: "py27-postgres-pyodbc-w32" PYTHON_ARCH: "64" PYTHON_VERSION: "2.7" PYTHON_HOME: "C:\\Python27-x64" db: postgresql - - TOX_ENV: "py34-postgres-pyodbc-w32" + - TOXENV: "py34-postgres-pyodbc-w32" PYTHON_ARCH: "64" PYTHON_VERSION: "3.4" PYTHON_HOME: "C:\\Python34-x64" db: postgresql - - TOX_ENV: "py27-sqlite-w32" + - TOXENV: "py27-sqlite-w32" PYTHON_ARCH: "32" PYTHON_VERSION: "2.7" PYTHON_HOME: "C:\\Python27" - - TOX_ENV: "py27-sqlite-w32" + - TOXENV: "py27-sqlite-w32" PYTHON_ARCH: "64" PYTHON_VERSION: "2.7" PYTHON_HOME: "C:\\Python27-x64" - - TOX_ENV: "py34-sqlite-w32" + - TOXENV: "py34-sqlite-w32" PYTHON_ARCH: "32" PYTHON_VERSION: "3.4" PYTHON_HOME: "C:\\Python34" - - TOX_ENV: "py34-sqlite-w32" + - TOXENV: "py34-sqlite-w32" PYTHON_ARCH: "64" PYTHON_VERSION: "3.4" PYTHON_HOME: "C:\\Python34-x64" - - TOX_ENV: "py35-sqlite-w32" + - TOXENV: "py35-sqlite-w32" PYTHON_ARCH: "32" PYTHON_VERSION: "3.5" PYTHON_HOME: "C:\\Python35" - - TOX_ENV: "py35-sqlite-w32" + - TOXENV: "py35-sqlite-w32" PYTHON_ARCH: "64" PYTHON_VERSION: "3.5" PYTHON_HOME: "C:\\Python35-x64" - - TOX_ENV: "py36-sqlite-w32" + - TOXENV: "py36-sqlite-w32" PYTHON_ARCH: "32" PYTHON_VERSION: "3.6" PYTHON_HOME: "C:\\Python36" - - TOX_ENV: "py36-sqlite-w32" + - TOXENV: "py36-sqlite-w32" PYTHON_ARCH: "64" PYTHON_VERSION: "3.6" PYTHON_HOME: "C:\\Python36-x64" - - TOX_ENV: "py27-sqlite-memory-w32" + - TOXENV: "py27-sqlite-memory-w32" PYTHON_ARCH: "32" PYTHON_VERSION: "2.7" PYTHON_HOME: "C:\\Python27" - - TOX_ENV: "py34-sqlite-memory-w32" + - TOXENV: "py34-sqlite-memory-w32" PYTHON_ARCH: "64" PYTHON_VERSION: "3.4" PYTHON_HOME: "C:\\Python34-x64" - - TOX_ENV: "py35-sqlite-memory-w32" + - TOXENV: "py35-sqlite-memory-w32" PYTHON_ARCH: "32" PYTHON_VERSION: "3.5" PYTHON_HOME: "C:\\Python35" - - TOX_ENV: "py36-sqlite-memory-w32" + - TOXENV: "py36-sqlite-memory-w32" PYTHON_ARCH: "64" PYTHON_VERSION: "3.6" PYTHON_HOME: "C:\\Python36-x64" @@ -268,7 +268,7 @@ install: build: false test_script: - - "%CMD_IN_ENV% tox -e %TOX_ENV%" + - "%CMD_IN_ENV% tox" after_test: - "remove-old-files.py -o 180 %LOCALAPPDATA%\\pip\\Cache" From 7d665e6381edcee40c2cddc8a117d37057b66a1e Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 15 Dec 2017 13:41:00 +0300 Subject: [PATCH 125/509] Docs: odbc drivers are only implemented for MySQL, Pg and MSSQL [skip ci] --- docs/SQLObject.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index 98367ae9..1ccc222f 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -54,7 +54,8 @@ built-in driver or PySQLite_. Firebird_ is supported via fdb_ or kinterbasdb_; pyfirebirdsql_ is supported but has problems. `MAX DB`_ (also known as SAP DB) is supported via sapdb_. Sybase via Sybase_. `MSSQL Server`_ via pymssql_ (+ FreeTDS_) or adodbapi_ (Win32). PyODBC_ and -PyPyODBC_ are supported but have problems (not all tests passed). +PyPyODBC_ are supported for MySQL, PostgreSQL and MSSQL but have +problems (not all tests passed). .. _MySQL: https://www.mysql.com/ .. _MySQLdb: https://sourceforge.net/projects/mysql-python/ From ac9cf3ac1641537f5d77e82b8f69ba57798224c4 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 15 Dec 2017 13:42:43 +0300 Subject: [PATCH 126/509] Docs: Document extras that are available for installation [skip ci] --- docs/News.rst | 5 +++++ docs/download.rst | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/docs/News.rst b/docs/News.rst index 312aba02..adcca1c3 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -10,6 +10,11 @@ News SQLObject 3.6.0 (master) ======================== +Documentation +------------- + +* Document extras that are available for installation. + Build ===== diff --git a/docs/download.rst b/docs/download.rst index 5aea6d08..6877d6ad 100644 --- a/docs/download.rst +++ b/docs/download.rst @@ -38,6 +38,49 @@ when you install ``SQLObject==bugfix`` you will be installing a specific version, and "bugfix" is just a kind of label for a way of acquiring the version (it points to a branch in the repository). +Drivers +------- + +SQLObject can be used with a number of drivers_. They can be installed +separately but it's also possible to install them with ``pip install``, +for example ``pip install SQLObject[mysql]`` or +``pip install SQLObject[postgres]``. The following drivers are +available: + +.. _drivers: SQLObject.html#requirements + +Firebird/Interbase +^^^^^^^^^^^^^^^^^^ + +fdb firebirdsql kinterbasdb + +MS SQL +^^^^^^ + +adodbapi pymssql + +MySQL +^^^^^ + +mysql (installs MySQL-python for Python 2.7 and mysqlclient for Python 3.4+) +mysql-connector oursql (only for Python 2.7) pymysql + +ODBC +^^^^ + +pyodbc pypyodbc odbc (synonym for pyodbc) + +PostgreSQL +^^^^^^^^^^ + +psycopg1 psycopg2 psycopg postgres postgresql (synonyms for psycopg2) +pygresql pypostgresql py-postgresql pg8000 + +The rest +^^^^^^^^ + +sapdb sqlite (pysqlite) sybase + Repositories ------------ From a9b98c8b18916c6701f8d1ef6899b26e272a8cd4 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 15 Dec 2017 14:55:47 +0300 Subject: [PATCH 127/509] Docs: Regenerate API docs [skip ci] --- docs/api/sqlobject.boundattributes.rst | 4 ++-- docs/api/sqlobject.cache.rst | 4 ++-- docs/api/sqlobject.classregistry.rst | 4 ++-- docs/api/sqlobject.col.rst | 4 ++-- docs/api/sqlobject.compat.rst | 4 ++-- docs/api/sqlobject.conftest.rst | 4 ++-- docs/api/sqlobject.constraints.rst | 4 ++-- docs/api/sqlobject.converters.rst | 4 ++-- docs/api/sqlobject.dbconnection.rst | 4 ++-- docs/api/sqlobject.dberrors.rst | 4 ++-- docs/api/sqlobject.declarative.rst | 4 ++-- docs/api/sqlobject.events.rst | 4 ++-- docs/api/sqlobject.firebird.firebirdconnection.rst | 4 ++-- docs/api/sqlobject.firebird.rst | 4 ++-- docs/api/sqlobject.include.hashcol.rst | 4 ++-- docs/api/sqlobject.include.rst | 4 ++-- docs/api/sqlobject.include.tests.rst | 4 ++-- docs/api/sqlobject.include.tests.test_hashcol.rst | 4 ++-- docs/api/sqlobject.index.rst | 4 ++-- docs/api/sqlobject.inheritance.iteration.rst | 4 ++-- docs/api/sqlobject.inheritance.rst | 4 ++-- docs/api/sqlobject.inheritance.tests.rst | 4 ++-- docs/api/sqlobject.inheritance.tests.test_aggregates.rst | 4 ++-- docs/api/sqlobject.inheritance.tests.test_asdict.rst | 4 ++-- .../sqlobject.inheritance.tests.test_deep_inheritance.rst | 4 ++-- .../api/sqlobject.inheritance.tests.test_destroy_cascade.rst | 4 ++-- docs/api/sqlobject.inheritance.tests.test_foreignKey.rst | 4 ++-- docs/api/sqlobject.inheritance.tests.test_indexes.rst | 4 ++-- docs/api/sqlobject.inheritance.tests.test_inheritance.rst | 4 ++-- .../sqlobject.inheritance.tests.test_inheritance_tree.rst | 4 ++-- docs/api/sqlobject.joins.rst | 4 ++-- docs/api/sqlobject.main.rst | 4 ++-- docs/api/sqlobject.manager.command.rst | 4 ++-- docs/api/sqlobject.manager.rst | 4 ++-- docs/api/sqlobject.maxdb.maxdbconnection.rst | 4 ++-- docs/api/sqlobject.maxdb.rst | 4 ++-- docs/api/sqlobject.mssql.mssqlconnection.rst | 4 ++-- docs/api/sqlobject.mssql.rst | 4 ++-- docs/api/sqlobject.mysql.mysqlconnection.rst | 4 ++-- docs/api/sqlobject.mysql.rst | 4 ++-- docs/api/sqlobject.postgres.pgconnection.rst | 4 ++-- docs/api/sqlobject.postgres.rst | 4 ++-- docs/api/sqlobject.rdbhost.rdbhostconnection.rst | 4 ++-- docs/api/sqlobject.rdbhost.rst | 4 ++-- docs/api/sqlobject.sqlbuilder.rst | 4 ++-- docs/api/sqlobject.sqlite.rst | 4 ++-- docs/api/sqlobject.sqlite.sqliteconnection.rst | 4 ++-- docs/api/sqlobject.sresults.rst | 4 ++-- docs/api/sqlobject.styles.rst | 4 ++-- docs/api/sqlobject.sybase.rst | 4 ++-- docs/api/sqlobject.sybase.sybaseconnection.rst | 4 ++-- docs/api/sqlobject.tests.dbtest.rst | 4 ++-- docs/api/sqlobject.tests.rst | 5 +++-- docs/api/sqlobject.tests.test_ForeignKey.rst | 4 ++-- docs/api/sqlobject.tests.test_NoneValuedResultItem.rst | 4 ++-- docs/api/sqlobject.tests.test_SQLMultipleJoin.rst | 4 ++-- docs/api/sqlobject.tests.test_SQLRelatedJoin.rst | 4 ++-- docs/api/sqlobject.tests.test_SingleJoin.rst | 4 ++-- docs/api/sqlobject.tests.test_aggregates.rst | 4 ++-- docs/api/sqlobject.tests.test_aliases.rst | 4 ++-- docs/api/sqlobject.tests.test_asdict.rst | 4 ++-- docs/api/sqlobject.tests.test_auto.rst | 4 ++-- docs/api/sqlobject.tests.test_basic.rst | 4 ++-- docs/api/sqlobject.tests.test_blob.rst | 4 ++-- docs/api/sqlobject.tests.test_boundattributes.rst | 4 ++-- docs/api/sqlobject.tests.test_cache.rst | 4 ++-- docs/api/sqlobject.tests.test_class_hash.rst | 4 ++-- docs/api/sqlobject.tests.test_columns_order.rst | 4 ++-- docs/api/sqlobject.tests.test_combining_joins.rst | 4 ++-- docs/api/sqlobject.tests.test_comparison.rst | 4 ++-- docs/api/sqlobject.tests.test_complex_sorting.rst | 4 ++-- docs/api/sqlobject.tests.test_constraints.rst | 4 ++-- docs/api/sqlobject.tests.test_converters.rst | 4 ++-- docs/api/sqlobject.tests.test_create_drop.rst | 4 ++-- docs/api/sqlobject.tests.test_csvexport.rst | 4 ++-- docs/api/sqlobject.tests.test_cyclic_reference.rst | 4 ++-- docs/api/sqlobject.tests.test_datetime.rst | 4 ++-- docs/api/sqlobject.tests.test_decimal.rst | 4 ++-- docs/api/sqlobject.tests.test_declarative.rst | 4 ++-- docs/api/sqlobject.tests.test_default_style.rst | 4 ++-- docs/api/sqlobject.tests.test_delete.rst | 4 ++-- docs/api/sqlobject.tests.test_distinct.rst | 4 ++-- docs/api/sqlobject.tests.test_empty.rst | 4 ++-- docs/api/sqlobject.tests.test_enum.rst | 4 ++-- docs/api/sqlobject.tests.test_events.rst | 4 ++-- docs/api/sqlobject.tests.test_exceptions.rst | 4 ++-- docs/api/sqlobject.tests.test_expire.rst | 4 ++-- docs/api/sqlobject.tests.test_groupBy.rst | 4 ++-- docs/api/sqlobject.tests.test_identity.rst | 4 ++-- docs/api/sqlobject.tests.test_indexes.rst | 4 ++-- docs/api/sqlobject.tests.test_inheritance.rst | 4 ++-- docs/api/sqlobject.tests.test_joins.rst | 4 ++-- docs/api/sqlobject.tests.test_joins_conditional.rst | 4 ++-- docs/api/sqlobject.tests.test_jsonbcol.rst | 4 ++-- docs/api/sqlobject.tests.test_jsoncol.rst | 4 ++-- docs/api/sqlobject.tests.test_lazy.rst | 4 ++-- docs/api/sqlobject.tests.test_md5.rst | 4 ++-- docs/api/sqlobject.tests.test_mysql.rst | 4 ++-- docs/api/sqlobject.tests.test_new_joins.rst | 4 ++-- docs/api/sqlobject.tests.test_parse_uri.rst | 4 ++-- docs/api/sqlobject.tests.test_paste.rst | 4 ++-- docs/api/sqlobject.tests.test_perConnection.rst | 4 ++-- docs/api/sqlobject.tests.test_pickle.rst | 4 ++-- docs/api/sqlobject.tests.test_picklecol.rst | 4 ++-- docs/api/sqlobject.tests.test_postgres.rst | 4 ++-- docs/api/sqlobject.tests.test_reparent_sqlmeta.rst | 4 ++-- docs/api/sqlobject.tests.test_schema.rst | 4 ++-- docs/api/sqlobject.tests.test_select.rst | 4 ++-- docs/api/sqlobject.tests.test_select_through.rst | 4 ++-- docs/api/sqlobject.tests.test_setters.rst | 4 ++-- docs/api/sqlobject.tests.test_slice.rst | 4 ++-- docs/api/sqlobject.tests.test_sorting.rst | 4 ++-- docs/api/sqlobject.tests.test_sqlbuilder.rst | 4 ++-- docs/api/sqlobject.tests.test_sqlbuilder_dbspecific.rst | 4 ++-- docs/api/sqlobject.tests.test_sqlbuilder_importproxy.rst | 4 ++-- docs/api/sqlobject.tests.test_sqlbuilder_joins_instances.rst | 4 ++-- docs/api/sqlobject.tests.test_sqlite.rst | 4 ++-- docs/api/sqlobject.tests.test_sqlmeta_idName.rst | 4 ++-- docs/api/sqlobject.tests.test_sqlobject_admin.rst | 4 ++-- docs/api/sqlobject.tests.test_string_id.rst | 4 ++-- docs/api/sqlobject.tests.test_style.rst | 4 ++-- docs/api/sqlobject.tests.test_subqueries.rst | 4 ++-- docs/api/sqlobject.tests.test_transactions.rst | 4 ++-- docs/api/sqlobject.tests.test_unicode.rst | 4 ++-- docs/api/sqlobject.tests.test_uuidcol.rst | 4 ++-- docs/api/sqlobject.tests.test_validation.rst | 4 ++-- docs/api/sqlobject.tests.test_views.rst | 4 ++-- docs/api/sqlobject.util.csvexport.rst | 4 ++-- docs/api/sqlobject.util.csvimport.rst | 4 ++-- docs/api/sqlobject.util.moduleloader.rst | 4 ++-- docs/api/sqlobject.util.rst | 4 ++-- docs/api/sqlobject.util.threadinglocal.rst | 4 ++-- docs/api/sqlobject.versioning.rst | 4 ++-- docs/api/sqlobject.versioning.test.rst | 4 ++-- docs/api/sqlobject.versioning.test.test_version.rst | 4 ++-- docs/api/sqlobject.views.rst | 4 ++-- docs/api/sqlobject.wsgi_middleware.rst | 4 ++-- 137 files changed, 275 insertions(+), 274 deletions(-) diff --git a/docs/api/sqlobject.boundattributes.rst b/docs/api/sqlobject.boundattributes.rst index 1518f8da..ebc0ab5a 100644 --- a/docs/api/sqlobject.boundattributes.rst +++ b/docs/api/sqlobject.boundattributes.rst @@ -1,5 +1,5 @@ -sqlobject.boundattributes module -================================ +sqlobject\.boundattributes module +================================= .. automodule:: sqlobject.boundattributes :members: diff --git a/docs/api/sqlobject.cache.rst b/docs/api/sqlobject.cache.rst index 6c74d5be..657e1e86 100644 --- a/docs/api/sqlobject.cache.rst +++ b/docs/api/sqlobject.cache.rst @@ -1,5 +1,5 @@ -sqlobject.cache module -====================== +sqlobject\.cache module +======================= .. automodule:: sqlobject.cache :members: diff --git a/docs/api/sqlobject.classregistry.rst b/docs/api/sqlobject.classregistry.rst index 08824917..80ed01a7 100644 --- a/docs/api/sqlobject.classregistry.rst +++ b/docs/api/sqlobject.classregistry.rst @@ -1,5 +1,5 @@ -sqlobject.classregistry module -============================== +sqlobject\.classregistry module +=============================== .. automodule:: sqlobject.classregistry :members: diff --git a/docs/api/sqlobject.col.rst b/docs/api/sqlobject.col.rst index 5282fc2f..4c649dc9 100644 --- a/docs/api/sqlobject.col.rst +++ b/docs/api/sqlobject.col.rst @@ -1,5 +1,5 @@ -sqlobject.col module -==================== +sqlobject\.col module +===================== .. automodule:: sqlobject.col :members: diff --git a/docs/api/sqlobject.compat.rst b/docs/api/sqlobject.compat.rst index cdb4f6dd..4191c0cf 100644 --- a/docs/api/sqlobject.compat.rst +++ b/docs/api/sqlobject.compat.rst @@ -1,5 +1,5 @@ -sqlobject.compat module -======================= +sqlobject\.compat module +======================== .. automodule:: sqlobject.compat :members: diff --git a/docs/api/sqlobject.conftest.rst b/docs/api/sqlobject.conftest.rst index 8e564281..e29d059d 100644 --- a/docs/api/sqlobject.conftest.rst +++ b/docs/api/sqlobject.conftest.rst @@ -1,5 +1,5 @@ -sqlobject.conftest module -========================= +sqlobject\.conftest module +========================== .. automodule:: sqlobject.conftest :members: diff --git a/docs/api/sqlobject.constraints.rst b/docs/api/sqlobject.constraints.rst index ad39272b..88a736b3 100644 --- a/docs/api/sqlobject.constraints.rst +++ b/docs/api/sqlobject.constraints.rst @@ -1,5 +1,5 @@ -sqlobject.constraints module -============================ +sqlobject\.constraints module +============================= .. automodule:: sqlobject.constraints :members: diff --git a/docs/api/sqlobject.converters.rst b/docs/api/sqlobject.converters.rst index 82b5cff7..38f7777f 100644 --- a/docs/api/sqlobject.converters.rst +++ b/docs/api/sqlobject.converters.rst @@ -1,5 +1,5 @@ -sqlobject.converters module -=========================== +sqlobject\.converters module +============================ .. automodule:: sqlobject.converters :members: diff --git a/docs/api/sqlobject.dbconnection.rst b/docs/api/sqlobject.dbconnection.rst index 6a6adc35..6ab39d10 100644 --- a/docs/api/sqlobject.dbconnection.rst +++ b/docs/api/sqlobject.dbconnection.rst @@ -1,5 +1,5 @@ -sqlobject.dbconnection module -============================= +sqlobject\.dbconnection module +============================== .. automodule:: sqlobject.dbconnection :members: diff --git a/docs/api/sqlobject.dberrors.rst b/docs/api/sqlobject.dberrors.rst index 3035746a..e8be2dbf 100644 --- a/docs/api/sqlobject.dberrors.rst +++ b/docs/api/sqlobject.dberrors.rst @@ -1,5 +1,5 @@ -sqlobject.dberrors module -========================= +sqlobject\.dberrors module +========================== .. automodule:: sqlobject.dberrors :members: diff --git a/docs/api/sqlobject.declarative.rst b/docs/api/sqlobject.declarative.rst index 9cc7e9bd..f89a88b4 100644 --- a/docs/api/sqlobject.declarative.rst +++ b/docs/api/sqlobject.declarative.rst @@ -1,5 +1,5 @@ -sqlobject.declarative module -============================ +sqlobject\.declarative module +============================= .. automodule:: sqlobject.declarative :members: diff --git a/docs/api/sqlobject.events.rst b/docs/api/sqlobject.events.rst index 8c33239d..18ddcc78 100644 --- a/docs/api/sqlobject.events.rst +++ b/docs/api/sqlobject.events.rst @@ -1,5 +1,5 @@ -sqlobject.events module -======================= +sqlobject\.events module +======================== .. automodule:: sqlobject.events :members: diff --git a/docs/api/sqlobject.firebird.firebirdconnection.rst b/docs/api/sqlobject.firebird.firebirdconnection.rst index 6fdf26e9..e517e981 100644 --- a/docs/api/sqlobject.firebird.firebirdconnection.rst +++ b/docs/api/sqlobject.firebird.firebirdconnection.rst @@ -1,5 +1,5 @@ -sqlobject.firebird.firebirdconnection module -============================================ +sqlobject\.firebird\.firebirdconnection module +============================================== .. automodule:: sqlobject.firebird.firebirdconnection :members: diff --git a/docs/api/sqlobject.firebird.rst b/docs/api/sqlobject.firebird.rst index 78cec9ae..a1f5b0ae 100644 --- a/docs/api/sqlobject.firebird.rst +++ b/docs/api/sqlobject.firebird.rst @@ -1,5 +1,5 @@ -sqlobject.firebird package -========================== +sqlobject\.firebird package +=========================== .. automodule:: sqlobject.firebird :members: diff --git a/docs/api/sqlobject.include.hashcol.rst b/docs/api/sqlobject.include.hashcol.rst index 76396aa4..7abe8d54 100644 --- a/docs/api/sqlobject.include.hashcol.rst +++ b/docs/api/sqlobject.include.hashcol.rst @@ -1,5 +1,5 @@ -sqlobject.include.hashcol module -================================ +sqlobject\.include\.hashcol module +================================== .. automodule:: sqlobject.include.hashcol :members: diff --git a/docs/api/sqlobject.include.rst b/docs/api/sqlobject.include.rst index 62086bfc..aebc9e47 100644 --- a/docs/api/sqlobject.include.rst +++ b/docs/api/sqlobject.include.rst @@ -1,5 +1,5 @@ -sqlobject.include package -========================= +sqlobject\.include package +========================== .. automodule:: sqlobject.include :members: diff --git a/docs/api/sqlobject.include.tests.rst b/docs/api/sqlobject.include.tests.rst index e17b4def..0bf1f136 100644 --- a/docs/api/sqlobject.include.tests.rst +++ b/docs/api/sqlobject.include.tests.rst @@ -1,5 +1,5 @@ -sqlobject.include.tests package -=============================== +sqlobject\.include\.tests package +================================= .. automodule:: sqlobject.include.tests :members: diff --git a/docs/api/sqlobject.include.tests.test_hashcol.rst b/docs/api/sqlobject.include.tests.test_hashcol.rst index 99c80d9e..0cd6cb95 100644 --- a/docs/api/sqlobject.include.tests.test_hashcol.rst +++ b/docs/api/sqlobject.include.tests.test_hashcol.rst @@ -1,5 +1,5 @@ -sqlobject.include.tests.test_hashcol module -=========================================== +sqlobject\.include\.tests\.test\_hashcol module +=============================================== .. automodule:: sqlobject.include.tests.test_hashcol :members: diff --git a/docs/api/sqlobject.index.rst b/docs/api/sqlobject.index.rst index bc96433c..c2facd02 100644 --- a/docs/api/sqlobject.index.rst +++ b/docs/api/sqlobject.index.rst @@ -1,5 +1,5 @@ -sqlobject.index module -====================== +sqlobject\.index module +======================= .. automodule:: sqlobject.index :members: diff --git a/docs/api/sqlobject.inheritance.iteration.rst b/docs/api/sqlobject.inheritance.iteration.rst index 0e9538f8..b6318065 100644 --- a/docs/api/sqlobject.inheritance.iteration.rst +++ b/docs/api/sqlobject.inheritance.iteration.rst @@ -1,5 +1,5 @@ -sqlobject.inheritance.iteration module -====================================== +sqlobject\.inheritance\.iteration module +======================================== .. automodule:: sqlobject.inheritance.iteration :members: diff --git a/docs/api/sqlobject.inheritance.rst b/docs/api/sqlobject.inheritance.rst index 7ab19a77..5d9dae4c 100644 --- a/docs/api/sqlobject.inheritance.rst +++ b/docs/api/sqlobject.inheritance.rst @@ -1,5 +1,5 @@ -sqlobject.inheritance package -============================= +sqlobject\.inheritance package +============================== .. automodule:: sqlobject.inheritance :members: diff --git a/docs/api/sqlobject.inheritance.tests.rst b/docs/api/sqlobject.inheritance.tests.rst index 994c85ab..c29cbc40 100644 --- a/docs/api/sqlobject.inheritance.tests.rst +++ b/docs/api/sqlobject.inheritance.tests.rst @@ -1,5 +1,5 @@ -sqlobject.inheritance.tests package -=================================== +sqlobject\.inheritance\.tests package +===================================== .. automodule:: sqlobject.inheritance.tests :members: diff --git a/docs/api/sqlobject.inheritance.tests.test_aggregates.rst b/docs/api/sqlobject.inheritance.tests.test_aggregates.rst index ee01f6b6..b93b20f4 100644 --- a/docs/api/sqlobject.inheritance.tests.test_aggregates.rst +++ b/docs/api/sqlobject.inheritance.tests.test_aggregates.rst @@ -1,5 +1,5 @@ -sqlobject.inheritance.tests.test_aggregates module -================================================== +sqlobject\.inheritance\.tests\.test\_aggregates module +====================================================== .. automodule:: sqlobject.inheritance.tests.test_aggregates :members: diff --git a/docs/api/sqlobject.inheritance.tests.test_asdict.rst b/docs/api/sqlobject.inheritance.tests.test_asdict.rst index ff95591f..350e2105 100644 --- a/docs/api/sqlobject.inheritance.tests.test_asdict.rst +++ b/docs/api/sqlobject.inheritance.tests.test_asdict.rst @@ -1,5 +1,5 @@ -sqlobject.inheritance.tests.test_asdict module -============================================== +sqlobject\.inheritance\.tests\.test\_asdict module +================================================== .. automodule:: sqlobject.inheritance.tests.test_asdict :members: diff --git a/docs/api/sqlobject.inheritance.tests.test_deep_inheritance.rst b/docs/api/sqlobject.inheritance.tests.test_deep_inheritance.rst index ed4bf269..a75ee175 100644 --- a/docs/api/sqlobject.inheritance.tests.test_deep_inheritance.rst +++ b/docs/api/sqlobject.inheritance.tests.test_deep_inheritance.rst @@ -1,5 +1,5 @@ -sqlobject.inheritance.tests.test_deep_inheritance module -======================================================== +sqlobject\.inheritance\.tests\.test\_deep\_inheritance module +============================================================= .. automodule:: sqlobject.inheritance.tests.test_deep_inheritance :members: diff --git a/docs/api/sqlobject.inheritance.tests.test_destroy_cascade.rst b/docs/api/sqlobject.inheritance.tests.test_destroy_cascade.rst index 3c5e96dc..80d5359c 100644 --- a/docs/api/sqlobject.inheritance.tests.test_destroy_cascade.rst +++ b/docs/api/sqlobject.inheritance.tests.test_destroy_cascade.rst @@ -1,5 +1,5 @@ -sqlobject.inheritance.tests.test_destroy_cascade module -======================================================= +sqlobject\.inheritance\.tests\.test\_destroy\_cascade module +============================================================ .. automodule:: sqlobject.inheritance.tests.test_destroy_cascade :members: diff --git a/docs/api/sqlobject.inheritance.tests.test_foreignKey.rst b/docs/api/sqlobject.inheritance.tests.test_foreignKey.rst index e3f09426..ebe96a5d 100644 --- a/docs/api/sqlobject.inheritance.tests.test_foreignKey.rst +++ b/docs/api/sqlobject.inheritance.tests.test_foreignKey.rst @@ -1,5 +1,5 @@ -sqlobject.inheritance.tests.test_foreignKey module -================================================== +sqlobject\.inheritance\.tests\.test\_foreignKey module +====================================================== .. automodule:: sqlobject.inheritance.tests.test_foreignKey :members: diff --git a/docs/api/sqlobject.inheritance.tests.test_indexes.rst b/docs/api/sqlobject.inheritance.tests.test_indexes.rst index b2e8d5e6..75ef706c 100644 --- a/docs/api/sqlobject.inheritance.tests.test_indexes.rst +++ b/docs/api/sqlobject.inheritance.tests.test_indexes.rst @@ -1,5 +1,5 @@ -sqlobject.inheritance.tests.test_indexes module -=============================================== +sqlobject\.inheritance\.tests\.test\_indexes module +=================================================== .. automodule:: sqlobject.inheritance.tests.test_indexes :members: diff --git a/docs/api/sqlobject.inheritance.tests.test_inheritance.rst b/docs/api/sqlobject.inheritance.tests.test_inheritance.rst index a0c8e080..f3a19e87 100644 --- a/docs/api/sqlobject.inheritance.tests.test_inheritance.rst +++ b/docs/api/sqlobject.inheritance.tests.test_inheritance.rst @@ -1,5 +1,5 @@ -sqlobject.inheritance.tests.test_inheritance module -=================================================== +sqlobject\.inheritance\.tests\.test\_inheritance module +======================================================= .. automodule:: sqlobject.inheritance.tests.test_inheritance :members: diff --git a/docs/api/sqlobject.inheritance.tests.test_inheritance_tree.rst b/docs/api/sqlobject.inheritance.tests.test_inheritance_tree.rst index b9224cca..66feb6a6 100644 --- a/docs/api/sqlobject.inheritance.tests.test_inheritance_tree.rst +++ b/docs/api/sqlobject.inheritance.tests.test_inheritance_tree.rst @@ -1,5 +1,5 @@ -sqlobject.inheritance.tests.test_inheritance_tree module -======================================================== +sqlobject\.inheritance\.tests\.test\_inheritance\_tree module +============================================================= .. automodule:: sqlobject.inheritance.tests.test_inheritance_tree :members: diff --git a/docs/api/sqlobject.joins.rst b/docs/api/sqlobject.joins.rst index 70e43b04..c864c429 100644 --- a/docs/api/sqlobject.joins.rst +++ b/docs/api/sqlobject.joins.rst @@ -1,5 +1,5 @@ -sqlobject.joins module -====================== +sqlobject\.joins module +======================= .. automodule:: sqlobject.joins :members: diff --git a/docs/api/sqlobject.main.rst b/docs/api/sqlobject.main.rst index b4de5566..5f8c4b8e 100644 --- a/docs/api/sqlobject.main.rst +++ b/docs/api/sqlobject.main.rst @@ -1,5 +1,5 @@ -sqlobject.main module -===================== +sqlobject\.main module +====================== .. automodule:: sqlobject.main :members: diff --git a/docs/api/sqlobject.manager.command.rst b/docs/api/sqlobject.manager.command.rst index bae2b682..7f768f9f 100644 --- a/docs/api/sqlobject.manager.command.rst +++ b/docs/api/sqlobject.manager.command.rst @@ -1,5 +1,5 @@ -sqlobject.manager.command module -================================ +sqlobject\.manager\.command module +================================== .. automodule:: sqlobject.manager.command :members: diff --git a/docs/api/sqlobject.manager.rst b/docs/api/sqlobject.manager.rst index 3a8c8a81..2b3387c6 100644 --- a/docs/api/sqlobject.manager.rst +++ b/docs/api/sqlobject.manager.rst @@ -1,5 +1,5 @@ -sqlobject.manager package -========================= +sqlobject\.manager package +========================== .. automodule:: sqlobject.manager :members: diff --git a/docs/api/sqlobject.maxdb.maxdbconnection.rst b/docs/api/sqlobject.maxdb.maxdbconnection.rst index 1a6490ea..c2cae465 100644 --- a/docs/api/sqlobject.maxdb.maxdbconnection.rst +++ b/docs/api/sqlobject.maxdb.maxdbconnection.rst @@ -1,5 +1,5 @@ -sqlobject.maxdb.maxdbconnection module -====================================== +sqlobject\.maxdb\.maxdbconnection module +======================================== .. automodule:: sqlobject.maxdb.maxdbconnection :members: diff --git a/docs/api/sqlobject.maxdb.rst b/docs/api/sqlobject.maxdb.rst index d591970e..1ca83a35 100644 --- a/docs/api/sqlobject.maxdb.rst +++ b/docs/api/sqlobject.maxdb.rst @@ -1,5 +1,5 @@ -sqlobject.maxdb package -======================= +sqlobject\.maxdb package +======================== .. automodule:: sqlobject.maxdb :members: diff --git a/docs/api/sqlobject.mssql.mssqlconnection.rst b/docs/api/sqlobject.mssql.mssqlconnection.rst index ffcc0023..d3121122 100644 --- a/docs/api/sqlobject.mssql.mssqlconnection.rst +++ b/docs/api/sqlobject.mssql.mssqlconnection.rst @@ -1,5 +1,5 @@ -sqlobject.mssql.mssqlconnection module -====================================== +sqlobject\.mssql\.mssqlconnection module +======================================== .. automodule:: sqlobject.mssql.mssqlconnection :members: diff --git a/docs/api/sqlobject.mssql.rst b/docs/api/sqlobject.mssql.rst index 7e622693..84c45418 100644 --- a/docs/api/sqlobject.mssql.rst +++ b/docs/api/sqlobject.mssql.rst @@ -1,5 +1,5 @@ -sqlobject.mssql package -======================= +sqlobject\.mssql package +======================== .. automodule:: sqlobject.mssql :members: diff --git a/docs/api/sqlobject.mysql.mysqlconnection.rst b/docs/api/sqlobject.mysql.mysqlconnection.rst index 3e5a9ef8..224601ef 100644 --- a/docs/api/sqlobject.mysql.mysqlconnection.rst +++ b/docs/api/sqlobject.mysql.mysqlconnection.rst @@ -1,5 +1,5 @@ -sqlobject.mysql.mysqlconnection module -====================================== +sqlobject\.mysql\.mysqlconnection module +======================================== .. automodule:: sqlobject.mysql.mysqlconnection :members: diff --git a/docs/api/sqlobject.mysql.rst b/docs/api/sqlobject.mysql.rst index 7e69a9e2..e244266d 100644 --- a/docs/api/sqlobject.mysql.rst +++ b/docs/api/sqlobject.mysql.rst @@ -1,5 +1,5 @@ -sqlobject.mysql package -======================= +sqlobject\.mysql package +======================== .. automodule:: sqlobject.mysql :members: diff --git a/docs/api/sqlobject.postgres.pgconnection.rst b/docs/api/sqlobject.postgres.pgconnection.rst index 854104d5..3880e511 100644 --- a/docs/api/sqlobject.postgres.pgconnection.rst +++ b/docs/api/sqlobject.postgres.pgconnection.rst @@ -1,5 +1,5 @@ -sqlobject.postgres.pgconnection module -====================================== +sqlobject\.postgres\.pgconnection module +======================================== .. automodule:: sqlobject.postgres.pgconnection :members: diff --git a/docs/api/sqlobject.postgres.rst b/docs/api/sqlobject.postgres.rst index ad93e75d..5decb52a 100644 --- a/docs/api/sqlobject.postgres.rst +++ b/docs/api/sqlobject.postgres.rst @@ -1,5 +1,5 @@ -sqlobject.postgres package -========================== +sqlobject\.postgres package +=========================== .. automodule:: sqlobject.postgres :members: diff --git a/docs/api/sqlobject.rdbhost.rdbhostconnection.rst b/docs/api/sqlobject.rdbhost.rdbhostconnection.rst index 3f8e7379..016d0e66 100644 --- a/docs/api/sqlobject.rdbhost.rdbhostconnection.rst +++ b/docs/api/sqlobject.rdbhost.rdbhostconnection.rst @@ -1,5 +1,5 @@ -sqlobject.rdbhost.rdbhostconnection module -========================================== +sqlobject\.rdbhost\.rdbhostconnection module +============================================ .. automodule:: sqlobject.rdbhost.rdbhostconnection :members: diff --git a/docs/api/sqlobject.rdbhost.rst b/docs/api/sqlobject.rdbhost.rst index 19f0020d..c4f57c87 100644 --- a/docs/api/sqlobject.rdbhost.rst +++ b/docs/api/sqlobject.rdbhost.rst @@ -1,5 +1,5 @@ -sqlobject.rdbhost package -========================= +sqlobject\.rdbhost package +========================== .. automodule:: sqlobject.rdbhost :members: diff --git a/docs/api/sqlobject.sqlbuilder.rst b/docs/api/sqlobject.sqlbuilder.rst index bd21c086..4c49ca06 100644 --- a/docs/api/sqlobject.sqlbuilder.rst +++ b/docs/api/sqlobject.sqlbuilder.rst @@ -1,5 +1,5 @@ -sqlobject.sqlbuilder module -=========================== +sqlobject\.sqlbuilder module +============================ .. automodule:: sqlobject.sqlbuilder :members: diff --git a/docs/api/sqlobject.sqlite.rst b/docs/api/sqlobject.sqlite.rst index f62364ef..8afe099e 100644 --- a/docs/api/sqlobject.sqlite.rst +++ b/docs/api/sqlobject.sqlite.rst @@ -1,5 +1,5 @@ -sqlobject.sqlite package -======================== +sqlobject\.sqlite package +========================= .. automodule:: sqlobject.sqlite :members: diff --git a/docs/api/sqlobject.sqlite.sqliteconnection.rst b/docs/api/sqlobject.sqlite.sqliteconnection.rst index 0ce1763a..37e64745 100644 --- a/docs/api/sqlobject.sqlite.sqliteconnection.rst +++ b/docs/api/sqlobject.sqlite.sqliteconnection.rst @@ -1,5 +1,5 @@ -sqlobject.sqlite.sqliteconnection module -======================================== +sqlobject\.sqlite\.sqliteconnection module +========================================== .. automodule:: sqlobject.sqlite.sqliteconnection :members: diff --git a/docs/api/sqlobject.sresults.rst b/docs/api/sqlobject.sresults.rst index 690de42e..7b18b85f 100644 --- a/docs/api/sqlobject.sresults.rst +++ b/docs/api/sqlobject.sresults.rst @@ -1,5 +1,5 @@ -sqlobject.sresults module -========================= +sqlobject\.sresults module +========================== .. automodule:: sqlobject.sresults :members: diff --git a/docs/api/sqlobject.styles.rst b/docs/api/sqlobject.styles.rst index 04aeb8c8..f5238168 100644 --- a/docs/api/sqlobject.styles.rst +++ b/docs/api/sqlobject.styles.rst @@ -1,5 +1,5 @@ -sqlobject.styles module -======================= +sqlobject\.styles module +======================== .. automodule:: sqlobject.styles :members: diff --git a/docs/api/sqlobject.sybase.rst b/docs/api/sqlobject.sybase.rst index b5d5aef8..84e1fc2a 100644 --- a/docs/api/sqlobject.sybase.rst +++ b/docs/api/sqlobject.sybase.rst @@ -1,5 +1,5 @@ -sqlobject.sybase package -======================== +sqlobject\.sybase package +========================= .. automodule:: sqlobject.sybase :members: diff --git a/docs/api/sqlobject.sybase.sybaseconnection.rst b/docs/api/sqlobject.sybase.sybaseconnection.rst index 3cdf4c02..b684c94a 100644 --- a/docs/api/sqlobject.sybase.sybaseconnection.rst +++ b/docs/api/sqlobject.sybase.sybaseconnection.rst @@ -1,5 +1,5 @@ -sqlobject.sybase.sybaseconnection module -======================================== +sqlobject\.sybase\.sybaseconnection module +========================================== .. automodule:: sqlobject.sybase.sybaseconnection :members: diff --git a/docs/api/sqlobject.tests.dbtest.rst b/docs/api/sqlobject.tests.dbtest.rst index b6fb5132..617ef7f7 100644 --- a/docs/api/sqlobject.tests.dbtest.rst +++ b/docs/api/sqlobject.tests.dbtest.rst @@ -1,5 +1,5 @@ -sqlobject.tests.dbtest module -============================= +sqlobject\.tests\.dbtest module +=============================== .. automodule:: sqlobject.tests.dbtest :members: diff --git a/docs/api/sqlobject.tests.rst b/docs/api/sqlobject.tests.rst index 98f38cd6..e7a409ce 100644 --- a/docs/api/sqlobject.tests.rst +++ b/docs/api/sqlobject.tests.rst @@ -1,5 +1,5 @@ -sqlobject.tests package -======================= +sqlobject\.tests package +======================== .. automodule:: sqlobject.tests :members: @@ -34,6 +34,7 @@ Submodules sqlobject.tests.test_converters sqlobject.tests.test_create_drop sqlobject.tests.test_csvexport + sqlobject.tests.test_csvimport sqlobject.tests.test_cyclic_reference sqlobject.tests.test_datetime sqlobject.tests.test_decimal diff --git a/docs/api/sqlobject.tests.test_ForeignKey.rst b/docs/api/sqlobject.tests.test_ForeignKey.rst index a4a9dc33..dd3528bb 100644 --- a/docs/api/sqlobject.tests.test_ForeignKey.rst +++ b/docs/api/sqlobject.tests.test_ForeignKey.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_ForeignKey module -====================================== +sqlobject\.tests\.test\_ForeignKey module +========================================= .. automodule:: sqlobject.tests.test_ForeignKey :members: diff --git a/docs/api/sqlobject.tests.test_NoneValuedResultItem.rst b/docs/api/sqlobject.tests.test_NoneValuedResultItem.rst index 9e0a01e2..498f61ff 100644 --- a/docs/api/sqlobject.tests.test_NoneValuedResultItem.rst +++ b/docs/api/sqlobject.tests.test_NoneValuedResultItem.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_NoneValuedResultItem module -================================================ +sqlobject\.tests\.test\_NoneValuedResultItem module +=================================================== .. automodule:: sqlobject.tests.test_NoneValuedResultItem :members: diff --git a/docs/api/sqlobject.tests.test_SQLMultipleJoin.rst b/docs/api/sqlobject.tests.test_SQLMultipleJoin.rst index c7e1ee1b..9778df98 100644 --- a/docs/api/sqlobject.tests.test_SQLMultipleJoin.rst +++ b/docs/api/sqlobject.tests.test_SQLMultipleJoin.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_SQLMultipleJoin module -=========================================== +sqlobject\.tests\.test\_SQLMultipleJoin module +============================================== .. automodule:: sqlobject.tests.test_SQLMultipleJoin :members: diff --git a/docs/api/sqlobject.tests.test_SQLRelatedJoin.rst b/docs/api/sqlobject.tests.test_SQLRelatedJoin.rst index ffd4f028..67606574 100644 --- a/docs/api/sqlobject.tests.test_SQLRelatedJoin.rst +++ b/docs/api/sqlobject.tests.test_SQLRelatedJoin.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_SQLRelatedJoin module -========================================== +sqlobject\.tests\.test\_SQLRelatedJoin module +============================================= .. automodule:: sqlobject.tests.test_SQLRelatedJoin :members: diff --git a/docs/api/sqlobject.tests.test_SingleJoin.rst b/docs/api/sqlobject.tests.test_SingleJoin.rst index 2f0f52a3..5ded2b3c 100644 --- a/docs/api/sqlobject.tests.test_SingleJoin.rst +++ b/docs/api/sqlobject.tests.test_SingleJoin.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_SingleJoin module -====================================== +sqlobject\.tests\.test\_SingleJoin module +========================================= .. automodule:: sqlobject.tests.test_SingleJoin :members: diff --git a/docs/api/sqlobject.tests.test_aggregates.rst b/docs/api/sqlobject.tests.test_aggregates.rst index c64faf15..451944f7 100644 --- a/docs/api/sqlobject.tests.test_aggregates.rst +++ b/docs/api/sqlobject.tests.test_aggregates.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_aggregates module -====================================== +sqlobject\.tests\.test\_aggregates module +========================================= .. automodule:: sqlobject.tests.test_aggregates :members: diff --git a/docs/api/sqlobject.tests.test_aliases.rst b/docs/api/sqlobject.tests.test_aliases.rst index c883b8c1..e26df53c 100644 --- a/docs/api/sqlobject.tests.test_aliases.rst +++ b/docs/api/sqlobject.tests.test_aliases.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_aliases module -=================================== +sqlobject\.tests\.test\_aliases module +====================================== .. automodule:: sqlobject.tests.test_aliases :members: diff --git a/docs/api/sqlobject.tests.test_asdict.rst b/docs/api/sqlobject.tests.test_asdict.rst index 40e4c364..be828dc4 100644 --- a/docs/api/sqlobject.tests.test_asdict.rst +++ b/docs/api/sqlobject.tests.test_asdict.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_asdict module -================================== +sqlobject\.tests\.test\_asdict module +===================================== .. automodule:: sqlobject.tests.test_asdict :members: diff --git a/docs/api/sqlobject.tests.test_auto.rst b/docs/api/sqlobject.tests.test_auto.rst index 0ea2f524..328ee8e3 100644 --- a/docs/api/sqlobject.tests.test_auto.rst +++ b/docs/api/sqlobject.tests.test_auto.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_auto module -================================ +sqlobject\.tests\.test\_auto module +=================================== .. automodule:: sqlobject.tests.test_auto :members: diff --git a/docs/api/sqlobject.tests.test_basic.rst b/docs/api/sqlobject.tests.test_basic.rst index fabffe60..9a16a4af 100644 --- a/docs/api/sqlobject.tests.test_basic.rst +++ b/docs/api/sqlobject.tests.test_basic.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_basic module -================================= +sqlobject\.tests\.test\_basic module +==================================== .. automodule:: sqlobject.tests.test_basic :members: diff --git a/docs/api/sqlobject.tests.test_blob.rst b/docs/api/sqlobject.tests.test_blob.rst index e3c67850..bc958eba 100644 --- a/docs/api/sqlobject.tests.test_blob.rst +++ b/docs/api/sqlobject.tests.test_blob.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_blob module -================================ +sqlobject\.tests\.test\_blob module +=================================== .. automodule:: sqlobject.tests.test_blob :members: diff --git a/docs/api/sqlobject.tests.test_boundattributes.rst b/docs/api/sqlobject.tests.test_boundattributes.rst index a648d71c..ec672dfb 100644 --- a/docs/api/sqlobject.tests.test_boundattributes.rst +++ b/docs/api/sqlobject.tests.test_boundattributes.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_boundattributes module -=========================================== +sqlobject\.tests\.test\_boundattributes module +============================================== .. automodule:: sqlobject.tests.test_boundattributes :members: diff --git a/docs/api/sqlobject.tests.test_cache.rst b/docs/api/sqlobject.tests.test_cache.rst index dd344907..3d8e8328 100644 --- a/docs/api/sqlobject.tests.test_cache.rst +++ b/docs/api/sqlobject.tests.test_cache.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_cache module -================================= +sqlobject\.tests\.test\_cache module +==================================== .. automodule:: sqlobject.tests.test_cache :members: diff --git a/docs/api/sqlobject.tests.test_class_hash.rst b/docs/api/sqlobject.tests.test_class_hash.rst index 17fc1371..77e9a5f7 100644 --- a/docs/api/sqlobject.tests.test_class_hash.rst +++ b/docs/api/sqlobject.tests.test_class_hash.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_class_hash module -====================================== +sqlobject\.tests\.test\_class\_hash module +========================================== .. automodule:: sqlobject.tests.test_class_hash :members: diff --git a/docs/api/sqlobject.tests.test_columns_order.rst b/docs/api/sqlobject.tests.test_columns_order.rst index 12c5b619..ced1883c 100644 --- a/docs/api/sqlobject.tests.test_columns_order.rst +++ b/docs/api/sqlobject.tests.test_columns_order.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_columns_order module -========================================= +sqlobject\.tests\.test\_columns\_order module +============================================= .. automodule:: sqlobject.tests.test_columns_order :members: diff --git a/docs/api/sqlobject.tests.test_combining_joins.rst b/docs/api/sqlobject.tests.test_combining_joins.rst index 7ab4faa3..99cd4059 100644 --- a/docs/api/sqlobject.tests.test_combining_joins.rst +++ b/docs/api/sqlobject.tests.test_combining_joins.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_combining_joins module -=========================================== +sqlobject\.tests\.test\_combining\_joins module +=============================================== .. automodule:: sqlobject.tests.test_combining_joins :members: diff --git a/docs/api/sqlobject.tests.test_comparison.rst b/docs/api/sqlobject.tests.test_comparison.rst index f44f5ffc..e54aacc3 100644 --- a/docs/api/sqlobject.tests.test_comparison.rst +++ b/docs/api/sqlobject.tests.test_comparison.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_comparison module -====================================== +sqlobject\.tests\.test\_comparison module +========================================= .. automodule:: sqlobject.tests.test_comparison :members: diff --git a/docs/api/sqlobject.tests.test_complex_sorting.rst b/docs/api/sqlobject.tests.test_complex_sorting.rst index a2f9eb8b..fdcd3eda 100644 --- a/docs/api/sqlobject.tests.test_complex_sorting.rst +++ b/docs/api/sqlobject.tests.test_complex_sorting.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_complex_sorting module -=========================================== +sqlobject\.tests\.test\_complex\_sorting module +=============================================== .. automodule:: sqlobject.tests.test_complex_sorting :members: diff --git a/docs/api/sqlobject.tests.test_constraints.rst b/docs/api/sqlobject.tests.test_constraints.rst index 6ddd2f69..d3521779 100644 --- a/docs/api/sqlobject.tests.test_constraints.rst +++ b/docs/api/sqlobject.tests.test_constraints.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_constraints module -======================================= +sqlobject\.tests\.test\_constraints module +========================================== .. automodule:: sqlobject.tests.test_constraints :members: diff --git a/docs/api/sqlobject.tests.test_converters.rst b/docs/api/sqlobject.tests.test_converters.rst index fd05137e..4548363b 100644 --- a/docs/api/sqlobject.tests.test_converters.rst +++ b/docs/api/sqlobject.tests.test_converters.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_converters module -====================================== +sqlobject\.tests\.test\_converters module +========================================= .. automodule:: sqlobject.tests.test_converters :members: diff --git a/docs/api/sqlobject.tests.test_create_drop.rst b/docs/api/sqlobject.tests.test_create_drop.rst index 173f9608..3ffe5565 100644 --- a/docs/api/sqlobject.tests.test_create_drop.rst +++ b/docs/api/sqlobject.tests.test_create_drop.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_create_drop module -======================================= +sqlobject\.tests\.test\_create\_drop module +=========================================== .. automodule:: sqlobject.tests.test_create_drop :members: diff --git a/docs/api/sqlobject.tests.test_csvexport.rst b/docs/api/sqlobject.tests.test_csvexport.rst index 26b28675..2e098d8b 100644 --- a/docs/api/sqlobject.tests.test_csvexport.rst +++ b/docs/api/sqlobject.tests.test_csvexport.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_csvexport module -===================================== +sqlobject\.tests\.test\_csvexport module +======================================== .. automodule:: sqlobject.tests.test_csvexport :members: diff --git a/docs/api/sqlobject.tests.test_cyclic_reference.rst b/docs/api/sqlobject.tests.test_cyclic_reference.rst index 21ecd08d..b43d7bfb 100644 --- a/docs/api/sqlobject.tests.test_cyclic_reference.rst +++ b/docs/api/sqlobject.tests.test_cyclic_reference.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_cyclic_reference module -============================================ +sqlobject\.tests\.test\_cyclic\_reference module +================================================ .. automodule:: sqlobject.tests.test_cyclic_reference :members: diff --git a/docs/api/sqlobject.tests.test_datetime.rst b/docs/api/sqlobject.tests.test_datetime.rst index e2198966..d76a114b 100644 --- a/docs/api/sqlobject.tests.test_datetime.rst +++ b/docs/api/sqlobject.tests.test_datetime.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_datetime module -==================================== +sqlobject\.tests\.test\_datetime module +======================================= .. automodule:: sqlobject.tests.test_datetime :members: diff --git a/docs/api/sqlobject.tests.test_decimal.rst b/docs/api/sqlobject.tests.test_decimal.rst index 7752caaf..224d2053 100644 --- a/docs/api/sqlobject.tests.test_decimal.rst +++ b/docs/api/sqlobject.tests.test_decimal.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_decimal module -=================================== +sqlobject\.tests\.test\_decimal module +====================================== .. automodule:: sqlobject.tests.test_decimal :members: diff --git a/docs/api/sqlobject.tests.test_declarative.rst b/docs/api/sqlobject.tests.test_declarative.rst index 2c5c2c23..097a81fc 100644 --- a/docs/api/sqlobject.tests.test_declarative.rst +++ b/docs/api/sqlobject.tests.test_declarative.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_declarative module -======================================= +sqlobject\.tests\.test\_declarative module +========================================== .. automodule:: sqlobject.tests.test_declarative :members: diff --git a/docs/api/sqlobject.tests.test_default_style.rst b/docs/api/sqlobject.tests.test_default_style.rst index 8245134b..50868333 100644 --- a/docs/api/sqlobject.tests.test_default_style.rst +++ b/docs/api/sqlobject.tests.test_default_style.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_default_style module -========================================= +sqlobject\.tests\.test\_default\_style module +============================================= .. automodule:: sqlobject.tests.test_default_style :members: diff --git a/docs/api/sqlobject.tests.test_delete.rst b/docs/api/sqlobject.tests.test_delete.rst index 65f95c8b..aa915722 100644 --- a/docs/api/sqlobject.tests.test_delete.rst +++ b/docs/api/sqlobject.tests.test_delete.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_delete module -================================== +sqlobject\.tests\.test\_delete module +===================================== .. automodule:: sqlobject.tests.test_delete :members: diff --git a/docs/api/sqlobject.tests.test_distinct.rst b/docs/api/sqlobject.tests.test_distinct.rst index c7ab42ca..89cee6c2 100644 --- a/docs/api/sqlobject.tests.test_distinct.rst +++ b/docs/api/sqlobject.tests.test_distinct.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_distinct module -==================================== +sqlobject\.tests\.test\_distinct module +======================================= .. automodule:: sqlobject.tests.test_distinct :members: diff --git a/docs/api/sqlobject.tests.test_empty.rst b/docs/api/sqlobject.tests.test_empty.rst index d10bc015..111994c7 100644 --- a/docs/api/sqlobject.tests.test_empty.rst +++ b/docs/api/sqlobject.tests.test_empty.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_empty module -================================= +sqlobject\.tests\.test\_empty module +==================================== .. automodule:: sqlobject.tests.test_empty :members: diff --git a/docs/api/sqlobject.tests.test_enum.rst b/docs/api/sqlobject.tests.test_enum.rst index 11f97770..a02cfc2a 100644 --- a/docs/api/sqlobject.tests.test_enum.rst +++ b/docs/api/sqlobject.tests.test_enum.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_enum module -================================ +sqlobject\.tests\.test\_enum module +=================================== .. automodule:: sqlobject.tests.test_enum :members: diff --git a/docs/api/sqlobject.tests.test_events.rst b/docs/api/sqlobject.tests.test_events.rst index d6c08997..fe270079 100644 --- a/docs/api/sqlobject.tests.test_events.rst +++ b/docs/api/sqlobject.tests.test_events.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_events module -================================== +sqlobject\.tests\.test\_events module +===================================== .. automodule:: sqlobject.tests.test_events :members: diff --git a/docs/api/sqlobject.tests.test_exceptions.rst b/docs/api/sqlobject.tests.test_exceptions.rst index 6c92b729..3352e3d4 100644 --- a/docs/api/sqlobject.tests.test_exceptions.rst +++ b/docs/api/sqlobject.tests.test_exceptions.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_exceptions module -====================================== +sqlobject\.tests\.test\_exceptions module +========================================= .. automodule:: sqlobject.tests.test_exceptions :members: diff --git a/docs/api/sqlobject.tests.test_expire.rst b/docs/api/sqlobject.tests.test_expire.rst index e2d56ea9..6f568627 100644 --- a/docs/api/sqlobject.tests.test_expire.rst +++ b/docs/api/sqlobject.tests.test_expire.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_expire module -================================== +sqlobject\.tests\.test\_expire module +===================================== .. automodule:: sqlobject.tests.test_expire :members: diff --git a/docs/api/sqlobject.tests.test_groupBy.rst b/docs/api/sqlobject.tests.test_groupBy.rst index fd8cc9ff..9536c568 100644 --- a/docs/api/sqlobject.tests.test_groupBy.rst +++ b/docs/api/sqlobject.tests.test_groupBy.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_groupBy module -=================================== +sqlobject\.tests\.test\_groupBy module +====================================== .. automodule:: sqlobject.tests.test_groupBy :members: diff --git a/docs/api/sqlobject.tests.test_identity.rst b/docs/api/sqlobject.tests.test_identity.rst index 8e8537c4..3fc6961f 100644 --- a/docs/api/sqlobject.tests.test_identity.rst +++ b/docs/api/sqlobject.tests.test_identity.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_identity module -==================================== +sqlobject\.tests\.test\_identity module +======================================= .. automodule:: sqlobject.tests.test_identity :members: diff --git a/docs/api/sqlobject.tests.test_indexes.rst b/docs/api/sqlobject.tests.test_indexes.rst index f862ac8d..2ab389ca 100644 --- a/docs/api/sqlobject.tests.test_indexes.rst +++ b/docs/api/sqlobject.tests.test_indexes.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_indexes module -=================================== +sqlobject\.tests\.test\_indexes module +====================================== .. automodule:: sqlobject.tests.test_indexes :members: diff --git a/docs/api/sqlobject.tests.test_inheritance.rst b/docs/api/sqlobject.tests.test_inheritance.rst index 2913d3a6..c54693e3 100644 --- a/docs/api/sqlobject.tests.test_inheritance.rst +++ b/docs/api/sqlobject.tests.test_inheritance.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_inheritance module -======================================= +sqlobject\.tests\.test\_inheritance module +========================================== .. automodule:: sqlobject.tests.test_inheritance :members: diff --git a/docs/api/sqlobject.tests.test_joins.rst b/docs/api/sqlobject.tests.test_joins.rst index 08f486eb..a9f1c912 100644 --- a/docs/api/sqlobject.tests.test_joins.rst +++ b/docs/api/sqlobject.tests.test_joins.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_joins module -================================= +sqlobject\.tests\.test\_joins module +==================================== .. automodule:: sqlobject.tests.test_joins :members: diff --git a/docs/api/sqlobject.tests.test_joins_conditional.rst b/docs/api/sqlobject.tests.test_joins_conditional.rst index a347d30c..41d2b748 100644 --- a/docs/api/sqlobject.tests.test_joins_conditional.rst +++ b/docs/api/sqlobject.tests.test_joins_conditional.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_joins_conditional module -============================================= +sqlobject\.tests\.test\_joins\_conditional module +================================================= .. automodule:: sqlobject.tests.test_joins_conditional :members: diff --git a/docs/api/sqlobject.tests.test_jsonbcol.rst b/docs/api/sqlobject.tests.test_jsonbcol.rst index ef8a6b86..9a20476f 100644 --- a/docs/api/sqlobject.tests.test_jsonbcol.rst +++ b/docs/api/sqlobject.tests.test_jsonbcol.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_jsonbcol module -==================================== +sqlobject\.tests\.test\_jsonbcol module +======================================= .. automodule:: sqlobject.tests.test_jsonbcol :members: diff --git a/docs/api/sqlobject.tests.test_jsoncol.rst b/docs/api/sqlobject.tests.test_jsoncol.rst index 93ba6fb4..8bc266f6 100644 --- a/docs/api/sqlobject.tests.test_jsoncol.rst +++ b/docs/api/sqlobject.tests.test_jsoncol.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_jsoncol module -=================================== +sqlobject\.tests\.test\_jsoncol module +====================================== .. automodule:: sqlobject.tests.test_jsoncol :members: diff --git a/docs/api/sqlobject.tests.test_lazy.rst b/docs/api/sqlobject.tests.test_lazy.rst index 317b3650..1d23c93f 100644 --- a/docs/api/sqlobject.tests.test_lazy.rst +++ b/docs/api/sqlobject.tests.test_lazy.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_lazy module -================================ +sqlobject\.tests\.test\_lazy module +=================================== .. automodule:: sqlobject.tests.test_lazy :members: diff --git a/docs/api/sqlobject.tests.test_md5.rst b/docs/api/sqlobject.tests.test_md5.rst index d71f26b0..8ea42178 100644 --- a/docs/api/sqlobject.tests.test_md5.rst +++ b/docs/api/sqlobject.tests.test_md5.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_md5 module -=============================== +sqlobject\.tests\.test\_md5 module +================================== .. automodule:: sqlobject.tests.test_md5 :members: diff --git a/docs/api/sqlobject.tests.test_mysql.rst b/docs/api/sqlobject.tests.test_mysql.rst index 881f36db..1ac3d767 100644 --- a/docs/api/sqlobject.tests.test_mysql.rst +++ b/docs/api/sqlobject.tests.test_mysql.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_mysql module -================================= +sqlobject\.tests\.test\_mysql module +==================================== .. automodule:: sqlobject.tests.test_mysql :members: diff --git a/docs/api/sqlobject.tests.test_new_joins.rst b/docs/api/sqlobject.tests.test_new_joins.rst index abff0b3f..f6c56d64 100644 --- a/docs/api/sqlobject.tests.test_new_joins.rst +++ b/docs/api/sqlobject.tests.test_new_joins.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_new_joins module -===================================== +sqlobject\.tests\.test\_new\_joins module +========================================= .. automodule:: sqlobject.tests.test_new_joins :members: diff --git a/docs/api/sqlobject.tests.test_parse_uri.rst b/docs/api/sqlobject.tests.test_parse_uri.rst index 8d33ae5b..d5adf4e9 100644 --- a/docs/api/sqlobject.tests.test_parse_uri.rst +++ b/docs/api/sqlobject.tests.test_parse_uri.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_parse_uri module -===================================== +sqlobject\.tests\.test\_parse\_uri module +========================================= .. automodule:: sqlobject.tests.test_parse_uri :members: diff --git a/docs/api/sqlobject.tests.test_paste.rst b/docs/api/sqlobject.tests.test_paste.rst index 64607769..cf1b30d3 100644 --- a/docs/api/sqlobject.tests.test_paste.rst +++ b/docs/api/sqlobject.tests.test_paste.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_paste module -================================= +sqlobject\.tests\.test\_paste module +==================================== .. automodule:: sqlobject.tests.test_paste :members: diff --git a/docs/api/sqlobject.tests.test_perConnection.rst b/docs/api/sqlobject.tests.test_perConnection.rst index d36711a0..7534fca3 100644 --- a/docs/api/sqlobject.tests.test_perConnection.rst +++ b/docs/api/sqlobject.tests.test_perConnection.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_perConnection module -========================================= +sqlobject\.tests\.test\_perConnection module +============================================ .. automodule:: sqlobject.tests.test_perConnection :members: diff --git a/docs/api/sqlobject.tests.test_pickle.rst b/docs/api/sqlobject.tests.test_pickle.rst index a1540275..0237ccd3 100644 --- a/docs/api/sqlobject.tests.test_pickle.rst +++ b/docs/api/sqlobject.tests.test_pickle.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_pickle module -================================== +sqlobject\.tests\.test\_pickle module +===================================== .. automodule:: sqlobject.tests.test_pickle :members: diff --git a/docs/api/sqlobject.tests.test_picklecol.rst b/docs/api/sqlobject.tests.test_picklecol.rst index be2c174f..ea3f1655 100644 --- a/docs/api/sqlobject.tests.test_picklecol.rst +++ b/docs/api/sqlobject.tests.test_picklecol.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_picklecol module -===================================== +sqlobject\.tests\.test\_picklecol module +======================================== .. automodule:: sqlobject.tests.test_picklecol :members: diff --git a/docs/api/sqlobject.tests.test_postgres.rst b/docs/api/sqlobject.tests.test_postgres.rst index 393803db..00a6b45c 100644 --- a/docs/api/sqlobject.tests.test_postgres.rst +++ b/docs/api/sqlobject.tests.test_postgres.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_postgres module -==================================== +sqlobject\.tests\.test\_postgres module +======================================= .. automodule:: sqlobject.tests.test_postgres :members: diff --git a/docs/api/sqlobject.tests.test_reparent_sqlmeta.rst b/docs/api/sqlobject.tests.test_reparent_sqlmeta.rst index 60a316e9..e40f45bb 100644 --- a/docs/api/sqlobject.tests.test_reparent_sqlmeta.rst +++ b/docs/api/sqlobject.tests.test_reparent_sqlmeta.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_reparent_sqlmeta module -============================================ +sqlobject\.tests\.test\_reparent\_sqlmeta module +================================================ .. automodule:: sqlobject.tests.test_reparent_sqlmeta :members: diff --git a/docs/api/sqlobject.tests.test_schema.rst b/docs/api/sqlobject.tests.test_schema.rst index b5a5c6bc..f776e2aa 100644 --- a/docs/api/sqlobject.tests.test_schema.rst +++ b/docs/api/sqlobject.tests.test_schema.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_schema module -================================== +sqlobject\.tests\.test\_schema module +===================================== .. automodule:: sqlobject.tests.test_schema :members: diff --git a/docs/api/sqlobject.tests.test_select.rst b/docs/api/sqlobject.tests.test_select.rst index f3bda2ac..24c15796 100644 --- a/docs/api/sqlobject.tests.test_select.rst +++ b/docs/api/sqlobject.tests.test_select.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_select module -================================== +sqlobject\.tests\.test\_select module +===================================== .. automodule:: sqlobject.tests.test_select :members: diff --git a/docs/api/sqlobject.tests.test_select_through.rst b/docs/api/sqlobject.tests.test_select_through.rst index 8a1c7a92..776becf4 100644 --- a/docs/api/sqlobject.tests.test_select_through.rst +++ b/docs/api/sqlobject.tests.test_select_through.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_select_through module -========================================== +sqlobject\.tests\.test\_select\_through module +============================================== .. automodule:: sqlobject.tests.test_select_through :members: diff --git a/docs/api/sqlobject.tests.test_setters.rst b/docs/api/sqlobject.tests.test_setters.rst index 110c04d3..e94f949c 100644 --- a/docs/api/sqlobject.tests.test_setters.rst +++ b/docs/api/sqlobject.tests.test_setters.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_setters module -=================================== +sqlobject\.tests\.test\_setters module +====================================== .. automodule:: sqlobject.tests.test_setters :members: diff --git a/docs/api/sqlobject.tests.test_slice.rst b/docs/api/sqlobject.tests.test_slice.rst index 7486e203..116130ec 100644 --- a/docs/api/sqlobject.tests.test_slice.rst +++ b/docs/api/sqlobject.tests.test_slice.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_slice module -================================= +sqlobject\.tests\.test\_slice module +==================================== .. automodule:: sqlobject.tests.test_slice :members: diff --git a/docs/api/sqlobject.tests.test_sorting.rst b/docs/api/sqlobject.tests.test_sorting.rst index f15e9fea..2a3cf121 100644 --- a/docs/api/sqlobject.tests.test_sorting.rst +++ b/docs/api/sqlobject.tests.test_sorting.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_sorting module -=================================== +sqlobject\.tests\.test\_sorting module +====================================== .. automodule:: sqlobject.tests.test_sorting :members: diff --git a/docs/api/sqlobject.tests.test_sqlbuilder.rst b/docs/api/sqlobject.tests.test_sqlbuilder.rst index 18f50c13..02a39b3e 100644 --- a/docs/api/sqlobject.tests.test_sqlbuilder.rst +++ b/docs/api/sqlobject.tests.test_sqlbuilder.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_sqlbuilder module -====================================== +sqlobject\.tests\.test\_sqlbuilder module +========================================= .. automodule:: sqlobject.tests.test_sqlbuilder :members: diff --git a/docs/api/sqlobject.tests.test_sqlbuilder_dbspecific.rst b/docs/api/sqlobject.tests.test_sqlbuilder_dbspecific.rst index 27b8b45a..b71c441d 100644 --- a/docs/api/sqlobject.tests.test_sqlbuilder_dbspecific.rst +++ b/docs/api/sqlobject.tests.test_sqlbuilder_dbspecific.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_sqlbuilder_dbspecific module -================================================= +sqlobject\.tests\.test\_sqlbuilder\_dbspecific module +===================================================== .. automodule:: sqlobject.tests.test_sqlbuilder_dbspecific :members: diff --git a/docs/api/sqlobject.tests.test_sqlbuilder_importproxy.rst b/docs/api/sqlobject.tests.test_sqlbuilder_importproxy.rst index 45d83c04..d6c874d1 100644 --- a/docs/api/sqlobject.tests.test_sqlbuilder_importproxy.rst +++ b/docs/api/sqlobject.tests.test_sqlbuilder_importproxy.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_sqlbuilder_importproxy module -================================================== +sqlobject\.tests\.test\_sqlbuilder\_importproxy module +====================================================== .. automodule:: sqlobject.tests.test_sqlbuilder_importproxy :members: diff --git a/docs/api/sqlobject.tests.test_sqlbuilder_joins_instances.rst b/docs/api/sqlobject.tests.test_sqlbuilder_joins_instances.rst index 0789abd1..c6f2b4d5 100644 --- a/docs/api/sqlobject.tests.test_sqlbuilder_joins_instances.rst +++ b/docs/api/sqlobject.tests.test_sqlbuilder_joins_instances.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_sqlbuilder_joins_instances module -====================================================== +sqlobject\.tests\.test\_sqlbuilder\_joins\_instances module +=========================================================== .. automodule:: sqlobject.tests.test_sqlbuilder_joins_instances :members: diff --git a/docs/api/sqlobject.tests.test_sqlite.rst b/docs/api/sqlobject.tests.test_sqlite.rst index d6004569..3eedfab3 100644 --- a/docs/api/sqlobject.tests.test_sqlite.rst +++ b/docs/api/sqlobject.tests.test_sqlite.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_sqlite module -================================== +sqlobject\.tests\.test\_sqlite module +===================================== .. automodule:: sqlobject.tests.test_sqlite :members: diff --git a/docs/api/sqlobject.tests.test_sqlmeta_idName.rst b/docs/api/sqlobject.tests.test_sqlmeta_idName.rst index c051696c..e01eb945 100644 --- a/docs/api/sqlobject.tests.test_sqlmeta_idName.rst +++ b/docs/api/sqlobject.tests.test_sqlmeta_idName.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_sqlmeta_idName module -========================================== +sqlobject\.tests\.test\_sqlmeta\_idName module +============================================== .. automodule:: sqlobject.tests.test_sqlmeta_idName :members: diff --git a/docs/api/sqlobject.tests.test_sqlobject_admin.rst b/docs/api/sqlobject.tests.test_sqlobject_admin.rst index 71d3114a..b062e12f 100644 --- a/docs/api/sqlobject.tests.test_sqlobject_admin.rst +++ b/docs/api/sqlobject.tests.test_sqlobject_admin.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_sqlobject_admin module -=========================================== +sqlobject\.tests\.test\_sqlobject\_admin module +=============================================== .. automodule:: sqlobject.tests.test_sqlobject_admin :members: diff --git a/docs/api/sqlobject.tests.test_string_id.rst b/docs/api/sqlobject.tests.test_string_id.rst index 70116477..217ddd01 100644 --- a/docs/api/sqlobject.tests.test_string_id.rst +++ b/docs/api/sqlobject.tests.test_string_id.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_string_id module -===================================== +sqlobject\.tests\.test\_string\_id module +========================================= .. automodule:: sqlobject.tests.test_string_id :members: diff --git a/docs/api/sqlobject.tests.test_style.rst b/docs/api/sqlobject.tests.test_style.rst index 202721a4..1dc12bd3 100644 --- a/docs/api/sqlobject.tests.test_style.rst +++ b/docs/api/sqlobject.tests.test_style.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_style module -================================= +sqlobject\.tests\.test\_style module +==================================== .. automodule:: sqlobject.tests.test_style :members: diff --git a/docs/api/sqlobject.tests.test_subqueries.rst b/docs/api/sqlobject.tests.test_subqueries.rst index 97ee2874..83ffaed0 100644 --- a/docs/api/sqlobject.tests.test_subqueries.rst +++ b/docs/api/sqlobject.tests.test_subqueries.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_subqueries module -====================================== +sqlobject\.tests\.test\_subqueries module +========================================= .. automodule:: sqlobject.tests.test_subqueries :members: diff --git a/docs/api/sqlobject.tests.test_transactions.rst b/docs/api/sqlobject.tests.test_transactions.rst index 1e2cd7e5..355d49c8 100644 --- a/docs/api/sqlobject.tests.test_transactions.rst +++ b/docs/api/sqlobject.tests.test_transactions.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_transactions module -======================================== +sqlobject\.tests\.test\_transactions module +=========================================== .. automodule:: sqlobject.tests.test_transactions :members: diff --git a/docs/api/sqlobject.tests.test_unicode.rst b/docs/api/sqlobject.tests.test_unicode.rst index 7ac2e758..1e55d7c7 100644 --- a/docs/api/sqlobject.tests.test_unicode.rst +++ b/docs/api/sqlobject.tests.test_unicode.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_unicode module -=================================== +sqlobject\.tests\.test\_unicode module +====================================== .. automodule:: sqlobject.tests.test_unicode :members: diff --git a/docs/api/sqlobject.tests.test_uuidcol.rst b/docs/api/sqlobject.tests.test_uuidcol.rst index f6e30079..3d587e2a 100644 --- a/docs/api/sqlobject.tests.test_uuidcol.rst +++ b/docs/api/sqlobject.tests.test_uuidcol.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_uuidcol module -=================================== +sqlobject\.tests\.test\_uuidcol module +====================================== .. automodule:: sqlobject.tests.test_uuidcol :members: diff --git a/docs/api/sqlobject.tests.test_validation.rst b/docs/api/sqlobject.tests.test_validation.rst index c0240304..430cd6ef 100644 --- a/docs/api/sqlobject.tests.test_validation.rst +++ b/docs/api/sqlobject.tests.test_validation.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_validation module -====================================== +sqlobject\.tests\.test\_validation module +========================================= .. automodule:: sqlobject.tests.test_validation :members: diff --git a/docs/api/sqlobject.tests.test_views.rst b/docs/api/sqlobject.tests.test_views.rst index be986715..cb1cddbc 100644 --- a/docs/api/sqlobject.tests.test_views.rst +++ b/docs/api/sqlobject.tests.test_views.rst @@ -1,5 +1,5 @@ -sqlobject.tests.test_views module -================================= +sqlobject\.tests\.test\_views module +==================================== .. automodule:: sqlobject.tests.test_views :members: diff --git a/docs/api/sqlobject.util.csvexport.rst b/docs/api/sqlobject.util.csvexport.rst index 25a3cb86..465bed93 100644 --- a/docs/api/sqlobject.util.csvexport.rst +++ b/docs/api/sqlobject.util.csvexport.rst @@ -1,5 +1,5 @@ -sqlobject.util.csvexport module -=============================== +sqlobject\.util\.csvexport module +================================= .. automodule:: sqlobject.util.csvexport :members: diff --git a/docs/api/sqlobject.util.csvimport.rst b/docs/api/sqlobject.util.csvimport.rst index 415b518c..6b19ee8d 100644 --- a/docs/api/sqlobject.util.csvimport.rst +++ b/docs/api/sqlobject.util.csvimport.rst @@ -1,5 +1,5 @@ -sqlobject.util.csvimport module -=============================== +sqlobject\.util\.csvimport module +================================= .. automodule:: sqlobject.util.csvimport :members: diff --git a/docs/api/sqlobject.util.moduleloader.rst b/docs/api/sqlobject.util.moduleloader.rst index f262edad..9bfeb892 100644 --- a/docs/api/sqlobject.util.moduleloader.rst +++ b/docs/api/sqlobject.util.moduleloader.rst @@ -1,5 +1,5 @@ -sqlobject.util.moduleloader module -================================== +sqlobject\.util\.moduleloader module +==================================== .. automodule:: sqlobject.util.moduleloader :members: diff --git a/docs/api/sqlobject.util.rst b/docs/api/sqlobject.util.rst index 9f5c1b38..2e194f23 100644 --- a/docs/api/sqlobject.util.rst +++ b/docs/api/sqlobject.util.rst @@ -1,5 +1,5 @@ -sqlobject.util package -====================== +sqlobject\.util package +======================= .. automodule:: sqlobject.util :members: diff --git a/docs/api/sqlobject.util.threadinglocal.rst b/docs/api/sqlobject.util.threadinglocal.rst index dddba4d2..3511fe17 100644 --- a/docs/api/sqlobject.util.threadinglocal.rst +++ b/docs/api/sqlobject.util.threadinglocal.rst @@ -1,5 +1,5 @@ -sqlobject.util.threadinglocal module -==================================== +sqlobject\.util\.threadinglocal module +====================================== .. automodule:: sqlobject.util.threadinglocal :members: diff --git a/docs/api/sqlobject.versioning.rst b/docs/api/sqlobject.versioning.rst index 852d3e95..5f8c4d28 100644 --- a/docs/api/sqlobject.versioning.rst +++ b/docs/api/sqlobject.versioning.rst @@ -1,5 +1,5 @@ -sqlobject.versioning package -============================ +sqlobject\.versioning package +============================= .. automodule:: sqlobject.versioning :members: diff --git a/docs/api/sqlobject.versioning.test.rst b/docs/api/sqlobject.versioning.test.rst index 6f9ea366..f87edc23 100644 --- a/docs/api/sqlobject.versioning.test.rst +++ b/docs/api/sqlobject.versioning.test.rst @@ -1,5 +1,5 @@ -sqlobject.versioning.test package -================================= +sqlobject\.versioning\.test package +=================================== .. automodule:: sqlobject.versioning.test :members: diff --git a/docs/api/sqlobject.versioning.test.test_version.rst b/docs/api/sqlobject.versioning.test.test_version.rst index e2b21e1b..3a40a564 100644 --- a/docs/api/sqlobject.versioning.test.test_version.rst +++ b/docs/api/sqlobject.versioning.test.test_version.rst @@ -1,5 +1,5 @@ -sqlobject.versioning.test.test_version module -============================================= +sqlobject\.versioning\.test\.test\_version module +================================================= .. automodule:: sqlobject.versioning.test.test_version :members: diff --git a/docs/api/sqlobject.views.rst b/docs/api/sqlobject.views.rst index d0a30c58..ce4b406e 100644 --- a/docs/api/sqlobject.views.rst +++ b/docs/api/sqlobject.views.rst @@ -1,5 +1,5 @@ -sqlobject.views module -====================== +sqlobject\.views module +======================= .. automodule:: sqlobject.views :members: diff --git a/docs/api/sqlobject.wsgi_middleware.rst b/docs/api/sqlobject.wsgi_middleware.rst index 635e3e76..79bc8727 100644 --- a/docs/api/sqlobject.wsgi_middleware.rst +++ b/docs/api/sqlobject.wsgi_middleware.rst @@ -1,5 +1,5 @@ -sqlobject.wsgi_middleware module -================================ +sqlobject\.wsgi\_middleware module +================================== .. automodule:: sqlobject.wsgi_middleware :members: From f275254bfb51e2d3faff5a5bca1116ecee542e1c Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 15 Dec 2017 13:43:09 +0300 Subject: [PATCH 128/509] Docs: Add docs/api/sqlobject.tests.test_csvimport.rst [skip ci] --- docs/api/sqlobject.tests.test_csvimport.rst | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 docs/api/sqlobject.tests.test_csvimport.rst diff --git a/docs/api/sqlobject.tests.test_csvimport.rst b/docs/api/sqlobject.tests.test_csvimport.rst new file mode 100644 index 00000000..56981a8d --- /dev/null +++ b/docs/api/sqlobject.tests.test_csvimport.rst @@ -0,0 +1,7 @@ +sqlobject\.tests\.test\_csvimport module +======================================== + +.. automodule:: sqlobject.tests.test_csvimport + :members: + :undoc-members: + :show-inheritance: From 2a4b2a74fdeaa3366fe07c81ad2ddc4dfb385243 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 15 Dec 2017 14:57:33 +0300 Subject: [PATCH 129/509] Docs: Remove unused start label [skip ci] --- docs/News.rst | 2 -- docs/News1.rst | 2 -- docs/News2.rst | 2 -- docs/News3.rst | 2 -- docs/News4.rst | 2 -- docs/News5.rst | 2 -- 6 files changed, 12 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index adcca1c3..5590434f 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,8 +5,6 @@ News .. contents:: Contents: :backlinks: none -.. _start: - SQLObject 3.6.0 (master) ======================== diff --git a/docs/News1.rst b/docs/News1.rst index 77296c21..e3838c22 100644 --- a/docs/News1.rst +++ b/docs/News1.rst @@ -5,8 +5,6 @@ News .. contents:: Contents: :backlinks: none -.. _start: - SQLObject 0.6.1 =============== diff --git a/docs/News2.rst b/docs/News2.rst index 9a37d77b..2e23ed40 100644 --- a/docs/News2.rst +++ b/docs/News2.rst @@ -5,8 +5,6 @@ News .. contents:: Contents: :backlinks: none -.. _start: - SQLObject 0.8.7 =============== diff --git a/docs/News3.rst b/docs/News3.rst index a6805270..2b6f0672 100644 --- a/docs/News3.rst +++ b/docs/News3.rst @@ -5,8 +5,6 @@ News .. contents:: Contents: :backlinks: none -.. _start: - SQLObject 0.10.9 ================ diff --git a/docs/News4.rst b/docs/News4.rst index 11f76d42..546a7fd4 100644 --- a/docs/News4.rst +++ b/docs/News4.rst @@ -5,8 +5,6 @@ News .. contents:: Contents: :backlinks: none -.. _start: - SQLObject 0.15.1 ================ diff --git a/docs/News5.rst b/docs/News5.rst index 6f1118ce..32f6659c 100644 --- a/docs/News5.rst +++ b/docs/News5.rst @@ -5,8 +5,6 @@ News .. contents:: Contents: :backlinks: none -.. _start: - SQLObject 2.2.1 =============== From a862d4c66da8a85847c400f82d770fb71fcf6a02 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 15 Dec 2017 16:06:06 +0300 Subject: [PATCH 130/509] CI: Run tests at AppVeyor with Python 2.7 32bit and 3.6 64bit AppVeyor runs 1 virtual machine so tests are executing very slowly. The commit removes most of the tests. --- appveyor.yml | 152 ++++----------------------------------------------- 1 file changed, 10 insertions(+), 142 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index c6641fca..a15419a0 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -38,66 +38,26 @@ environment: PYTHON_VERSION: "2.7" PYTHON_HOME: "C:\\Python27" db: mysql - - TOXENV: "py34-mysql-connector-w32" - PYTHON_ARCH: "32" - PYTHON_VERSION: "3.4" - PYTHON_HOME: "C:\\Python34" - db: mysql - - TOXENV: "py35-mysql-connector-w32" - PYTHON_ARCH: "32" - PYTHON_VERSION: "3.5" - PYTHON_HOME: "C:\\Python35" - db: mysql - TOXENV: "py36-mysql-connector-w32" - PYTHON_ARCH: "32" + PYTHON_ARCH: "64" PYTHON_VERSION: "3.6" - PYTHON_HOME: "C:\\Python36" + PYTHON_HOME: "C:\\Python36-x64" db: mysql - TOXENV: "py27-mysql-pyodbc-w32" - PYTHON_ARCH: "64" + PYTHON_ARCH: "32" PYTHON_VERSION: "2.7" - PYTHON_HOME: "C:\\Python27-x64" + PYTHON_HOME: "C:\\Python27" db: mysql - - TOXENV: "py34-mysql-pyodbc-w32" + - TOXENV: "py36-mysql-pyodbc-w32" PYTHON_ARCH: "64" - PYTHON_VERSION: "3.4" - PYTHON_HOME: "C:\\Python34-x64" + PYTHON_VERSION: "3.6" + PYTHON_HOME: "C:\\Python36-x64" db: mysql - TOXENV: "py27-postgres-psycopg-w32" PYTHON_ARCH: "32" PYTHON_VERSION: "2.7" PYTHON_HOME: "C:\\Python27" db: postgresql - - TOXENV: "py27-postgres-psycopg-w32" - PYTHON_ARCH: "64" - PYTHON_VERSION: "2.7" - PYTHON_HOME: "C:\\Python27-x64" - db: postgresql - - TOXENV: "py34-postgres-psycopg-w32" - PYTHON_ARCH: "32" - PYTHON_VERSION: "3.4" - PYTHON_HOME: "C:\\Python34" - db: postgresql - - TOXENV: "py34-postgres-psycopg-w32" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.4" - PYTHON_HOME: "C:\\Python34-x64" - db: postgresql - - TOXENV: "py35-postgres-psycopg-w32" - PYTHON_ARCH: "32" - PYTHON_VERSION: "3.5" - PYTHON_HOME: "C:\\Python35" - db: postgresql - - TOXENV: "py35-postgres-psycopg-w32" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.5" - PYTHON_HOME: "C:\\Python35-x64" - db: postgresql - - TOXENV: "py36-postgres-psycopg-w32" - PYTHON_ARCH: "32" - PYTHON_VERSION: "3.6" - PYTHON_HOME: "C:\\Python36" - db: postgresql - TOXENV: "py36-postgres-psycopg-w32" PYTHON_ARCH: "64" PYTHON_VERSION: "3.6" @@ -108,41 +68,11 @@ environment: PYTHON_VERSION: "2.7" PYTHON_HOME: "C:\\Python27-x64" db: postgresql - - TOXENV: "py34-postgres-pygresql-w32" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.4" - PYTHON_HOME: "C:\\Python34-x64" - db: postgresql - - TOXENV: "py35-postgres-pygresql-w32" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.5" - PYTHON_HOME: "C:\\Python35-x64" - db: postgresql - TOXENV: "py36-postgres-pygresql-w32" PYTHON_ARCH: "64" PYTHON_VERSION: "3.6" PYTHON_HOME: "C:\\Python36-x64" db: postgresql - - TOXENV: "py34-pypostgresql-w32" - PYTHON_ARCH: "32" - PYTHON_VERSION: "3.4" - PYTHON_HOME: "C:\\Python34" - db: postgresql - - TOXENV: "py34-pypostgresql-w32" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.4" - PYTHON_HOME: "C:\\Python34-x64" - db: postgresql - - TOXENV: "py35-pypostgresql-w32" - PYTHON_ARCH: "32" - PYTHON_VERSION: "3.5" - PYTHON_HOME: "C:\\Python35" - db: postgresql - - TOXENV: "py35-pypostgresql-w32" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.5" - PYTHON_HOME: "C:\\Python35-x64" - db: postgresql - TOXENV: "py36-pypostgresql-w32" PYTHON_ARCH: "32" PYTHON_VERSION: "3.6" @@ -158,36 +88,6 @@ environment: PYTHON_VERSION: "2.7" PYTHON_HOME: "C:\\Python27" db: postgresql - - TOXENV: "py27-postgres-pg8000-w32" - PYTHON_ARCH: "64" - PYTHON_VERSION: "2.7" - PYTHON_HOME: "C:\\Python27-x64" - db: postgresql - - TOXENV: "py34-postgres-pg8000-w32" - PYTHON_ARCH: "32" - PYTHON_VERSION: "3.4" - PYTHON_HOME: "C:\\Python34" - db: postgresql - - TOXENV: "py34-postgres-pg8000-w32" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.4" - PYTHON_HOME: "C:\\Python34-x64" - db: postgresql - - TOXENV: "py35-postgres-pg8000-w32" - PYTHON_ARCH: "32" - PYTHON_VERSION: "3.5" - PYTHON_HOME: "C:\\Python35" - db: postgresql - - TOXENV: "py35-postgres-pg8000-w32" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.5" - PYTHON_HOME: "C:\\Python35-x64" - db: postgresql - - TOXENV: "py36-postgres-pg8000-w32" - PYTHON_ARCH: "32" - PYTHON_VERSION: "3.6" - PYTHON_HOME: "C:\\Python36" - db: postgresql - TOXENV: "py36-postgres-pg8000-w32" PYTHON_ARCH: "64" PYTHON_VERSION: "3.6" @@ -198,39 +98,15 @@ environment: PYTHON_VERSION: "2.7" PYTHON_HOME: "C:\\Python27-x64" db: postgresql - - TOXENV: "py34-postgres-pyodbc-w32" + - TOXENV: "py36-postgres-pyodbc-w32" PYTHON_ARCH: "64" - PYTHON_VERSION: "3.4" - PYTHON_HOME: "C:\\Python34-x64" + PYTHON_VERSION: "3.6" + PYTHON_HOME: "C:\\Python36-x64" db: postgresql - TOXENV: "py27-sqlite-w32" PYTHON_ARCH: "32" PYTHON_VERSION: "2.7" PYTHON_HOME: "C:\\Python27" - - TOXENV: "py27-sqlite-w32" - PYTHON_ARCH: "64" - PYTHON_VERSION: "2.7" - PYTHON_HOME: "C:\\Python27-x64" - - TOXENV: "py34-sqlite-w32" - PYTHON_ARCH: "32" - PYTHON_VERSION: "3.4" - PYTHON_HOME: "C:\\Python34" - - TOXENV: "py34-sqlite-w32" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.4" - PYTHON_HOME: "C:\\Python34-x64" - - TOXENV: "py35-sqlite-w32" - PYTHON_ARCH: "32" - PYTHON_VERSION: "3.5" - PYTHON_HOME: "C:\\Python35" - - TOXENV: "py35-sqlite-w32" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.5" - PYTHON_HOME: "C:\\Python35-x64" - - TOXENV: "py36-sqlite-w32" - PYTHON_ARCH: "32" - PYTHON_VERSION: "3.6" - PYTHON_HOME: "C:\\Python36" - TOXENV: "py36-sqlite-w32" PYTHON_ARCH: "64" PYTHON_VERSION: "3.6" @@ -239,14 +115,6 @@ environment: PYTHON_ARCH: "32" PYTHON_VERSION: "2.7" PYTHON_HOME: "C:\\Python27" - - TOXENV: "py34-sqlite-memory-w32" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.4" - PYTHON_HOME: "C:\\Python34-x64" - - TOXENV: "py35-sqlite-memory-w32" - PYTHON_ARCH: "32" - PYTHON_VERSION: "3.5" - PYTHON_HOME: "C:\\Python35" - TOXENV: "py36-sqlite-memory-w32" PYTHON_ARCH: "64" PYTHON_VERSION: "3.6" From aa24465d6128d68a208e25a96040f1d69a0455da Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 15 Dec 2017 16:25:35 +0300 Subject: [PATCH 131/509] Build: -O2 [skip ci] --- setup.cfg | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/setup.cfg b/setup.cfg index a4729793..40ee4ca8 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,3 +1,9 @@ +[bdist_wheel] +universal = 1 + +[easy_install] +optimize = 2 + [egg_info] tag_build = tag_date = 0 @@ -8,6 +14,3 @@ exclude = .git,.tox,docs/europython/*.py # E305: expected 2 blank lines after class or function definition, found 1 ignore = E305 -[bdist_wheel] -universal = 1 - From ed6cdc748a16b86598834fd647c5b78f33843dd8 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 15 Dec 2017 18:30:11 +0300 Subject: [PATCH 132/509] Build: Require tox >= 2.0 (for passenv) [skip ci] --- devscripts/requirements/requirements_tox.txt | 2 +- tox.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/devscripts/requirements/requirements_tox.txt b/devscripts/requirements/requirements_tox.txt index 9927ea49..ff4ecb65 100644 --- a/devscripts/requirements/requirements_tox.txt +++ b/devscripts/requirements/requirements_tox.txt @@ -1 +1 @@ -tox >= 1.8 +tox >= 2.0 diff --git a/tox.ini b/tox.ini index 828dff1c..d924d4d8 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -minversion = 1.8 +minversion = 2.0 envlist = py27-{mysqldb,mysql-oursql},py{34,35,36}-{mysqlclient,pypostgresql},py{27,34,35,36}-{mysql-connector,pymysql,mysql-pyodbc,mysql-pypyodbc,postgres-psycopg,postgres-pygresql,postgres-pg8000,postgres-pyodbc,postgres-pypyodbc,sqlite,sqlite-memory},py{27,34,35,36}-{firebird-fdb,firebirdsql},py{27,34}-flake8,py{27,34,35,36}-{mssql-pyodbc,mysql-connector,mysql-pyodbc,mysql-pypyodbc,postgres-psycopg,postgres-pygresql,postgres-pg800,postgres-pyodbc,postgres-pypyodbc,sqlite,sqlite-memory}-w32,py{34,35,36}-pypostgresql-w32 # Base test environment settings From f56f2dba768c6c7e52652dde8e88183b1045862c Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 15 Dec 2017 21:10:51 +0300 Subject: [PATCH 133/509] Tests: rm -f sqlobject_test.sqdb --- tox.ini | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tox.ini b/tox.ini index d924d4d8..8a7d8b27 100644 --- a/tox.ini +++ b/tox.ini @@ -287,9 +287,9 @@ commands = {[postgres-pypyodbc]commands} [sqlite] commands = {[testenv]commands} - -rm /tmp/sqlobject_test.sqdb + -rm -f /tmp/sqlobject_test.sqdb pytest --cov=sqlobject -D sqlite:///tmp/sqlobject_test.sqdb?debug=1 - rm /tmp/sqlobject_test.sqdb + rm -f /tmp/sqlobject_test.sqdb [testenv:py27-sqlite] commands = {[sqlite]commands} @@ -327,7 +327,7 @@ commands = sudo rm -f /tmp/test.fdb isql-fb -u test -p test -i /var/lib/firebird/create_test_db pytest --cov=sqlobject -D 'firebird://test:test@localhost/tmp/test.fdb?debug=1' - sudo rm /tmp/test.fdb + sudo rm -f /tmp/test.fdb [testenv:py27-firebird-fdb] commands = {[fdb]commands} @@ -347,7 +347,7 @@ commands = sudo rm -f /tmp/test.fdb isql-fb -u test -p test -i /var/lib/firebird/create_test_db pytest --cov=sqlobject -D 'firebird://test:test@localhost:3050/tmp/test.fdb?driver=firebirdsql&charset=utf8&debug=1' - sudo rm /tmp/test.fdb + sudo rm -f /tmp/test.fdb [testenv:py27-firebirdsql] commands = {[firebirdsql]commands} From 1228c7cd9884b38ab16185ec15e2637d745b6841 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 17 Dec 2017 14:14:48 +0300 Subject: [PATCH 134/509] Tests(tox.ini): Set platform Default platform is linux, but for *-w32 environments it's win32. --- tox.ini | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/tox.ini b/tox.ini index 8a7d8b27..f25ba415 100644 --- a/tox.ini +++ b/tox.ini @@ -33,6 +33,7 @@ deps = firebirdsql: firebirdsql passenv = CI TRAVIS TRAVIS_* APPVEYOR DISTUTILS_USE_SDK MSSdk INCLUDE LIB PGPASSWORD WINDIR # Don't fail or warn on uninstalled commands +platform = linux whitelist_externals = mysql createdb @@ -380,6 +381,7 @@ commands = # Windows testing [mssql-pyodbc-w32] +platform = win32 commands = {envpython} -c "import pyodbc; print(pyodbc.drivers())" -sqlcmd -U sa -P "Password12!" -S .\SQL2014 -Q "DROP DATABASE sqlobject_test" @@ -388,18 +390,23 @@ commands = sqlcmd -U sa -P "Password12!" -S .\SQL2014 -Q "DROP DATABASE sqlobject_test" [testenv:py27-mssql-pyodbc-w32] +platform = win32 commands = {[mssql-pyodbc-w32]commands} [testenv:py34-mssql-pyodbc-w32] +platform = win32 commands = {[mssql-pyodbc-w32]commands} [testenv:py35-mssql-pyodbc-w32] +platform = win32 commands = {[mssql-pyodbc-w32]commands} [testenv:py36-mssql-pyodbc-w32] +platform = win32 commands = {[mssql-pyodbc-w32]commands} [mysql-connector-w32] +platform = win32 commands = {[testenv]commands} -mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' @@ -408,18 +415,23 @@ commands = mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' [testenv:py27-mysql-connector-w32] +platform = win32 commands = {[mysql-connector-w32]commands} [testenv:py34-mysql-connector-w32] +platform = win32 commands = {[mysql-connector-w32]commands} [testenv:py35-mysql-connector-w32] +platform = win32 commands = {[mysql-connector-w32]commands} [testenv:py36-mysql-connector-w32] +platform = win32 commands = {[mysql-connector-w32]commands} [mysql-pyodbc-w32] +platform = win32 commands = {[testenv]commands} {envpython} -c "import pyodbc; print(pyodbc.drivers())" @@ -429,18 +441,23 @@ commands = mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' [testenv:py27-mysql-pyodbc-w32] +platform = win32 commands = {[mysql-pyodbc-w32]commands} [testenv:py34-mysql-pyodbc-w32] +platform = win32 commands = {[mysql-pyodbc-w32]commands} [testenv:py35-mysql-pyodbc-w32] +platform = win32 commands = {[mysql-pyodbc-w32]commands} [testenv:py36-mysql-pyodbc-w32] +platform = win32 commands = {[mysql-pyodbc-w32]commands} [mysql-pypyodbc-w32] +platform = win32 commands = {[testenv]commands} {envpython} -c "import pypyodbc; print(pypyodbc.drivers())" @@ -450,18 +467,23 @@ commands = mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' [testenv:py27-mysql-pypyodbc-w32] +platform = win32 commands = {[mysql-pypyodbc-w32]commands} [testenv:py34-mysql-pypyodbc-w32] +platform = win32 commands = {[mysql-pypyodbc-w32]commands} [testenv:py35-mysql-pypyodbc-w32] +platform = win32 commands = {[mysql-pypyodbc-w32]commands} [testenv:py36-mysql-pypyodbc-w32] +platform = win32 commands = {[mysql-pypyodbc-w32]commands} [psycopg-w32] +platform = win32 commands = {[testenv]commands} -dropdb -U postgres -w sqlobject_test @@ -470,18 +492,23 @@ commands = dropdb -U postgres -w sqlobject_test [testenv:py27-postgres-psycopg-w32] +platform = win32 commands = {[psycopg-w32]commands} [testenv:py34-postgres-psycopg-w32] +platform = win32 commands = {[psycopg-w32]commands} [testenv:py35-postgres-psycopg-w32] +platform = win32 commands = {[psycopg-w32]commands} [testenv:py36-postgres-psycopg-w32] +platform = win32 commands = {[psycopg-w32]commands} [pygresql-w32] +platform = win32 commands = {[testenv]commands} -dropdb -U postgres -w sqlobject_test @@ -490,18 +517,23 @@ commands = dropdb -U postgres -w sqlobject_test [testenv:py27-postgres-pygresql-w32] +platform = win32 commands = {[pygresql-w32]commands} [testenv:py34-postgres-pygresql-w32] +platform = win32 commands = {[pygresql-w32]commands} [testenv:py35-postgres-pygresql-w32] +platform = win32 commands = {[pygresql-w32]commands} [testenv:py36-postgres-pygresql-w32] +platform = win32 commands = {[pygresql-w32]commands} [pypostgresql-w32] +platform = win32 commands = {[testenv]commands} -dropdb -U postgres -w sqlobject_test @@ -510,15 +542,19 @@ commands = dropdb -U postgres -w sqlobject_test [testenv:py34-pypostgresql-w32] +platform = win32 commands = {[pypostgresql-w32]commands} [testenv:py35-pypostgresql-w32] +platform = win32 commands = {[pypostgresql-w32]commands} [testenv:py36-pypostgresql-w32] +platform = win32 commands = {[pypostgresql-w32]commands} [pg8000-w32] +platform = win32 commands = {[testenv]commands} -dropdb -U postgres -w sqlobject_test @@ -527,18 +563,23 @@ commands = dropdb -U postgres -w sqlobject_test [testenv:py27-postgres-pg8000-w32] +platform = win32 commands = {[pg8000-w32]commands} [testenv:py34-postgres-pg8000-w32] +platform = win32 commands = {[pg8000-w32]commands} [testenv:py35-postgres-pg8000-w32] +platform = win32 commands = {[pg8000-w32]commands} [testenv:py36-postgres-pg8000-w32] +platform = win32 commands = {[pg8000-w32]commands} [postgres-pyodbc-w32] +platform = win32 commands = {[testenv]commands} {envpython} -c "import pyodbc; print(pyodbc.drivers())" @@ -548,18 +589,23 @@ commands = dropdb -U postgres -w sqlobject_test [testenv:py27-postgres-pyodbc-w32] +platform = win32 commands = {[postgres-pyodbc-w32]commands} [testenv:py34-postgres-pyodbc-w32] +platform = win32 commands = {[postgres-pyodbc-w32]commands} [testenv:py35-postgres-pyodbc-w32] +platform = win32 commands = {[postgres-pyodbc-w32]commands} [testenv:py36-postgres-pyodbc-w32] +platform = win32 commands = {[postgres-pyodbc-w32]commands} [postgres-pypyodbc-w32] +platform = win32 commands = {[testenv]commands} {envpython} -c "import pypyodbc; print(pypyodbc.drivers())" @@ -569,47 +615,61 @@ commands = dropdb -U postgres -w sqlobject_test [testenv:py27-postgres-pypyodbc-w32] +platform = win32 commands = {[postgres-pypyodbc-w32]commands} [testenv:py34-postgres-pypyodbc-w32] +platform = win32 commands = {[postgres-pypyodbc-w32]commands} [testenv:py35-postgres-pypyodbc-w32] +platform = win32 commands = {[postgres-pypyodbc-w32]commands} [testenv:py36-postgres-pypyodbc-w32] +platform = win32 commands = {[postgres-pypyodbc-w32]commands} [sqlite-w32] +platform = win32 commands = {[testenv]commands} pytest --cov=sqlobject -D sqlite:/C:/projects/sqlobject/sqlobject_test.sqdb?debug=1 [testenv:py27-sqlite-w32] +platform = win32 commands = {[sqlite-w32]commands} [testenv:py34-sqlite-w32] +platform = win32 commands = {[sqlite-w32]commands} [testenv:py35-sqlite-w32] +platform = win32 commands = {[sqlite-w32]commands} [testenv:py36-sqlite-w32] +platform = win32 commands = {[sqlite-w32]commands} [sqlite-memory-w32] +platform = win32 commands = {[testenv]commands} pytest --cov=sqlobject -D sqlite:/:memory:?debug=1 [testenv:py27-sqlite-memory-w32] +platform = win32 commands = {[sqlite-memory-w32]commands} [testenv:py34-sqlite-memory-w32] +platform = win32 commands = {[sqlite-memory-w32]commands} [testenv:py35-sqlite-memory-w32] +platform = win32 commands = {[sqlite-memory-w32]commands} [testenv:py36-sqlite-memory-w32] +platform = win32 commands = {[sqlite-memory-w32]commands} From 7ca3a7ed760aded7d5a159dfaaf74fd82c2e7e9f Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 5 Jan 2018 20:37:17 +0300 Subject: [PATCH 135/509] Docs: Update TODO [skip ci] --- docs/TODO.rst | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/docs/TODO.rst b/docs/TODO.rst index 2ae19ac1..8e5b3072 100644 --- a/docs/TODO.rst +++ b/docs/TODO.rst @@ -1,8 +1,32 @@ TODO ---- +* Restore oursql driver; use our fork. + +* Fix test ordering problem with Postgres. + +* Fix unicode problems with pyodbc at AppVeyor. + +* Resolve timeout problems with MSSQL. + +* https://github.com/d33tah/bpgsql, + https://github.com/olopez32/py-bpgsql, + https://pypi.python.org/pypi/ocpgdb/2.0.2, + https://magicstack.github.io/asyncpg/current/. + * PyPy. +* Use https://pypi.python.org/pypi/psycopg2cffi to run SQLObject + under PyPy. + +* https://pypi.python.org/pypi/turbodbc + +* PyODBC and PyPyODBC for linux and w32: SQLite (libsqliteodbc). + +* https://pypi.python.org/pypi/JayDeBeApi + +* Jython. + * Quote table/column names that are reserved keywords (order => "order", values => `values` for MySQL). From f3fc349e34bfc6def689d94ed6e9c6327c93c845 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 13 Jan 2018 21:01:19 +0300 Subject: [PATCH 136/509] Tests(tox): Shorten default list of environments By default only run SQLite3 and flake8 tests. --- devscripts/tox-select-envs | 2 +- tox.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/devscripts/tox-select-envs b/devscripts/tox-select-envs index 49cf3abf..34ff4b2c 100755 --- a/devscripts/tox-select-envs +++ b/devscripts/tox-select-envs @@ -2,7 +2,7 @@ pattern="$1" shift -envs="`tox --listenvs | grep -F $pattern | sed 's/$/,/'`" +envs="`tox --listenvs-all | grep -F $pattern | sed 's/$/,/'`" if [ -n "$envs" ]; then exec tox -e "$envs" "$@" diff --git a/tox.ini b/tox.ini index f25ba415..8fef6248 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 2.0 -envlist = py27-{mysqldb,mysql-oursql},py{34,35,36}-{mysqlclient,pypostgresql},py{27,34,35,36}-{mysql-connector,pymysql,mysql-pyodbc,mysql-pypyodbc,postgres-psycopg,postgres-pygresql,postgres-pg8000,postgres-pyodbc,postgres-pypyodbc,sqlite,sqlite-memory},py{27,34,35,36}-{firebird-fdb,firebirdsql},py{27,34}-flake8,py{27,34,35,36}-{mssql-pyodbc,mysql-connector,mysql-pyodbc,mysql-pypyodbc,postgres-psycopg,postgres-pygresql,postgres-pg800,postgres-pyodbc,postgres-pypyodbc,sqlite,sqlite-memory}-w32,py{34,35,36}-pypostgresql-w32 +envlist = py{27,34,35,36}-sqlite{,-memory},py{27,34}-flake8 # Base test environment settings [testenv] From a6cc22eb346a42a67142fb7a1b59b5fce51387fa Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 13 Jan 2018 22:22:48 +0300 Subject: [PATCH 137/509] Tests(tox): Fix pypyodbc driver's name --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 8fef6248..7044bc29 100644 --- a/tox.ini +++ b/tox.ini @@ -611,7 +611,7 @@ commands = {envpython} -c "import pypyodbc; print(pypyodbc.drivers())" -dropdb -U postgres -w sqlobject_test createdb -U postgres -w sqlobject_test - pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=odbc&odbcdrv=PostgreSQL%20ANSI%28x64%29&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=PostgreSQL%20ANSI%28x64%29&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb -U postgres -w sqlobject_test [testenv:py27-postgres-pypyodbc-w32] From e69b735685ee068ba7468adbdfe1d3051b5ecb1e Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 13 Jan 2018 22:43:43 +0300 Subject: [PATCH 138/509] Fix(oursql): Extend support for Python 3 Use our fork. --- .travis.yml | 9 +++++++++ docs/News.rst | 6 ++++++ docs/TODO.rst | 4 ++-- docs/download.rst | 2 +- setup.py | 2 +- tox.ini | 12 +++++++++++- 6 files changed, 30 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 72148bb9..45256499 100644 --- a/.travis.yml +++ b/.travis.yml @@ -44,6 +44,12 @@ matrix: env: TOXENV=py36-mysql-connector - python: "2.7" env: TOXENV=py27-mysql-oursql + - python: "3.4" + env: TOXENV=py34-mysql-oursql3 + - python: "3.5" + env: TOXENV=py35-mysql-oursql3 + - python: "3.6" + env: TOXENV=py36-mysql-oursql3 - python: "2.7" env: TOXENV=py27-pymysql - python: "3.4" @@ -120,6 +126,9 @@ matrix: env: TOXENV=py36-firebirdsql allow_failures: + - env: TOXENV=py34-mysql-oursql3 + - env: TOXENV=py35-mysql-oursql3 + - env: TOXENV=py36-mysql-oursql3 - env: TOXENV=py27-firebird-fdb - env: TOXENV=py34-firebird-fdb - env: TOXENV=py35-firebird-fdb diff --git a/docs/News.rst b/docs/News.rst index 5590434f..9dc81258 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,12 @@ News SQLObject 3.6.0 (master) ======================== +Drivers +------- + +* Extend support for oursql and Python 3 (require our fork); there are + some unicode-related problems. + Documentation ------------- diff --git a/docs/TODO.rst b/docs/TODO.rst index 8e5b3072..b226405d 100644 --- a/docs/TODO.rst +++ b/docs/TODO.rst @@ -1,10 +1,10 @@ TODO ---- -* Restore oursql driver; use our fork. - * Fix test ordering problem with Postgres. +* Fix unicode problems with oursql. + * Fix unicode problems with pyodbc at AppVeyor. * Resolve timeout problems with MSSQL. diff --git a/docs/download.rst b/docs/download.rst index 6877d6ad..a0289983 100644 --- a/docs/download.rst +++ b/docs/download.rst @@ -63,7 +63,7 @@ MySQL ^^^^^ mysql (installs MySQL-python for Python 2.7 and mysqlclient for Python 3.4+) -mysql-connector oursql (only for Python 2.7) pymysql +mysql-connector oursql pymysql ODBC ^^^^ diff --git a/setup.py b/setup.py index 2adc4ab9..20c3ff10 100755 --- a/setup.py +++ b/setup.py @@ -44,7 +44,7 @@ 'mysql:python_version=="2.7"': ['MySQL-python'], 'mysql:python_version>="3.4"': ['mysqlclient'], 'mysql-connector': ['mysql-connector'], - 'oursql:python_version=="2.7"': ['oursql'], + 'oursql': ['oursql'], 'pymysql': ['pymysql'], # ODBC 'odbc': ['pyodbc'], diff --git a/tox.ini b/tox.ini index 7044bc29..bf85a352 100644 --- a/tox.ini +++ b/tox.ini @@ -21,7 +21,8 @@ deps = mysqldb: mysql-python mysqlclient: mysqlclient mysql-connector: mysql-connector <= 2.2.2 - mysql-oursql: oursql + mysql-oursql: git+https://github.com/sqlobject/oursql.git@master#egg=oursql + mysql-oursql3: git+https://github.com/sqlobject/oursql.git@py3k#egg=oursql pymysql: pymysql postgres-psycopg: psycopg2 postgres-pygresql: pygresql @@ -103,6 +104,15 @@ commands = [testenv:py27-mysql-oursql] commands = {[oursql]commands} +[testenv:py34-mysql-oursql3] +commands = {[oursql]commands} + +[testenv:py35-mysql-oursql3] +commands = {[oursql]commands} + +[testenv:py36-mysql-oursql3] +commands = {[oursql]commands} + [pymysql] commands = {[testenv]commands} From 30447df1495f7192a6bea7241cc13ef4942b059c Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 14 Jan 2018 07:12:40 +0300 Subject: [PATCH 139/509] Docs: Fix subsection header [skip ci] --- docs/News.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index 9dc81258..9e5d127b 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -11,7 +11,7 @@ SQLObject 3.6.0 (master) Drivers ------- -* Extend support for oursql and Python 3 (require our fork); there are +* Extend support for oursql and Python 3 (require our fork). There are some unicode-related problems. Documentation @@ -20,7 +20,7 @@ Documentation * Document extras that are available for installation. Build -===== +----- * Use ``python_version`` environment marker in ``setup.py`` to make ``install_requires`` and ``extras_require`` declarative. This makes From 9770622c4a1d5a2ea286e4ddf57bc40009889afa Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 2 Feb 2018 01:44:47 +0300 Subject: [PATCH 140/509] Fix(mysql): Fix oursql Encode queries to bytes to fix unicode problems in binary data. Enable autoreconnect. --- .travis.yml | 3 --- docs/News.rst | 3 +-- docs/TODO.rst | 2 -- sqlobject/mysql/mysqlconnection.py | 8 +++++++- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index 45256499..5a6b8e98 100644 --- a/.travis.yml +++ b/.travis.yml @@ -126,9 +126,6 @@ matrix: env: TOXENV=py36-firebirdsql allow_failures: - - env: TOXENV=py34-mysql-oursql3 - - env: TOXENV=py35-mysql-oursql3 - - env: TOXENV=py36-mysql-oursql3 - env: TOXENV=py27-firebird-fdb - env: TOXENV=py34-firebird-fdb - env: TOXENV=py35-firebird-fdb diff --git a/docs/News.rst b/docs/News.rst index 9e5d127b..9ce26cf7 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -11,8 +11,7 @@ SQLObject 3.6.0 (master) Drivers ------- -* Extend support for oursql and Python 3 (require our fork). There are - some unicode-related problems. +* Extend support for oursql and Python 3 (require our fork of the driver). Documentation ------------- diff --git a/docs/TODO.rst b/docs/TODO.rst index b226405d..1ce14676 100644 --- a/docs/TODO.rst +++ b/docs/TODO.rst @@ -3,8 +3,6 @@ TODO * Fix test ordering problem with Postgres. -* Fix unicode problems with oursql. - * Fix unicode problems with pyodbc at AppVeyor. * Resolve timeout problems with MSSQL. diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index ba7e7264..96517dd2 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -131,6 +131,12 @@ def __init__(self, db, user, password='', host='localhost', port=0, **kw): self.CR_SERVER_LOST = 2013 self.ER_DUP_ENTRY = '23000' + elif self.driver == 'oursql': + if "use_unicode" not in self.kw: + self.kw["use_unicode"] = not PY2 + # oursql doesn't implement ping(True) yet + self.kw["autoreconnect"] = True + global mysql_Bin if not PY2 and mysql_Bin is None: mysql_Bin = self.module.Binary @@ -218,7 +224,7 @@ def _executeRetry(self, conn, cursor, query): self.printDebug(conn, query, 'QueryR') dbEncoding = self.dbEncoding if dbEncoding and not isinstance(query, bytes) and ( - self.driver == 'connector'): + self.driver in ('connector', 'oursql')): query = query.encode(dbEncoding, 'surrogateescape') # When a server connection is lost and a query is attempted, most of # the time the query will raise a SERVER_LOST exception, then at the From 02191ead0900875a95aa02fb11a1b72935a09571 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 2 Feb 2018 21:32:30 +0300 Subject: [PATCH 141/509] CI: Fix AppVeyor config: ODBC dirver for MySQL is 64 bit --- appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index a15419a0..ef71aeff 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -44,9 +44,9 @@ environment: PYTHON_HOME: "C:\\Python36-x64" db: mysql - TOXENV: "py27-mysql-pyodbc-w32" - PYTHON_ARCH: "32" + PYTHON_ARCH: "64" PYTHON_VERSION: "2.7" - PYTHON_HOME: "C:\\Python27" + PYTHON_HOME: "C:\\Python27-x64" db: mysql - TOXENV: "py36-mysql-pyodbc-w32" PYTHON_ARCH: "64" From 9c8dec32f56a8c9115668f5f7f2d42a21753a5fd Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 2 Feb 2018 21:38:11 +0300 Subject: [PATCH 142/509] CI: Run PyMySQL tests at AppVeyor --- appveyor.yml | 10 ++++++++++ tox.ini | 25 +++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/appveyor.yml b/appveyor.yml index ef71aeff..f5a23b26 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -43,6 +43,16 @@ environment: PYTHON_VERSION: "3.6" PYTHON_HOME: "C:\\Python36-x64" db: mysql + - TOXENV: "py27-pymysql-w32" + PYTHON_ARCH: "32" + PYTHON_VERSION: "2.7" + PYTHON_HOME: "C:\\Python27" + db: mysql + - TOXENV: "py36-pymysql-w32" + PYTHON_ARCH: "64" + PYTHON_VERSION: "3.6" + PYTHON_HOME: "C:\\Python36-x64" + db: mysql - TOXENV: "py27-mysql-pyodbc-w32" PYTHON_ARCH: "64" PYTHON_VERSION: "2.7" diff --git a/tox.ini b/tox.ini index bf85a352..54498f6f 100644 --- a/tox.ini +++ b/tox.ini @@ -440,6 +440,31 @@ commands = {[mysql-connector-w32]commands} platform = win32 commands = {[mysql-connector-w32]commands} +[pymysql-w32] +platform = win32 +commands = + {[testenv]commands} + -mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' + mysql -u root "-pPassword12!" -e 'create database sqlobject_test;' + pytest --cov=sqlobject -D "mysql://root:Password12!@localhost/sqlobject_test?driver=pymysql&charset=utf8&debug=1" + mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' + +[testenv:py27-pymysql-w32] +platform = win32 +commands = {[pymysql-w32]commands} + +[testenv:py34-pymysql-w32] +platform = win32 +commands = {[pymysql-w32]commands} + +[testenv:py35-pymysql-w32] +platform = win32 +commands = {[pymysql-w32]commands} + +[testenv:py36-pymysql-w32] +platform = win32 +commands = {[pymysql-w32]commands} + [mysql-pyodbc-w32] platform = win32 commands = From bc58c615babc7a170989e074a6af956e67fe0f1b Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 4 Feb 2018 09:21:16 +0300 Subject: [PATCH 143/509] Build: Use module returned by imp.load_source() directly --- setup.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/setup.py b/setup.py index 20c3ff10..4018c698 100755 --- a/setup.py +++ b/setup.py @@ -11,8 +11,7 @@ is_setuptools = False versionpath = join(abspath(dirname(__file__)), "sqlobject", "__version__.py") -load_source("sqlobject_version", versionpath) -from sqlobject_version import version # noqa: ignore flake8 E402 +sqlobject_version = load_source("sqlobject_version", versionpath) subpackages = ['firebird', 'include', 'include.tests', 'inheritance', 'inheritance.tests', @@ -69,7 +68,7 @@ kw['python_requires'] = '>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*' setup(name="SQLObject", - version=version, + version=sqlobject_version.version, description="Object-Relational Manager, aka database wrapper", long_description="""\ SQLObject is a popular *Object Relational Manager* for providing an @@ -111,7 +110,8 @@ maintainer="Oleg Broytman", maintainer_email="phd@phdru.name", url="http://sqlobject.org/", - download_url="https://pypi.python.org/pypi/SQLObject/%s" % version, + download_url="https://pypi.python.org/pypi/SQLObject/%s" % + sqlobject_version.version, keywords=["sql", "orm", "object-relational mapper"], license="LGPL", platforms="Any", From d86fbb9597160f3495566dd28a5dd291d445525f Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 17 Feb 2018 01:48:58 +0300 Subject: [PATCH 144/509] Feat: Close cursors after using Free resources immediately instead of waiting for gc. --- docs/News.rst | 6 ++++++ sqlobject/dbconnection.py | 12 +++++++++--- sqlobject/firebird/firebirdconnection.py | 1 + sqlobject/maxdb/maxdbconnection.py | 1 + sqlobject/mssql/mssqlconnection.py | 7 ++++++- sqlobject/mysql/mysqlconnection.py | 1 + sqlobject/postgres/pgconnection.py | 2 ++ sqlobject/sqlite/sqliteconnection.py | 1 + sqlobject/sybase/sybaseconnection.py | 6 +++++- 9 files changed, 32 insertions(+), 5 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index 9ce26cf7..1bb32ce7 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,12 @@ News SQLObject 3.6.0 (master) ======================== +Minor features +-------------- + +* Close cursors after using to free resources immediately + instead of waiting for gc. + Drivers ------- diff --git a/sqlobject/dbconnection.py b/sqlobject/dbconnection.py index 41e9b6a0..3bde3cc6 100644 --- a/sqlobject/dbconnection.py +++ b/sqlobject/dbconnection.py @@ -427,7 +427,9 @@ def _executeRetry(self, conn, cursor, query): def _query(self, conn, s): if self.debug: self.printDebug(conn, s, 'Query') - self._executeRetry(conn, conn.cursor(), s) + c = conn.cursor() + self._executeRetry(conn, c, s) + c.close() def query(self, s): return self._runWithConnection(self._query, s) @@ -438,6 +440,7 @@ def _queryAll(self, conn, s): c = conn.cursor() self._executeRetry(conn, c, s) value = c.fetchall() + c.close() if self.debugOutput: self.printDebug(conn, value, 'QueryAll', 'result') return value @@ -455,6 +458,7 @@ def _queryAllDescription(self, conn, s): c = conn.cursor() self._executeRetry(conn, c, s) value = c.fetchall() + c.close() if self.debugOutput: self.printDebug(conn, value, 'QueryAll', 'result') return c.description, value @@ -468,6 +472,7 @@ def _queryOne(self, conn, s): c = conn.cursor() self._executeRetry(conn, c, s) value = c.fetchone() + c.close() if self.debugOutput: self.printDebug(conn, value, 'QueryOne', 'result') return value @@ -778,10 +783,11 @@ def _cleanup(self): if getattr(self, 'query', None) is None: # already cleaned up return - self.query = None + self.cursor.close() if not self.keepConnection: self.dbconn.releaseConnection(self.rawconn) - self.dbconn = self.rawconn = self.select = self.cursor = None + self.query = self.dbconn = self.rawconn = \ + self.select = self.cursor = None def __del__(self): self._cleanup() diff --git a/sqlobject/firebird/firebirdconnection.py b/sqlobject/firebird/firebirdconnection.py index 3bf3fb57..4624b487 100644 --- a/sqlobject/firebird/firebirdconnection.py +++ b/sqlobject/firebird/firebirdconnection.py @@ -135,6 +135,7 @@ def _queryInsertID(self, conn, soInstance, id, names, values): if self.debug: self.printDebug(conn, q, 'QueryIns') c.execute(q) + c.close() if self.debugOutput: self.printDebug(conn, id, 'QueryIns', 'result') return id diff --git a/sqlobject/maxdb/maxdbconnection.py b/sqlobject/maxdb/maxdbconnection.py index c46c3eab..4fd53b1b 100644 --- a/sqlobject/maxdb/maxdbconnection.py +++ b/sqlobject/maxdb/maxdbconnection.py @@ -138,6 +138,7 @@ def _queryInsertID(self, conn, soInstance, id, names, values): if self.debug: self.printDebug(conn, q, 'QueryIns') c.execute(q) + c.close() if self.debugOutput: self.printDebug(conn, id, 'QueryIns', 'result') return id diff --git a/sqlobject/mssql/mssqlconnection.py b/sqlobject/mssql/mssqlconnection.py index 0201031d..0a53670c 100644 --- a/sqlobject/mssql/mssqlconnection.py +++ b/sqlobject/mssql/mssqlconnection.py @@ -137,7 +137,9 @@ def insert_id(self, conn): # converting the identity to an int is ugly, but it gets returned # as a decimal otherwise :S c.execute('SELECT CONVERT(INT, @@IDENTITY)') - return c.fetchone()[0] + result = c.fetchone()[0] + c.close() + return result def makeConnection(self): if self.driver in ('odbc', 'pyodbc', 'pypyodbc'): @@ -169,6 +171,7 @@ def _hasIdentity(self, conn, table): c = conn.cursor() c.execute(query) r = c.fetchone() + c.close() return r is not None def _queryInsertID(self, conn, soInstance, id, names, values): @@ -206,6 +209,7 @@ def _queryInsertID(self, conn, soInstance, id, names, values): c.execute(q) if has_identity: c.execute('SET IDENTITY_INSERT %s OFF' % table) + c.close() if id is None: id = self.insert_id(conn) @@ -329,6 +333,7 @@ def _setAutoCommit(self, conn, auto): option = "OFF" c = conn.cursor() c.execute("SET AUTOCOMMIT " + option) + c.close() # precision and scale is needed for decimal columns def guessClass(self, t, size, precision, scale): diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index 96517dd2..51cbde40 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -300,6 +300,7 @@ def _queryInsertID(self, conn, soInstance, id, names, values): id = c.fetchone()[0] else: id = c.insert_id() + c.close() if self.debugOutput: self.printDebug(conn, id, 'QueryIns', 'result') return id diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index a3068665..b8a83c79 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -230,6 +230,7 @@ def makeConnection(self): conn.setencoding(encoding=dbEncoding) self._executeRetry(conn, c, "SET client_encoding TO '%s'" % dbEncoding) + c.close() return conn def _executeRetry(self, conn, cursor, query): @@ -303,6 +304,7 @@ def _queryInsertID(self, conn, soInstance, id, names, values): self._executeRetry(conn, c, q) if id is None: id = c.fetchone()[0] + c.close() if self.debugOutput: self.printDebug(conn, id, 'QueryIns', 'result') return id diff --git a/sqlobject/sqlite/sqliteconnection.py b/sqlobject/sqlite/sqliteconnection.py index 93ad429c..fbb07a55 100644 --- a/sqlobject/sqlite/sqliteconnection.py +++ b/sqlobject/sqlite/sqliteconnection.py @@ -258,6 +258,7 @@ def _queryInsertID(self, conn, soInstance, id, names, values): # lastrowid is a DB-API extension from "PEP 0249": if id is None: id = int(c.lastrowid) + c.close() if self.debugOutput: self.printDebug(conn, id, 'QueryIns', 'result') return id diff --git a/sqlobject/sybase/sybaseconnection.py b/sqlobject/sybase/sybaseconnection.py index f79441a2..11f44344 100644 --- a/sqlobject/sybase/sybaseconnection.py +++ b/sqlobject/sybase/sybaseconnection.py @@ -46,7 +46,9 @@ def insert_id(self, conn): """ c = conn.cursor() c.execute('SELECT @@IDENTITY') - return c.fetchone()[0] + result = c.fetchone()[0] + c.close() + return result def makeConnection(self): return self.module.connect(self.host, self.user, self.password, @@ -68,6 +70,7 @@ def _hasIdentity(self, conn, table): c = conn.cursor() c.execute(query) r = c.fetchone() + c.close() return r is not None def _queryInsertID(self, conn, soInstance, id, names, values): @@ -93,6 +96,7 @@ def _queryInsertID(self, conn, soInstance, id, names, values): c.execute(q) if has_identity and identity_insert_on: c.execute('SET IDENTITY_INSERT %s OFF' % table) + c.close() if id is None: id = self.insert_id(conn) if self.debugOutput: From 96a66ecdfa7cdc630de0ad057ce7d3a33e401c2a Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 11 Feb 2018 21:58:02 +0300 Subject: [PATCH 145/509] Fix(mssqlconnection): Fix _setAutoCommit --- docs/News.rst | 2 ++ sqlobject/mssql/mssqlconnection.py | 25 ++++++++++++++----------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index 1bb32ce7..82517ad4 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -19,6 +19,8 @@ Drivers * Extend support for oursql and Python 3 (require our fork of the driver). +* Fix _setAutoCommit for MSSQL. + Documentation ------------- diff --git a/sqlobject/mssql/mssqlconnection.py b/sqlobject/mssql/mssqlconnection.py index 0a53670c..9079d317 100644 --- a/sqlobject/mssql/mssqlconnection.py +++ b/sqlobject/mssql/mssqlconnection.py @@ -159,6 +159,20 @@ def makeConnection(self): cur.close() return conn + def _setAutoCommit(self, conn, auto): + auto = bool(auto) + if self.driver in ('adodb', 'adodbapi'): + if auto: + option = "ON" + else: + option = "OFF" + c = conn.cursor() + c.execute("SET AUTOCOMMIT " + option) + elif self.driver == 'pymssql': + conn.autocommit(auto) + elif self.driver in ('odbc', 'pyodbc', 'pypyodbc'): + conn.autocommit = auto + HAS_IDENTITY = """ select 1 from INFORMATION_SCHEMA.COLUMNS @@ -324,17 +338,6 @@ def columnsFromSchema(self, tableName, soClass): results.append(colClass(**kw)) return results - def _setAutoCommit(self, conn, auto): - # raise Exception(repr(auto)) - return - # conn.auto_commit = auto - option = "ON" - if auto == 0: - option = "OFF" - c = conn.cursor() - c.execute("SET AUTOCOMMIT " + option) - c.close() - # precision and scale is needed for decimal columns def guessClass(self, t, size, precision, scale): """ From f08401c205e30d8c8eb70978f850577cff8598a9 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 11 Feb 2018 22:46:15 +0300 Subject: [PATCH 146/509] Fix cursor.arraysize - pymssql doesn't have arraysize --- docs/News.rst | 2 ++ sqlobject/inheritance/iteration.py | 12 ++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index 82517ad4..47564559 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -21,6 +21,8 @@ Drivers * Fix _setAutoCommit for MSSQL. +* Fix cursor.arraysize - pymssql doesn't have arraysize. + Documentation ------------- diff --git a/sqlobject/inheritance/iteration.py b/sqlobject/inheritance/iteration.py index fd7b78f5..558700ea 100644 --- a/sqlobject/inheritance/iteration.py +++ b/sqlobject/inheritance/iteration.py @@ -11,7 +11,11 @@ def __init__(self, dbconn, rawconn, select, keepConnection=False): super(InheritableIteration, self).__init__(dbconn, rawconn, select, keepConnection) self.lazyColumns = select.ops.get('lazyColumns', False) - self.cursor.arraysize = self.defaultArraySize + try: + self.cursor.arraysize = self.defaultArraySize + self.use_arraysize = True + except AttributeError: # pymssql doesn't have arraysize + self.use_arraysize = False self._results = [] # Find the index of the childName column childNameIdx = None @@ -24,7 +28,11 @@ def __init__(self, dbconn, rawconn, select, keepConnection=False): def next(self): if not self._results: - self._results = list(self.cursor.fetchmany()) + if self.use_arraysize: + _results = self.cursor.fetchmany() + else: + _results = self.cursor.fetchmany(size=self.defaultArraySize) + self._results = list(_results) if not self.lazyColumns: self.fetchChildren() if not self._results: From 2a1839364d1a3b4ba260ede53886526ee8cd4860 Mon Sep 17 00:00:00 2001 From: "Michael S. Root" Date: Thu, 22 Feb 2018 16:38:31 -0800 Subject: [PATCH 147/509] Bugfix for TypeError using selectBy on a BLOBCol --- sqlobject/dbconnection.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sqlobject/dbconnection.py b/sqlobject/dbconnection.py index 3bde3cc6..2dfa45ef 100644 --- a/sqlobject/dbconnection.py +++ b/sqlobject/dbconnection.py @@ -666,7 +666,6 @@ def _SO_intermediateInsert(self, table, firstColumn, firstValue, def _SO_columnClause(self, soClass, kw): from . import main - ops = {None: "IS"} data = [] if 'id' in kw: data.append((soClass.sqlmeta.idName, kw.pop('id'))) @@ -694,7 +693,7 @@ def _SO_columnClause(self, soClass, kw): return None return ' AND '.join( ['%s %s %s' % - (dbName, ops.get(value, "="), self.sqlrepr(value)) + (dbName, "IS" if value is None else "=", self.sqlrepr(value)) for dbName, value in data]) From 4ec83426e3c13505026f411cfcccbf0d82cdb3c5 Mon Sep 17 00:00:00 2001 From: "Michael S. Root" Date: Thu, 22 Feb 2018 17:39:35 -0800 Subject: [PATCH 148/509] Added test for 2a1839364d1a3b4ba260ede53886526ee8cd4860 --- sqlobject/tests/test_blob.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sqlobject/tests/test_blob.py b/sqlobject/tests/test_blob.py index 8c43d8a5..9d135d1e 100644 --- a/sqlobject/tests/test_blob.py +++ b/sqlobject/tests/test_blob.py @@ -30,3 +30,6 @@ def test_BLOBCol(): prof2 = ImageData.get(iid) assert prof2.image == data + + ImageData(image='string') + assert ImageData.selectBy(image='string').count() == 1 From 38a83488fc97663409afdceb51d0ccecf6f22ebd Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 18 Feb 2018 00:22:41 +0300 Subject: [PATCH 149/509] Feat(mssql): Set timeout for ODBC with MSSQL --- docs/News.rst | 4 +++- sqlobject/mssql/mssqlconnection.py | 19 +++++++++++++------ tox.ini | 3 +-- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index 47564559..cb50657d 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -19,9 +19,11 @@ Drivers * Extend support for oursql and Python 3 (require our fork of the driver). +* Fix cursor.arraysize - pymssql doesn't have arraysize. + * Fix _setAutoCommit for MSSQL. -* Fix cursor.arraysize - pymssql doesn't have arraysize. +* Set timeout for ODBC with MSSQL. Documentation ------------- diff --git a/sqlobject/mssql/mssqlconnection.py b/sqlobject/mssql/mssqlconnection.py index 9079d317..b135fe44 100644 --- a/sqlobject/mssql/mssqlconnection.py +++ b/sqlobject/mssql/mssqlconnection.py @@ -51,6 +51,11 @@ def __init__(self, db, user, password='', host='localhost', port=None, raise ImportError( 'Cannot find an MSSQL driver, tried %s' % drivers) + timeout = kw.pop('timeout', None) + if timeout: + timeout = int(timeout) + self.timeout = timeout + if driver in ('odbc', 'pyodbc', 'pypyodbc'): self.make_odbc_conn_str(kw.pop('odbcdrv', 'SQL Server'), db, host, port, user, password @@ -91,11 +96,6 @@ def __init__(self, db, user, password='', host='localhost', port=None, # don't know whether pymssql uses unicode self.usingUnicodeStrings = False - timeout = kw.pop('timeout', None) - if timeout: - timeout = int(timeout) - self.timeout = timeout - def _make_conn_str(keys): keys_dict = {} for attr, value in ( @@ -145,7 +145,14 @@ def makeConnection(self): if self.driver in ('odbc', 'pyodbc', 'pypyodbc'): self.debugWriter.write( "ODBC connect string: " + self.odbc_conn_str) - conn = self.module.connect(self.odbc_conn_str) + timeout = self.timeout + if timeout: + kw = dict(timeout=timeout) + else: + kw = dict() + conn = self.module.connect(self.odbc_conn_str, **kw) + if timeout: + conn.timeout = timeout else: conn_descr = self.make_conn_str(self) if isinstance(conn_descr, dict): diff --git a/tox.ini b/tox.ini index 54498f6f..c902edba 100644 --- a/tox.ini +++ b/tox.ini @@ -17,7 +17,6 @@ commands = deps = -rdevscripts/requirements/requirements_tests.txt py27: egenix-mx-base - mssql-pyodbc: pytest-timeout mysqldb: mysql-python mysqlclient: mysqlclient mysql-connector: mysql-connector <= 2.2.2 @@ -396,7 +395,7 @@ commands = {envpython} -c "import pyodbc; print(pyodbc.drivers())" -sqlcmd -U sa -P "Password12!" -S .\SQL2014 -Q "DROP DATABASE sqlobject_test" sqlcmd -U sa -P "Password12!" -S .\SQL2014 -Q "CREATE DATABASE sqlobject_test" - pytest --cov=sqlobject -D "mssql://sa:Password12!@localhost\SQL2014/sqlobject_test?driver=pyodbc&odbcdrv=SQL%20Server&debug=1" --timeout=30 + pytest --cov=sqlobject -D "mssql://sa:Password12!@localhost\SQL2014/sqlobject_test?driver=pyodbc&odbcdrv=SQL%20Server&timeout=30&debug=1" sqlcmd -U sa -P "Password12!" -S .\SQL2014 -Q "DROP DATABASE sqlobject_test" [testenv:py27-mssql-pyodbc-w32] From 2a7d28573d1e4f07250da1d30209304fdb6de90d Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 23 Feb 2018 09:55:38 +0300 Subject: [PATCH 150/509] Tests(blob): Use byte string for test --- sqlobject/tests/test_blob.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/sqlobject/tests/test_blob.py b/sqlobject/tests/test_blob.py index 9d135d1e..2c9b20ff 100644 --- a/sqlobject/tests/test_blob.py +++ b/sqlobject/tests/test_blob.py @@ -22,8 +22,7 @@ def test_BLOBCol(): else: data = bytes(range(256)) - prof = ImageData() - prof.image = data + prof = ImageData(image=data) iid = prof.id ImageData._connection.cache.clear() @@ -31,5 +30,5 @@ def test_BLOBCol(): prof2 = ImageData.get(iid) assert prof2.image == data - ImageData(image='string') - assert ImageData.selectBy(image='string').count() == 1 + ImageData(image=b'string') + assert ImageData.selectBy(image=b'string').count() == 1 From 0ff26ed5b30d7834e310d3c8adbf91f17c23323d Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 23 Feb 2018 09:56:23 +0300 Subject: [PATCH 151/509] Docs: Update News [skip ci] --- docs/News.rst | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index cb50657d..35c78f1f 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -14,17 +14,22 @@ Minor features * Close cursors after using to free resources immediately instead of waiting for gc. +Bug fixes +--------- + +* Fix for TypeError using selectBy on a BLOBCol. PR by Michael S. Root. + Drivers ------- -* Extend support for oursql and Python 3 (require our fork of the driver). +* Extend support for oursql and Python 3 (requires our fork of the driver). * Fix cursor.arraysize - pymssql doesn't have arraysize. -* Fix _setAutoCommit for MSSQL. - * Set timeout for ODBC with MSSQL. +* Fix _setAutoCommit for MSSQL. + Documentation ------------- From d3495297930135d1aeb183144abd01e8aad1cd2a Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 24 Feb 2018 18:41:06 +0300 Subject: [PATCH 152/509] Build: Document changing Python version at SF [skip ci] --- devscripts/BRANCH-CHECKLIST | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devscripts/BRANCH-CHECKLIST b/devscripts/BRANCH-CHECKLIST index 2b51cb09..280f494d 100644 --- a/devscripts/BRANCH-CHECKLIST +++ b/devscripts/BRANCH-CHECKLIST @@ -21,7 +21,7 @@ a branch, a commit id or a tag. 2. To deprecate a version of Python edit files ANNOUNCE.rst, README.rst, devscripts/release, devscripts/setup, docs/News.rst, docs/SQLObject.rst, docs/TODO.rst, requirements.txt, setup.py, sqlobject/main.py, - tox.ini in master. + tox.ini in master. Edit metadata at SourceForge. 3. Do a null-merge from the new branch to the higher branch or the master. From 91b21bf69f10e15bbdd0cb6c10aa988868c974bf Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 24 Feb 2018 18:59:03 +0300 Subject: [PATCH 153/509] Build: Edit build-all-docs during release process [skip ci] --- devscripts/RELEASE-CHECKLIST | 46 +++++++++++++++++++----------------- devscripts/prerelease | 4 ++-- 2 files changed, 26 insertions(+), 24 deletions(-) diff --git a/devscripts/RELEASE-CHECKLIST b/devscripts/RELEASE-CHECKLIST index c1607770..205f9732 100644 --- a/devscripts/RELEASE-CHECKLIST +++ b/devscripts/RELEASE-CHECKLIST @@ -4,51 +4,53 @@ 1. Check out the release branch. If it is a stable release - edit docs/News.rst to set release date. Commit. -2. If it's the first stable release of the branch - edit build-all-docs, +2. If release branch is not master - run ../prerelease $NEW_TAG; if it's + master - run ../prerelease $NEW_TAG master. + + The script checks out the release branch and calls editor; update + version, the list of contributors, the list of changes and download + URL in ANNOUNCE.rst; edit __version__.py and README.rst in the release + branch - fix versions. Edit section [egg_info] in setup.cfg - set if + it is a stable or development release. In setup.py edit "Development + Status" in trove classifiers; edit download URL: if a non-stable + version - append 'dev' and date stamp, for a stable version remove + 'dev' and date stamp). + + If it's the first stable release of the branch - edit build-all-docs, advance stable branch. Commit. If it's not master - merge to all higher branches and master. -3. If release branch is not master - run ../prerelease $NEW_TAG; if it's - master - run ../prerelease $NEW_TAG master. - -3a. The script checks out the release branch and calls editor; update - version, the list of contributors, the list of changes and download - URL in ANNOUNCE.rst; edit __version__.py and README.rst in the release - branch - fix versions. Edit section [egg_info] in setup.cfg - set if - it is a stable or development release. In setup.py edit "Development - Status" in trove classifiers; edit download URL: if a non-stable - version - append 'dev' and date stamp, for a stable version remove - 'dev' and date stamp). Commit. Verify. + Commit. Verify. -4. If it's not master - null-merge to the next higher branch. +3. If it's not master - null-merge to the next higher branch. -5. If release branch is not master - run ../prerelease-tag $NEW_TAG; if +4. If release branch is not master - run ../prerelease-tag $NEW_TAG; if it's master - run ../prerelease-tag $NEW_TAG master. This checks out the release branch and creates the new tag at the head of the release branch. -6. Run ../release. This generates and uploads new archives to PyPI and +5. Run ../release. This generates and uploads new archives to PyPI and if it is a stable release - uploads archives and release announcement (ANNOUNCE.rst) to SourceForge. -7. Hide/show old releases at PyPI and SourceForge. +6. Hide/show old releases at PyPI and SourceForge. -8. Run ../push-all in the development repository to push all branches +7. Run ../push-all in the development repository to push all branches and tags to the public repositories. -9. Run ../postrelease. The script restores ANNOUNCE.rst from the previous +8. Run ../postrelease. The script restores ANNOUNCE.rst from the previous commit (HEAD~). It calls editor; update next version, remove the list of contributors and the list of changes, edit download URL in ANNOUNCE.rst. Edit docs/News.rst - add new version. -10. Generate new docs using ./build-all-docs. Upload docs using - ./publish-docs. +9. Generate new docs using ./build-all-docs. Upload docs using + ./publish-docs. -11. Send announcement to the SQLObject mailing list. For a stable +10. Send announcement to the SQLObject mailing list. For a stable release send announcements to python, python-announce and python-db mailing lists. -11. Announce new release(s) at Twitter (https://twitter.com/SQLObject) and +10. Announce new release(s) at Twitter (https://twitter.com/SQLObject) and Wikipedia (https://en.wikipedia.org/wiki/SQLObject). If it is a stable release - announce it at https://en.wikipedia.org/wiki/Comparison_of_object-relational_mapping_software. diff --git a/devscripts/prerelease b/devscripts/prerelease index 17ed8904..edd7358e 100755 --- a/devscripts/prerelease +++ b/devscripts/prerelease @@ -22,5 +22,5 @@ micro = $micro release_level = '$state' serial = $serial version_info = (major, minor, micro, release_level, serial)" > sqlobject/__version__.py && -`git var GIT_EDITOR` ANNOUNCE.rst docs/News.rst sqlobject/__version__.py README.rst setup.cfg setup.py && -exec git commit --message="Release $tag" ANNOUNCE.rst docs/News.rst sqlobject/__version__.py README.rst setup.cfg setup.py +`git var GIT_EDITOR` devscripts/build-all-docs docs/News.rst ANNOUNCE.rst sqlobject/__version__.py README.rst setup.cfg setup.py && +exec git commit --message="Release $tag" devscripts/build-all-docs docs/News.rst ANNOUNCE.rst sqlobject/__version__.py README.rst setup.cfg setup.py From 0fd1c2134fe29a0bb0f55798702083bb0d61ca05 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 24 Feb 2018 18:50:36 +0300 Subject: [PATCH 154/509] Release 3.6.0 --- ANNOUNCE.rst | 53 +++++++++++++++++++++++++++------------ README.rst | 2 +- devscripts/build-all-docs | 2 +- docs/News.rst | 6 +++-- sqlobject/__version__.py | 4 +-- 5 files changed, 45 insertions(+), 22 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 2f45be41..3aca1fb1 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,28 +1,49 @@ Hello! -I'm pleased to announce version 3.6.1a1, the first alpha of the upcoming -release of branch 3.6 of SQLObject. +I'm pleased to announce version 3.6.0, the first stable release of branch +3.6 of SQLObject. -I'm pleased to announce version 3.6.1a2, the second alpha of the upcoming -release of branch 3.6 of SQLObject. -I'm pleased to announce version 3.6.1b1, the first beta of the upcoming -release of branch 3.6 of SQLObject. +What's new in SQLObject +======================= -I'm pleased to announce version 3.6.1rc1, the first release candidate -of the upcoming release of branch 3.6 of SQLObject. +Contributor for this release is Michael S. Root. -I'm pleased to announce version 3.6.0, the first stable release of branch -3.6 of SQLObject. +Minor features +-------------- -I'm pleased to announce version 3.6.1, the first bugfix release of branch -3.6 of SQLObject. +* Close cursors after using to free resources immediately + instead of waiting for gc. +Bug fixes +--------- -What's new in SQLObject -======================= +* Fix for TypeError using selectBy on a BLOBCol. PR by Michael S. Root. + +Drivers +------- + +* Extend support for oursql and Python 3 (requires our fork of the driver). + +* Fix cursor.arraysize - pymssql doesn't have arraysize. + +* Set timeout for ODBC with MSSQL. + +* Fix _setAutoCommit for MSSQL. + +Documentation +------------- + +* Document extras that are available for installation. + +Build +----- + +* Use ``python_version`` environment marker in ``setup.py`` to make + ``install_requires`` and ``extras_require`` declarative. This makes + the universal wheel truly universal. -Contributors for this release are +* Use ``python_requires`` keyword in ``setup.py``. For a more complete list, please see the news: http://sqlobject.org/News.html @@ -54,7 +75,7 @@ Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Download: -https://pypi.python.org/pypi/SQLObject/3.6.0a0.dev20171115 +https://pypi.python.org/pypi/SQLObject/3.6.0 News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index d32d4120..66165d1f 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,4 @@ -SQLObject 3.5.0 +SQLObject 3.6.0 =============== Thanks for looking at SQLObject. SQLObject is an object-relational diff --git a/devscripts/build-all-docs b/devscripts/build-all-docs index 5fd0c945..3eb17ed5 100755 --- a/devscripts/build-all-docs +++ b/devscripts/build-all-docs @@ -11,7 +11,7 @@ cd "$PROG_DIR" && PROG_DIR="`pwd`" && cd "$PROG_DIR"/SQLObject && -build_docs 3.5.0 && +build_docs 3.6.0 && build_docs master devel && rm -rf docs/html && diff --git a/docs/News.rst b/docs/News.rst index 35c78f1f..66ef00e4 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,8 +5,10 @@ News .. contents:: Contents: :backlinks: none -SQLObject 3.6.0 (master) -======================== +SQLObject 3.6.0 +=============== + +Released 24 Feb 2018. Minor features -------------- diff --git a/sqlobject/__version__.py b/sqlobject/__version__.py index 88c8ca08..5d92a176 100644 --- a/sqlobject/__version__.py +++ b/sqlobject/__version__.py @@ -1,7 +1,7 @@ -version = '3.5.0' +version = '3.6.0' major = 3 -minor = 5 +minor = 6 micro = 0 release_level = 'final' serial = 0 From 39b3cd463dbad05e1785ce60084b0bfe57292e50 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 24 Feb 2018 19:10:59 +0300 Subject: [PATCH 155/509] Prepare for the next release [skip ci] --- ANNOUNCE.rst | 53 ++++++++++++---------------------------- README.rst | 2 +- docs/News.rst | 3 +++ sqlobject/__version__.py | 6 ++--- 4 files changed, 23 insertions(+), 41 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 3aca1fb1..2e052100 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,49 +1,28 @@ Hello! -I'm pleased to announce version 3.6.0, the first stable release of branch -3.6 of SQLObject. +I'm pleased to announce version 3.7.0a1, the first alpha of the upcoming +release of branch 3.7 of SQLObject. +I'm pleased to announce version 3.7.0a2, the second alpha of the upcoming +release of branch 3.7 of SQLObject. -What's new in SQLObject -======================= - -Contributor for this release is Michael S. Root. - -Minor features --------------- - -* Close cursors after using to free resources immediately - instead of waiting for gc. - -Bug fixes ---------- - -* Fix for TypeError using selectBy on a BLOBCol. PR by Michael S. Root. +I'm pleased to announce version 3.7.0b1, the first beta of the upcoming +release of branch 3.7 of SQLObject. -Drivers -------- +I'm pleased to announce version 3.7.0rc1, the first release candidate +of the upcoming release of branch 3.7 of SQLObject. -* Extend support for oursql and Python 3 (requires our fork of the driver). +I'm pleased to announce version 3.7.0, the first stable release of branch +3.7 of SQLObject. -* Fix cursor.arraysize - pymssql doesn't have arraysize. +I'm pleased to announce version 3.7.0, the first bugfix release of branch +3.7 of SQLObject. -* Set timeout for ODBC with MSSQL. -* Fix _setAutoCommit for MSSQL. - -Documentation -------------- - -* Document extras that are available for installation. - -Build ------ - -* Use ``python_version`` environment marker in ``setup.py`` to make - ``install_requires`` and ``extras_require`` declarative. This makes - the universal wheel truly universal. +What's new in SQLObject +======================= -* Use ``python_requires`` keyword in ``setup.py``. +Contributors for this release are For a more complete list, please see the news: http://sqlobject.org/News.html @@ -75,7 +54,7 @@ Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Download: -https://pypi.python.org/pypi/SQLObject/3.6.0 +https://pypi.python.org/pypi/SQLObject/3.7.0a0.dev20171115 News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 66165d1f..9eb1399d 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,4 @@ -SQLObject 3.6.0 +SQLObject 3.7.0 =============== Thanks for looking at SQLObject. SQLObject is an object-relational diff --git a/docs/News.rst b/docs/News.rst index 66ef00e4..f531748c 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,6 +5,9 @@ News .. contents:: Contents: :backlinks: none +SQLObject 3.7.0 (master) +======================== + SQLObject 3.6.0 =============== diff --git a/sqlobject/__version__.py b/sqlobject/__version__.py index 5d92a176..cd242701 100644 --- a/sqlobject/__version__.py +++ b/sqlobject/__version__.py @@ -1,8 +1,8 @@ -version = '3.6.0' +version = '3.7.0' major = 3 -minor = 6 +minor = 7 micro = 0 -release_level = 'final' +release_level = 'dev' serial = 0 version_info = (major, minor, micro, release_level, serial) From 6eaa00e3173bac72d1e32e2be98b44f8ce682983 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 24 Feb 2018 19:20:26 +0300 Subject: [PATCH 156/509] Build(publish-docs): chmod a+rX [skip ci] --- devscripts/publish-docs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devscripts/publish-docs b/devscripts/publish-docs index 37276d7e..1ecdc505 100755 --- a/devscripts/publish-docs +++ b/devscripts/publish-docs @@ -1,5 +1,5 @@ #! /bin/sh -cd "`dirname \"$0\"`"/SQLObject-docs && chmod -R u=rwX,go=rX . && +cd "`dirname \"$0\"`"/SQLObject-docs && chmod -R a+rX . && exec rsync -hlrtP4 --del . \ web.sourceforge.net:/home/project-web/sqlobject/htdocs/ From a2579ba30985e8019422ab0563a502ddfda42fb6 Mon Sep 17 00:00:00 2001 From: Scott Stahl Date: Fri, 9 Mar 2018 23:14:07 -0500 Subject: [PATCH 157/509] Add signals on commit and rollback --- sqlobject/dbconnection.py | 17 ++++++++++++++++ sqlobject/events.py | 13 +++++++++++++ sqlobject/tests/test_transactions.py | 29 +++++++++++++++++++++++++++- 3 files changed, 58 insertions(+), 1 deletion(-) diff --git a/sqlobject/dbconnection.py b/sqlobject/dbconnection.py index 2dfa45ef..cdcc64a4 100644 --- a/sqlobject/dbconnection.py +++ b/sqlobject/dbconnection.py @@ -13,6 +13,7 @@ import warnings import weakref +from .events import send, CommitSignal, RollbackSignal from .cache import CacheSet from . import classregistry from . import col @@ -855,6 +856,7 @@ def commit(self, close=False): return if self._dbConnection.debug: self._dbConnection.printDebug(self._connection, '', 'COMMIT') + self._send_event(CommitSignal) self._connection.commit() subCaches = [(sub[0], sub[1].allIDs()) for sub in self.cache.allSubCachesByClassNames().items()] @@ -874,6 +876,7 @@ def rollback(self): if self._dbConnection.debug: self._dbConnection.printDebug(self._connection, '', 'ROLLBACK') subCaches = [(sub, sub.allIDs()) for sub in self.cache.allSubCaches()] + self._send_event(RollbackSignal) self._connection.rollback() for subCache, ids in subCaches: @@ -883,6 +886,20 @@ def rollback(self): inst.expire() self._makeObsolete() + def _send_event(self, signal): + """ + Pushes a list of class_names and related ids in cache. + :param signal: Type of event signal to use + """ + from .main import sqlmeta + cached_classes_and_ids = [ + (class_name, cache.allIDs()) for class_name, cache in + self.cache.allSubCachesByClassNames().items() + ] + + if cached_classes_and_ids: + send(signal, sqlmeta, cached_classes_and_ids) + def __getattr__(self, attr): """ If nothing else works, let the parent connection handle it. diff --git a/sqlobject/events.py b/sqlobject/events.py index bf329df9..d38a2276 100644 --- a/sqlobject/events.py +++ b/sqlobject/events.py @@ -211,6 +211,19 @@ class DropTableSignal(Signal): after the table has been dropped. """ + +class CommitSignal(Signal): + """ + Called on transaction commit + """ + + +class RollbackSignal(Signal): + """ + Called on transaction rollback + """ + + ############################################################ # Event Debugging ############################################################ diff --git a/sqlobject/tests/test_transactions.py b/sqlobject/tests/test_transactions.py index b52ad52f..091de474 100644 --- a/sqlobject/tests/test_transactions.py +++ b/sqlobject/tests/test_transactions.py @@ -1,7 +1,8 @@ import pytest from sqlobject import SQLObject, SQLObjectNotFound, StringCol from sqlobject.tests.dbtest import raises, setupClass, supports - +from sqlobject import events +from sqlobject.main import sqlmeta ######################################## # Transaction test @@ -24,7 +25,25 @@ class sqlmeta: name = StringCol(length=10, alternateID=True, dbName='name_col') +def make_watcher(): + log = [] + + def watch(*args): + log.append(args) + + watch.log = log + return watch + + +def make_listen(signal): + watcher = make_watcher() + events.listen(watcher, sqlmeta, signal) + return watcher + + def test_transaction(): + commit_watcher = make_listen(events.CommitSignal) + rollback_watcher = make_listen(events.RollbackSignal) setupClass(SOTestSOTrans) SOTestSOTrans(name='bob') SOTestSOTrans(name='tim') @@ -44,6 +63,14 @@ def test_transaction(): trans.rollback() trans.begin() assert b.name == 'robert' + assert len(commit_watcher.log) == 1 + assert commit_watcher.log[0][0][0][0] == 'SOTestSOTrans' + assert commit_watcher.log[0][0][0][1] == [1, 2] + assert len(rollback_watcher.log) == 2 + assert rollback_watcher.log[0][0][0][0] == 'SOTestSOTrans' + assert rollback_watcher.log[0][0][0][1] == [3] + assert rollback_watcher.log[1][0][0][0] == 'SOTestSOTrans' + assert rollback_watcher.log[1][0][0][1] == [1, 2] finally: SOTestSOTrans._connection.autoCommit = True From 7b40a34f669819596c00be0e952dd70b24dc90e1 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 10 Mar 2018 19:27:42 +0300 Subject: [PATCH 158/509] Docs: Update News and the list of contributors [skip ci] --- docs/Authors.rst | 1 + docs/News.rst | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/docs/Authors.rst b/docs/Authors.rst index 3f3d55ba..92f936ea 100644 --- a/docs/Authors.rst +++ b/docs/Authors.rst @@ -36,6 +36,7 @@ Contributions have been made by: * Lutz Steinborn * Shailesh Mungikar * Michael S. Root +* Scott Stahl * Oleg Broytman .. image:: https://sourceforge.net/sflogo.php?group_id=74338&type=10 diff --git a/docs/News.rst b/docs/News.rst index f531748c..17626cde 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,11 @@ News SQLObject 3.7.0 (master) ======================== +Features +-------- + +* Add signals on commit and rollback; pull request by Scott Stahl. + SQLObject 3.6.0 =============== From a6dd93557d300a5f6c5f5f15332272ba68182402 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 10 Mar 2018 19:21:40 +0300 Subject: [PATCH 159/509] Style(dbconnection.py): Sort imports --- sqlobject/dbconnection.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sqlobject/dbconnection.py b/sqlobject/dbconnection.py index cdcc64a4..5fc0f4fa 100644 --- a/sqlobject/dbconnection.py +++ b/sqlobject/dbconnection.py @@ -13,14 +13,14 @@ import warnings import weakref -from .events import send, CommitSignal, RollbackSignal -from .cache import CacheSet from . import classregistry from . import col -from .converters import sqlrepr from . import sqlbuilder -from .util.threadinglocal import local as threading_local +from .cache import CacheSet from .compat import PY2, string_type, unicode_type +from .converters import sqlrepr +from .events import send, CommitSignal, RollbackSignal +from .util.threadinglocal import local as threading_local warnings.filterwarnings("ignore", "DB-API extension cursor.lastrowid used") @@ -891,13 +891,13 @@ def _send_event(self, signal): Pushes a list of class_names and related ids in cache. :param signal: Type of event signal to use """ - from .main import sqlmeta cached_classes_and_ids = [ (class_name, cache.allIDs()) for class_name, cache in self.cache.allSubCachesByClassNames().items() ] if cached_classes_and_ids: + from .main import sqlmeta # Import here to avoid circular import send(signal, sqlmeta, cached_classes_and_ids) def __getattr__(self, attr): From 81e8d6e839b2518f2f13ccf736c58d46fbfe3f6e Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 4 Mar 2018 02:28:31 +0300 Subject: [PATCH 160/509] Docs: Remove outdated unmaintained drivers from TODO Remove asyncpg because it requires asyncio and SQLObject doesn't work with asyncio yet. [skip ci] --- docs/TODO.rst | 5 ----- 1 file changed, 5 deletions(-) diff --git a/docs/TODO.rst b/docs/TODO.rst index 1ce14676..41e24b16 100644 --- a/docs/TODO.rst +++ b/docs/TODO.rst @@ -7,11 +7,6 @@ TODO * Resolve timeout problems with MSSQL. -* https://github.com/d33tah/bpgsql, - https://github.com/olopez32/py-bpgsql, - https://pypi.python.org/pypi/ocpgdb/2.0.2, - https://magicstack.github.io/asyncpg/current/. - * PyPy. * Use https://pypi.python.org/pypi/psycopg2cffi to run SQLObject From 79a9466b4bbaab9b6ac228fbdda6498ad6f62786 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 10 Mar 2018 19:23:27 +0300 Subject: [PATCH 161/509] Fix(dbconnection.py): Remove unused `_connections` --- sqlobject/dbconnection.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sqlobject/dbconnection.py b/sqlobject/dbconnection.py index 5fc0f4fa..1f71b1b5 100644 --- a/sqlobject/dbconnection.py +++ b/sqlobject/dbconnection.py @@ -22,9 +22,8 @@ from .events import send, CommitSignal, RollbackSignal from .util.threadinglocal import local as threading_local -warnings.filterwarnings("ignore", "DB-API extension cursor.lastrowid used") -_connections = {} +warnings.filterwarnings("ignore", "DB-API extension cursor.lastrowid used") def _closeConnection(ref): From 64177145ad9186a31576451dda9c20ee01c034a2 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 10 Mar 2018 19:43:43 +0300 Subject: [PATCH 162/509] CI: Allow failures with ODBC tests at Appveyor --- appveyor.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/appveyor.yml b/appveyor.yml index f5a23b26..8c70af69 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -130,6 +130,15 @@ environment: PYTHON_VERSION: "3.6" PYTHON_HOME: "C:\\Python36-x64" +matrix: + allow_failures: + - TOXENV: "py27-mysql-pyodbc-w32" + - TOXENV: "py36-mysql-pyodbc-w32" + - TOXENV: "py27-postgres-pyodbc-w32" + - TOXENV: "py36-postgres-pyodbc-w32" + + fast_finish: true + install: # Ensure we use the right python version - "SET PATH=%PYTHON_HOME%;%PYTHON_HOME%\\Scripts;C:\\Program Files\\MySQL\\MySQL Server 5.7\\bin;C:\\Program Files\\PostgreSQL\\9.5\\bin;%PATH%" From 5de3056d6276941f041adb2ec8f6f62b29c37dc6 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 10 Mar 2018 21:06:43 +0300 Subject: [PATCH 163/509] CI: Fix .travis.yml Indent matrix.include. --- .travis.yml | 196 ++++++++++++++++++++++++++-------------------------- 1 file changed, 98 insertions(+), 98 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5a6b8e98..32ab10d9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,104 +26,104 @@ addons: matrix: include: - - python: "2.7" - env: TOXENV=py27-mysqldb - - python: "3.4" - env: TOXENV=py34-mysqlclient - - python: "3.5" - env: TOXENV=py35-mysqlclient - - python: "3.6" - env: TOXENV=py36-mysqlclient - - python: "2.7" - env: TOXENV=py27-mysql-connector - - python: "3.4" - env: TOXENV=py34-mysql-connector - - python: "3.5" - env: TOXENV=py35-mysql-connector - - python: "3.6" - env: TOXENV=py36-mysql-connector - - python: "2.7" - env: TOXENV=py27-mysql-oursql - - python: "3.4" - env: TOXENV=py34-mysql-oursql3 - - python: "3.5" - env: TOXENV=py35-mysql-oursql3 - - python: "3.6" - env: TOXENV=py36-mysql-oursql3 - - python: "2.7" - env: TOXENV=py27-pymysql - - python: "3.4" - env: TOXENV=py34-pymysql - - python: "3.5" - env: TOXENV=py35-pymysql - - python: "3.6" - env: TOXENV=py36-pymysql - - python: "2.7" - env: TOXENV=py27-postgres-psycopg - - python: "3.4" - env: TOXENV=py34-postgres-psycopg - - python: "3.5" - env: TOXENV=py35-postgres-psycopg - - python: "3.6" - env: TOXENV=py36-postgres-psycopg - - python: "2.7" - env: TOXENV=py27-postgres-pygresql - - python: "3.4" - env: TOXENV=py34-postgres-pygresql - - python: "3.5" - env: TOXENV=py35-postgres-pygresql - - python: "3.6" - env: TOXENV=py36-postgres-pygresql - - python: "3.4" - env: TOXENV=py34-pypostgresql - - python: "3.5" - env: TOXENV=py35-pypostgresql - - python: "3.6" - env: TOXENV=py36-pypostgresql - - python: "2.7" - env: TOXENV=py27-postgres-pg8000 - - python: "3.4" - env: TOXENV=py34-postgres-pg8000 - - python: "3.5" - env: TOXENV=py35-postgres-pg8000 - - python: "3.6" - env: TOXENV=py36-postgres-pg8000 - - python: "2.7" - env: TOXENV=py27-sqlite - - python: "3.4" - env: TOXENV=py34-sqlite - - python: "3.5" - env: TOXENV=py35-sqlite - - python: "3.6" - env: TOXENV=py36-sqlite - - python: "2.7" - env: TOXENV=py27-sqlite-memory - - python: "3.4" - env: TOXENV=py34-sqlite-memory - - python: "3.5" - env: TOXENV=py35-sqlite-memory - - python: "3.6" - env: TOXENV=py36-sqlite-memory - - python: "2.7" - env: TOXENV=py27-flake8 - - python: "3.4" - env: TOXENV=py34-flake8 - - python: "2.7" - env: TOXENV=py27-firebird-fdb - - python: "3.4" - env: TOXENV=py34-firebird-fdb - - python: "3.5" - env: TOXENV=py35-firebird-fdb - - python: "3.6" - env: TOXENV=py36-firebird-fdb - - python: "2.7" - env: TOXENV=py27-firebirdsql - - python: "3.4" - env: TOXENV=py34-firebirdsql - - python: "3.5" - env: TOXENV=py35-firebirdsql - - python: "3.6" - env: TOXENV=py36-firebirdsql + - python: "2.7" + env: TOXENV=py27-mysqldb + - python: "3.4" + env: TOXENV=py34-mysqlclient + - python: "3.5" + env: TOXENV=py35-mysqlclient + - python: "3.6" + env: TOXENV=py36-mysqlclient + - python: "2.7" + env: TOXENV=py27-mysql-connector + - python: "3.4" + env: TOXENV=py34-mysql-connector + - python: "3.5" + env: TOXENV=py35-mysql-connector + - python: "3.6" + env: TOXENV=py36-mysql-connector + - python: "2.7" + env: TOXENV=py27-mysql-oursql + - python: "3.4" + env: TOXENV=py34-mysql-oursql3 + - python: "3.5" + env: TOXENV=py35-mysql-oursql3 + - python: "3.6" + env: TOXENV=py36-mysql-oursql3 + - python: "2.7" + env: TOXENV=py27-pymysql + - python: "3.4" + env: TOXENV=py34-pymysql + - python: "3.5" + env: TOXENV=py35-pymysql + - python: "3.6" + env: TOXENV=py36-pymysql + - python: "2.7" + env: TOXENV=py27-postgres-psycopg + - python: "3.4" + env: TOXENV=py34-postgres-psycopg + - python: "3.5" + env: TOXENV=py35-postgres-psycopg + - python: "3.6" + env: TOXENV=py36-postgres-psycopg + - python: "2.7" + env: TOXENV=py27-postgres-pygresql + - python: "3.4" + env: TOXENV=py34-postgres-pygresql + - python: "3.5" + env: TOXENV=py35-postgres-pygresql + - python: "3.6" + env: TOXENV=py36-postgres-pygresql + - python: "3.4" + env: TOXENV=py34-pypostgresql + - python: "3.5" + env: TOXENV=py35-pypostgresql + - python: "3.6" + env: TOXENV=py36-pypostgresql + - python: "2.7" + env: TOXENV=py27-postgres-pg8000 + - python: "3.4" + env: TOXENV=py34-postgres-pg8000 + - python: "3.5" + env: TOXENV=py35-postgres-pg8000 + - python: "3.6" + env: TOXENV=py36-postgres-pg8000 + - python: "2.7" + env: TOXENV=py27-sqlite + - python: "3.4" + env: TOXENV=py34-sqlite + - python: "3.5" + env: TOXENV=py35-sqlite + - python: "3.6" + env: TOXENV=py36-sqlite + - python: "2.7" + env: TOXENV=py27-sqlite-memory + - python: "3.4" + env: TOXENV=py34-sqlite-memory + - python: "3.5" + env: TOXENV=py35-sqlite-memory + - python: "3.6" + env: TOXENV=py36-sqlite-memory + - python: "2.7" + env: TOXENV=py27-flake8 + - python: "3.4" + env: TOXENV=py34-flake8 + - python: "2.7" + env: TOXENV=py27-firebird-fdb + - python: "3.4" + env: TOXENV=py34-firebird-fdb + - python: "3.5" + env: TOXENV=py35-firebird-fdb + - python: "3.6" + env: TOXENV=py36-firebird-fdb + - python: "2.7" + env: TOXENV=py27-firebirdsql + - python: "3.4" + env: TOXENV=py34-firebirdsql + - python: "3.5" + env: TOXENV=py35-firebirdsql + - python: "3.6" + env: TOXENV=py36-firebirdsql allow_failures: - env: TOXENV=py27-firebird-fdb From 65741c221ba31675e8046c196a3990d15922dba3 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 28 Mar 2018 22:57:01 +0300 Subject: [PATCH 164/509] Build(setup.py): Use setuptools instead of distutils --- setup.py | 100 ++++++++++++++++++++++++------------------------------- 1 file changed, 44 insertions(+), 56 deletions(-) diff --git a/setup.py b/setup.py index 4018c698..7563540f 100755 --- a/setup.py +++ b/setup.py @@ -2,13 +2,7 @@ from imp import load_source from os.path import abspath, dirname, join - -try: - from setuptools import setup - is_setuptools = True -except ImportError: - from distutils.core import setup - is_setuptools = False +from setuptools import setup versionpath = join(abspath(dirname(__file__)), "sqlobject", "__version__.py") sqlobject_version = load_source("sqlobject_version", versionpath) @@ -19,54 +13,6 @@ 'sqlite', 'sybase', 'tests', 'util', 'versioning', 'versioning.test'] -kw = {} -if is_setuptools: - kw['entry_points'] = """ - [paste.filter_app_factory] - main = sqlobject.wsgi_middleware:make_middleware - """ - kw['install_requires'] = [ - "FormEncode>=1.1.1,!=1.3.0; python_version=='2.7'", - "FormEncode>=1.3.1; python_version>='3.4'", - "PyDispatcher>=2.0.4", - ] - - kw['extras_require'] = { - # Firebird/Interbase - 'fdb': ['fdb'], - 'firebirdsql': ['firebirdsql'], - 'kinterbasdb': ['kinterbasdb'], - # MS SQL - 'adodbapi': ['adodbapi'], - 'pymssql': ['pymssql'], - # MySQL - 'mysql:python_version=="2.7"': ['MySQL-python'], - 'mysql:python_version>="3.4"': ['mysqlclient'], - 'mysql-connector': ['mysql-connector'], - 'oursql': ['oursql'], - 'pymysql': ['pymysql'], - # ODBC - 'odbc': ['pyodbc'], - 'pyodbc': ['pyodbc'], - 'pypyodbc': ['pypyodbc'], - # PostgreSQL - 'psycopg1': ['psycopg1'], - 'psycopg2': ['psycopg2'], - 'psycopg': ['psycopg2'], - 'postgres': ['psycopg2'], - 'postgresql': ['psycopg2'], - 'pygresql': ['pygresql'], - 'pypostgresql': ['py-postgresql'], - 'py-postgresql': ['py-postgresql'], - 'pg8000': ['pg8000'], - # - 'sapdb': ['sapdb'], - 'sqlite': ['pysqlite'], - 'sybase': ['Sybase'], - } - - kw['python_requires'] = '>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*' - setup(name="SQLObject", version=sqlobject_version.version, description="Object-Relational Manager, aka database wrapper", @@ -121,8 +67,50 @@ package_data={ "sqlobject.maxdb": ["readme.txt"], }, + entry_points=""" + [paste.filter_app_factory] + main = sqlobject.wsgi_middleware:make_middleware + """, + python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*', requires=['FormEncode', 'PyDispatcher'], - **kw + install_requires=[ + "FormEncode>=1.1.1,!=1.3.0; python_version=='2.7'", + "FormEncode>=1.3.1; python_version>='3.4'", + "PyDispatcher>=2.0.4", + ], + extras_require={ + # Firebird/Interbase + 'fdb': ['fdb'], + 'firebirdsql': ['firebirdsql'], + 'kinterbasdb': ['kinterbasdb'], + # MS SQL + 'adodbapi': ['adodbapi'], + 'pymssql': ['pymssql'], + # MySQL + 'mysql:python_version=="2.7"': ['MySQL-python'], + 'mysql:python_version>="3.4"': ['mysqlclient'], + 'mysql-connector': ['mysql-connector'], + 'oursql': ['oursql'], + 'pymysql': ['pymysql'], + # ODBC + 'odbc': ['pyodbc'], + 'pyodbc': ['pyodbc'], + 'pypyodbc': ['pypyodbc'], + # PostgreSQL + 'psycopg1': ['psycopg1'], + 'psycopg2': ['psycopg2'], + 'psycopg': ['psycopg2'], + 'postgres': ['psycopg2'], + 'postgresql': ['psycopg2'], + 'pygresql': ['pygresql'], + 'pypostgresql': ['py-postgresql'], + 'py-postgresql': ['py-postgresql'], + 'pg8000': ['pg8000'], + # + 'sapdb': ['sapdb'], + 'sqlite': ['pysqlite'], + 'sybase': ['Sybase'], + }, ) # Send announce to: From e7ac97c5a0ce2f6c4d1627ddb103af9956cc5bb2 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 30 Mar 2018 00:35:22 +0300 Subject: [PATCH 165/509] Build(setup.py): Add `project_urls` --- devscripts/BRANCH-CHECKLIST | 2 +- devscripts/RELEASE-CHECKLIST | 2 +- setup.py | 13 ++++++++++++- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/devscripts/BRANCH-CHECKLIST b/devscripts/BRANCH-CHECKLIST index 280f494d..0357e27d 100644 --- a/devscripts/BRANCH-CHECKLIST +++ b/devscripts/BRANCH-CHECKLIST @@ -8,7 +8,7 @@ a branch, a commit id or a tag. __version__.py and News.rst in the branch - set version. In setup.cfg in the branch edit section [publish] - uncomment doc-dest for stable branch. In setup.py in the branch edit URL (remove - '/devel') and download URL. In setup.py and DeveloperGuide.rst edit + '/devel') and download URLs. In setup.py and DeveloperGuide.rst edit Travis CI build status image URL (change branch). Commit. 1b. If the branching point was master the script checks out master and diff --git a/devscripts/RELEASE-CHECKLIST b/devscripts/RELEASE-CHECKLIST index 205f9732..29fa8a90 100644 --- a/devscripts/RELEASE-CHECKLIST +++ b/devscripts/RELEASE-CHECKLIST @@ -12,7 +12,7 @@ URL in ANNOUNCE.rst; edit __version__.py and README.rst in the release branch - fix versions. Edit section [egg_info] in setup.cfg - set if it is a stable or development release. In setup.py edit "Development - Status" in trove classifiers; edit download URL: if a non-stable + Status" in trove classifiers; edit download URLs: if a non-stable version - append 'dev' and date stamp, for a stable version remove 'dev' and date stamp). diff --git a/setup.py b/setup.py index 7563540f..752a5a49 100755 --- a/setup.py +++ b/setup.py @@ -58,11 +58,22 @@ url="http://sqlobject.org/", download_url="https://pypi.python.org/pypi/SQLObject/%s" % sqlobject_version.version, + project_urls={ + 'Homepage': 'http://sqlobject.org/', + 'Development docs': 'http://sqlobject.org/devel/', + 'Download': 'https://pypi.python.org/pypi/SQLObject/%s' % + sqlobject_version.version, + 'Github repo': 'https://github.com/sqlobject', + 'Issue tracker': 'https://github.com/sqlobject/sqlobject/issues', + 'SourceForge project': 'https://sourceforge.net/projects/sqlobject/', + 'Twitter': 'https://twitter.com/SQLObject', + 'Wikipedia': 'https://en.wikipedia.org/wiki/SQLObject', + }, keywords=["sql", "orm", "object-relational mapper"], license="LGPL", platforms="Any", packages=["sqlobject"] + - ['sqlobject.%s' % package for package in subpackages], + ['sqlobject.%s' % package for package in subpackages], scripts=["scripts/sqlobject-admin", "scripts/sqlobject-convertOldURI"], package_data={ "sqlobject.maxdb": ["readme.txt"], From 372793d4cc90edf616037409c775cad6ea5db151 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 30 Mar 2018 23:57:26 +0300 Subject: [PATCH 166/509] Build(setup.py): Add long_description_content_type --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 752a5a49..c2a18ac9 100755 --- a/setup.py +++ b/setup.py @@ -35,6 +35,7 @@ .. image:: https://travis-ci.org/sqlobject/sqlobject.svg?branch=master :target: https://travis-ci.org/sqlobject/sqlobject """, + long_description_content_type="text/x-rst", classifiers=[ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", From ce59826cdea8aa02d8695290c92d309ce96e2d34 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 31 Mar 2018 20:56:18 +0300 Subject: [PATCH 167/509] Build(release): Do not GPG-sign release files New pypi.io deprecated GPG signatures. [skip ci] --- devscripts/release | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devscripts/release b/devscripts/release index 1de12856..3e890b79 100755 --- a/devscripts/release +++ b/devscripts/release @@ -34,5 +34,5 @@ if [ "$state" = final ]; then ../sftp-frs fi && -twine upload --sign dist/* && +twine upload dist/* && exec rm -rf build dist docs/html SQLObject.egg-info From 6e17054a2ee004bcaeee7e915d31dd9270f7694c Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 1 Apr 2018 03:06:44 +0300 Subject: [PATCH 168/509] Build(.gitignore): Ignore `.pytest_cache` [skip ci] --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 8647366f..9825d011 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /.cache/ +/.pytest_cache/ /.tox/ /SQLObject.egg-info/ /build/ From b32db3beb07d6f054be9fa85022a629389652e34 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 1 Apr 2018 03:46:11 +0300 Subject: [PATCH 169/509] CI(appveyor.yml): Upgrade `pip` using `python -m pip` Avoid `WindowsError: [Error 5] Access is denied`. --- appveyor.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 8c70af69..c42d7387 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -145,8 +145,9 @@ install: - "SET TOXPYTHON=%PYTHON_HOME%\\python.exe" - "python --version" - "python -c \"import struct; print(struct.calcsize('P') * 8)\"" + - "python -m pip install --upgrade pip setuptools" + - "pip install --upgrade tox ppu" - "pip --version" - - "pip install --upgrade pip setuptools tox ppu" # List ODBC drivers - ps: Get-OdbcDriver -Platform 32-bit | Select-Object -ExpandProperty Name - ps: Get-OdbcDriver -Platform 64-bit | Select-Object -ExpandProperty Name From e2bcd57798cfc6a1d182d409ec0b974f1f438694 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 9 Apr 2018 01:29:07 +0300 Subject: [PATCH 170/509] Style(setup.py): Reindent parameters --- setup.py | 187 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 94 insertions(+), 93 deletions(-) diff --git a/setup.py b/setup.py index c2a18ac9..8217d370 100755 --- a/setup.py +++ b/setup.py @@ -13,10 +13,11 @@ 'sqlite', 'sybase', 'tests', 'util', 'versioning', 'versioning.test'] -setup(name="SQLObject", - version=sqlobject_version.version, - description="Object-Relational Manager, aka database wrapper", - long_description="""\ +setup( + name="SQLObject", + version=sqlobject_version.version, + description="Object-Relational Manager, aka database wrapper", + long_description="""\ SQLObject is a popular *Object Relational Manager* for providing an object interface to your database, with tables as classes, rows as instances, and columns as attributes. @@ -35,95 +36,95 @@ .. image:: https://travis-ci.org/sqlobject/sqlobject.svg?branch=master :target: https://travis-ci.org/sqlobject/sqlobject """, - long_description_content_type="text/x-rst", - classifiers=[ - "Development Status :: 5 - Production/Stable", - "Intended Audience :: Developers", - "License :: OSI Approved :: " - "GNU Library or Lesser General Public License (LGPL)", - "Programming Language :: Python", - "Programming Language :: Python :: 2", - "Programming Language :: Python :: 2.7", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.4", - "Programming Language :: Python :: 3.5", - "Programming Language :: Python :: 3.6", - "Topic :: Database", - "Topic :: Database :: Front-Ends", - "Topic :: Software Development :: Libraries :: Python Modules", - ], - author="Ian Bicking", - author_email="ianb@colorstudy.com", - maintainer="Oleg Broytman", - maintainer_email="phd@phdru.name", - url="http://sqlobject.org/", - download_url="https://pypi.python.org/pypi/SQLObject/%s" % - sqlobject_version.version, - project_urls={ - 'Homepage': 'http://sqlobject.org/', - 'Development docs': 'http://sqlobject.org/devel/', - 'Download': 'https://pypi.python.org/pypi/SQLObject/%s' % - sqlobject_version.version, - 'Github repo': 'https://github.com/sqlobject', - 'Issue tracker': 'https://github.com/sqlobject/sqlobject/issues', - 'SourceForge project': 'https://sourceforge.net/projects/sqlobject/', - 'Twitter': 'https://twitter.com/SQLObject', - 'Wikipedia': 'https://en.wikipedia.org/wiki/SQLObject', - }, - keywords=["sql", "orm", "object-relational mapper"], - license="LGPL", - platforms="Any", - packages=["sqlobject"] + - ['sqlobject.%s' % package for package in subpackages], - scripts=["scripts/sqlobject-admin", "scripts/sqlobject-convertOldURI"], - package_data={ - "sqlobject.maxdb": ["readme.txt"], - }, - entry_points=""" - [paste.filter_app_factory] - main = sqlobject.wsgi_middleware:make_middleware - """, - python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*', - requires=['FormEncode', 'PyDispatcher'], - install_requires=[ - "FormEncode>=1.1.1,!=1.3.0; python_version=='2.7'", - "FormEncode>=1.3.1; python_version>='3.4'", - "PyDispatcher>=2.0.4", - ], - extras_require={ - # Firebird/Interbase - 'fdb': ['fdb'], - 'firebirdsql': ['firebirdsql'], - 'kinterbasdb': ['kinterbasdb'], - # MS SQL - 'adodbapi': ['adodbapi'], - 'pymssql': ['pymssql'], - # MySQL - 'mysql:python_version=="2.7"': ['MySQL-python'], - 'mysql:python_version>="3.4"': ['mysqlclient'], - 'mysql-connector': ['mysql-connector'], - 'oursql': ['oursql'], - 'pymysql': ['pymysql'], - # ODBC - 'odbc': ['pyodbc'], - 'pyodbc': ['pyodbc'], - 'pypyodbc': ['pypyodbc'], - # PostgreSQL - 'psycopg1': ['psycopg1'], - 'psycopg2': ['psycopg2'], - 'psycopg': ['psycopg2'], - 'postgres': ['psycopg2'], - 'postgresql': ['psycopg2'], - 'pygresql': ['pygresql'], - 'pypostgresql': ['py-postgresql'], - 'py-postgresql': ['py-postgresql'], - 'pg8000': ['pg8000'], - # - 'sapdb': ['sapdb'], - 'sqlite': ['pysqlite'], - 'sybase': ['Sybase'], - }, - ) + long_description_content_type="text/x-rst", + classifiers=[ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "License :: OSI Approved :: " + "GNU Library or Lesser General Public License (LGPL)", + "Programming Language :: Python", + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.4", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Topic :: Database", + "Topic :: Database :: Front-Ends", + "Topic :: Software Development :: Libraries :: Python Modules", + ], + author="Ian Bicking", + author_email="ianb@colorstudy.com", + maintainer="Oleg Broytman", + maintainer_email="phd@phdru.name", + url="http://sqlobject.org/", + download_url="https://pypi.python.org/pypi/SQLObject/%s" % + sqlobject_version.version, + project_urls={ + 'Homepage': 'http://sqlobject.org/', + 'Development docs': 'http://sqlobject.org/devel/', + 'Download': 'https://pypi.python.org/pypi/SQLObject/%s' % + sqlobject_version.version, + 'Github repo': 'https://github.com/sqlobject', + 'Issue tracker': 'https://github.com/sqlobject/sqlobject/issues', + 'SourceForge project': 'https://sourceforge.net/projects/sqlobject/', + 'Twitter': 'https://twitter.com/SQLObject', + 'Wikipedia': 'https://en.wikipedia.org/wiki/SQLObject', + }, + keywords=["sql", "orm", "object-relational mapper"], + license="LGPL", + platforms="Any", + packages=["sqlobject"] + + ['sqlobject.%s' % package for package in subpackages], + scripts=["scripts/sqlobject-admin", "scripts/sqlobject-convertOldURI"], + package_data={ + "sqlobject.maxdb": ["readme.txt"], + }, + entry_points=""" + [paste.filter_app_factory] + main = sqlobject.wsgi_middleware:make_middleware + """, + python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*', + requires=['FormEncode', 'PyDispatcher'], + install_requires=[ + "FormEncode>=1.1.1,!=1.3.0; python_version=='2.7'", + "FormEncode>=1.3.1; python_version>='3.4'", + "PyDispatcher>=2.0.4", + ], + extras_require={ + # Firebird/Interbase + 'fdb': ['fdb'], + 'firebirdsql': ['firebirdsql'], + 'kinterbasdb': ['kinterbasdb'], + # MS SQL + 'adodbapi': ['adodbapi'], + 'pymssql': ['pymssql'], + # MySQL + 'mysql:python_version=="2.7"': ['MySQL-python'], + 'mysql:python_version>="3.4"': ['mysqlclient'], + 'mysql-connector': ['mysql-connector'], + 'oursql': ['oursql'], + 'pymysql': ['pymysql'], + # ODBC + 'odbc': ['pyodbc'], + 'pyodbc': ['pyodbc'], + 'pypyodbc': ['pypyodbc'], + # PostgreSQL + 'psycopg1': ['psycopg1'], + 'psycopg2': ['psycopg2'], + 'psycopg': ['psycopg2'], + 'postgres': ['psycopg2'], + 'postgresql': ['psycopg2'], + 'pygresql': ['pygresql'], + 'pypostgresql': ['py-postgresql'], + 'py-postgresql': ['py-postgresql'], + 'pg8000': ['pg8000'], + # + 'sapdb': ['sapdb'], + 'sqlite': ['pysqlite'], + 'sybase': ['Sybase'], + }, +) # Send announce to: # sqlobject-discuss@lists.sourceforge.net From fec1260acd46aaf9852b1f5bdf33da83aab7e9af Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 16 Apr 2018 20:49:10 +0300 Subject: [PATCH 171/509] Build, docs: pypi.python.org => pypi.org --- ANNOUNCE.rst | 2 +- docs/DeveloperGuide.rst | 4 ++-- docs/News.rst | 8 ++++---- docs/Python3.rst | 2 +- docs/SQLObject.rst | 14 +++++++------- docs/TODO.rst | 10 +++++----- docs/download.rst | 2 +- setup.py | 6 +++--- sqlobject/compat.py | 2 +- 9 files changed, 25 insertions(+), 25 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 2e052100..781eee7c 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -54,7 +54,7 @@ Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Download: -https://pypi.python.org/pypi/SQLObject/3.7.0a0.dev20171115 +https://pypi.org/project/SQLObject/3.7.0a0.dev20171115/ News and changes: http://sqlobject.org/News.html diff --git a/docs/DeveloperGuide.rst b/docs/DeveloperGuide.rst index 5e889c8e..966c379d 100644 --- a/docs/DeveloperGuide.rst +++ b/docs/DeveloperGuide.rst @@ -234,7 +234,7 @@ Tests are important. Tests keep everything from falling apart. All new additions should have tests. Testing uses pytest, an alternative to ``unittest``. It is available -at http://pytest.org/ and https://pypi.python.org/pypi/pytest. Read its +at http://pytest.org/ and https://pypi.org/project/pytest/. Read its `getting started`_ document for more. .. _getting started: http://docs.pytest.org/en/latest/getting-started.html @@ -283,7 +283,7 @@ To avoid triggering unnecessary test run at CI services add text `[skip ci] ``[ci skip]`` anywhere in your commit messages for commits that don't change code (documentation updates and such). -We use `coverage.py `_ +We use `coverage.py `_ to measures code coverage by tests and upload the result for analyzis to `Coveralls `_ and `Codecov `_: diff --git a/docs/News.rst b/docs/News.rst index 17626cde..209ae25e 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -68,7 +68,7 @@ Minor features Drivers ------- -* Add support for `pg8000 `_ +* Add support for `pg8000 `_ PostgreSQL driver. * Fix autoreconnect with pymysql driver. Contributed by Shailesh Mungikar. @@ -202,7 +202,7 @@ Minor features 'connector', 'oursql' and 'pymysql'. Default is to test for mysqldb only. * Add support for `MySQL Connector - `_ (pure python; `binary + `_ (pure python; `binary packages `_ are not at PyPI and hence are hard to install and test). @@ -224,11 +224,11 @@ Drivers (work in progress) * Extend support for PyGreSQL driver. There are still some problems. * Add support for `py-postgresql - `_ PostgreSQL driver. There + `_ PostgreSQL driver. There are still problems with the driver. * Add support for `pyfirebirdsql - `_.There are still problems with + `_.There are still problems with the driver. Bug fixes diff --git a/docs/Python3.rst b/docs/Python3.rst index f14b106a..ad4fb56a 100644 --- a/docs/Python3.rst +++ b/docs/Python3.rst @@ -40,7 +40,7 @@ Note that the default encoding of MySQL databases is *latin1*, which can cause problems with general Unicode strings. We recommend specifying the character set as *utf8* when using MySQL to protect against these issues. -.. _mysqlclient: https://pypi.python.org/pypi/mysqlclient +.. _mysqlclient: https://pypi.org/project/mysqlclient/ Using databases created with SQLObject and Python 2 in Python 3 diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index 1ccc222f..dd96d070 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -59,21 +59,21 @@ problems (not all tests passed). .. _MySQL: https://www.mysql.com/ .. _MySQLdb: https://sourceforge.net/projects/mysql-python/ -.. _mysqlclient: https://pypi.python.org/pypi/mysqlclient -.. _`MySQL Connector`: https://pypi.python.org/pypi/mysql-connector +.. _mysqlclient: https://pypi.org/project/mysqlclient/ +.. _`MySQL Connector`: https://pypi.org/project/mysql-connector/ .. _oursql: https://github.com/python-oursql/oursql .. _PyMySQL: https://github.com/PyMySQL/PyMySQL/ .. _PostgreSQL: https://postgresql.org .. _psycopg2: http://initd.org/psycopg/ .. _PyGreSQL: http://www.pygresql.org/ -.. _py-postgresql: https://pypi.python.org/pypi/py-postgresql -.. _pg8000: https://pypi.python.org/pypi/pg8000 +.. _py-postgresql: https://pypi.org/project/py-postgresql/ +.. _pg8000: https://pypi.org/project/pg8000/ .. _SQLite: https://sqlite.org/ .. _PySQLite: https://github.com/ghaering/pysqlite .. _Firebird: http://www.firebirdsql.org/en/python-driver/ .. _fdb: http://www.firebirdsql.org/en/devel-python-driver/ .. _kinterbasdb: http://kinterbasdb.sourceforge.net/ -.. _pyfirebirdsql: https://pypi.python.org/pypi/firebirdsql +.. _pyfirebirdsql: https://pypi.org/project/firebirdsql/ .. _`MAX DB`: http://maxdb.sap.com/ .. _sapdb: http://maxdb.sap.com/doc/7_8/50/01923f25b842438a408805774f6989/frameset.htm .. _Sybase: http://www.object-craft.com.au/projects/sybase/ @@ -81,8 +81,8 @@ problems (not all tests passed). .. _pymssql: http://www.pymssql.org/en/latest/index.html .. _FreeTDS: http://www.freetds.org/ .. _adodbapi: http://adodbapi.sourceforge.net/ -.. _PyODBC: https://pypi.python.org/pypi/pyodbc -.. _PyPyODBC: https://pypi.python.org/pypi/pypyodbc +.. _PyODBC: https://pypi.org/project/pyodbc/ +.. _PyPyODBC: https://pypi.org/project/pypyodbc/ Python 2.7 or 3.4+ is required. diff --git a/docs/TODO.rst b/docs/TODO.rst index 41e24b16..106a5996 100644 --- a/docs/TODO.rst +++ b/docs/TODO.rst @@ -9,14 +9,14 @@ TODO * PyPy. -* Use https://pypi.python.org/pypi/psycopg2cffi to run SQLObject +* Use https://pypi.org/project/psycopg2cffi/ to run SQLObject under PyPy. -* https://pypi.python.org/pypi/turbodbc +* https://pypi.org/project/turbodbc/ * PyODBC and PyPyODBC for linux and w32: SQLite (libsqliteodbc). -* https://pypi.python.org/pypi/JayDeBeApi +* https://pypi.org/project/JayDeBeApi/ * Jython. @@ -92,7 +92,7 @@ TODO * Support PyODBC driver for all backends. -* `dbms `_ is a DB API wrapper for DB +* `dbms `_ is a DB API wrapper for DB API drivers for IBM DB2, Firebird, MSSQL Server, MySQL, Oracle, PostgreSQL, SQLite and ODBC. @@ -109,7 +109,7 @@ TODO * Use DBUtils_, especially SolidConnection. -.. _DBUtils: https://pypi.python.org/pypi/DBUtils +.. _DBUtils: https://pypi.org/project/DBUtils/ * ``_fromDatabase`` currently doesn't support IDs that don't fit into the normal naming scheme. It should do so. You can still use ``_idName`` diff --git a/docs/download.rst b/docs/download.rst index a0289983..4d87846c 100644 --- a/docs/download.rst +++ b/docs/download.rst @@ -2,7 +2,7 @@ Download SQLObject ++++++++++++++++++ The latest releases are always available on the `Python Package Index -`_, and is installable +`_, and is installable with `pip `_ or `easy_install `_. diff --git a/setup.py b/setup.py index 8217d370..77a99476 100755 --- a/setup.py +++ b/setup.py @@ -58,12 +58,12 @@ maintainer="Oleg Broytman", maintainer_email="phd@phdru.name", url="http://sqlobject.org/", - download_url="https://pypi.python.org/pypi/SQLObject/%s" % + download_url="https://pypi.org/project/SQLObject/%s/" % sqlobject_version.version, project_urls={ 'Homepage': 'http://sqlobject.org/', 'Development docs': 'http://sqlobject.org/devel/', - 'Download': 'https://pypi.python.org/pypi/SQLObject/%s' % + 'Download': 'https://pypi.org/project/SQLObject/%s/' % sqlobject_version.version, 'Github repo': 'https://github.com/sqlobject', 'Issue tracker': 'https://github.com/sqlobject/sqlobject/issues', @@ -168,7 +168,7 @@ https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Download: -https://pypi.python.org/pypi/SQLObject/@@ +https://pypi.org/project/SQLObject/@@/ News and changes: http://sqlobject.org/docs/News.html diff --git a/sqlobject/compat.py b/sqlobject/compat.py index 7e8d0e1c..18aba9d0 100644 --- a/sqlobject/compat.py +++ b/sqlobject/compat.py @@ -1,7 +1,7 @@ import sys import types -# Credit to six authors: https://pypi.python.org/pypi/six +# Credit to six authors: https://pypi.org/project/six/ # License: MIT From 5f8e6ecf48f314e7d990f69914542959ebf19010 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 1 Jun 2018 05:04:01 +0300 Subject: [PATCH 172/509] Fix(mysql): Fix SSL-related parameters for MySQL-connector Fixes: #144. --- docs/News.rst | 6 ++++++ sqlobject/mysql/mysqlconnection.py | 15 ++++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index 209ae25e..1705c76f 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -13,6 +13,12 @@ Features * Add signals on commit and rollback; pull request by Scott Stahl. +Bug fixes +--------- + +* Fix SSL-related parameters for MySQL-connector (connector uses + a different param style). Bug reported by Christophe Popov. + SQLObject 3.6.0 =============== diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index 51cbde40..310b21d0 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -111,11 +111,16 @@ def __init__(self, db, user, password='', host='localhost', port=0, **kw): "client_flag", "local_infile"): if key in kw: self.kw[key] = int(kw.pop(key)) - for key in ("ssl_key", "ssl_cert", "ssl_ca", "ssl_capath"): - if key in kw: - if "ssl" not in self.kw: - self.kw["ssl"] = {} - self.kw["ssl"][key[4:]] = kw.pop(key) + if driver == 'connector': + for key in ("ssl_key", "ssl_cert", "ssl_ca", "ssl_capath"): + if key in kw: + self.kw[key] = kw.pop(key) + else: + for key in ("ssl_key", "ssl_cert", "ssl_ca", "ssl_capath"): + if key in kw: + if "ssl" not in self.kw: + self.kw["ssl"] = {} + self.kw["ssl"][key[4:]] = kw.pop(key) if "charset" in kw: self.dbEncoding = self.kw["charset"] = kw.pop("charset") else: From 1ab0c67224f5bb1d20e8d4d3659494e638ea0dfc Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 3 Jun 2018 23:43:44 +0300 Subject: [PATCH 173/509] Feat(postgres): Remove psycopg1 --- docs/News.rst | 5 +++++ docs/SQLObject.rst | 6 +++--- docs/download.rst | 2 +- setup.py | 1 - sqlobject/postgres/pgconnection.py | 13 ++----------- 5 files changed, 11 insertions(+), 16 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index 1705c76f..422882ed 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -19,6 +19,11 @@ Bug fixes * Fix SSL-related parameters for MySQL-connector (connector uses a different param style). Bug reported by Christophe Popov. +Drivers +------- + +* Remove psycopg1. Driver ``psycopg`` is now just an alias for ``psycopg2``. + SQLObject 3.6.0 =============== diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index dd96d070..46d820ee 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -48,7 +48,7 @@ Requirements Currently SQLObject supports MySQL_ via MySQLdb_ aka MySQL-python (called mysqlclient_ for Python 3), `MySQL Connector`_, oursql_, PyMySQL_, PyODBC_ -and PyPyODBC_. For PostgreSQL_ psycopg2_ or psycopg1 are recommended; +and PyPyODBC_. For PostgreSQL_ psycopg2_ is recommended; PyGreSQL_, py-postgresql_ and pg8000_ are supported; SQLite_ has a built-in driver or PySQLite_. Firebird_ is supported via fdb_ or kinterbasdb_; pyfirebirdsql_ is supported but has problems. `MAX DB`_ @@ -1832,8 +1832,8 @@ PostgresConnection supports transactions and all other features. The user can choose a DB API driver for PostgreSQL by using a ``driver`` parameter in DB URI or PostgresConnection that can be a comma-separated -list of driver names. Possible drivers are: ``psycopg2``, psycopg1, -``psycopg`` (tries psycopg2 and psycopg1), ``pygresql``, ``pypostgresql``, +list of driver names. Possible drivers are: ``psycopg2``, +``psycopg`` (alias for ``psycopg2``), ``pygresql``, ``pypostgresql``, ``pg8000``, ``pyodbc``, ``pypyodbc`` or ``odbc`` (try ``pyodbc`` and ``pypyodbc``). Default is ``psycopg``. diff --git a/docs/download.rst b/docs/download.rst index 4d87846c..1d9e5467 100644 --- a/docs/download.rst +++ b/docs/download.rst @@ -73,7 +73,7 @@ pyodbc pypyodbc odbc (synonym for pyodbc) PostgreSQL ^^^^^^^^^^ -psycopg1 psycopg2 psycopg postgres postgresql (synonyms for psycopg2) +psycopg2 psycopg postgres postgresql (synonyms for psycopg2) pygresql pypostgresql py-postgresql pg8000 The rest diff --git a/setup.py b/setup.py index 77a99476..b0fb3832 100755 --- a/setup.py +++ b/setup.py @@ -110,7 +110,6 @@ 'pyodbc': ['pyodbc'], 'pypyodbc': ['pypyodbc'], # PostgreSQL - 'psycopg1': ['psycopg1'], 'psycopg2': ['psycopg2'], 'psycopg': ['psycopg2'], 'postgres': ['psycopg2'], diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index b8a83c79..b567f997 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -38,18 +38,9 @@ def __init__(self, dsn=None, host=None, port=None, db=None, if not driver: continue try: - if driver == 'psycopg2': + if driver in ('psycopg', 'psycopg2'): import psycopg2 as psycopg self.module = psycopg - elif driver == 'psycopg1': - import psycopg - self.module = psycopg - elif driver == 'psycopg': - try: - import psycopg2 as psycopg - except ImportError: - import psycopg - self.module = psycopg elif driver == 'pygresql': import pgdb self.module = pgdb @@ -74,7 +65,7 @@ def __init__(self, dsn=None, host=None, port=None, db=None, else: raise ValueError( 'Unknown PostgreSQL driver "%s", ' - 'expected psycopg, psycopg2, psycopg1, ' + 'expected psycopg, psycopg2, ' 'pygresql, pypostgresql, pg8000, ' 'odbc, pyodbc or pypyodbc' % driver) except ImportError: From a4bc6269f4515f7cd929e90ac73f4e7272e6c8fb Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 3 Jun 2018 23:46:28 +0300 Subject: [PATCH 174/509] Feat(tox): Install psycopg2 from psycopg2-binary package --- docs/News.rst | 7 +++++++ tox.ini | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/News.rst b/docs/News.rst index 422882ed..51b3d0e0 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -24,6 +24,13 @@ Drivers * Remove psycopg1. Driver ``psycopg`` is now just an alias for ``psycopg2``. +Tests +----- + +* Install psycopg2 from `psycopg2-binary`_ package. + +.. _`psycopg2-binary`: https://pypi.org/project/psycopg2-binary/ + SQLObject 3.6.0 =============== diff --git a/tox.ini b/tox.ini index c902edba..5ca1e8b9 100644 --- a/tox.ini +++ b/tox.ini @@ -23,7 +23,7 @@ deps = mysql-oursql: git+https://github.com/sqlobject/oursql.git@master#egg=oursql mysql-oursql3: git+https://github.com/sqlobject/oursql.git@py3k#egg=oursql pymysql: pymysql - postgres-psycopg: psycopg2 + postgres-psycopg: psycopg2-binary postgres-pygresql: pygresql pypostgresql: git+https://github.com/sqlobject/py-postgresql.git@fix_w32#egg=pypostgresql postgres-pg8000: git+https://github.com/sqlobject/pg8000.git@getuser#egg=pg8000 From b1fd69522c0c18d79c572bdefcc384fa1a30525f Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 6 Jun 2018 19:08:52 +0300 Subject: [PATCH 175/509] Release 3.7.0 --- ANNOUNCE.rst | 40 +++++++++++++++++++++++---------------- devscripts/build-all-docs | 2 +- docs/News.rst | 6 ++++-- setup.cfg | 5 ----- sqlobject/__version__.py | 2 +- 5 files changed, 30 insertions(+), 25 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 781eee7c..a81ce5eb 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,28 +1,36 @@ Hello! -I'm pleased to announce version 3.7.0a1, the first alpha of the upcoming -release of branch 3.7 of SQLObject. +I'm pleased to announce version 3.7.0, the first stable release of branch +3.7 of SQLObject. -I'm pleased to announce version 3.7.0a2, the second alpha of the upcoming -release of branch 3.7 of SQLObject. -I'm pleased to announce version 3.7.0b1, the first beta of the upcoming -release of branch 3.7 of SQLObject. +What's new in SQLObject +======================= -I'm pleased to announce version 3.7.0rc1, the first release candidate -of the upcoming release of branch 3.7 of SQLObject. +Contributors for this release are Scott Stahl and Christophe Popov. -I'm pleased to announce version 3.7.0, the first stable release of branch -3.7 of SQLObject. +Features +-------- -I'm pleased to announce version 3.7.0, the first bugfix release of branch -3.7 of SQLObject. +* Add signals on commit and rollback; pull request by Scott Stahl. +Bug fixes +--------- -What's new in SQLObject -======================= +* Fix SSL-related parameters for MySQL-connector (connector uses + a different param style). Bug reported by Christophe Popov. + +Drivers +------- + +* Remove psycopg1. Driver ``psycopg`` is now just an alias for ``psycopg2``. + +Tests +----- + +* Install psycopg2 from `psycopg2-binary`_ package. -Contributors for this release are +.. _`psycopg2-binary`: https://pypi.org/project/psycopg2-binary/ For a more complete list, please see the news: http://sqlobject.org/News.html @@ -54,7 +62,7 @@ Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Download: -https://pypi.org/project/SQLObject/3.7.0a0.dev20171115/ +https://pypi.org/project/SQLObject/3.7.0/ News and changes: http://sqlobject.org/News.html diff --git a/devscripts/build-all-docs b/devscripts/build-all-docs index 3eb17ed5..233c0680 100755 --- a/devscripts/build-all-docs +++ b/devscripts/build-all-docs @@ -11,7 +11,7 @@ cd "$PROG_DIR" && PROG_DIR="`pwd`" && cd "$PROG_DIR"/SQLObject && -build_docs 3.6.0 && +build_docs 3.7.0 && build_docs master devel && rm -rf docs/html && diff --git a/docs/News.rst b/docs/News.rst index 51b3d0e0..fe8965f4 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,8 +5,10 @@ News .. contents:: Contents: :backlinks: none -SQLObject 3.7.0 (master) -======================== +SQLObject 3.7.0 +=============== + +Released 6 June 2018. Features -------- diff --git a/setup.cfg b/setup.cfg index 40ee4ca8..121fe8b8 100644 --- a/setup.cfg +++ b/setup.cfg @@ -4,11 +4,6 @@ universal = 1 [easy_install] optimize = 2 -[egg_info] -tag_build = -tag_date = 0 -tag_svn_revision = 0 - [flake8] exclude = .git,.tox,docs/europython/*.py # E305: expected 2 blank lines after class or function definition, found 1 diff --git a/sqlobject/__version__.py b/sqlobject/__version__.py index cd242701..ba9bc27f 100644 --- a/sqlobject/__version__.py +++ b/sqlobject/__version__.py @@ -3,6 +3,6 @@ major = 3 minor = 7 micro = 0 -release_level = 'dev' +release_level = 'final' serial = 0 version_info = (major, minor, micro, release_level, serial) From f788aca840acfd356fbcc4e802840e555d819d12 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 6 Jun 2018 19:22:19 +0300 Subject: [PATCH 176/509] Prepare for the next release --- ANNOUNCE.rst | 40 ++++++++++++++++------------------------ README.rst | 2 +- docs/News.rst | 3 +++ setup.cfg | 5 +++++ sqlobject/__version__.py | 6 +++--- 5 files changed, 28 insertions(+), 28 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index a81ce5eb..2f549674 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,36 +1,28 @@ Hello! -I'm pleased to announce version 3.7.0, the first stable release of branch -3.7 of SQLObject. +I'm pleased to announce version 3.8.0a1, the first alpha of the upcoming +release of branch 3.8 of SQLObject. +I'm pleased to announce version 3.8.0a2, the second alpha of the upcoming +release of branch 3.8 of SQLObject. -What's new in SQLObject -======================= - -Contributors for this release are Scott Stahl and Christophe Popov. - -Features --------- +I'm pleased to announce version 3.8.0b1, the first beta of the upcoming +release of branch 3.8 of SQLObject. -* Add signals on commit and rollback; pull request by Scott Stahl. +I'm pleased to announce version 3.8.0rc1, the first release candidate +of the upcoming release of branch 3.8 of SQLObject. -Bug fixes ---------- +I'm pleased to announce version 3.8.0, the first stable release of branch +3.8 of SQLObject. -* Fix SSL-related parameters for MySQL-connector (connector uses - a different param style). Bug reported by Christophe Popov. +I'm pleased to announce version 3.8.1, the first bugfix release of branch +3.8 of SQLObject. -Drivers -------- -* Remove psycopg1. Driver ``psycopg`` is now just an alias for ``psycopg2``. - -Tests ------ - -* Install psycopg2 from `psycopg2-binary`_ package. +What's new in SQLObject +======================= -.. _`psycopg2-binary`: https://pypi.org/project/psycopg2-binary/ +Contributors for this release are For a more complete list, please see the news: http://sqlobject.org/News.html @@ -62,7 +54,7 @@ Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Download: -https://pypi.org/project/SQLObject/3.7.0/ +https://pypi.org/project/SQLObject/3.8.0a0.dev20180606/ News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 9eb1399d..3e96729c 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,4 @@ -SQLObject 3.7.0 +SQLObject 3.8.0 =============== Thanks for looking at SQLObject. SQLObject is an object-relational diff --git a/docs/News.rst b/docs/News.rst index fe8965f4..117c0b4a 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,6 +5,9 @@ News .. contents:: Contents: :backlinks: none +SQLObject 3.8.0 (master) +======================== + SQLObject 3.7.0 =============== diff --git a/setup.cfg b/setup.cfg index 121fe8b8..40ee4ca8 100644 --- a/setup.cfg +++ b/setup.cfg @@ -4,6 +4,11 @@ universal = 1 [easy_install] optimize = 2 +[egg_info] +tag_build = +tag_date = 0 +tag_svn_revision = 0 + [flake8] exclude = .git,.tox,docs/europython/*.py # E305: expected 2 blank lines after class or function definition, found 1 diff --git a/sqlobject/__version__.py b/sqlobject/__version__.py index ba9bc27f..a21e936c 100644 --- a/sqlobject/__version__.py +++ b/sqlobject/__version__.py @@ -1,8 +1,8 @@ -version = '3.7.0' +version = '3.8.0' major = 3 -minor = 7 +minor = 8 micro = 0 -release_level = 'final' +release_level = 'dev' serial = 0 version_info = (major, minor, micro, release_level, serial) From ff3deab26f6a43cc7a1e5b02cb4889240d8a3106 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 6 Jun 2018 19:39:31 +0300 Subject: [PATCH 177/509] Build(release): Stop copying released files --- devscripts/release | 1 - 1 file changed, 1 deletion(-) diff --git a/devscripts/release b/devscripts/release index 3e890b79..3bae6e72 100755 --- a/devscripts/release +++ b/devscripts/release @@ -28,7 +28,6 @@ version=`python setup.py --version` split_tag $version if [ "$state" = final ]; then - cp -a dist/* "$HOME"/tmp/ && rsync -ahP4 dist/* frs.sourceforge.net:/home/frs/project/sqlobject/sqlobject/"$version"/ && rsync -ahP4 ANNOUNCE.rst frs.sourceforge.net:/home/frs/project/sqlobject/sqlobject/"$version"/README.rst || exit 1 ../sftp-frs From 9a83dad081d9b450bdadc2c34ba17dd604c0964d Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 6 Jun 2018 19:40:18 +0300 Subject: [PATCH 178/509] Build(postrelease): Restore setup.cfg; edit README.rst --- devscripts/RELEASE-CHECKLIST | 9 +++++---- devscripts/postrelease | 6 +++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/devscripts/RELEASE-CHECKLIST b/devscripts/RELEASE-CHECKLIST index 29fa8a90..78c3fbf1 100644 --- a/devscripts/RELEASE-CHECKLIST +++ b/devscripts/RELEASE-CHECKLIST @@ -38,10 +38,11 @@ 7. Run ../push-all in the development repository to push all branches and tags to the public repositories. -8. Run ../postrelease. The script restores ANNOUNCE.rst from the previous - commit (HEAD~). It calls editor; update next version, remove the list - of contributors and the list of changes, edit download URL in - ANNOUNCE.rst. Edit docs/News.rst - add new version. +8. Run ../postrelease. The script restores ANNOUNCE.rst and setup.cfg + from the previous commit (HEAD~). It calls editor; update next version, + remove the list of contributors and the list of changes, edit download + URL in ANNOUNCE.rst. Edit README.rst and docs/News.rst - add new + version. 9. Generate new docs using ./build-all-docs. Upload docs using ./publish-docs. diff --git a/devscripts/postrelease b/devscripts/postrelease index bfb03d49..55dfe674 100755 --- a/devscripts/postrelease +++ b/devscripts/postrelease @@ -1,6 +1,6 @@ #! /bin/sh -git checkout HEAD~ ANNOUNCE.rst && +git checkout HEAD~ ANNOUNCE.rst setup.cfg && -`git var GIT_EDITOR` ANNOUNCE.rst docs/News.rst && -exec git commit --message="Prepare for the next release" ANNOUNCE.rst docs/News.rst +`git var GIT_EDITOR` ANNOUNCE.rst setup.cfg README.rst docs/News.rst && +exec git commit --message="Prepare for the next release" ANNOUNCE.rst setup.cfg README.rst docs/News.rst From 6560970c84f472973facdfe1c47a9829977f8522 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 6 Jun 2018 21:13:19 +0300 Subject: [PATCH 179/509] Build(RELEASE-CHECKLIST): PyPI lost ability to hide old releases [skip ci] --- devscripts/RELEASE-CHECKLIST | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devscripts/RELEASE-CHECKLIST b/devscripts/RELEASE-CHECKLIST index 78c3fbf1..e6949c4d 100644 --- a/devscripts/RELEASE-CHECKLIST +++ b/devscripts/RELEASE-CHECKLIST @@ -33,7 +33,7 @@ if it is a stable release - uploads archives and release announcement (ANNOUNCE.rst) to SourceForge. -6. Hide/show old releases at PyPI and SourceForge. +6. Move old releases at SourceForge to subdirectory OldFiles. 7. Run ../push-all in the development repository to push all branches and tags to the public repositories. From 1978118064d9f3f6e80472d89773fb2622194183 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 28 Jun 2018 17:22:23 +0300 Subject: [PATCH 180/509] Build, Tests(tox): Add Python 3.7 [skip ci] --- devscripts/release | 2 +- devscripts/run-all-tests | 2 +- devscripts/setup | 2 +- tox.ini | 103 ++++++++++++++++++++++++++++++++++++++- 4 files changed, 105 insertions(+), 4 deletions(-) diff --git a/devscripts/release b/devscripts/release index 3bae6e72..e46403cc 100755 --- a/devscripts/release +++ b/devscripts/release @@ -11,7 +11,7 @@ python setup.py build_py && python setup.py build --executable '/usr/bin/env python' && python setup.py sdist && -for py in 2.7 3.4 3.5 3.6; do +for py in 2.7 3.4 3.5 3.6 3.7; do find build -name '*.py[co]' -delete && python$py setup.py build_py && python$py setup.py build --executable '/usr/bin/env python' && diff --git a/devscripts/run-all-tests b/devscripts/run-all-tests index da6dbe4c..2e67aaa9 100755 --- a/devscripts/run-all-tests +++ b/devscripts/run-all-tests @@ -3,7 +3,7 @@ cd "`dirname \"$0\"`"/SQLObject && SO_DIR="`dirname $0`" -for py_ver in 2.7 3.4 3.5 3.6; do +for py_ver in 2.7 3.4 3.5 3.6 3.7; do echo "---------- PYTHON $py_ver "$1" ----------" "$SO_DIR"/cleanup && PY_VER=$py_ver "$SO_DIR"/run-tests-"$1" \ diff --git a/devscripts/setup b/devscripts/setup index 4edd6797..c85aae00 100755 --- a/devscripts/setup +++ b/devscripts/setup @@ -3,7 +3,7 @@ umask 022 # -rwxr-xr-x cd "`dirname \"$0\"`"/SQLObject && -for py_ver in 2.7 3.4 3.5 3.6; do +for py_ver in 2.7 3.4 3.5 3.6 3.7; do python$py_ver -m pip install --install-option=-O2 --upgrade . done && diff --git a/tox.ini b/tox.ini index 5ca1e8b9..443c0892 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 2.0 -envlist = py{27,34,35,36}-sqlite{,-memory},py{27,34}-flake8 +envlist = py{27,34,35,36,37}-sqlite{,-memory},py{27,34}-flake8 # Base test environment settings [testenv] @@ -11,6 +11,7 @@ basepython = py34: {env:TOXPYTHON:python3.4} py35: {env:TOXPYTHON:python3.5} py36: {env:TOXPYTHON:python3.6} + py37: {env:TOXPYTHON:python3.7} commands = {envpython} --version {envpython} -c "import struct; print(struct.calcsize('P') * 8)" @@ -72,6 +73,9 @@ commands = {[mysqlclient]commands} [testenv:py36-mysqlclient] commands = {[mysqlclient]commands} +[testenv:py37-mysqlclient] +commands = {[mysqlclient]commands} + [mysql-connector] commands = {[testenv]commands} @@ -92,6 +96,9 @@ commands = {[mysql-connector]commands} [testenv:py36-mysql-connector] commands = {[mysql-connector]commands} +[testenv:py37-mysql-connector] +commands = {[mysql-connector]commands} + [oursql] commands = {[testenv]commands} @@ -112,6 +119,9 @@ commands = {[oursql]commands} [testenv:py36-mysql-oursql3] commands = {[oursql]commands} +[testenv:py37-mysql-oursql3] +commands = {[oursql]commands} + [pymysql] commands = {[testenv]commands} @@ -132,6 +142,9 @@ commands = {[pymysql]commands} [testenv:py36-pymysql] commands = {[pymysql]commands} +[testenv:py37-pymysql] +commands = {[pymysql]commands} + [mysql-pyodbc] commands = {[testenv]commands} @@ -153,6 +166,9 @@ commands = {[mysql-pyodbc]commands} [testenv:py36-mysql-pyodbc] commands = {[mysql-pyodbc]commands} +[testenv:py37-mysql-pyodbc] +commands = {[mysql-pyodbc]commands} + [mysql-pypyodbc] commands = {[testenv]commands} @@ -173,6 +189,9 @@ commands = {[mysql-pypyodbc]commands} [testenv:py36-mysql-pypyodbc] commands = {[mysql-pypyodbc]commands} +[testenv:py37-mysql-pypyodbc] +commands = {[mysql-pypyodbc]commands} + # PostgreSQL test environments [psycopg] commands = @@ -194,6 +213,9 @@ commands = {[psycopg]commands} [testenv:py36-postgres-psycopg] commands = {[psycopg]commands} +[testenv:py37-postgres-psycopg] +commands = {[psycopg]commands} + [pygresql] commands = {[testenv]commands} @@ -214,6 +236,9 @@ commands = {[pygresql]commands} [testenv:py36-postgres-pygresql] commands = {[pygresql]commands} +[testenv:py37-postgres-pygresql] +commands = {[pygresql]commands} + [pypostgresql] commands = {[testenv]commands} @@ -231,6 +256,9 @@ commands = {[pypostgresql]commands} [testenv:py36-pypostgresql] commands = {[pypostgresql]commands} +[testenv:py37-pypostgresql] +commands = {[pypostgresql]commands} + [pg8000] commands = {[testenv]commands} @@ -251,6 +279,9 @@ commands = {[pg8000]commands} [testenv:py36-postgres-pg8000] commands = {[pg8000]commands} +[testenv:py37-postgres-pg8000] +commands = {[pg8000]commands} + [postgres-pyodbc] commands = {[testenv]commands} @@ -272,6 +303,9 @@ commands = {[postgres-pyodbc]commands} [testenv:py36-postgres-pyodbc] commands = {[postgres-pyodbc]commands} +[testenv:py37-postgres-pyodbc] +commands = {[postgres-pyodbc]commands} + [postgres-pypyodbc] commands = {[testenv]commands} @@ -292,6 +326,9 @@ commands = {[postgres-pypyodbc]commands} [testenv:py36-postgres-pypyodbc] commands = {[postgres-pypyodbc]commands} +[testenv:py37-postgres-pypyodbc] +commands = {[postgres-pypyodbc]commands} + # SQLite test environments [sqlite] @@ -313,6 +350,9 @@ commands = {[sqlite]commands} [testenv:py36-sqlite] commands = {[sqlite]commands} +[testenv:py37-sqlite] +commands = {[sqlite]commands} + [sqlite-memory] commands = {[testenv]commands} @@ -330,6 +370,9 @@ commands = {[sqlite-memory]commands} [testenv:py36-sqlite-memory] commands = {[sqlite-memory]commands} +[testenv:py37-sqlite-memory] +commands = {[sqlite-memory]commands} + # Firebird database test environments [fdb] commands = @@ -351,6 +394,9 @@ commands = {[fdb]commands} [testenv:py36-firebird-fdb] commands = {[fdb]commands} +[testenv:py37-firebird-fdb] +commands = {[fdb]commands} + [firebirdsql] commands = {[testenv]commands} @@ -371,6 +417,9 @@ commands = {[firebirdsql]commands} [testenv:py36-firebirdsql] commands = {[firebirdsql]commands} +[testenv:py37-firebirdsql] +commands = {[firebirdsql]commands} + # Special test environments [testenv:py27-flake8] changedir = ./ @@ -414,6 +463,10 @@ commands = {[mssql-pyodbc-w32]commands} platform = win32 commands = {[mssql-pyodbc-w32]commands} +[testenv:py37-mssql-pyodbc-w32] +platform = win32 +commands = {[mssql-pyodbc-w32]commands} + [mysql-connector-w32] platform = win32 commands = @@ -439,6 +492,10 @@ commands = {[mysql-connector-w32]commands} platform = win32 commands = {[mysql-connector-w32]commands} +[testenv:py37-mysql-connector-w32] +platform = win32 +commands = {[mysql-connector-w32]commands} + [pymysql-w32] platform = win32 commands = @@ -464,6 +521,10 @@ commands = {[pymysql-w32]commands} platform = win32 commands = {[pymysql-w32]commands} +[testenv:py37-pymysql-w32] +platform = win32 +commands = {[pymysql-w32]commands} + [mysql-pyodbc-w32] platform = win32 commands = @@ -490,6 +551,10 @@ commands = {[mysql-pyodbc-w32]commands} platform = win32 commands = {[mysql-pyodbc-w32]commands} +[testenv:py37-mysql-pyodbc-w32] +platform = win32 +commands = {[mysql-pyodbc-w32]commands} + [mysql-pypyodbc-w32] platform = win32 commands = @@ -516,6 +581,10 @@ commands = {[mysql-pypyodbc-w32]commands} platform = win32 commands = {[mysql-pypyodbc-w32]commands} +[testenv:py37-mysql-pypyodbc-w32] +platform = win32 +commands = {[mysql-pypyodbc-w32]commands} + [psycopg-w32] platform = win32 commands = @@ -541,6 +610,10 @@ commands = {[psycopg-w32]commands} platform = win32 commands = {[psycopg-w32]commands} +[testenv:py37-postgres-psycopg-w32] +platform = win32 +commands = {[psycopg-w32]commands} + [pygresql-w32] platform = win32 commands = @@ -566,6 +639,10 @@ commands = {[pygresql-w32]commands} platform = win32 commands = {[pygresql-w32]commands} +[testenv:py37-postgres-pygresql-w32] +platform = win32 +commands = {[pygresql-w32]commands} + [pypostgresql-w32] platform = win32 commands = @@ -587,6 +664,10 @@ commands = {[pypostgresql-w32]commands} platform = win32 commands = {[pypostgresql-w32]commands} +[testenv:py37-pypostgresql-w32] +platform = win32 +commands = {[pypostgresql-w32]commands} + [pg8000-w32] platform = win32 commands = @@ -612,6 +693,10 @@ commands = {[pg8000-w32]commands} platform = win32 commands = {[pg8000-w32]commands} +[testenv:py37-postgres-pg8000-w32] +platform = win32 +commands = {[pg8000-w32]commands} + [postgres-pyodbc-w32] platform = win32 commands = @@ -638,6 +723,10 @@ commands = {[postgres-pyodbc-w32]commands} platform = win32 commands = {[postgres-pyodbc-w32]commands} +[testenv:py37-postgres-pyodbc-w32] +platform = win32 +commands = {[postgres-pyodbc-w32]commands} + [postgres-pypyodbc-w32] platform = win32 commands = @@ -664,6 +753,10 @@ commands = {[postgres-pypyodbc-w32]commands} platform = win32 commands = {[postgres-pypyodbc-w32]commands} +[testenv:py37-postgres-pypyodbc-w32] +platform = win32 +commands = {[postgres-pypyodbc-w32]commands} + [sqlite-w32] platform = win32 commands = @@ -686,6 +779,10 @@ commands = {[sqlite-w32]commands} platform = win32 commands = {[sqlite-w32]commands} +[testenv:py37-sqlite-w32] +platform = win32 +commands = {[sqlite-w32]commands} + [sqlite-memory-w32] platform = win32 commands = @@ -707,3 +804,7 @@ commands = {[sqlite-memory-w32]commands} [testenv:py36-sqlite-memory-w32] platform = win32 commands = {[sqlite-memory-w32]commands} + +[testenv:py37-sqlite-memory-w32] +platform = win32 +commands = {[sqlite-memory-w32]commands} From c93aef83f61769db976871aa479348ad24bd784a Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 21 Aug 2018 19:16:08 +0300 Subject: [PATCH 181/509] Build(release): Stop releasing eggs It's enough to release a wheel. [skip ci] --- devscripts/release | 9 --------- 1 file changed, 9 deletions(-) diff --git a/devscripts/release b/devscripts/release index e46403cc..9dcff1a2 100755 --- a/devscripts/release +++ b/devscripts/release @@ -11,15 +11,6 @@ python setup.py build_py && python setup.py build --executable '/usr/bin/env python' && python setup.py sdist && -for py in 2.7 3.4 3.5 3.6 3.7; do - find build -name '*.py[co]' -delete && - python$py setup.py build_py && - python$py setup.py build --executable '/usr/bin/env python' && - python$py -m compileall build && - python$py -O -m compileall build && - python$py setup.py bdist_egg || exit 1 -done - find build -name '*.py[co]' -delete && python setup.py bdist_wheel --universal && From 85bc51c511ef8bd476df5d380038b83c73c2c6fe Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 15 Nov 2018 22:54:10 +0300 Subject: [PATCH 182/509] Feat(devscripts): Better sort flake8 results Sort flake8 results (file:line:column) by the column in the reverse order. [skip ci] --- devscripts/flake8/split | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devscripts/flake8/split b/devscripts/flake8/split index 958b7585..2cdbfaca 100755 --- a/devscripts/flake8/split +++ b/devscripts/flake8/split @@ -1,5 +1,5 @@ #! /bin/sh while read _count code; do - grep -F " $code " all-results | sort -t : -k 1,1 -k 2,2nr >"$code" + grep -F " $code " all-results | sort -t : -k 1,1 -k 2,2nr -k 3,3nr >"$code" done Date: Tue, 27 Nov 2018 00:10:52 +0300 Subject: [PATCH 183/509] Style: Ignore flake8 W503 line break before binary operator --- setup.cfg | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 40ee4ca8..6f87a788 100644 --- a/setup.cfg +++ b/setup.cfg @@ -12,5 +12,6 @@ tag_svn_revision = 0 [flake8] exclude = .git,.tox,docs/europython/*.py # E305: expected 2 blank lines after class or function definition, found 1 -ignore = E305 +# W503 line break before binary operator +ignore = E305,W503 From f4ef555f893a5b738b1eb1ac54e8dc566c03abde Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 27 Nov 2018 00:11:38 +0300 Subject: [PATCH 184/509] Style: Ignore flake8 W605 invalid escape sequence flake8 is overzealous marking `re.search('\s+')` as invalid. --- setup.cfg | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 6f87a788..461bc50f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -13,5 +13,6 @@ tag_svn_revision = 0 exclude = .git,.tox,docs/europython/*.py # E305: expected 2 blank lines after class or function definition, found 1 # W503 line break before binary operator -ignore = E305,W503 +# W605 invalid escape sequence +ignore = E305,W503,W605 From 62156a3c41349b4d310fc15dc065fed17c7bf7f8 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 27 Nov 2018 00:24:04 +0300 Subject: [PATCH 185/509] Style: Ignore flake8 W504 line break after binary operator --- setup.py | 4 +-- sqlobject/col.py | 4 +-- sqlobject/dbconnection.py | 10 +++---- sqlobject/declarative.py | 4 +-- sqlobject/inheritance/__init__.py | 12 ++++----- sqlobject/joins.py | 24 ++++++++--------- sqlobject/main.py | 8 +++--- sqlobject/manager/command.py | 40 ++++++++++++++-------------- sqlobject/postgres/pgconnection.py | 4 +-- sqlobject/sqlite/sqliteconnection.py | 4 +-- sqlobject/sresults.py | 4 +-- sqlobject/tests/dbtest.py | 7 ++--- sqlobject/tests/test_ForeignKey.py | 4 +-- sqlobject/tests/test_auto.py | 4 +-- sqlobject/tests/test_declarative.py | 4 +-- sqlobject/tests/test_joins.py | 4 +-- sqlobject/tests/test_new_joins.py | 4 +-- sqlobject/tests/test_transactions.py | 4 +-- sqlobject/util/csvimport.py | 4 +-- 19 files changed, 75 insertions(+), 78 deletions(-) diff --git a/setup.py b/setup.py index b0fb3832..0ebca65b 100755 --- a/setup.py +++ b/setup.py @@ -74,8 +74,8 @@ keywords=["sql", "orm", "object-relational mapper"], license="LGPL", platforms="Any", - packages=["sqlobject"] + - ['sqlobject.%s' % package for package in subpackages], + packages=["sqlobject"] + + ['sqlobject.%s' % package for package in subpackages], scripts=["scripts/sqlobject-admin", "scripts/sqlobject-convertOldURI"], package_data={ "sqlobject.maxdb": ["readme.txt"], diff --git a/sqlobject/col.py b/sqlobject/col.py index 67719461..81195393 100644 --- a/sqlobject/col.py +++ b/sqlobject/col.py @@ -387,8 +387,8 @@ def firebirdCreateSQL(self): [self.dbName, self._firebirdType()] + self._extraSQL()) else: return ' '.join( - [self.dbName] + [self._firebirdType()[0]] + - self._extraSQL() + [self._firebirdType()[1]]) + [self.dbName] + [self._firebirdType()[0]] + + self._extraSQL() + [self._firebirdType()[1]]) def maxdbCreateSQL(self): return ' '.join([self.dbName, self._maxdbType()] + self._extraSQL()) diff --git a/sqlobject/dbconnection.py b/sqlobject/dbconnection.py index 1f71b1b5..fbff4576 100644 --- a/sqlobject/dbconnection.py +++ b/sqlobject/dbconnection.py @@ -618,9 +618,9 @@ def _SO_selectOne(self, so, columnNames): def _SO_selectOneAlt(self, so, columnNames, condition): if columnNames: - columns = [isinstance(x, string_type) and - sqlbuilder.SQLConstant(x) or - x for x in columnNames] + columns = [isinstance(x, string_type) + and sqlbuilder.SQLConstant(x) + or x for x in columnNames] else: columns = None return self.queryOne(self.sqlrepr(sqlbuilder.Select( @@ -1070,8 +1070,8 @@ def registerConnection(self, schemes, builder): def registerConnectionInstance(self, inst): if inst.name: - assert (inst.name not in self.instanceNames or - self.instanceNames[inst.name] is cls # noqa + assert (inst.name not in self.instanceNames + or self.instanceNames[inst.name] is cls # noqa ), ("A instance has already been registered " "with the name %s" % inst.name) assert inst.name.find(':') == -1, \ diff --git a/sqlobject/declarative.py b/sqlobject/declarative.py index d03a46ed..8fe2cbd4 100644 --- a/sqlobject/declarative.py +++ b/sqlobject/declarative.py @@ -199,8 +199,8 @@ def __repr__(self, cls): @staticmethod def _repr_vars(dictNames): names = [n for n in dictNames - if not n.startswith('_') and - n != 'declarative_count'] + if not n.startswith('_') + and n != 'declarative_count'] names.sort() return names diff --git a/sqlobject/inheritance/__init__.py b/sqlobject/inheritance/__init__.py index f340e790..e6c57b44 100644 --- a/sqlobject/inheritance/__init__.py +++ b/sqlobject/inheritance/__init__.py @@ -31,8 +31,8 @@ def __init__(self, sourceClass, clause, clauseTables=None, if clause is None or isinstance(clause, str) and clause == 'all': clause = sqlbuilder.SQLTrueClause - dbName = (ops.get('connection', None) or - sourceClass._connection).dbName + dbName = (ops.get('connection', None) + or sourceClass._connection).dbName tablesSet = tablesUsedSet(clause, dbName) tablesSet.add(str(sourceClass.sqlmeta.table)) @@ -415,8 +415,8 @@ def _create(self, id, **kw): # If we are outside a transaction and this is a child, # destroy the parent connection = self._connection - if (not isinstance(connection, dbconnection.Transaction) and - connection.autoCommit) and self.sqlmeta.parentClass: + if (not isinstance(connection, dbconnection.Transaction) + and connection.autoCommit) and self.sqlmeta.parentClass: self._parent.destroySelf() # TC: Do we need to do this?? self._parent = None @@ -457,8 +457,8 @@ def select(cls, clause=None, *args, **kwargs): # if the clause was one of TRUE varians, replace it if (clause is None) or (clause is sqlbuilder.SQLTrueClause) \ or ( - isinstance(clause, string_type) and - (clause == 'all')): + isinstance(clause, string_type) + and (clause == 'all')): clause = addClause else: # patch WHERE condition: diff --git a/sqlobject/joins.py b/sqlobject/joins.py index c847e21b..afb0f881 100644 --- a/sqlobject/joins.py +++ b/sqlobject/joins.py @@ -440,19 +440,19 @@ def _finishSet(self): events.listen(self.event_CreateTableSignal, self.otherClass, events.CreateTableSignal) self.clause = ( - (self.otherClass.q.id == - sqlbuilder.Field(self.intermediateTable, self.otherColumn)) & - (sqlbuilder.Field(self.intermediateTable, self.joinColumn) == - self.soClass.q.id)) + (self.otherClass.q.id + == sqlbuilder.Field(self.intermediateTable, self.otherColumn)) + & (sqlbuilder.Field(self.intermediateTable, self.joinColumn) + == self.soClass.q.id)) def __get__(self, obj, type): if obj is None: return self query = ( - (self.otherClass.q.id == - sqlbuilder.Field(self.intermediateTable, self.otherColumn)) & - (sqlbuilder.Field(self.intermediateTable, self.joinColumn) == - obj.id)) + (self.otherClass.q.id + == sqlbuilder.Field(self.intermediateTable, self.otherColumn)) + & (sqlbuilder.Field(self.intermediateTable, self.joinColumn) + == obj.id)) select = self.otherClass.select(query) return _ManyToManySelectWrapper(obj, self, select) @@ -545,15 +545,15 @@ def _setOtherClass(self, otherClass): self.joinColumn = styles.getStyle( self.soClass).tableReference(self.soClass.sqlmeta.table) self.clause = ( - sqlbuilder.Field(self.otherClass.sqlmeta.table, self.joinColumn) == - self.soClass.q.id) + sqlbuilder.Field(self.otherClass.sqlmeta.table, self.joinColumn) + == self.soClass.q.id) def __get__(self, obj, type): if obj is None: return self query = ( - sqlbuilder.Field(self.otherClass.sqlmeta.table, self.joinColumn) == - obj.id) + sqlbuilder.Field(self.otherClass.sqlmeta.table, self.joinColumn) + == obj.id) select = self.otherClass.select(query) return _OneToManySelectWrapper(obj, self, select) diff --git a/sqlobject/main.py b/sqlobject/main.py index 88b3c0c1..5d9b537a 100644 --- a/sqlobject/main.py +++ b/sqlobject/main.py @@ -1410,8 +1410,8 @@ def _findAlternateID(cls, name, dbName, value, connection=None): *[getattr(cls.q, _n) == _v for _n, _v in zip(name, new_value)]) return (connection or cls._connection)._SO_selectOneAlt( cls, - [cls.sqlmeta.idName] + - [column.dbName for column in cls.sqlmeta.columnList], + [cls.sqlmeta.idName] + + [column.dbName for column in cls.sqlmeta.columnList], condition), None @classmethod @@ -1536,8 +1536,8 @@ def createTableSQL(cls, createJoinTables=True, createIndexes=True, def createJoinTables(cls, ifNotExists=False, connection=None): conn = connection or cls._connection for join in cls._getJoinsToCreate(): - if (ifNotExists and - conn.tableExists(join.intermediateTable)): + if (ifNotExists + and conn.tableExists(join.intermediateTable)): continue conn._SO_createJoinTable(join) diff --git a/sqlobject/manager/command.py b/sqlobject/manager/command.py index e79053fb..e9891d91 100755 --- a/sqlobject/manager/command.py +++ b/sqlobject/manager/command.py @@ -297,8 +297,8 @@ def run(self): if self.description: self.parser.description = self.description self.options, self.args = self.parser.parse_args(self.raw_args) - if (getattr(self.options, 'simulate', False) and - not self.options.verbose): + if (getattr(self.options, 'simulate', False) + and not self.options.verbose): self.options.verbose = 1 if self.min_args is not None and len(self.args) < self.min_args: self.runner.invalid( @@ -391,9 +391,9 @@ def classes_from_module(self, module): else: for name in dir(module): value = getattr(module, name) - if (isinstance(value, type) and - issubclass(value, sqlobject.SQLObject) and - value.__module__ == module.__name__): + if (isinstance(value, type) + and issubclass(value, sqlobject.SQLObject) + and value.__module__ == module.__name__): all.append(value) return all @@ -414,8 +414,8 @@ def config(self): return None config_file = self.options.config_file if appconfig: - if (not config_file.startswith('egg:') and - not config_file.startswith('config:')): + if (not config_file.startswith('egg:') + and not config_file.startswith('config:')): config_file = 'config:' + config_file return appconfig(config_file, relative_to=os.getcwd()) @@ -446,9 +446,9 @@ def ini_config(self, conf_fn): possible_sections = [] for section in p.sections(): name = section.strip().lower() - if (conf_section == name or - (conf_section == name.split(':')[-1] and - name.split(':')[0] in ('app', 'application'))): + if (conf_section == name + or (conf_section == name.split(':')[-1] + and name.split(':')[0] in ('app', 'application'))): possible_sections.append(section) if not possible_sections: @@ -514,8 +514,8 @@ def classes_from_egg(self, egg_spec): def load_options_from_egg(self, egg_spec): dist, conf = self.config_from_egg(egg_spec) - if (hasattr(self.options, 'output_dir') and - not self.options.output_dir and conf.get('history_dir')): + if (hasattr(self.options, 'output_dir') + and not self.options.output_dir and conf.get('history_dir')): dir = conf['history_dir'] dir = dir.replace('$base', dist.location) self.options.output_dir = dir @@ -653,8 +653,8 @@ def command(self): dbs_created = [] constraints = {} for soClass in self.classes(require_some=True): - if (self.options.create_db and - soClass._connection not in dbs_created): + if (self.options.create_db + and soClass._connection not in dbs_created): if not self.options.simulate: try: soClass._connection.createEmptyDatabase() @@ -1007,8 +1007,8 @@ def command(self): f = open(os.path.join(last_version_dir, fn), 'r') content = f.read() f.close() - if (self.strip_comments(files_copy[fn]) != - self.strip_comments(content)): + if (self.strip_comments(files_copy[fn]) + != self.strip_comments(content)): if v > 1: print("Content does not match: %s" % fn) break @@ -1063,8 +1063,8 @@ def command(self): print("Cannot edit upgrader because there is no " "previous version") else: - breaker = ('-' * 20 + ' lines below this will be ignored ' + - '-' * 20) + breaker = ('-' * 20 + ' lines below this will be ignored ' + + '-' * 20) pre_text = breaker + '\n' + '\n'.join(all_diffs) text = self.open_editor('\n\n' + pre_text, breaker=breaker, extension='.sql') @@ -1117,8 +1117,8 @@ def base_dir(self): def find_output_dir(self): today = time.strftime('%Y-%m-%d', time.localtime()) if self.options.version_name: - dir = os.path.join(self.base_dir(), today + '-' + - self.options.version_name) + dir = os.path.join(self.base_dir(), today + '-' + + self.options.version_name) if os.path.exists(dir): print("Error, directory already exists: %s" % dir) diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index b567f997..8dd1db58 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -249,8 +249,8 @@ def _executeRetry(self, conn, cursor, query): except self.module.ProgrammingError as e: msg = ErrorMessage(e) if ( - (len(e.args) > 2) and (e.args[1] == 'ERROR') and - (e.args[2] == '23505')) \ + (len(e.args) > 2) and (e.args[1] == 'ERROR') + and (e.args[2] == '23505')) \ or ((len(e.args) >= 2) and (e.args[1] == '23505')): raise dberrors.DuplicateEntryError(msg) else: diff --git a/sqlobject/sqlite/sqliteconnection.py b/sqlobject/sqlite/sqliteconnection.py index fbb07a55..db83eee1 100644 --- a/sqlobject/sqlite/sqliteconnection.py +++ b/sqlobject/sqlite/sqliteconnection.py @@ -170,8 +170,8 @@ def releaseConnection(self, conn, explicit=False): return threadid = self._threadOrigination.get(id(conn)) DBAPI.releaseConnection(self, conn, explicit=explicit) - if (self._pool is not None and threadid and - threadid not in self._threadPool): + if (self._pool is not None and threadid + and threadid not in self._threadPool): self._threadPool[threadid] = conn else: if self._pool and conn in self._pool: diff --git a/sqlobject/sresults.py b/sqlobject/sresults.py index 9abfa899..4573cd10 100644 --- a/sqlobject/sresults.py +++ b/sqlobject/sresults.py @@ -214,8 +214,8 @@ def count(self): """ Counting elements of current select results """ assert not self.ops.get('start') and not self.ops.get('end'), \ "start/end/limit have no meaning with 'count'" - assert not (self.ops.get('distinct') and - (self.ops.get('start') or self.ops.get('end'))), \ + assert not (self.ops.get('distinct') + and (self.ops.get('start') or self.ops.get('end'))), \ "distinct-counting of sliced objects is not supported" if self.ops.get('distinct'): # Column must be specified, so we are using unique ID column. diff --git a/sqlobject/tests/dbtest.py b/sqlobject/tests/dbtest.py index 545c3859..b1cf6e4b 100644 --- a/sqlobject/tests/dbtest.py +++ b/sqlobject/tests/dbtest.py @@ -122,11 +122,8 @@ def getConnectionURI(): else: if (connection.dbName == 'firebird') \ or ( - (connection.dbName == 'mysql') and - ( - (os.environ.get('APPVEYOR')) or - (os.environ.get('TRAVIS')) - ) + (connection.dbName == 'mysql') + and ((os.environ.get('APPVEYOR')) or (os.environ.get('TRAVIS'))) ): use_microseconds(False) diff --git a/sqlobject/tests/test_ForeignKey.py b/sqlobject/tests/test_ForeignKey.py index 0e802750..50715eff 100644 --- a/sqlobject/tests/test_ForeignKey.py +++ b/sqlobject/tests/test_ForeignKey.py @@ -71,8 +71,8 @@ def test1(): assert s.count() == 1 assert s[0] == w1 s = SOTestWorkKey.select( - (SOTestWorkKey.q.composer == c) & - (SOTestWorkKey.q.title == 'Symphony No. 9')) + (SOTestWorkKey.q.composer == c) + & (SOTestWorkKey.q.title == 'Symphony No. 9')) assert s.count() == 1 assert s[0] == w1 diff --git a/sqlobject/tests/test_auto.py b/sqlobject/tests/test_auto.py index a97e1a8d..1b66821e 100644 --- a/sqlobject/tests/test_auto.py +++ b/sqlobject/tests/test_auto.py @@ -48,8 +48,8 @@ def test_dynamicColumn(self): nickname = StringCol('nickname', length=10) Person.sqlmeta.addColumn(nickname, changeSchema=True) Person(name='robert', nickname='bob') - assert ([p.name for p in Person.select('all')] == - ['bob', 'jake', 'jane', 'robert', 'tim']) + assert ([p.name for p in Person.select('all')] + == ['bob', 'jake', 'jane', 'robert', 'tim']) Person.sqlmeta.delColumn(nickname, changeSchema=True) def test_dynamicJoin(self): diff --git a/sqlobject/tests/test_declarative.py b/sqlobject/tests/test_declarative.py index 3bd452b8..4c75be6c 100644 --- a/sqlobject/tests/test_declarative.py +++ b/sqlobject/tests/test_declarative.py @@ -41,8 +41,8 @@ def __instanceinit__(self, new_attrs): def add_attrs(old_attrs, new_attrs): old_attrs = old_attrs[:] for name in new_attrs.keys(): - if (name in old_attrs or name.startswith('_') or - name in ('add_attrs', 'declarative_count', 'attrs')): + if (name in old_attrs or name.startswith('_') + or name in ('add_attrs', 'declarative_count', 'attrs')): continue old_attrs.append(name) old_attrs.sort() diff --git a/sqlobject/tests/test_joins.py b/sqlobject/tests/test_joins.py index 684d2a93..9cc7c19e 100644 --- a/sqlobject/tests/test_joins.py +++ b/sqlobject/tests/test_joins.py @@ -111,8 +111,8 @@ def test_basic(self): def test_defaultOrder(self): p1 = PersonJoiner2.byName('bob') - assert ([i.zip for i in p1.addressJoiner2s] == - ['33333', '22222', '11111']) + assert ([i.zip for i in p1.addressJoiner2s] + == ['33333', '22222', '11111']) _personJoiner3_getters = [] diff --git a/sqlobject/tests/test_new_joins.py b/sqlobject/tests/test_new_joins.py index 3a97e98b..82d27d34 100644 --- a/sqlobject/tests/test_new_joins.py +++ b/sqlobject/tests/test_new_joins.py @@ -116,8 +116,8 @@ def test_basic(self): def test_defaultOrder(self): p1 = PersonJNew2.byName('bob') - assert ([i.zip for i in p1.addressJ2s] == - ['33333', '22222', '11111']) + assert ([i.zip for i in p1.addressJ2s] + == ['33333', '22222', '11111']) _personJ3_getters = [] diff --git a/sqlobject/tests/test_transactions.py b/sqlobject/tests/test_transactions.py index 091de474..b9ac5006 100644 --- a/sqlobject/tests/test_transactions.py +++ b/sqlobject/tests/test_transactions.py @@ -53,8 +53,8 @@ def test_transaction(): SOTestSOTrans(name='joe', connection=trans) trans.rollback() trans.begin() - assert ([n.name for n in SOTestSOTrans.select(connection=trans)] == - ['bob', 'tim']) + assert ([n.name for n in SOTestSOTrans.select(connection=trans)] + == ['bob', 'tim']) b = SOTestSOTrans.byName('bob', connection=trans) b.name = 'robert' trans.commit() diff --git a/sqlobject/util/csvimport.py b/sqlobject/util/csvimport.py index ba0fa0d2..e2ec686a 100644 --- a/sqlobject/util/csvimport.py +++ b/sqlobject/util/csvimport.py @@ -88,8 +88,8 @@ class names will be attributes of that. """ objects = {} classnames = data.keys() - if (not keyorder and isinstance(class_getter, types.ModuleType) and - hasattr(class_getter, 'soClasses')): + if (not keyorder and isinstance(class_getter, types.ModuleType) + and hasattr(class_getter, 'soClasses')): keyorder = [c.__name__ for c in class_getter.soClasses] if not keyorder: classnames.sort() From 0119773190ecc22b1cb1dd491132b6d2d6dd2ad5 Mon Sep 17 00:00:00 2001 From: Neil Date: Wed, 23 Jan 2019 12:00:34 +0200 Subject: [PATCH 186/509] Exclude sqlmeta members from some of the api docs The inclusion of of these sqlmeta members in these files breaks reproducible builds as sphinx includes the memory addresses when building the documentation. Since the contents aren't particularly useful, the simplest fix is to simply exclude them from the documentation build. --- docs/api/sqlobject.include.tests.test_hashcol.rst | 1 + docs/api/sqlobject.inheritance.tests.test_aggregates.rst | 1 + docs/api/sqlobject.inheritance.tests.test_asdict.rst | 1 + docs/api/sqlobject.inheritance.tests.test_deep_inheritance.rst | 1 + docs/api/sqlobject.inheritance.tests.test_destroy_cascade.rst | 1 + docs/api/sqlobject.inheritance.tests.test_foreignKey.rst | 1 + docs/api/sqlobject.inheritance.tests.test_indexes.rst | 1 + docs/api/sqlobject.inheritance.tests.test_inheritance.rst | 1 + docs/api/sqlobject.inheritance.tests.test_inheritance_tree.rst | 1 + docs/api/sqlobject.manager.command.rst | 1 + docs/api/sqlobject.tests.test_ForeignKey.rst | 1 + docs/api/sqlobject.tests.test_NoneValuedResultItem.rst | 1 + docs/api/sqlobject.tests.test_SQLMultipleJoin.rst | 1 + docs/api/sqlobject.tests.test_SQLRelatedJoin.rst | 1 + docs/api/sqlobject.tests.test_SingleJoin.rst | 1 + docs/api/sqlobject.tests.test_aggregates.rst | 1 + docs/api/sqlobject.tests.test_aliases.rst | 1 + docs/api/sqlobject.tests.test_asdict.rst | 1 + docs/api/sqlobject.tests.test_auto.rst | 1 + docs/api/sqlobject.tests.test_basic.rst | 1 + docs/api/sqlobject.tests.test_blob.rst | 1 + docs/api/sqlobject.tests.test_cache.rst | 1 + docs/api/sqlobject.tests.test_class_hash.rst | 1 + docs/api/sqlobject.tests.test_columns_order.rst | 1 + docs/api/sqlobject.tests.test_combining_joins.rst | 1 + docs/api/sqlobject.tests.test_complex_sorting.rst | 1 + docs/api/sqlobject.tests.test_create_drop.rst | 1 + docs/api/sqlobject.tests.test_csvexport.rst | 1 + docs/api/sqlobject.tests.test_cyclic_reference.rst | 1 + docs/api/sqlobject.tests.test_datetime.rst | 1 + docs/api/sqlobject.tests.test_decimal.rst | 1 + docs/api/sqlobject.tests.test_delete.rst | 1 + docs/api/sqlobject.tests.test_distinct.rst | 1 + docs/api/sqlobject.tests.test_enum.rst | 1 + docs/api/sqlobject.tests.test_events.rst | 1 + docs/api/sqlobject.tests.test_exceptions.rst | 1 + docs/api/sqlobject.tests.test_expire.rst | 1 + docs/api/sqlobject.tests.test_groupBy.rst | 1 + docs/api/sqlobject.tests.test_identity.rst | 1 + docs/api/sqlobject.tests.test_indexes.rst | 1 + docs/api/sqlobject.tests.test_inheritance.rst | 1 + docs/api/sqlobject.tests.test_joins.rst | 1 + docs/api/sqlobject.tests.test_joins_conditional.rst | 1 + docs/api/sqlobject.tests.test_jsonbcol.rst | 1 + docs/api/sqlobject.tests.test_jsoncol.rst | 1 + docs/api/sqlobject.tests.test_lazy.rst | 1 + docs/api/sqlobject.tests.test_new_joins.rst | 1 + docs/api/sqlobject.tests.test_paste.rst | 1 + docs/api/sqlobject.tests.test_perConnection.rst | 1 + docs/api/sqlobject.tests.test_pickle.rst | 1 + docs/api/sqlobject.tests.test_picklecol.rst | 1 + docs/api/sqlobject.tests.test_postgres.rst | 1 + docs/api/sqlobject.tests.test_reparent_sqlmeta.rst | 1 + docs/api/sqlobject.tests.test_schema.rst | 1 + docs/api/sqlobject.tests.test_select.rst | 1 + docs/api/sqlobject.tests.test_select_through.rst | 1 + docs/api/sqlobject.tests.test_setters.rst | 1 + docs/api/sqlobject.tests.test_slice.rst | 1 + docs/api/sqlobject.tests.test_sorting.rst | 1 + docs/api/sqlobject.tests.test_sqlbuilder.rst | 1 + docs/api/sqlobject.tests.test_sqlbuilder_dbspecific.rst | 1 + docs/api/sqlobject.tests.test_sqlbuilder_joins_instances.rst | 1 + docs/api/sqlobject.tests.test_sqlite.rst | 1 + docs/api/sqlobject.tests.test_sqlobject_admin.rst | 1 + docs/api/sqlobject.tests.test_string_id.rst | 1 + docs/api/sqlobject.tests.test_style.rst | 1 + docs/api/sqlobject.tests.test_subqueries.rst | 1 + docs/api/sqlobject.tests.test_transactions.rst | 1 + docs/api/sqlobject.tests.test_unicode.rst | 1 + docs/api/sqlobject.tests.test_uuidcol.rst | 1 + docs/api/sqlobject.tests.test_validation.rst | 1 + docs/api/sqlobject.tests.test_views.rst | 1 + docs/api/sqlobject.versioning.test.test_version.rst | 1 + 73 files changed, 73 insertions(+) diff --git a/docs/api/sqlobject.include.tests.test_hashcol.rst b/docs/api/sqlobject.include.tests.test_hashcol.rst index 0cd6cb95..2ec99027 100644 --- a/docs/api/sqlobject.include.tests.test_hashcol.rst +++ b/docs/api/sqlobject.include.tests.test_hashcol.rst @@ -5,3 +5,4 @@ sqlobject\.include\.tests\.test\_hashcol module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.inheritance.tests.test_aggregates.rst b/docs/api/sqlobject.inheritance.tests.test_aggregates.rst index b93b20f4..15fa5afd 100644 --- a/docs/api/sqlobject.inheritance.tests.test_aggregates.rst +++ b/docs/api/sqlobject.inheritance.tests.test_aggregates.rst @@ -5,3 +5,4 @@ sqlobject\.inheritance\.tests\.test\_aggregates module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.inheritance.tests.test_asdict.rst b/docs/api/sqlobject.inheritance.tests.test_asdict.rst index 350e2105..c24c5114 100644 --- a/docs/api/sqlobject.inheritance.tests.test_asdict.rst +++ b/docs/api/sqlobject.inheritance.tests.test_asdict.rst @@ -5,3 +5,4 @@ sqlobject\.inheritance\.tests\.test\_asdict module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.inheritance.tests.test_deep_inheritance.rst b/docs/api/sqlobject.inheritance.tests.test_deep_inheritance.rst index a75ee175..eb1661dd 100644 --- a/docs/api/sqlobject.inheritance.tests.test_deep_inheritance.rst +++ b/docs/api/sqlobject.inheritance.tests.test_deep_inheritance.rst @@ -5,3 +5,4 @@ sqlobject\.inheritance\.tests\.test\_deep\_inheritance module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.inheritance.tests.test_destroy_cascade.rst b/docs/api/sqlobject.inheritance.tests.test_destroy_cascade.rst index 80d5359c..3504fe65 100644 --- a/docs/api/sqlobject.inheritance.tests.test_destroy_cascade.rst +++ b/docs/api/sqlobject.inheritance.tests.test_destroy_cascade.rst @@ -5,3 +5,4 @@ sqlobject\.inheritance\.tests\.test\_destroy\_cascade module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.inheritance.tests.test_foreignKey.rst b/docs/api/sqlobject.inheritance.tests.test_foreignKey.rst index ebe96a5d..b6e28aa5 100644 --- a/docs/api/sqlobject.inheritance.tests.test_foreignKey.rst +++ b/docs/api/sqlobject.inheritance.tests.test_foreignKey.rst @@ -5,3 +5,4 @@ sqlobject\.inheritance\.tests\.test\_foreignKey module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.inheritance.tests.test_indexes.rst b/docs/api/sqlobject.inheritance.tests.test_indexes.rst index 75ef706c..bb2e3f7b 100644 --- a/docs/api/sqlobject.inheritance.tests.test_indexes.rst +++ b/docs/api/sqlobject.inheritance.tests.test_indexes.rst @@ -5,3 +5,4 @@ sqlobject\.inheritance\.tests\.test\_indexes module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,indexDefinitions diff --git a/docs/api/sqlobject.inheritance.tests.test_inheritance.rst b/docs/api/sqlobject.inheritance.tests.test_inheritance.rst index f3a19e87..0c186b0a 100644 --- a/docs/api/sqlobject.inheritance.tests.test_inheritance.rst +++ b/docs/api/sqlobject.inheritance.tests.test_inheritance.rst @@ -5,3 +5,4 @@ sqlobject\.inheritance\.tests\.test\_inheritance module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.inheritance.tests.test_inheritance_tree.rst b/docs/api/sqlobject.inheritance.tests.test_inheritance_tree.rst index 66feb6a6..b56d0474 100644 --- a/docs/api/sqlobject.inheritance.tests.test_inheritance_tree.rst +++ b/docs/api/sqlobject.inheritance.tests.test_inheritance_tree.rst @@ -5,3 +5,4 @@ sqlobject\.inheritance\.tests\.test\_inheritance\_tree module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.manager.command.rst b/docs/api/sqlobject.manager.command.rst index 7f768f9f..be4a0073 100644 --- a/docs/api/sqlobject.manager.command.rst +++ b/docs/api/sqlobject.manager.command.rst @@ -5,3 +5,4 @@ sqlobject\.manager\.command module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_ForeignKey.rst b/docs/api/sqlobject.tests.test_ForeignKey.rst index dd3528bb..1ca6c9d7 100644 --- a/docs/api/sqlobject.tests.test_ForeignKey.rst +++ b/docs/api/sqlobject.tests.test_ForeignKey.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_ForeignKey module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_NoneValuedResultItem.rst b/docs/api/sqlobject.tests.test_NoneValuedResultItem.rst index 498f61ff..bac55967 100644 --- a/docs/api/sqlobject.tests.test_NoneValuedResultItem.rst +++ b/docs/api/sqlobject.tests.test_NoneValuedResultItem.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_NoneValuedResultItem module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_SQLMultipleJoin.rst b/docs/api/sqlobject.tests.test_SQLMultipleJoin.rst index 9778df98..a7473fbd 100644 --- a/docs/api/sqlobject.tests.test_SQLMultipleJoin.rst +++ b/docs/api/sqlobject.tests.test_SQLMultipleJoin.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_SQLMultipleJoin module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_SQLRelatedJoin.rst b/docs/api/sqlobject.tests.test_SQLRelatedJoin.rst index 67606574..e1813011 100644 --- a/docs/api/sqlobject.tests.test_SQLRelatedJoin.rst +++ b/docs/api/sqlobject.tests.test_SQLRelatedJoin.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_SQLRelatedJoin module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_SingleJoin.rst b/docs/api/sqlobject.tests.test_SingleJoin.rst index 5ded2b3c..7f4179da 100644 --- a/docs/api/sqlobject.tests.test_SingleJoin.rst +++ b/docs/api/sqlobject.tests.test_SingleJoin.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_SingleJoin module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_aggregates.rst b/docs/api/sqlobject.tests.test_aggregates.rst index 451944f7..117aadde 100644 --- a/docs/api/sqlobject.tests.test_aggregates.rst +++ b/docs/api/sqlobject.tests.test_aggregates.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_aggregates module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_aliases.rst b/docs/api/sqlobject.tests.test_aliases.rst index e26df53c..d96edd13 100644 --- a/docs/api/sqlobject.tests.test_aliases.rst +++ b/docs/api/sqlobject.tests.test_aliases.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_aliases module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_asdict.rst b/docs/api/sqlobject.tests.test_asdict.rst index be828dc4..b316c7ef 100644 --- a/docs/api/sqlobject.tests.test_asdict.rst +++ b/docs/api/sqlobject.tests.test_asdict.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_asdict module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_auto.rst b/docs/api/sqlobject.tests.test_auto.rst index 328ee8e3..9c23284c 100644 --- a/docs/api/sqlobject.tests.test_auto.rst +++ b/docs/api/sqlobject.tests.test_auto.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_auto module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_basic.rst b/docs/api/sqlobject.tests.test_basic.rst index 9a16a4af..549436dd 100644 --- a/docs/api/sqlobject.tests.test_basic.rst +++ b/docs/api/sqlobject.tests.test_basic.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_basic module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_blob.rst b/docs/api/sqlobject.tests.test_blob.rst index bc958eba..798a66c0 100644 --- a/docs/api/sqlobject.tests.test_blob.rst +++ b/docs/api/sqlobject.tests.test_blob.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_blob module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_cache.rst b/docs/api/sqlobject.tests.test_cache.rst index 3d8e8328..3e01991e 100644 --- a/docs/api/sqlobject.tests.test_cache.rst +++ b/docs/api/sqlobject.tests.test_cache.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_cache module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_class_hash.rst b/docs/api/sqlobject.tests.test_class_hash.rst index 77e9a5f7..076937ab 100644 --- a/docs/api/sqlobject.tests.test_class_hash.rst +++ b/docs/api/sqlobject.tests.test_class_hash.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_class\_hash module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_columns_order.rst b/docs/api/sqlobject.tests.test_columns_order.rst index ced1883c..6187c32d 100644 --- a/docs/api/sqlobject.tests.test_columns_order.rst +++ b/docs/api/sqlobject.tests.test_columns_order.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_columns\_order module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_combining_joins.rst b/docs/api/sqlobject.tests.test_combining_joins.rst index 99cd4059..7b30db09 100644 --- a/docs/api/sqlobject.tests.test_combining_joins.rst +++ b/docs/api/sqlobject.tests.test_combining_joins.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_combining\_joins module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_complex_sorting.rst b/docs/api/sqlobject.tests.test_complex_sorting.rst index fdcd3eda..570fe23c 100644 --- a/docs/api/sqlobject.tests.test_complex_sorting.rst +++ b/docs/api/sqlobject.tests.test_complex_sorting.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_complex\_sorting module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_create_drop.rst b/docs/api/sqlobject.tests.test_create_drop.rst index 3ffe5565..d7845b9b 100644 --- a/docs/api/sqlobject.tests.test_create_drop.rst +++ b/docs/api/sqlobject.tests.test_create_drop.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_create\_drop module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_csvexport.rst b/docs/api/sqlobject.tests.test_csvexport.rst index 2e098d8b..2935f61d 100644 --- a/docs/api/sqlobject.tests.test_csvexport.rst +++ b/docs/api/sqlobject.tests.test_csvexport.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_csvexport module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_cyclic_reference.rst b/docs/api/sqlobject.tests.test_cyclic_reference.rst index b43d7bfb..1cb34572 100644 --- a/docs/api/sqlobject.tests.test_cyclic_reference.rst +++ b/docs/api/sqlobject.tests.test_cyclic_reference.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_cyclic\_reference module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_datetime.rst b/docs/api/sqlobject.tests.test_datetime.rst index d76a114b..b6b42358 100644 --- a/docs/api/sqlobject.tests.test_datetime.rst +++ b/docs/api/sqlobject.tests.test_datetime.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_datetime module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_decimal.rst b/docs/api/sqlobject.tests.test_decimal.rst index 224d2053..9e680e3a 100644 --- a/docs/api/sqlobject.tests.test_decimal.rst +++ b/docs/api/sqlobject.tests.test_decimal.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_decimal module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_delete.rst b/docs/api/sqlobject.tests.test_delete.rst index aa915722..8ee8eb76 100644 --- a/docs/api/sqlobject.tests.test_delete.rst +++ b/docs/api/sqlobject.tests.test_delete.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_delete module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_distinct.rst b/docs/api/sqlobject.tests.test_distinct.rst index 89cee6c2..5b2b72c6 100644 --- a/docs/api/sqlobject.tests.test_distinct.rst +++ b/docs/api/sqlobject.tests.test_distinct.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_distinct module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_enum.rst b/docs/api/sqlobject.tests.test_enum.rst index a02cfc2a..c5c5a0f1 100644 --- a/docs/api/sqlobject.tests.test_enum.rst +++ b/docs/api/sqlobject.tests.test_enum.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_enum module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_events.rst b/docs/api/sqlobject.tests.test_events.rst index fe270079..78c7b839 100644 --- a/docs/api/sqlobject.tests.test_events.rst +++ b/docs/api/sqlobject.tests.test_events.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_events module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_exceptions.rst b/docs/api/sqlobject.tests.test_exceptions.rst index 3352e3d4..45d09fd2 100644 --- a/docs/api/sqlobject.tests.test_exceptions.rst +++ b/docs/api/sqlobject.tests.test_exceptions.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_exceptions module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_expire.rst b/docs/api/sqlobject.tests.test_expire.rst index 6f568627..26b81f54 100644 --- a/docs/api/sqlobject.tests.test_expire.rst +++ b/docs/api/sqlobject.tests.test_expire.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_expire module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_groupBy.rst b/docs/api/sqlobject.tests.test_groupBy.rst index 9536c568..f823fd07 100644 --- a/docs/api/sqlobject.tests.test_groupBy.rst +++ b/docs/api/sqlobject.tests.test_groupBy.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_groupBy module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_identity.rst b/docs/api/sqlobject.tests.test_identity.rst index 3fc6961f..e154f2dc 100644 --- a/docs/api/sqlobject.tests.test_identity.rst +++ b/docs/api/sqlobject.tests.test_identity.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_identity module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_indexes.rst b/docs/api/sqlobject.tests.test_indexes.rst index 2ab389ca..cfe8e4bc 100644 --- a/docs/api/sqlobject.tests.test_indexes.rst +++ b/docs/api/sqlobject.tests.test_indexes.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_indexes module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns,indexDefinitions diff --git a/docs/api/sqlobject.tests.test_inheritance.rst b/docs/api/sqlobject.tests.test_inheritance.rst index c54693e3..369aa4df 100644 --- a/docs/api/sqlobject.tests.test_inheritance.rst +++ b/docs/api/sqlobject.tests.test_inheritance.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_inheritance module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_joins.rst b/docs/api/sqlobject.tests.test_joins.rst index a9f1c912..67ef3475 100644 --- a/docs/api/sqlobject.tests.test_joins.rst +++ b/docs/api/sqlobject.tests.test_joins.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_joins module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_joins_conditional.rst b/docs/api/sqlobject.tests.test_joins_conditional.rst index 41d2b748..8bc28896 100644 --- a/docs/api/sqlobject.tests.test_joins_conditional.rst +++ b/docs/api/sqlobject.tests.test_joins_conditional.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_joins\_conditional module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_jsonbcol.rst b/docs/api/sqlobject.tests.test_jsonbcol.rst index 9a20476f..48eba47e 100644 --- a/docs/api/sqlobject.tests.test_jsonbcol.rst +++ b/docs/api/sqlobject.tests.test_jsonbcol.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_jsonbcol module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_jsoncol.rst b/docs/api/sqlobject.tests.test_jsoncol.rst index 8bc266f6..18334b2a 100644 --- a/docs/api/sqlobject.tests.test_jsoncol.rst +++ b/docs/api/sqlobject.tests.test_jsoncol.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_jsoncol module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_lazy.rst b/docs/api/sqlobject.tests.test_lazy.rst index 1d23c93f..34df4cbb 100644 --- a/docs/api/sqlobject.tests.test_lazy.rst +++ b/docs/api/sqlobject.tests.test_lazy.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_lazy module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_new_joins.rst b/docs/api/sqlobject.tests.test_new_joins.rst index f6c56d64..5f751be7 100644 --- a/docs/api/sqlobject.tests.test_new_joins.rst +++ b/docs/api/sqlobject.tests.test_new_joins.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_new\_joins module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_paste.rst b/docs/api/sqlobject.tests.test_paste.rst index cf1b30d3..2a284741 100644 --- a/docs/api/sqlobject.tests.test_paste.rst +++ b/docs/api/sqlobject.tests.test_paste.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_paste module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_perConnection.rst b/docs/api/sqlobject.tests.test_perConnection.rst index 7534fca3..e4d43710 100644 --- a/docs/api/sqlobject.tests.test_perConnection.rst +++ b/docs/api/sqlobject.tests.test_perConnection.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_perConnection module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_pickle.rst b/docs/api/sqlobject.tests.test_pickle.rst index 0237ccd3..6e7cfe33 100644 --- a/docs/api/sqlobject.tests.test_pickle.rst +++ b/docs/api/sqlobject.tests.test_pickle.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_pickle module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_picklecol.rst b/docs/api/sqlobject.tests.test_picklecol.rst index ea3f1655..56db3212 100644 --- a/docs/api/sqlobject.tests.test_picklecol.rst +++ b/docs/api/sqlobject.tests.test_picklecol.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_picklecol module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_postgres.rst b/docs/api/sqlobject.tests.test_postgres.rst index 00a6b45c..374a7869 100644 --- a/docs/api/sqlobject.tests.test_postgres.rst +++ b/docs/api/sqlobject.tests.test_postgres.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_postgres module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_reparent_sqlmeta.rst b/docs/api/sqlobject.tests.test_reparent_sqlmeta.rst index e40f45bb..2af5978d 100644 --- a/docs/api/sqlobject.tests.test_reparent_sqlmeta.rst +++ b/docs/api/sqlobject.tests.test_reparent_sqlmeta.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_reparent\_sqlmeta module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_schema.rst b/docs/api/sqlobject.tests.test_schema.rst index f776e2aa..42f80883 100644 --- a/docs/api/sqlobject.tests.test_schema.rst +++ b/docs/api/sqlobject.tests.test_schema.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_schema module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_select.rst b/docs/api/sqlobject.tests.test_select.rst index 24c15796..0ba89a83 100644 --- a/docs/api/sqlobject.tests.test_select.rst +++ b/docs/api/sqlobject.tests.test_select.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_select module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_select_through.rst b/docs/api/sqlobject.tests.test_select_through.rst index 776becf4..8c5cdaa1 100644 --- a/docs/api/sqlobject.tests.test_select_through.rst +++ b/docs/api/sqlobject.tests.test_select_through.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_select\_through module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_setters.rst b/docs/api/sqlobject.tests.test_setters.rst index e94f949c..0bb4d136 100644 --- a/docs/api/sqlobject.tests.test_setters.rst +++ b/docs/api/sqlobject.tests.test_setters.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_setters module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_slice.rst b/docs/api/sqlobject.tests.test_slice.rst index 116130ec..f0559438 100644 --- a/docs/api/sqlobject.tests.test_slice.rst +++ b/docs/api/sqlobject.tests.test_slice.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_slice module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_sorting.rst b/docs/api/sqlobject.tests.test_sorting.rst index 2a3cf121..04e1510a 100644 --- a/docs/api/sqlobject.tests.test_sorting.rst +++ b/docs/api/sqlobject.tests.test_sorting.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_sorting module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_sqlbuilder.rst b/docs/api/sqlobject.tests.test_sqlbuilder.rst index 02a39b3e..e70be201 100644 --- a/docs/api/sqlobject.tests.test_sqlbuilder.rst +++ b/docs/api/sqlobject.tests.test_sqlbuilder.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_sqlbuilder module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_sqlbuilder_dbspecific.rst b/docs/api/sqlobject.tests.test_sqlbuilder_dbspecific.rst index b71c441d..b3291a43 100644 --- a/docs/api/sqlobject.tests.test_sqlbuilder_dbspecific.rst +++ b/docs/api/sqlobject.tests.test_sqlbuilder_dbspecific.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_sqlbuilder\_dbspecific module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_sqlbuilder_joins_instances.rst b/docs/api/sqlobject.tests.test_sqlbuilder_joins_instances.rst index c6f2b4d5..d92359b0 100644 --- a/docs/api/sqlobject.tests.test_sqlbuilder_joins_instances.rst +++ b/docs/api/sqlobject.tests.test_sqlbuilder_joins_instances.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_sqlbuilder\_joins\_instances module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_sqlite.rst b/docs/api/sqlobject.tests.test_sqlite.rst index 3eedfab3..1da10c03 100644 --- a/docs/api/sqlobject.tests.test_sqlite.rst +++ b/docs/api/sqlobject.tests.test_sqlite.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_sqlite module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_sqlobject_admin.rst b/docs/api/sqlobject.tests.test_sqlobject_admin.rst index b062e12f..d76ebc52 100644 --- a/docs/api/sqlobject.tests.test_sqlobject_admin.rst +++ b/docs/api/sqlobject.tests.test_sqlobject_admin.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_sqlobject\_admin module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_string_id.rst b/docs/api/sqlobject.tests.test_string_id.rst index 217ddd01..fbadd05c 100644 --- a/docs/api/sqlobject.tests.test_string_id.rst +++ b/docs/api/sqlobject.tests.test_string_id.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_string\_id module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_style.rst b/docs/api/sqlobject.tests.test_style.rst index 1dc12bd3..04722741 100644 --- a/docs/api/sqlobject.tests.test_style.rst +++ b/docs/api/sqlobject.tests.test_style.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_style module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_subqueries.rst b/docs/api/sqlobject.tests.test_subqueries.rst index 83ffaed0..59b034be 100644 --- a/docs/api/sqlobject.tests.test_subqueries.rst +++ b/docs/api/sqlobject.tests.test_subqueries.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_subqueries module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_transactions.rst b/docs/api/sqlobject.tests.test_transactions.rst index 355d49c8..940636ca 100644 --- a/docs/api/sqlobject.tests.test_transactions.rst +++ b/docs/api/sqlobject.tests.test_transactions.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_transactions module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_unicode.rst b/docs/api/sqlobject.tests.test_unicode.rst index 1e55d7c7..cb48d1ad 100644 --- a/docs/api/sqlobject.tests.test_unicode.rst +++ b/docs/api/sqlobject.tests.test_unicode.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_unicode module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_uuidcol.rst b/docs/api/sqlobject.tests.test_uuidcol.rst index 3d587e2a..4ca71612 100644 --- a/docs/api/sqlobject.tests.test_uuidcol.rst +++ b/docs/api/sqlobject.tests.test_uuidcol.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_uuidcol module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_validation.rst b/docs/api/sqlobject.tests.test_validation.rst index 430cd6ef..98ccedec 100644 --- a/docs/api/sqlobject.tests.test_validation.rst +++ b/docs/api/sqlobject.tests.test_validation.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_validation module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_views.rst b/docs/api/sqlobject.tests.test_views.rst index cb1cddbc..291d57c7 100644 --- a/docs/api/sqlobject.tests.test_views.rst +++ b/docs/api/sqlobject.tests.test_views.rst @@ -5,3 +5,4 @@ sqlobject\.tests\.test\_views module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.versioning.test.test_version.rst b/docs/api/sqlobject.versioning.test.test_version.rst index 3a40a564..6ddf7722 100644 --- a/docs/api/sqlobject.versioning.test.test_version.rst +++ b/docs/api/sqlobject.versioning.test.test_version.rst @@ -5,3 +5,4 @@ sqlobject\.versioning\.test\.test\_version module :members: :undoc-members: :show-inheritance: + :exclude-members: columnDefinitions,columnList,columns From e4cad6d3ca0dc2010853f78f4695b3575715129d Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 25 Jan 2019 20:20:47 +0300 Subject: [PATCH 187/509] Fix(mysql): Fix unicode errors in mysqlclient --- sqlobject/mysql/mysqlconnection.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index 310b21d0..2d7afa58 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -229,7 +229,7 @@ def _executeRetry(self, conn, cursor, query): self.printDebug(conn, query, 'QueryR') dbEncoding = self.dbEncoding if dbEncoding and not isinstance(query, bytes) and ( - self.driver in ('connector', 'oursql')): + self.driver in ('mysqldb', 'connector', 'oursql')): query = query.encode(dbEncoding, 'surrogateescape') # When a server connection is lost and a query is attempted, most of # the time the query will raise a SERVER_LOST exception, then at the From 61490a3548546c0b55a4facc12b57cf51cf2c507 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 25 Jan 2019 20:22:10 +0300 Subject: [PATCH 188/509] Tests(mysqlclient): Fix "index is too long" --- sqlobject/inheritance/tests/test_asdict.py | 2 +- sqlobject/inheritance/tests/test_deep_inheritance.py | 2 +- sqlobject/inheritance/tests/test_inheritance.py | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sqlobject/inheritance/tests/test_asdict.py b/sqlobject/inheritance/tests/test_asdict.py index 5129ac27..95d6b818 100644 --- a/sqlobject/inheritance/tests/test_asdict.py +++ b/sqlobject/inheritance/tests/test_asdict.py @@ -9,7 +9,7 @@ class InheritablePersonAD(InheritableSQLObject): firstName = StringCol() - lastName = StringCol(alternateID=True, length=255) + lastName = StringCol(alternateID=True, length=100) class ManagerAD(InheritablePersonAD): diff --git a/sqlobject/inheritance/tests/test_deep_inheritance.py b/sqlobject/inheritance/tests/test_deep_inheritance.py index 411beb22..1ef4d36f 100644 --- a/sqlobject/inheritance/tests/test_deep_inheritance.py +++ b/sqlobject/inheritance/tests/test_deep_inheritance.py @@ -10,7 +10,7 @@ class DIPerson(InheritableSQLObject): firstName = StringCol(length=100) - lastName = StringCol(alternateID=True, length=255) + lastName = StringCol(alternateID=True, length=100) manager = ForeignKey("DIManager", default=None) diff --git a/sqlobject/inheritance/tests/test_inheritance.py b/sqlobject/inheritance/tests/test_inheritance.py index 2f5930ed..cc26c8f5 100644 --- a/sqlobject/inheritance/tests/test_inheritance.py +++ b/sqlobject/inheritance/tests/test_inheritance.py @@ -9,13 +9,13 @@ class InheritablePerson(InheritableSQLObject): - firstName = StringCol() - lastName = StringCol(alternateID=True, length=255) + firstName = StringCol(length=100) + lastName = StringCol(alternateID=True, length=100) class Employee(InheritablePerson): _inheritable = False - so_position = StringCol() + so_position = StringCol(length=100) def setup(): From 10b0670f7a03cbcbac8a5e095c67209ace16629c Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 28 Jan 2019 06:16:31 +0300 Subject: [PATCH 189/509] Update news [skip ci] --- ANNOUNCE.rst | 2 +- docs/News.rst | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 2f549674..d0fdf39e 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -22,7 +22,7 @@ I'm pleased to announce version 3.8.1, the first bugfix release of branch What's new in SQLObject ======================= -Contributors for this release are +Contributor for this release is Neil Muller. For a more complete list, please see the news: http://sqlobject.org/News.html diff --git a/docs/News.rst b/docs/News.rst index 117c0b4a..96aa176f 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,23 @@ News SQLObject 3.8.0 (master) ======================== +Bug fixes +--------- + +* Fixed a unicode problem in the latest mysqlclient. + +Documentation +------------- + +* Exclude sqlmeta members from some of the api docs. + The inclusion of of these sqlmeta members in these files breaks + reproducible builds. + +Development +----------- + +* Source code was made flake8-clean using the latest flake8. + SQLObject 3.7.0 =============== From 57eacb3965939a1742b87143e89cb94f50726874 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 28 Jan 2019 06:22:04 +0300 Subject: [PATCH 190/509] CI(appveyor): Remove pyodbc tests --- appveyor.yml | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index c42d7387..c41ee60f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -53,16 +53,6 @@ environment: PYTHON_VERSION: "3.6" PYTHON_HOME: "C:\\Python36-x64" db: mysql - - TOXENV: "py27-mysql-pyodbc-w32" - PYTHON_ARCH: "64" - PYTHON_VERSION: "2.7" - PYTHON_HOME: "C:\\Python27-x64" - db: mysql - - TOXENV: "py36-mysql-pyodbc-w32" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.6" - PYTHON_HOME: "C:\\Python36-x64" - db: mysql - TOXENV: "py27-postgres-psycopg-w32" PYTHON_ARCH: "32" PYTHON_VERSION: "2.7" @@ -103,16 +93,6 @@ environment: PYTHON_VERSION: "3.6" PYTHON_HOME: "C:\\Python36-x64" db: postgresql - - TOXENV: "py27-postgres-pyodbc-w32" - PYTHON_ARCH: "64" - PYTHON_VERSION: "2.7" - PYTHON_HOME: "C:\\Python27-x64" - db: postgresql - - TOXENV: "py36-postgres-pyodbc-w32" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.6" - PYTHON_HOME: "C:\\Python36-x64" - db: postgresql - TOXENV: "py27-sqlite-w32" PYTHON_ARCH: "32" PYTHON_VERSION: "2.7" @@ -131,12 +111,6 @@ environment: PYTHON_HOME: "C:\\Python36-x64" matrix: - allow_failures: - - TOXENV: "py27-mysql-pyodbc-w32" - - TOXENV: "py36-mysql-pyodbc-w32" - - TOXENV: "py27-postgres-pyodbc-w32" - - TOXENV: "py36-postgres-pyodbc-w32" - fast_finish: true install: From bd36a6b5eac5fe99a25cce859f42c50e18f941b4 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 28 Jan 2019 06:32:40 +0300 Subject: [PATCH 191/509] CI(travis): Limit the number of FireBird tests Run FireBird tests with Python 2.7 and 3.6. --- .travis.yml | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/.travis.yml b/.travis.yml index 32ab10d9..f4c59247 100644 --- a/.travis.yml +++ b/.travis.yml @@ -110,29 +110,17 @@ matrix: env: TOXENV=py34-flake8 - python: "2.7" env: TOXENV=py27-firebird-fdb - - python: "3.4" - env: TOXENV=py34-firebird-fdb - - python: "3.5" - env: TOXENV=py35-firebird-fdb - python: "3.6" env: TOXENV=py36-firebird-fdb - python: "2.7" env: TOXENV=py27-firebirdsql - - python: "3.4" - env: TOXENV=py34-firebirdsql - - python: "3.5" - env: TOXENV=py35-firebirdsql - python: "3.6" env: TOXENV=py36-firebirdsql allow_failures: - env: TOXENV=py27-firebird-fdb - - env: TOXENV=py34-firebird-fdb - - env: TOXENV=py35-firebird-fdb - env: TOXENV=py36-firebird-fdb - env: TOXENV=py27-firebirdsql - - env: TOXENV=py34-firebirdsql - - env: TOXENV=py35-firebirdsql - env: TOXENV=py36-firebirdsql fast_finish: true From 67690eb2498a912b3836284653f0ae5e55011dff Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 28 Jan 2019 06:40:26 +0300 Subject: [PATCH 192/509] CI: Run tests with Python 3.7 --- .travis.yml | 36 ++++++++++++++++++++++++++++++++++-- appveyor.yml | 43 +++++++++++++++++++++++++++++++++++++++++++ docs/News.rst | 5 +++++ tox.ini | 4 ++-- 4 files changed, 84 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index f4c59247..d78da315 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,6 +14,10 @@ python: cache: pip +services: + - mysql + - postgres + addons: apt: packages: @@ -34,6 +38,9 @@ matrix: env: TOXENV=py35-mysqlclient - python: "3.6" env: TOXENV=py36-mysqlclient + - python: "3.7" + dist: xenial + env: TOXENV=py37-mysqlclient - python: "2.7" env: TOXENV=py27-mysql-connector - python: "3.4" @@ -42,6 +49,9 @@ matrix: env: TOXENV=py35-mysql-connector - python: "3.6" env: TOXENV=py36-mysql-connector + - python: "3.7" + dist: xenial + env: TOXENV=py37-mysql-connector - python: "2.7" env: TOXENV=py27-mysql-oursql - python: "3.4" @@ -58,6 +68,9 @@ matrix: env: TOXENV=py35-pymysql - python: "3.6" env: TOXENV=py36-pymysql + - python: "3.7" + dist: xenial + env: TOXENV=py37-pymysql - python: "2.7" env: TOXENV=py27-postgres-psycopg - python: "3.4" @@ -66,6 +79,9 @@ matrix: env: TOXENV=py35-postgres-psycopg - python: "3.6" env: TOXENV=py36-postgres-psycopg + - python: "3.7" + dist: xenial + env: TOXENV=py37-postgres-psycopg - python: "2.7" env: TOXENV=py27-postgres-pygresql - python: "3.4" @@ -74,12 +90,18 @@ matrix: env: TOXENV=py35-postgres-pygresql - python: "3.6" env: TOXENV=py36-postgres-pygresql + - python: "3.7" + dist: xenial + env: TOXENV=py37-postgres-pygresql - python: "3.4" env: TOXENV=py34-pypostgresql - python: "3.5" env: TOXENV=py35-pypostgresql - python: "3.6" env: TOXENV=py36-pypostgresql + - python: "3.7" + dist: xenial + env: TOXENV=py37-pypostgresql - python: "2.7" env: TOXENV=py27-postgres-pg8000 - python: "3.4" @@ -88,6 +110,9 @@ matrix: env: TOXENV=py35-postgres-pg8000 - python: "3.6" env: TOXENV=py36-postgres-pg8000 + - python: "3.7" + dist: xenial + env: TOXENV=py37-postgres-pg8000 - python: "2.7" env: TOXENV=py27-sqlite - python: "3.4" @@ -96,6 +121,9 @@ matrix: env: TOXENV=py35-sqlite - python: "3.6" env: TOXENV=py36-sqlite + - python: "3.7" + dist: xenial + env: TOXENV=py37-sqlite - python: "2.7" env: TOXENV=py27-sqlite-memory - python: "3.4" @@ -104,10 +132,14 @@ matrix: env: TOXENV=py35-sqlite-memory - python: "3.6" env: TOXENV=py36-sqlite-memory + - python: "3.7" + dist: xenial + env: TOXENV=py37-sqlite-memory - python: "2.7" env: TOXENV=py27-flake8 - - python: "3.4" - env: TOXENV=py34-flake8 + - python: "3.7" + dist: xenial + env: TOXENV=py37-flake8 - python: "2.7" env: TOXENV=py27-firebird-fdb - python: "3.6" diff --git a/appveyor.yml b/appveyor.yml index c41ee60f..1e26d057 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -43,6 +43,11 @@ environment: PYTHON_VERSION: "3.6" PYTHON_HOME: "C:\\Python36-x64" db: mysql + - TOXENV: "py37-mysql-connector-w32" + PYTHON_ARCH: "64" + PYTHON_VERSION: "3.7" + PYTHON_HOME: "C:\\Python37-x64" + db: mysql - TOXENV: "py27-pymysql-w32" PYTHON_ARCH: "32" PYTHON_VERSION: "2.7" @@ -53,6 +58,11 @@ environment: PYTHON_VERSION: "3.6" PYTHON_HOME: "C:\\Python36-x64" db: mysql + - TOXENV: "py37-pymysql-w32" + PYTHON_ARCH: "64" + PYTHON_VERSION: "3.7" + PYTHON_HOME: "C:\\Python37-x64" + db: mysql - TOXENV: "py27-postgres-psycopg-w32" PYTHON_ARCH: "32" PYTHON_VERSION: "2.7" @@ -63,6 +73,11 @@ environment: PYTHON_VERSION: "3.6" PYTHON_HOME: "C:\\Python36-x64" db: postgresql + - TOXENV: "py37-postgres-psycopg-w32" + PYTHON_ARCH: "64" + PYTHON_VERSION: "3.7" + PYTHON_HOME: "C:\\Python37-x64" + db: postgresql - TOXENV: "py27-postgres-pygresql-w32" PYTHON_ARCH: "64" PYTHON_VERSION: "2.7" @@ -73,16 +88,31 @@ environment: PYTHON_VERSION: "3.6" PYTHON_HOME: "C:\\Python36-x64" db: postgresql + - TOXENV: "py37-postgres-pygresql-w32" + PYTHON_ARCH: "64" + PYTHON_VERSION: "3.7" + PYTHON_HOME: "C:\\Python37-x64" + db: postgresql - TOXENV: "py36-pypostgresql-w32" PYTHON_ARCH: "32" PYTHON_VERSION: "3.6" PYTHON_HOME: "C:\\Python36" db: postgresql + - TOXENV: "py37-pypostgresql-w32" + PYTHON_ARCH: "32" + PYTHON_VERSION: "3.7" + PYTHON_HOME: "C:\\Python37" + db: postgresql - TOXENV: "py36-pypostgresql-w32" PYTHON_ARCH: "64" PYTHON_VERSION: "3.6" PYTHON_HOME: "C:\\Python36-x64" db: postgresql + - TOXENV: "py37-pypostgresql-w32" + PYTHON_ARCH: "64" + PYTHON_VERSION: "3.7" + PYTHON_HOME: "C:\\Python37-x64" + db: postgresql - TOXENV: "py27-postgres-pg8000-w32" PYTHON_ARCH: "32" PYTHON_VERSION: "2.7" @@ -93,6 +123,11 @@ environment: PYTHON_VERSION: "3.6" PYTHON_HOME: "C:\\Python36-x64" db: postgresql + - TOXENV: "py37-postgres-pg8000-w32" + PYTHON_ARCH: "64" + PYTHON_VERSION: "3.7" + PYTHON_HOME: "C:\\Python37-x64" + db: postgresql - TOXENV: "py27-sqlite-w32" PYTHON_ARCH: "32" PYTHON_VERSION: "2.7" @@ -101,6 +136,10 @@ environment: PYTHON_ARCH: "64" PYTHON_VERSION: "3.6" PYTHON_HOME: "C:\\Python36-x64" + - TOXENV: "py37-sqlite-w32" + PYTHON_ARCH: "64" + PYTHON_VERSION: "3.7" + PYTHON_HOME: "C:\\Python37-x64" - TOXENV: "py27-sqlite-memory-w32" PYTHON_ARCH: "32" PYTHON_VERSION: "2.7" @@ -109,6 +148,10 @@ environment: PYTHON_ARCH: "64" PYTHON_VERSION: "3.6" PYTHON_HOME: "C:\\Python36-x64" + - TOXENV: "py37-sqlite-memory-w32" + PYTHON_ARCH: "64" + PYTHON_VERSION: "3.7" + PYTHON_HOME: "C:\\Python37-x64" matrix: fast_finish: true diff --git a/docs/News.rst b/docs/News.rst index 96aa176f..7d1d9466 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -25,6 +25,11 @@ Development * Source code was made flake8-clean using the latest flake8. +CI +-- + +* Run tests with Python 3.7. + SQLObject 3.7.0 =============== diff --git a/tox.ini b/tox.ini index 443c0892..6786932e 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 2.0 -envlist = py{27,34,35,36,37}-sqlite{,-memory},py{27,34}-flake8 +envlist = py{27,34,35,36,37}-sqlite{,-memory},py{27,37}-flake8 # Base test environment settings [testenv] @@ -429,7 +429,7 @@ commands = {[testenv]commands} flake8 . -[testenv:py34-flake8] +[testenv:py37-flake8] changedir = ./ deps = flake8 From 253f4f987a212e578ee7f3ca89a0eb295fdc5c5a Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 28 Jan 2019 22:23:32 +0300 Subject: [PATCH 193/509] Tests(tox): Require tox < 3.1 to avoid basepython conflicts --- appveyor.yml | 2 +- devscripts/requirements/requirements_tox.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 1e26d057..8530db41 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -163,7 +163,7 @@ install: - "python --version" - "python -c \"import struct; print(struct.calcsize('P') * 8)\"" - "python -m pip install --upgrade pip setuptools" - - "pip install --upgrade tox ppu" + - "pip install --upgrade \"tox < 3.1\" ppu" - "pip --version" # List ODBC drivers - ps: Get-OdbcDriver -Platform 32-bit | Select-Object -ExpandProperty Name diff --git a/devscripts/requirements/requirements_tox.txt b/devscripts/requirements/requirements_tox.txt index ff4ecb65..8c9b6ed3 100644 --- a/devscripts/requirements/requirements_tox.txt +++ b/devscripts/requirements/requirements_tox.txt @@ -1 +1 @@ -tox >= 2.0 +tox >= 2.0, < 3.1 From e1f18e16930cf54fe782eee94be7fc4ea589bdba Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 1 Feb 2019 02:02:27 +0300 Subject: [PATCH 194/509] CI(AppVeyor): Work around a strange problem with Py3.7 Work around a very strange problem with Python 3.7 at AppVeyor by copying correct validators.py to formencode. --- setup.cfg | 2 +- tox.ini | 53 +- validators.py | 3089 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 3130 insertions(+), 14 deletions(-) create mode 100644 validators.py diff --git a/setup.cfg b/setup.cfg index 461bc50f..af28274e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -10,7 +10,7 @@ tag_date = 0 tag_svn_revision = 0 [flake8] -exclude = .git,.tox,docs/europython/*.py +exclude = .git,.tox,docs/europython/*.py,validators.py # E305: expected 2 blank lines after class or function definition, found 1 # W503 line break before binary operator # W605 invalid escape sequence diff --git a/tox.ini b/tox.ini index 6786932e..0af7ecbe 100644 --- a/tox.ini +++ b/tox.ini @@ -36,6 +36,7 @@ passenv = CI TRAVIS TRAVIS_* APPVEYOR DISTUTILS_USE_SDK MSSdk INCLUDE LIB PGPASS # Don't fail or warn on uninstalled commands platform = linux whitelist_externals = + cmd mysql createdb dropdb @@ -465,7 +466,9 @@ commands = {[mssql-pyodbc-w32]commands} [testenv:py37-mssql-pyodbc-w32] platform = win32 -commands = {[mssql-pyodbc-w32]commands} +commands = + cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" + {[mssql-pyodbc-w32]commands} [mysql-connector-w32] platform = win32 @@ -494,7 +497,9 @@ commands = {[mysql-connector-w32]commands} [testenv:py37-mysql-connector-w32] platform = win32 -commands = {[mysql-connector-w32]commands} +commands = + cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" + {[mysql-connector-w32]commands} [pymysql-w32] platform = win32 @@ -523,7 +528,9 @@ commands = {[pymysql-w32]commands} [testenv:py37-pymysql-w32] platform = win32 -commands = {[pymysql-w32]commands} +commands = + cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" + {[pymysql-w32]commands} [mysql-pyodbc-w32] platform = win32 @@ -553,7 +560,9 @@ commands = {[mysql-pyodbc-w32]commands} [testenv:py37-mysql-pyodbc-w32] platform = win32 -commands = {[mysql-pyodbc-w32]commands} +commands = + cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" + {[mysql-pyodbc-w32]commands} [mysql-pypyodbc-w32] platform = win32 @@ -583,7 +592,9 @@ commands = {[mysql-pypyodbc-w32]commands} [testenv:py37-mysql-pypyodbc-w32] platform = win32 -commands = {[mysql-pypyodbc-w32]commands} +commands = + cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" + {[mysql-pypyodbc-w32]commands} [psycopg-w32] platform = win32 @@ -612,7 +623,9 @@ commands = {[psycopg-w32]commands} [testenv:py37-postgres-psycopg-w32] platform = win32 -commands = {[psycopg-w32]commands} +commands = + cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" + {[psycopg-w32]commands} [pygresql-w32] platform = win32 @@ -641,7 +654,9 @@ commands = {[pygresql-w32]commands} [testenv:py37-postgres-pygresql-w32] platform = win32 -commands = {[pygresql-w32]commands} +commands = + cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" + {[pygresql-w32]commands} [pypostgresql-w32] platform = win32 @@ -666,7 +681,9 @@ commands = {[pypostgresql-w32]commands} [testenv:py37-pypostgresql-w32] platform = win32 -commands = {[pypostgresql-w32]commands} +commands = + cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" + {[pypostgresql-w32]commands} [pg8000-w32] platform = win32 @@ -695,7 +712,9 @@ commands = {[pg8000-w32]commands} [testenv:py37-postgres-pg8000-w32] platform = win32 -commands = {[pg8000-w32]commands} +commands = + cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" + {[pg8000-w32]commands} [postgres-pyodbc-w32] platform = win32 @@ -725,7 +744,9 @@ commands = {[postgres-pyodbc-w32]commands} [testenv:py37-postgres-pyodbc-w32] platform = win32 -commands = {[postgres-pyodbc-w32]commands} +commands = + cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" + {[postgres-pyodbc-w32]commands} [postgres-pypyodbc-w32] platform = win32 @@ -755,7 +776,9 @@ commands = {[postgres-pypyodbc-w32]commands} [testenv:py37-postgres-pypyodbc-w32] platform = win32 -commands = {[postgres-pypyodbc-w32]commands} +commands = + cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" + {[postgres-pypyodbc-w32]commands} [sqlite-w32] platform = win32 @@ -781,7 +804,9 @@ commands = {[sqlite-w32]commands} [testenv:py37-sqlite-w32] platform = win32 -commands = {[sqlite-w32]commands} +commands = + cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" + {[sqlite-w32]commands} [sqlite-memory-w32] platform = win32 @@ -807,4 +832,6 @@ commands = {[sqlite-memory-w32]commands} [testenv:py37-sqlite-memory-w32] platform = win32 -commands = {[sqlite-memory-w32]commands} +commands = + cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" + {[sqlite-memory-w32]commands} diff --git a/validators.py b/validators.py new file mode 100644 index 00000000..233d5dd5 --- /dev/null +++ b/validators.py @@ -0,0 +1,3089 @@ +## FormEncode, a Form processor +## Copyright (C) 2003, Ian Bicking + +""" +Validator/Converters for use with FormEncode. +""" + +import cgi +import locale +import re +import warnings +from encodings import idna + +try: # import dnspython + import dns.resolver + import dns.exception +except (IOError, ImportError): + have_dns = False +else: + have_dns = True + + +# These are only imported when needed +httplib = None +random = None +sha1 = None +socket = None +urlparse = None + +from .api import (FancyValidator, Identity, Invalid, NoDefault, Validator, + deprecation_warning, is_empty) + +assert Identity and Invalid and NoDefault # silence unused import warnings + +# Dummy i18n translation function, nothing is translated here. +# Instead this is actually done in api.message. +# The surrounding _('string') of the strings is only for extracting +# the strings automatically. +# If you run pygettext with this source comment this function out temporarily. +_ = lambda s: s + + +############################################################ +## Utility methods +############################################################ + +# These all deal with accepting both datetime and mxDateTime modules and types +datetime_module = None +mxDateTime_module = None + + +def import_datetime(module_type): + global datetime_module, mxDateTime_module + module_type = module_type.lower() if module_type else 'datetime' + if module_type == 'datetime': + if datetime_module is None: + import datetime as datetime_module + return datetime_module + elif module_type == 'mxdatetime': + if mxDateTime_module is None: + from mx import DateTime as mxDateTime_module + return mxDateTime_module + else: + raise ImportError('Invalid datetime module %r' % module_type) + + +def datetime_now(module): + if module.__name__ == 'datetime': + return module.datetime.now() + else: + return module.now() + + +def datetime_makedate(module, year, month, day): + if module.__name__ == 'datetime': + return module.date(year, month, day) + else: + try: + return module.DateTime(year, month, day) + except module.RangeError as e: + raise ValueError(str(e)) + + +def datetime_time(module): + if module.__name__ == 'datetime': + return module.time + else: + return module.Time + + +def datetime_isotime(module): + if module.__name__ == 'datetime': + return module.time.isoformat + else: + return module.ISO.Time + + +############################################################ +## Wrapper Validators +############################################################ + +class ConfirmType(FancyValidator): + """ + Confirms that the input/output is of the proper type. + + Uses the parameters: + + subclass: + The class or a tuple of classes; the item must be an instance + of the class or a subclass. + type: + A type or tuple of types (or classes); the item must be of + the exact class or type. Subclasses are not allowed. + + Examples:: + + >>> cint = ConfirmType(subclass=int) + >>> cint.to_python(True) + True + >>> cint.to_python('1') + Traceback (most recent call last): + ... + Invalid: '1' is not a subclass of + >>> cintfloat = ConfirmType(subclass=(float, int)) + >>> cintfloat.to_python(1.0), cintfloat.from_python(1.0) + (1.0, 1.0) + >>> cintfloat.to_python(1), cintfloat.from_python(1) + (1, 1) + >>> cintfloat.to_python(None) + Traceback (most recent call last): + ... + Invalid: None is not a subclass of one of the types , + >>> cint2 = ConfirmType(type=int) + >>> cint2(accept_python=False).from_python(True) + Traceback (most recent call last): + ... + Invalid: True must be of the type + """ + + accept_iterator = True + + subclass = None + type = None + + messages = dict( + subclass=_('%(object)r is not a subclass of %(subclass)s'), + inSubclass=_('%(object)r is not a subclass of one of the types %(subclassList)s'), + inType=_('%(object)r must be one of the types %(typeList)s'), + type=_('%(object)r must be of the type %(type)s')) + + def __init__(self, *args, **kw): + FancyValidator.__init__(self, *args, **kw) + if self.subclass: + if isinstance(self.subclass, list): + self.subclass = tuple(self.subclass) + elif not isinstance(self.subclass, tuple): + self.subclass = (self.subclass,) + self._validate_python = self.confirm_subclass + if self.type: + if isinstance(self.type, list): + self.type = tuple(self.type) + elif not isinstance(self.type, tuple): + self.type = (self.type,) + self._validate_python = self.confirm_type + + def confirm_subclass(self, value, state): + if not isinstance(value, self.subclass): + if len(self.subclass) == 1: + msg = self.message('subclass', state, object=value, + subclass=self.subclass[0]) + else: + subclass_list = ', '.join(map(str, self.subclass)) + msg = self.message('inSubclass', state, object=value, + subclassList=subclass_list) + raise Invalid(msg, value, state) + + def confirm_type(self, value, state): + for t in self.type: + if type(value) is t: + break + else: + if len(self.type) == 1: + msg = self.message('type', state, object=value, + type=self.type[0]) + else: + msg = self.message('inType', state, object=value, + typeList=', '.join(map(str, self.type))) + raise Invalid(msg, value, state) + return value + + def is_empty(self, value): + return False + + +class Wrapper(FancyValidator): + """ + Used to convert functions to validator/converters. + + You can give a simple function for `_convert_to_python`, + `_convert_from_python`, `_validate_python` or `_validate_other`. + If that function raises an exception, the value is considered invalid. + Whatever value the function returns is considered the converted value. + + Unlike validators, the `state` argument is not used. Functions + like `int` can be used here, that take a single argument. + + Note that as Wrapper will generate a FancyValidator, empty + values (those who pass ``FancyValidator.is_empty)`` will return ``None``. + To override this behavior you can use ``Wrapper(empty_value=callable)``. + For example passing ``Wrapper(empty_value=lambda val: val)`` will return + the value itself when is considered empty. + + Examples:: + + >>> def downcase(v): + ... return v.lower() + >>> wrap = Wrapper(convert_to_python=downcase) + >>> wrap.to_python('This') + 'this' + >>> wrap.from_python('This') + 'This' + >>> wrap.to_python('') is None + True + >>> wrap2 = Wrapper( + ... convert_from_python=downcase, empty_value=lambda value: value) + >>> wrap2.from_python('This') + 'this' + >>> wrap2.to_python('') + '' + >>> wrap2.from_python(1) + Traceback (most recent call last): + ... + Invalid: 'int' object has no attribute 'lower' + >>> wrap3 = Wrapper(validate_python=int) + >>> wrap3.to_python('1') + '1' + >>> wrap3.to_python('a') # doctest: +ELLIPSIS + Traceback (most recent call last): + ... + Invalid: invalid literal for int()... + """ + + func_convert_to_python = None + func_convert_from_python = None + func_validate_python = None + func_validate_other = None + + _deprecated_methods = ( + ('func_to_python', 'func_convert_to_python'), + ('func_from_python', 'func_convert_from_python')) + + def __init__(self, *args, **kw): + # allow old method names as parameters + if 'to_python' in kw and 'convert_to_python' not in kw: + kw['convert_to_python'] = kw.pop('to_python') + if 'from_python' in kw and 'convert_from_python' not in kw: + kw['convert_from_python'] = kw.pop('from_python') + for n in ('convert_to_python', 'convert_from_python', + 'validate_python', 'validate_other'): + if n in kw: + kw['func_%s' % n] = kw.pop(n) + FancyValidator.__init__(self, *args, **kw) + self._convert_to_python = self.wrap(self.func_convert_to_python) + self._convert_from_python = self.wrap(self.func_convert_from_python) + self._validate_python = self.wrap(self.func_validate_python) + self._validate_other = self.wrap(self.func_validate_other) + + def wrap(self, func): + if not func: + return None + + def result(value, state, func=func): + try: + return func(value) + except Exception as e: + raise Invalid(str(e), value, state) + + return result + + +class Constant(FancyValidator): + """ + This converter converts everything to the same thing. + + I.e., you pass in the constant value when initializing, then all + values get converted to that constant value. + + This is only really useful for funny situations, like:: + + # Any evaluates sub validators in reverse order for to_python + fromEmailValidator = Any( + Constant('unknown@localhost'), + Email()) + + In this case, the if the email is not valid + ``'unknown@localhost'`` will be used instead. Of course, you + could use ``if_invalid`` instead. + + Examples:: + + >>> Constant('X').to_python('y') + 'X' + """ + + __unpackargs__ = ('value',) + + def _convert_to_python(self, value, state): + return self.value + + _convert_from_python = _convert_to_python + + +############################################################ +## Normal validators +############################################################ + +class MaxLength(FancyValidator): + """ + Invalid if the value is longer than `maxLength`. Uses len(), + so it can work for strings, lists, or anything with length. + + Examples:: + + >>> max5 = MaxLength(5) + >>> max5.to_python('12345') + '12345' + >>> max5.from_python('12345') + '12345' + >>> max5.to_python('123456') + Traceback (most recent call last): + ... + Invalid: Enter a value less than 5 characters long + >>> max5(accept_python=False).from_python('123456') + Traceback (most recent call last): + ... + Invalid: Enter a value less than 5 characters long + >>> max5.to_python([1, 2, 3]) + [1, 2, 3] + >>> max5.to_python([1, 2, 3, 4, 5, 6]) + Traceback (most recent call last): + ... + Invalid: Enter a value less than 5 characters long + >>> max5.to_python(5) + Traceback (most recent call last): + ... + Invalid: Invalid value (value with length expected) + """ + + __unpackargs__ = ('maxLength',) + + messages = dict( + tooLong=_('Enter a value less than %(maxLength)i characters long'), + invalid=_('Invalid value (value with length expected)')) + + def _validate_python(self, value, state): + try: + if value and len(value) > self.maxLength: + raise Invalid( + self.message('tooLong', state, + maxLength=self.maxLength), value, state) + else: + return None + except TypeError: + raise Invalid( + self.message('invalid', state), value, state) + + +class MinLength(FancyValidator): + """ + Invalid if the value is shorter than `minlength`. Uses len(), so + it can work for strings, lists, or anything with length. Note + that you **must** use ``not_empty=True`` if you don't want to + accept empty values -- empty values are not tested for length. + + Examples:: + + >>> min5 = MinLength(5) + >>> min5.to_python('12345') + '12345' + >>> min5.from_python('12345') + '12345' + >>> min5.to_python('1234') + Traceback (most recent call last): + ... + Invalid: Enter a value at least 5 characters long + >>> min5(accept_python=False).from_python('1234') + Traceback (most recent call last): + ... + Invalid: Enter a value at least 5 characters long + >>> min5.to_python([1, 2, 3, 4, 5]) + [1, 2, 3, 4, 5] + >>> min5.to_python([1, 2, 3]) + Traceback (most recent call last): + ... + Invalid: Enter a value at least 5 characters long + >>> min5.to_python(5) + Traceback (most recent call last): + ... + Invalid: Invalid value (value with length expected) + + """ + + __unpackargs__ = ('minLength',) + + messages = dict( + tooShort=_('Enter a value at least %(minLength)i characters long'), + invalid=_('Invalid value (value with length expected)')) + + def _validate_python(self, value, state): + try: + if len(value) < self.minLength: + raise Invalid( + self.message('tooShort', state, + minLength=self.minLength), value, state) + except TypeError: + raise Invalid( + self.message('invalid', state), value, state) + + +class NotEmpty(FancyValidator): + """ + Invalid if value is empty (empty string, empty list, etc). + + Generally for objects that Python considers false, except zero + which is not considered invalid. + + Examples:: + + >>> ne = NotEmpty(messages=dict(empty='enter something')) + >>> ne.to_python('') + Traceback (most recent call last): + ... + Invalid: enter something + >>> ne.to_python(0) + 0 + """ + not_empty = True + + messages = dict( + empty=_('Please enter a value')) + + def _validate_python(self, value, state): + if value == 0: + # This isn't "empty" for this definition. + return value + if not value: + raise Invalid(self.message('empty', state), value, state) + + +class Empty(FancyValidator): + """ + Invalid unless the value is empty. Use cleverly, if at all. + + Examples:: + + >>> Empty.to_python(0) + Traceback (most recent call last): + ... + Invalid: You cannot enter a value here + """ + + messages = dict( + notEmpty=_('You cannot enter a value here')) + + def _validate_python(self, value, state): + if value or value == 0: + raise Invalid(self.message('notEmpty', state), value, state) + + +class Regex(FancyValidator): + """ + Invalid if the value doesn't match the regular expression `regex`. + + The regular expression can be a compiled re object, or a string + which will be compiled for you. + + Use strip=True if you want to strip the value before validation, + and as a form of conversion (often useful). + + Examples:: + + >>> cap = Regex(r'^[A-Z]+$') + >>> cap.to_python('ABC') + 'ABC' + + Note that ``.from_python()`` calls (in general) do not validate + the input:: + + >>> cap.from_python('abc') + 'abc' + >>> cap(accept_python=False).from_python('abc') + Traceback (most recent call last): + ... + Invalid: The input is not valid + >>> cap.to_python(1) + Traceback (most recent call last): + ... + Invalid: The input must be a string (not a : 1) + >>> Regex(r'^[A-Z]+$', strip=True).to_python(' ABC ') + 'ABC' + >>> Regex(r'this', regexOps=('I',)).to_python('THIS') + 'THIS' + """ + + regexOps = () + strip = False + regex = None + + __unpackargs__ = ('regex',) + + messages = dict( + invalid=_('The input is not valid')) + + def __init__(self, *args, **kw): + FancyValidator.__init__(self, *args, **kw) + if isinstance(self.regex, str): + ops = 0 + assert not isinstance(self.regexOps, str), ( + "regexOps should be a list of options from the re module " + "(names, or actual values)") + for op in self.regexOps: + if isinstance(op, str): + ops |= getattr(re, op) + else: + ops |= op + self.regex = re.compile(self.regex, ops) + + def _validate_python(self, value, state): + self.assert_string(value, state) + if self.strip and isinstance(value, str): + value = value.strip() + if not self.regex.search(value): + raise Invalid(self.message('invalid', state), value, state) + + def _convert_to_python(self, value, state): + if self.strip and isinstance(value, str): + return value.strip() + return value + + +class PlainText(Regex): + """ + Test that the field contains only letters, numbers, underscore, + and the hyphen. Subclasses Regex. + + Examples:: + + >>> PlainText.to_python('_this9_') + '_this9_' + >>> PlainText.from_python(' this ') + ' this ' + >>> PlainText(accept_python=False).from_python(' this ') + Traceback (most recent call last): + ... + Invalid: Enter only letters, numbers, or _ (underscore) + >>> PlainText(strip=True).to_python(' this ') + 'this' + >>> PlainText(strip=True).from_python(' this ') + 'this' + """ + + regex = r"^[a-zA-Z_\-0-9]*$" + + messages = dict( + invalid=_('Enter only letters, numbers, or _ (underscore)')) + + +class OneOf(FancyValidator): + """ + Tests that the value is one of the members of a given list. + + If ``testValueList=True``, then if the input value is a list or + tuple, all the members of the sequence will be checked (i.e., the + input must be a subset of the allowed values). + + Use ``hideList=True`` to keep the list of valid values out of the + error message in exceptions. + + Examples:: + + >>> oneof = OneOf([1, 2, 3]) + >>> oneof.to_python(1) + 1 + >>> oneof.to_python(4) + Traceback (most recent call last): + ... + Invalid: Value must be one of: 1; 2; 3 (not 4) + >>> oneof(testValueList=True).to_python([2, 3, [1, 2, 3]]) + [2, 3, [1, 2, 3]] + >>> oneof.to_python([2, 3, [1, 2, 3]]) + Traceback (most recent call last): + ... + Invalid: Value must be one of: 1; 2; 3 (not [2, 3, [1, 2, 3]]) + """ + + list = None + testValueList = False + hideList = False + + __unpackargs__ = ('list',) + + messages = dict( + invalid=_('Invalid value'), + notIn=_('Value must be one of: %(items)s (not %(value)r)')) + + def _validate_python(self, value, state): + if self.testValueList and isinstance(value, (list, tuple)): + for v in value: + self._validate_python(v, state) + else: + if not value in self.list: + if self.hideList: + raise Invalid(self.message('invalid', state), value, state) + else: + try: + items = '; '.join(map(str, self.list)) + except UnicodeError: + items = '; '.join(map(str, self.list)) + raise Invalid( + self.message('notIn', state, + items=items, value=value), value, state) + + @property + def accept_iterator(self): + return self.testValueList + + +class DictConverter(FancyValidator): + """ + Converts values based on a dictionary which has values as keys for + the resultant values. + + If ``allowNull`` is passed, it will not balk if a false value + (e.g., '' or None) is given (it will return None in these cases). + + to_python takes keys and gives values, from_python takes values and + gives keys. + + If you give hideDict=True, then the contents of the dictionary + will not show up in error messages. + + Examples:: + + >>> dc = DictConverter({1: 'one', 2: 'two'}) + >>> dc.to_python(1) + 'one' + >>> dc.from_python('one') + 1 + >>> dc.to_python(3) + Traceback (most recent call last): + .... + Invalid: Enter a value from: 1; 2 + >>> dc2 = dc(hideDict=True) + >>> dc2.hideDict + True + >>> dc2.dict + {1: 'one', 2: 'two'} + >>> dc2.to_python(3) + Traceback (most recent call last): + .... + Invalid: Choose something + >>> dc.from_python('three') + Traceback (most recent call last): + .... + Invalid: Nothing in my dictionary goes by the value 'three'. Choose one of: 'one'; 'two' + """ + + messages = dict( + keyNotFound=_('Choose something'), + chooseKey=_('Enter a value from: %(items)s'), + valueNotFound=_('That value is not known'), + chooseValue=_('Nothing in my dictionary goes by the value %(value)s.' + ' Choose one of: %(items)s')) + + dict = None + hideDict = False + + __unpackargs__ = ('dict',) + + def _convert_to_python(self, value, state): + try: + return self.dict[value] + except KeyError: + if self.hideDict: + raise Invalid(self.message('keyNotFound', state), value, state) + else: + items = sorted(self.dict) + items = '; '.join(map(repr, items)) + raise Invalid(self.message('chooseKey', + state, items=items), value, state) + + def _convert_from_python(self, value, state): + for k, v in self.dict.items(): + if value == v: + return k + if self.hideDict: + raise Invalid(self.message('valueNotFound', state), value, state) + else: + items = '; '.join(map(repr, iter(self.dict.values()))) + raise Invalid( + self.message('chooseValue', state, + value=repr(value), items=items), value, state) + + +class IndexListConverter(FancyValidator): + """ + Converts a index (which may be a string like '2') to the value in + the given list. + + Examples:: + + >>> index = IndexListConverter(['zero', 'one', 'two']) + >>> index.to_python(0) + 'zero' + >>> index.from_python('zero') + 0 + >>> index.to_python('1') + 'one' + >>> index.to_python(5) + Traceback (most recent call last): + Invalid: Index out of range + >>> index(not_empty=True).to_python(None) + Traceback (most recent call last): + Invalid: Please enter a value + >>> index.from_python('five') + Traceback (most recent call last): + Invalid: Item 'five' was not found in the list + """ + + list = None + + __unpackargs__ = ('list',) + + messages = dict( + integer=_('Must be an integer index'), + outOfRange=_('Index out of range'), + notFound=_('Item %(value)s was not found in the list')) + + def _convert_to_python(self, value, state): + try: + value = int(value) + except (ValueError, TypeError): + raise Invalid(self.message('integer', state), value, state) + try: + return self.list[value] + except IndexError: + raise Invalid(self.message('outOfRange', state), value, state) + + def _convert_from_python(self, value, state): + for i, v in enumerate(self.list): + if v == value: + return i + raise Invalid( + self.message('notFound', state, value=repr(value)), value, state) + + +class DateValidator(FancyValidator): + """ + Validates that a date is within the given range. Be sure to call + DateConverter first if you aren't expecting mxDateTime input. + + ``earliest_date`` and ``latest_date`` may be functions; if so, + they will be called each time before validating. + + ``after_now`` means a time after the current timestamp; note that + just a few milliseconds before now is invalid! ``today_or_after`` + is more permissive, and ignores hours and minutes. + + Examples:: + + >>> from datetime import datetime, timedelta + >>> d = DateValidator(earliest_date=datetime(2003, 1, 1)) + >>> d.to_python(datetime(2004, 1, 1)) + datetime.datetime(2004, 1, 1, 0, 0) + >>> d.to_python(datetime(2002, 1, 1)) + Traceback (most recent call last): + ... + Invalid: Date must be after Wednesday, 01 January 2003 + >>> d.to_python(datetime(2003, 1, 1)) + datetime.datetime(2003, 1, 1, 0, 0) + >>> d = DateValidator(after_now=True) + >>> now = datetime.now() + >>> d.to_python(now+timedelta(seconds=5)) == now+timedelta(seconds=5) + True + >>> d.to_python(now-timedelta(days=1)) + Traceback (most recent call last): + ... + Invalid: The date must be sometime in the future + >>> d.to_python(now+timedelta(days=1)) > now + True + >>> d = DateValidator(today_or_after=True) + >>> d.to_python(now) == now + True + + """ + + earliest_date = None + latest_date = None + after_now = False + # Like after_now, but just after this morning: + today_or_after = False + # Use None or 'datetime' for the datetime module in the standard lib, + # or 'mxDateTime' to force the mxDateTime module + datetime_module = None + + messages = dict( + after=_('Date must be after %(date)s'), + before=_('Date must be before %(date)s'), + # Double %'s, because this will be substituted twice: + date_format=_('%%A, %%d %%B %%Y'), + future=_('The date must be sometime in the future')) + + def _validate_python(self, value, state): + date_format = self.message('date_format', state) + if (str is not str # Python 2 + and isinstance(date_format, str)): + # strftime uses the locale encoding, not Unicode + encoding = locale.getlocale(locale.LC_TIME)[1] or 'utf-8' + date_format = date_format.encode(encoding) + else: + encoding = None + if self.earliest_date: + if callable(self.earliest_date): + earliest_date = self.earliest_date() + else: + earliest_date = self.earliest_date + if value < earliest_date: + date_formatted = earliest_date.strftime(date_format) + if encoding: + date_formatted = date_formatted.decode(encoding) + raise Invalid( + self.message('after', state, date=date_formatted), + value, state) + if self.latest_date: + if callable(self.latest_date): + latest_date = self.latest_date() + else: + latest_date = self.latest_date + if value > latest_date: + date_formatted = latest_date.strftime(date_format) + if encoding: + date_formatted = date_formatted.decode(encoding) + raise Invalid( + self.message('before', state, date=date_formatted), + value, state) + if self.after_now: + dt_mod = import_datetime(self.datetime_module) + now = datetime_now(dt_mod) + if value < now: + date_formatted = now.strftime(date_format) + if encoding: + date_formatted = date_formatted.decode(encoding) + raise Invalid( + self.message('future', state, date=date_formatted), + value, state) + if self.today_or_after: + dt_mod = import_datetime(self.datetime_module) + now = datetime_now(dt_mod) + today = datetime_makedate(dt_mod, + now.year, now.month, now.day) + value_as_date = datetime_makedate( + dt_mod, value.year, value.month, value.day) + if value_as_date < today: + date_formatted = now.strftime(date_format) + if encoding: + date_formatted = date_formatted.decode(encoding) + raise Invalid( + self.message('future', state, date=date_formatted), + value, state) + + +class Bool(FancyValidator): + """ + Always Valid, returns True or False based on the value and the + existance of the value. + + If you want to convert strings like ``'true'`` to booleans, then + use ``StringBool``. + + Examples:: + + >>> Bool.to_python(0) + False + >>> Bool.to_python(1) + True + >>> Bool.to_python('') + False + >>> Bool.to_python(None) + False + """ + + if_missing = False + + def _convert_to_python(self, value, state): + return bool(value) + + _convert_from_python = _convert_to_python + + def empty_value(self, value): + return False + + +class RangeValidator(FancyValidator): + """This is an abstract base class for Int and Number. + + It verifies that a value is within range. It accepts min and max + values in the constructor. + + (Since this is an abstract base class, the tests are in Int and Number.) + + """ + + messages = dict( + tooLow=_('Please enter a number that is %(min)s or greater'), + tooHigh=_('Please enter a number that is %(max)s or smaller')) + + min = None + max = None + + def _validate_python(self, value, state): + if self.min is not None: + if value < self.min: + msg = self.message('tooLow', state, min=self.min) + raise Invalid(msg, value, state) + if self.max is not None: + if value > self.max: + msg = self.message('tooHigh', state, max=self.max) + raise Invalid(msg, value, state) + + +class Int(RangeValidator): + """Convert a value to an integer. + + Example:: + + >>> Int.to_python('10') + 10 + >>> Int.to_python('ten') + Traceback (most recent call last): + ... + Invalid: Please enter an integer value + >>> Int(min=5).to_python('6') + 6 + >>> Int(max=10).to_python('11') + Traceback (most recent call last): + ... + Invalid: Please enter a number that is 10 or smaller + + """ + + messages = dict( + integer=_('Please enter an integer value')) + + def _convert_to_python(self, value, state): + try: + return int(value) + except (ValueError, TypeError): + raise Invalid(self.message('integer', state), value, state) + + _convert_from_python = _convert_to_python + + +class Number(RangeValidator): + """Convert a value to a float or integer. + + Tries to convert it to an integer if no information is lost. + + Example:: + + >>> Number.to_python('10') + 10 + >>> Number.to_python('10.5') + 10.5 + >>> Number.to_python('ten') + Traceback (most recent call last): + ... + Invalid: Please enter a number + >>> Number.to_python([1.2]) + Traceback (most recent call last): + ... + Invalid: Please enter a number + >>> Number(min=5).to_python('6.5') + 6.5 + >>> Number(max=10.5).to_python('11.5') + Traceback (most recent call last): + ... + Invalid: Please enter a number that is 10.5 or smaller + + """ + + messages = dict( + number=_('Please enter a number')) + + def _convert_to_python(self, value, state): + try: + value = float(value) + try: + int_value = int(value) + except OverflowError: + int_value = None + if value == int_value: + return int_value + return value + except (ValueError, TypeError): + raise Invalid(self.message('number', state), value, state) + + +class ByteString(FancyValidator): + """Convert to byte string, treating empty things as the empty string. + + Under Python 2.x you can also use the alias `String` for this validator. + + Also takes a `max` and `min` argument, and the string length must fall + in that range. + + Also you may give an `encoding` argument, which will encode any unicode + that is found. Lists and tuples are joined with `list_joiner` + (default ``', '``) in ``from_python``. + + :: + + >>> ByteString(min=2).to_python('a') + Traceback (most recent call last): + ... + Invalid: Enter a value 2 characters long or more + >>> ByteString(max=10).to_python('xxxxxxxxxxx') + Traceback (most recent call last): + ... + Invalid: Enter a value not more than 10 characters long + >>> ByteString().from_python(None) + '' + >>> ByteString().from_python([]) + '' + >>> ByteString().to_python(None) + '' + >>> ByteString(min=3).to_python(None) + Traceback (most recent call last): + ... + Invalid: Please enter a value + >>> ByteString(min=1).to_python('') + Traceback (most recent call last): + ... + Invalid: Please enter a value + + """ + + min = None + max = None + not_empty = None + encoding = None + list_joiner = ', ' + + messages = dict( + tooLong=_('Enter a value not more than %(max)i characters long'), + tooShort=_('Enter a value %(min)i characters long or more')) + + def __initargs__(self, new_attrs): + if self.not_empty is None and self.min: + self.not_empty = True + + def _convert_to_python(self, value, state): + if value is None: + value = '' + elif not isinstance(value, str): + try: + value = bytes(value) + except UnicodeEncodeError: + value = str(value) + if self.encoding is not None and isinstance(value, str): + value = value.encode(self.encoding) + return value + + def _convert_from_python(self, value, state): + if value is None: + value = '' + elif not isinstance(value, str): + if isinstance(value, (list, tuple)): + value = self.list_joiner.join( + self._convert_from_python(v, state) for v in value) + try: + value = str(value) + except UnicodeEncodeError: + value = str(value) + if self.encoding is not None and isinstance(value, str): + value = value.encode(self.encoding) + if self.strip: + value = value.strip() + return value + + def _validate_other(self, value, state): + if self.max is None and self.min is None: + return + if value is None: + value = '' + elif not isinstance(value, str): + try: + value = str(value) + except UnicodeEncodeError: + value = str(value) + if self.max is not None and len(value) > self.max: + raise Invalid( + self.message('tooLong', state, max=self.max), value, state) + if self.min is not None and len(value) < self.min: + raise Invalid( + self.message('tooShort', state, min=self.min), value, state) + + def empty_value(self, value): + return '' + + +class UnicodeString(ByteString): + """Convert things to unicode string. + + This is implemented as a specialization of the ByteString class. + + Under Python 3.x you can also use the alias `String` for this validator. + + In addition to the String arguments, an encoding argument is also + accepted. By default the encoding will be utf-8. You can overwrite + this using the encoding parameter. You can also set inputEncoding + and outputEncoding differently. An inputEncoding of None means + "do not decode", an outputEncoding of None means "do not encode". + + All converted strings are returned as Unicode strings. + + :: + + >>> UnicodeString().to_python(None) + u'' + >>> UnicodeString().to_python([]) + u'' + >>> UnicodeString(encoding='utf-7').to_python('Ni Ni Ni') + u'Ni Ni Ni' + + """ + encoding = 'utf-8' + inputEncoding = NoDefault + outputEncoding = NoDefault + messages = dict( + badEncoding=_('Invalid data or incorrect encoding')) + + def __init__(self, **kw): + ByteString.__init__(self, **kw) + if self.inputEncoding is NoDefault: + self.inputEncoding = self.encoding + if self.outputEncoding is NoDefault: + self.outputEncoding = self.encoding + + def _convert_to_python(self, value, state): + if not value: + return '' + if isinstance(value, str): + return value + if not isinstance(value, str): + if hasattr(value, '__unicode__'): + value = str(value) + return value + if not (str is str # Python 3 + and isinstance(value, bytes) and self.inputEncoding): + value = str(value) + if self.inputEncoding and not isinstance(value, str): + try: + value = str(value, self.inputEncoding) + except UnicodeDecodeError: + raise Invalid(self.message('badEncoding', state), value, state) + except TypeError: + raise Invalid( + self.message('badType', state, + type=type(value), value=value), value, state) + return value + + def _convert_from_python(self, value, state): + if not isinstance(value, str): + if hasattr(value, '__unicode__'): + value = str(value) + else: + value = str(value) + if self.outputEncoding and isinstance(value, str): + value = value.encode(self.outputEncoding) + return value + + def empty_value(self, value): + return '' + + +# Provide proper alias for native strings + +String = UnicodeString if str is str else ByteString + + +class Set(FancyValidator): + """ + This is for when you think you may return multiple values for a + certain field. + + This way the result will always be a list, even if there's only + one result. It's equivalent to ForEach(convert_to_list=True). + + If you give ``use_set=True``, then it will return an actual + ``set`` object. + + :: + + >>> Set.to_python(None) + [] + >>> Set.to_python('this') + ['this'] + >>> Set.to_python(('this', 'that')) + ['this', 'that'] + >>> s = Set(use_set=True) + >>> s.to_python(None) + set([]) + >>> s.to_python('this') + set(['this']) + >>> s.to_python(('this',)) + set(['this']) + """ + + use_set = False + + if_missing = () + accept_iterator = True + + def _convert_to_python(self, value, state): + if self.use_set: + if isinstance(value, set): + return value + elif isinstance(value, (list, tuple)): + return set(value) + elif value is None: + return set() + else: + return set([value]) + else: + if isinstance(value, list): + return value + elif isinstance(value, set): + return list(value) + elif isinstance(value, tuple): + return list(value) + elif value is None: + return [] + else: + return [value] + + def empty_value(self, value): + if self.use_set: + return set() + else: + return [] + + +class Email(FancyValidator): + r""" + Validate an email address. + + If you pass ``resolve_domain=True``, then it will try to resolve + the domain name to make sure it's valid. This takes longer, of + course. You must have the `dnspython `__ modules + installed to look up DNS (MX and A) records. + + :: + + >>> e = Email() + >>> e.to_python(' test@foo.com ') + 'test@foo.com' + >>> e.to_python('test') + Traceback (most recent call last): + ... + Invalid: An email address must contain a single @ + >>> e.to_python('test@foobar') + Traceback (most recent call last): + ... + Invalid: The domain portion of the email address is invalid (the portion after the @: foobar) + >>> e.to_python('test@foobar.com.5') + Traceback (most recent call last): + ... + Invalid: The domain portion of the email address is invalid (the portion after the @: foobar.com.5) + >>> e.to_python('test@foo..bar.com') + Traceback (most recent call last): + ... + Invalid: The domain portion of the email address is invalid (the portion after the @: foo..bar.com) + >>> e.to_python('test@.foo.bar.com') + Traceback (most recent call last): + ... + Invalid: The domain portion of the email address is invalid (the portion after the @: .foo.bar.com) + >>> e.to_python('nobody@xn--m7r7ml7t24h.com') + 'nobody@xn--m7r7ml7t24h.com' + >>> e.to_python('o*reilly@test.com') + 'o*reilly@test.com' + >>> e = Email(resolve_domain=True) + >>> e.resolve_domain + True + >>> e.to_python('doesnotexist@colorstudy.com') + 'doesnotexist@colorstudy.com' + >>> e.to_python('test@nyu.edu') + 'test@nyu.edu' + >>> # NOTE: If you do not have dnspython installed this example won't work: + >>> e.to_python('test@thisdomaindoesnotexistithinkforsure.com') + Traceback (most recent call last): + ... + Invalid: The domain of the email address does not exist (the portion after the @: thisdomaindoesnotexistithinkforsure.com) + >>> e.to_python('test@google.com') + u'test@google.com' + >>> e = Email(not_empty=False) + >>> e.to_python('') + + """ + + resolve_domain = False + resolve_timeout = 10 # timeout in seconds when resolving domains + + usernameRE = re.compile(r"^[\w!#$%&'*+\-/=?^`{|}~.]+$") + domainRE = re.compile(r''' + ^(?:[a-z0-9][a-z0-9\-]{,62}\.)+ # subdomain + (?:[a-z]{2,63}|xn--[a-z0-9\-]{2,59})$ # top level domain + ''', re.I | re.VERBOSE) + + messages = dict( + empty=_('Please enter an email address'), + noAt=_('An email address must contain a single @'), + badUsername=_('The username portion of the email address is invalid' + ' (the portion before the @: %(username)s)'), + socketError=_('An error occured when trying to connect to the server:' + ' %(error)s'), + badDomain=_('The domain portion of the email address is invalid' + ' (the portion after the @: %(domain)s)'), + domainDoesNotExist=_('The domain of the email address does not exist' + ' (the portion after the @: %(domain)s)')) + + def __init__(self, *args, **kw): + FancyValidator.__init__(self, *args, **kw) + if self.resolve_domain: + if not have_dns: + warnings.warn( + "dnspython is not installed on" + " your system (or the dns.resolver package cannot be found)." + " I cannot resolve domain names in addresses") + raise ImportError("no module named dns.resolver") + + def _validate_python(self, value, state): + if not value: + raise Invalid(self.message('empty', state), value, state) + value = value.strip() + splitted = value.split('@', 1) + try: + username, domain = splitted + except ValueError: + raise Invalid(self.message('noAt', state), value, state) + if not self.usernameRE.search(username): + raise Invalid( + self.message('badUsername', state, username=username), + value, state) + try: + idna_domain = [idna.ToASCII(p) for p in domain.split('.')] + if str is str: # Python 3 + idna_domain = [p.decode('ascii') for p in idna_domain] + idna_domain = '.'.join(idna_domain) + except UnicodeError: + # UnicodeError: label empty or too long + # This exception might happen if we have an invalid domain name part + # (for example test@.foo.bar.com) + raise Invalid( + self.message('badDomain', state, domain=domain), + value, state) + if not self.domainRE.search(idna_domain): + raise Invalid( + self.message('badDomain', state, domain=domain), + value, state) + if self.resolve_domain: + assert have_dns, "dnspython should be available" + global socket + if socket is None: + import socket + try: + try: + dns.resolver.query(domain, 'MX') + except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer) as e: + try: + dns.resolver.query(domain, 'A') + except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer) as e: + raise Invalid( + self.message('domainDoesNotExist', + state, domain=domain), value, state) + except (socket.error, dns.exception.DNSException) as e: + raise Invalid( + self.message('socketError', state, error=e), value, state) + + def _convert_to_python(self, value, state): + return value.strip() + + +class URL(FancyValidator): + """ + Validate a URL, either http://... or https://. If check_exists + is true, then we'll actually make a request for the page. + + If add_http is true, then if no scheme is present we'll add + http:// + + :: + + >>> u = URL(add_http=True) + >>> u.to_python('foo.com') + 'http://foo.com' + >>> u.to_python('http://hahaha.ha/bar.html') + 'http://hahaha.ha/bar.html' + >>> u.to_python('http://xn--m7r7ml7t24h.com') + 'http://xn--m7r7ml7t24h.com' + >>> u.to_python('http://xn--c1aay4a.xn--p1ai') + 'http://xn--c1aay4a.xn--p1ai' + >>> u.to_python('http://foo.com/test?bar=baz&fleem=morx') + 'http://foo.com/test?bar=baz&fleem=morx' + >>> u.to_python('http://foo.com/login?came_from=http%3A%2F%2Ffoo.com%2Ftest') + 'http://foo.com/login?came_from=http%3A%2F%2Ffoo.com%2Ftest' + >>> u.to_python('http://foo.com:8000/test.html') + 'http://foo.com:8000/test.html' + >>> u.to_python('http://foo.com/something\\nelse') + Traceback (most recent call last): + ... + Invalid: That is not a valid URL + >>> u.to_python('https://test.com') + 'https://test.com' + >>> u.to_python('http://test') + Traceback (most recent call last): + ... + Invalid: You must provide a full domain name (like test.com) + >>> u.to_python('http://test..com') + Traceback (most recent call last): + ... + Invalid: That is not a valid URL + >>> u = URL(add_http=False, check_exists=True) + >>> u.to_python('http://google.com') + 'http://google.com' + >>> u.to_python('google.com') + Traceback (most recent call last): + ... + Invalid: You must start your URL with http://, https://, etc + >>> u.to_python('http://www.formencode.org/does/not/exist/page.html') + Traceback (most recent call last): + ... + Invalid: The server responded that the page could not be found + >>> u.to_python('http://this.domain.does.not.exist.example.org/test.html') + ... # doctest: +ELLIPSIS + Traceback (most recent call last): + ... + Invalid: An error occured when trying to connect to the server: ... + + If you want to allow addresses without a TLD (e.g., ``localhost``) you can do:: + + >>> URL(require_tld=False).to_python('http://localhost') + 'http://localhost' + + By default, internationalized domain names (IDNA) in Unicode will be + accepted and encoded to ASCII using Punycode (as described in RFC 3490). + You may set allow_idna to False to change this behavior:: + + >>> URL(allow_idna=True).to_python( + ... 'http://\\u0433\\u0443\\u0433\\u043b.\\u0440\\u0444') + 'http://xn--c1aay4a.xn--p1ai' + >>> URL(allow_idna=True, add_http=True).to_python( + ... '\\u0433\\u0443\\u0433\\u043b.\\u0440\\u0444') + 'http://xn--c1aay4a.xn--p1ai' + >>> URL(allow_idna=False).to_python( + ... 'http://\\u0433\\u0443\\u0433\\u043b.\\u0440\\u0444') + Traceback (most recent call last): + ... + Invalid: That is not a valid URL + + """ + + add_http = True + allow_idna = True + check_exists = False + require_tld = True + + url_re = re.compile(r''' + ^(http|https):// + (?:[%:\w]*@)? # authenticator + (?: # ip or domain + (?P(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))| + (?P[a-z0-9][a-z0-9\-]{,62}\.)* # subdomain + (?P[a-z]{2,63}|xn--[a-z0-9\-]{2,59}) # top level domain + ) + (?::[0-9]{1,5})? # port + # files/delims/etc + (?P/[a-z0-9\-\._~:/\?#\[\]@!%\$&\'\(\)\*\+,;=]*)? + $ + ''', re.I | re.VERBOSE) + + scheme_re = re.compile(r'^[a-zA-Z]+:') + + messages = dict( + noScheme=_('You must start your URL with http://, https://, etc'), + badURL=_('That is not a valid URL'), + httpError=_('An error occurred when trying to access the URL:' + ' %(error)s'), + socketError=_('An error occured when trying to connect to the server:' + ' %(error)s'), + notFound=_('The server responded that the page could not be found'), + status=_('The server responded with a bad status code (%(status)s)'), + noTLD=_('You must provide a full domain name (like %(domain)s.com)')) + + def _convert_to_python(self, value, state): + value = value.strip() + if self.add_http: + if not self.scheme_re.search(value): + value = 'http://' + value + if self.allow_idna: + value = self._encode_idna(value) + match = self.scheme_re.search(value) + if not match: + raise Invalid(self.message('noScheme', state), value, state) + value = match.group(0).lower() + value[len(match.group(0)):] + match = self.url_re.search(value) + if not match: + raise Invalid(self.message('badURL', state), value, state) + if self.require_tld and not match.group('domain'): + raise Invalid( + self.message('noTLD', state, domain=match.group('tld')), + value, state) + if self.check_exists and value.startswith(('http://', 'https://')): + self._check_url_exists(value, state) + return value + + def _encode_idna(self, url): + global urlparse + if urlparse is None: + import urllib.parse + try: + scheme, netloc, path, params, query, fragment = urllib.parse.urlparse( + url) + except ValueError: + return url + try: + netloc = netloc.encode('idna') + if str is str: # Python 3 + netloc = netloc.decode('ascii') + return str(urllib.parse.urlunparse((scheme, netloc, + path, params, query, fragment))) + except UnicodeError: + return url + + def _check_url_exists(self, url, state): + global httplib, urlparse, socket + if httplib is None: + import http.client + if urlparse is None: + import urllib.parse + if socket is None: + import socket + scheme, netloc, path, params, query, fragment = urllib.parse.urlparse( + url, 'http') + if scheme == 'https': + ConnClass = http.client.HTTPSConnection + else: + ConnClass = http.client.HTTPConnection + try: + conn = ConnClass(netloc) + if params: + path += ';' + params + if query: + path += '?' + query + conn.request('HEAD', path) + res = conn.getresponse() + except http.client.HTTPException as e: + raise Invalid( + self.message('httpError', state, error=e), state, url) + except socket.error as e: + raise Invalid( + self.message('socketError', state, error=e), state, url) + else: + if res.status == 404: + raise Invalid( + self.message('notFound', state), state, url) + if not 200 <= res.status < 500: + raise Invalid( + self.message('status', state, status=res.status), + state, url) + + +class XRI(FancyValidator): + r""" + Validator for XRIs. + + It supports both i-names and i-numbers, of the first version of the XRI + standard. + + :: + + >>> inames = XRI(xri_type="i-name") + >>> inames.to_python(" =John.Smith ") + '=John.Smith' + >>> inames.to_python("@Free.Software.Foundation") + '@Free.Software.Foundation' + >>> inames.to_python("Python.Software.Foundation") + Traceback (most recent call last): + ... + Invalid: The type of i-name is not defined; it may be either individual or organizational + >>> inames.to_python("http://example.org") + Traceback (most recent call last): + ... + Invalid: The type of i-name is not defined; it may be either individual or organizational + >>> inames.to_python("=!2C43.1A9F.B6F6.E8E6") + Traceback (most recent call last): + ... + Invalid: "!2C43.1A9F.B6F6.E8E6" is an invalid i-name + >>> iname_with_schema = XRI(True, xri_type="i-name") + >>> iname_with_schema.to_python("=Richard.Stallman") + 'xri://=Richard.Stallman' + >>> inames.to_python("=John Smith") + Traceback (most recent call last): + ... + Invalid: "John Smith" is an invalid i-name + >>> inumbers = XRI(xri_type="i-number") + >>> inumbers.to_python("!!1000!de21.4536.2cb2.8074") + '!!1000!de21.4536.2cb2.8074' + >>> inumbers.to_python("@!1000.9554.fabd.129c!2847.df3c") + '@!1000.9554.fabd.129c!2847.df3c' + + """ + + iname_valid_pattern = re.compile(r""" + ^ + [\w]+ # A global alphanumeric i-name + (\.[\w]+)* # An i-name with dots + (\*[\w]+(\.[\w]+)*)* # A community i-name + $ + """, re.VERBOSE | re.UNICODE) + + iname_invalid_start = re.compile(r"^[\d\.-]", re.UNICODE) + """@cvar: These characters must not be at the beggining of the i-name""" + + inumber_pattern = re.compile(r""" + ^ + ( + [=@]! # It's a personal or organization i-number + | + !! # It's a network i-number + ) + [\dA-F]{1,4}(\.[\dA-F]{1,4}){0,3} # A global i-number + (![\dA-F]{1,4}(\.[\dA-F]{1,4}){0,3})* # Zero or more sub i-numbers + $ + """, re.VERBOSE | re.IGNORECASE) + + messages = dict( + noType=_('The type of i-name is not defined;' + ' it may be either individual or organizational'), + repeatedChar=_('Dots and dashes may not be repeated consecutively'), + badIname=_('"%(iname)s" is an invalid i-name'), + badInameStart=_('i-names may not start with numbers' + ' nor punctuation marks'), + badInumber=_('"%(inumber)s" is an invalid i-number'), + badType=_('The XRI must be a string (not a %(type)s: %(value)r)'), + badXri=_('"%(xri_type)s" is not a valid type of XRI')) + + def __init__(self, add_xri=False, xri_type="i-name", **kwargs): + """Create an XRI validator. + + @param add_xri: Should the schema be added if not present? + Officially it's optional. + @type add_xri: C{bool} + @param xri_type: What type of XRI should be validated? + Possible values: C{i-name} or C{i-number}. + @type xri_type: C{str} + + """ + self.add_xri = add_xri + assert xri_type in ('i-name', 'i-number'), ( + 'xri_type must be "i-name" or "i-number"') + self.xri_type = xri_type + super(XRI, self).__init__(**kwargs) + + def _convert_to_python(self, value, state): + """Prepend the 'xri://' schema if needed and remove trailing spaces""" + value = value.strip() + if self.add_xri and not value.startswith('xri://'): + value = 'xri://' + value + return value + + def _validate_python(self, value, state=None): + """Validate an XRI + + @raise Invalid: If at least one of the following conditions in met: + - C{value} is not a string. + - The XRI is not a personal, organizational or network one. + - The relevant validator (i-name or i-number) considers the XRI + is not valid. + + """ + if not isinstance(value, str): + raise Invalid( + self.message('badType', state, + type=str(type(value)), value=value), value, state) + + # Let's remove the schema, if any + if value.startswith('xri://'): + value = value[6:] + + if not value[0] in ('@', '=') and not ( + self.xri_type == 'i-number' and value[0] == '!'): + raise Invalid(self.message('noType', state), value, state) + + if self.xri_type == 'i-name': + self._validate_iname(value, state) + else: + self._validate_inumber(value, state) + + def _validate_iname(self, iname, state): + """Validate an i-name""" + # The type is not required here: + iname = iname[1:] + if '..' in iname or '--' in iname: + raise Invalid(self.message('repeatedChar', state), iname, state) + if self.iname_invalid_start.match(iname): + raise Invalid(self.message('badInameStart', state), iname, state) + if not self.iname_valid_pattern.match(iname) or '_' in iname: + raise Invalid( + self.message('badIname', state, iname=iname), iname, state) + + def _validate_inumber(self, inumber, state): + """Validate an i-number""" + if not self.__class__.inumber_pattern.match(inumber): + raise Invalid( + self.message('badInumber', state, + inumber=inumber, value=inumber), inumber, state) + + +class OpenId(FancyValidator): + r""" + OpenId validator. + + :: + >>> v = OpenId(add_schema=True) + >>> v.to_python(' example.net ') + 'http://example.net' + >>> v.to_python('@TurboGears') + 'xri://@TurboGears' + >>> w = OpenId(add_schema=False) + >>> w.to_python(' example.net ') + Traceback (most recent call last): + ... + Invalid: "example.net" is not a valid OpenId (it is neither an URL nor an XRI) + >>> w.to_python('!!1000') + '!!1000' + >>> w.to_python('look@me.com') + Traceback (most recent call last): + ... + Invalid: "look@me.com" is not a valid OpenId (it is neither an URL nor an XRI) + + """ + + messages = dict( + badId=_('"%(id)s" is not a valid OpenId' + ' (it is neither an URL nor an XRI)')) + + def __init__(self, add_schema=False, **kwargs): + """Create an OpenId validator. + + @param add_schema: Should the schema be added if not present? + @type add_schema: C{bool} + + """ + self.url_validator = URL(add_http=add_schema) + self.iname_validator = XRI(add_schema, xri_type="i-name") + self.inumber_validator = XRI(add_schema, xri_type="i-number") + + def _convert_to_python(self, value, state): + value = value.strip() + try: + return self.url_validator.to_python(value, state) + except Invalid: + try: + return self.iname_validator.to_python(value, state) + except Invalid: + try: + return self.inumber_validator.to_python(value, state) + except Invalid: + pass + # It's not an OpenId! + raise Invalid(self.message('badId', state, id=value), value, state) + + def _validate_python(self, value, state): + self._convert_to_python(value, state) + + +def StateProvince(*kw, **kwargs): + deprecation_warning("please use formencode.national.USStateProvince") + from formencode.national import USStateProvince + return USStateProvince(*kw, **kwargs) + + +def PhoneNumber(*kw, **kwargs): + deprecation_warning("please use formencode.national.USPhoneNumber") + from formencode.national import USPhoneNumber + return USPhoneNumber(*kw, **kwargs) + + +def IPhoneNumberValidator(*kw, **kwargs): + deprecation_warning( + "please use formencode.national.InternationalPhoneNumber") + from formencode.national import InternationalPhoneNumber + return InternationalPhoneNumber(*kw, **kwargs) + + +class FieldStorageUploadConverter(FancyValidator): + """ + Handles cgi.FieldStorage instances that are file uploads. + + This doesn't do any conversion, but it can detect empty upload + fields (which appear like normal fields, but have no filename when + no upload was given). + """ + def _convert_to_python(self, value, state=None): + if isinstance(value, cgi.FieldStorage): + if getattr(value, 'filename', None): + return value + raise Invalid('invalid', value, state) + else: + return value + + def is_empty(self, value): + if isinstance(value, cgi.FieldStorage): + return not bool(getattr(value, 'filename', None)) + return FancyValidator.is_empty(self, value) + + +class FileUploadKeeper(FancyValidator): + """ + Takes two inputs (a dictionary with keys ``static`` and + ``upload``) and converts them into one value on the Python side (a + dictionary with ``filename`` and ``content`` keys). The upload + takes priority over the static value. The filename may be None if + it can't be discovered. + + Handles uploads of both text and ``cgi.FieldStorage`` upload + values. + + This is basically for use when you have an upload field, and you + want to keep the upload around even if the rest of the form + submission fails. When converting *back* to the form submission, + there may be extra values ``'original_filename'`` and + ``'original_content'``, which may want to use in your form to show + the user you still have their content around. + + To use this, make sure you are using variabledecode, then use + something like:: + + + + + Then in your scheme:: + + class MyScheme(Scheme): + myfield = FileUploadKeeper() + + Note that big file uploads mean big hidden fields, and lots of + bytes passed back and forth in the case of an error. + """ + + upload_key = 'upload' + static_key = 'static' + + def _convert_to_python(self, value, state): + upload = value.get(self.upload_key) + static = value.get(self.static_key, '').strip() + filename = content = None + if isinstance(upload, cgi.FieldStorage): + filename = upload.filename + content = upload.value + elif isinstance(upload, str) and upload: + filename = None + # @@: Should this encode upload if it is unicode? + content = upload + if not content and static: + filename, content = static.split(None, 1) + filename = '' if filename == '-' else filename.decode('base64') + content = content.decode('base64') + return {'filename': filename, 'content': content} + + def _convert_from_python(self, value, state): + filename = value.get('filename', '') + content = value.get('content', '') + if filename or content: + result = self.pack_content(filename, content) + return {self.upload_key: '', + self.static_key: result, + 'original_filename': filename, + 'original_content': content} + else: + return {self.upload_key: '', + self.static_key: ''} + + def pack_content(self, filename, content): + enc_filename = self.base64encode(filename) or '-' + enc_content = (content or '').encode('base64') + result = '%s %s' % (enc_filename, enc_content) + return result + + +class DateConverter(FancyValidator): + """ + Validates and converts a string date, like mm/yy, dd/mm/yy, + dd-mm-yy, etc. Using ``month_style`` you can support + the three general styles ``mdy`` = ``us`` = ``mm/dd/yyyy``, + ``dmy`` = ``euro`` = ``dd/mm/yyyy`` and + ``ymd`` = ``iso`` = ``yyyy/mm/dd``. + + Accepts English month names, also abbreviated. Returns value as a + datetime object (you can get mx.DateTime objects if you use + ``datetime_module='mxDateTime'``). Two year dates are assumed to + be within 1950-2020, with dates from 21-49 being ambiguous and + signaling an error. + + Use accept_day=False if you just want a month/year (like for a + credit card expiration date). + + :: + + >>> d = DateConverter() + >>> d.to_python('12/3/09') + datetime.date(2009, 12, 3) + >>> d.to_python('12/3/2009') + datetime.date(2009, 12, 3) + >>> d.to_python('2/30/04') + Traceback (most recent call last): + ... + Invalid: That month only has 29 days + >>> d.to_python('13/2/05') + Traceback (most recent call last): + ... + Invalid: Please enter a month from 1 to 12 + >>> d.to_python('1/1/200') + Traceback (most recent call last): + ... + Invalid: Please enter a four-digit year after 1899 + + If you change ``month_style`` you can get European-style dates:: + + >>> d = DateConverter(month_style='dd/mm/yyyy') + >>> date = d.to_python('12/3/09') + >>> date + datetime.date(2009, 3, 12) + >>> d.from_python(date) + '12/03/2009' + """ + + # set to False if you want only month and year + accept_day = True + # allowed month styles: 'mdy' = 'us', 'dmy' = 'euro', 'ymd' = 'iso' + # also allowed: 'mm/dd/yyyy', 'dd/mm/yyyy', 'yyyy/mm/dd' + month_style = 'mdy' + # preferred separator for reverse conversion: '/', '.' or '-' + separator = '/' + + # Use 'datetime' to force the Python datetime module, or + # 'mxDateTime' to force the mxDateTime module (None means use + # datetime, or if not present mxDateTime) + datetime_module = None + + _month_names = { + 'jan': 1, 'january': 1, + 'feb': 2, 'febuary': 2, + 'mar': 3, 'march': 3, + 'apr': 4, 'april': 4, + 'may': 5, + 'jun': 6, 'june': 6, + 'jul': 7, 'july': 7, + 'aug': 8, 'august': 8, + 'sep': 9, 'sept': 9, 'september': 9, + 'oct': 10, 'october': 10, + 'nov': 11, 'november': 11, + 'dec': 12, 'december': 12, + } + + _date_re = dict( + dmy=re.compile( + r'^\s*(\d\d?)[\-\./\\](\d\d?|%s)[\-\./\\](\d\d\d?\d?)\s*$' + % '|'.join(_month_names), re.I), + mdy=re.compile( + r'^\s*(\d\d?|%s)[\-\./\\](\d\d?)[\-\./\\](\d\d\d?\d?)\s*$' + % '|'.join(_month_names), re.I), + ymd=re.compile( + r'^\s*(\d\d\d?\d?)[\-\./\\](\d\d?|%s)[\-\./\\](\d\d?)\s*$' + % '|'.join(_month_names), re.I), + my=re.compile( + r'^\s*(\d\d?|%s)[\-\./\\](\d\d\d?\d?)\s*$' + % '|'.join(_month_names), re.I), + ym=re.compile( + r'^\s*(\d\d\d?\d?)[\-\./\\](\d\d?|%s)\s*$' + % '|'.join(_month_names), re.I)) + + _formats = dict(d='%d', m='%m', y='%Y') + + _human_formats = dict(d=_('DD'), m=_('MM'), y=_('YYYY')) + + # Feb. should be leap-year aware (but mxDateTime does catch that) + _monthDays = { + 1: 31, 2: 29, 3: 31, 4: 30, 5: 31, 6: 30, 7: 31, 8: 31, + 9: 30, 10: 31, 11: 30, 12: 31} + + messages = dict( + badFormat=_('Please enter the date in the form %(format)s'), + monthRange=_('Please enter a month from 1 to 12'), + invalidDay=_('Please enter a valid day'), + dayRange=_('That month only has %(days)i days'), + invalidDate=_('That is not a valid day (%(exception)s)'), + unknownMonthName=_('Unknown month name: %(month)s'), + invalidYear=_('Please enter a number for the year'), + fourDigitYear=_('Please enter a four-digit year after 1899'), + wrongFormat=_('Please enter the date in the form %(format)s')) + + def __init__(self, *args, **kw): + super(DateConverter, self).__init__(*args, **kw) + month_style = (self.month_style or DateConverter.month_style).lower() + accept_day = bool(self.accept_day) + self.accept_day = self.accept_day + if month_style in ('mdy', + 'md', 'mm/dd/yyyy', 'mm/dd', 'us', 'american'): + month_style = 'mdy' + elif month_style in ('dmy', + 'dm', 'dd/mm/yyyy', 'dd/mm', 'euro', 'european'): + month_style = 'dmy' + elif month_style in ('ymd', + 'ym', 'yyyy/mm/dd', 'yyyy/mm', 'iso', 'china', 'chinese'): + month_style = 'ymd' + else: + raise TypeError('Bad month_style: %r' % month_style) + self.month_style = month_style + separator = self.separator + if not separator or separator == 'auto': + separator = dict(mdy='/', dmy='.', ymd='-')[month_style] + elif separator not in ('-', '.', '/', '\\'): + raise TypeError('Bad separator: %r' % separator) + self.separator = separator + self.format = separator.join(self._formats[part] + for part in month_style if part != 'd' or accept_day) + self.human_format = separator.join(self._human_formats[part] + for part in month_style if part != 'd' or accept_day) + + def _convert_to_python(self, value, state): + self.assert_string(value, state) + month_style = self.month_style + if not self.accept_day: + month_style = 'ym' if month_style == 'ymd' else 'my' + match = self._date_re[month_style].search(value) + if not match: + raise Invalid( + self.message('badFormat', state, + format=self.human_format), value, state) + groups = match.groups() + if self.accept_day: + if month_style == 'mdy': + month, day, year = groups + elif month_style == 'dmy': + day, month, year = groups + else: + year, month, day = groups + day = int(day) + if not 1 <= day <= 31: + raise Invalid(self.message('invalidDay', state), value, state) + else: + day = 1 + if month_style == 'my': + month, year = groups + else: + year, month = groups + month = self.make_month(month, state) + if not 1 <= month <= 12: + raise Invalid(self.message('monthRange', state), value, state) + if self._monthDays[month] < day: + raise Invalid( + self.message('dayRange', state, + days=self._monthDays[month]), value, state) + year = self.make_year(year, state) + dt_mod = import_datetime(self.datetime_module) + try: + return datetime_makedate(dt_mod, year, month, day) + except ValueError as v: + raise Invalid( + self.message('invalidDate', state, + exception=str(v)), value, state) + + def make_month(self, value, state): + try: + return int(value) + except ValueError: + try: + return self._month_names[value.lower().strip()] + except KeyError: + raise Invalid( + self.message('unknownMonthName', state, + month=value), value, state) + + def make_year(self, year, state): + try: + year = int(year) + except ValueError: + raise Invalid(self.message('invalidYear', state), year, state) + if year <= 20: + year += 2000 + elif 50 <= year < 100: + year += 1900 + if 20 < year < 50 or 99 < year < 1900: + raise Invalid(self.message('fourDigitYear', state), year, state) + return year + + def _convert_from_python(self, value, state): + if self.if_empty is not NoDefault and not value: + return '' + return value.strftime(self.format) + + +class TimeConverter(FancyValidator): + """ + Converts times in the format HH:MM:SSampm to (h, m, s). + Seconds are optional. + + For ampm, set use_ampm = True. For seconds, use_seconds = True. + Use 'optional' for either of these to make them optional. + + Examples:: + + >>> tim = TimeConverter() + >>> tim.to_python('8:30') + (8, 30) + >>> tim.to_python('20:30') + (20, 30) + >>> tim.to_python('30:00') + Traceback (most recent call last): + ... + Invalid: You must enter an hour in the range 0-23 + >>> tim.to_python('13:00pm') + Traceback (most recent call last): + ... + Invalid: You must enter an hour in the range 1-12 + >>> tim.to_python('12:-1') + Traceback (most recent call last): + ... + Invalid: You must enter a minute in the range 0-59 + >>> tim.to_python('12:02pm') + (12, 2) + >>> tim.to_python('12:02am') + (0, 2) + >>> tim.to_python('1:00PM') + (13, 0) + >>> tim.from_python((13, 0)) + '13:00:00' + >>> tim2 = tim(use_ampm=True, use_seconds=False) + >>> tim2.from_python((13, 0)) + '1:00pm' + >>> tim2.from_python((0, 0)) + '12:00am' + >>> tim2.from_python((12, 0)) + '12:00pm' + + Examples with ``datetime.time``:: + + >>> v = TimeConverter(use_datetime=True) + >>> a = v.to_python('18:00') + >>> a + datetime.time(18, 0) + >>> b = v.to_python('30:00') + Traceback (most recent call last): + ... + Invalid: You must enter an hour in the range 0-23 + >>> v2 = TimeConverter(prefer_ampm=True, use_datetime=True) + >>> v2.from_python(a) + '6:00:00pm' + >>> v3 = TimeConverter(prefer_ampm=True, + ... use_seconds=False, use_datetime=True) + >>> a = v3.to_python('18:00') + >>> a + datetime.time(18, 0) + >>> v3.from_python(a) + '6:00pm' + >>> a = v3.to_python('18:00:00') + Traceback (most recent call last): + ... + Invalid: You may not enter seconds + """ + + use_ampm = 'optional' + prefer_ampm = False + use_seconds = 'optional' + use_datetime = False + # This can be set to make it prefer mxDateTime: + datetime_module = None + + messages = dict( + noAMPM=_('You must indicate AM or PM'), + tooManyColon=_('There are too many :\'s'), + noSeconds=_('You may not enter seconds'), + secondsRequired=_('You must enter seconds'), + minutesRequired=_('You must enter minutes (after a :)'), + badNumber=_('The %(part)s value you gave is not a number: %(number)r'), + badHour=_('You must enter an hour in the range %(range)s'), + badMinute=_('You must enter a minute in the range 0-59'), + badSecond=_('You must enter a second in the range 0-59')) + + def _convert_to_python(self, value, state): + result = self._to_python_tuple(value, state) + if self.use_datetime: + dt_mod = import_datetime(self.datetime_module) + time_class = datetime_time(dt_mod) + return time_class(*result) + else: + return result + + def _to_python_tuple(self, value, state): + time = value.strip() + explicit_ampm = False + if self.use_ampm: + last_two = time[-2:].lower() + if last_two not in ('am', 'pm'): + if self.use_ampm != 'optional': + raise Invalid(self.message('noAMPM', state), value, state) + offset = 0 + else: + explicit_ampm = True + offset = 12 if last_two == 'pm' else 0 + time = time[:-2] + else: + offset = 0 + parts = time.split(':', 3) + if len(parts) > 3: + raise Invalid(self.message('tooManyColon', state), value, state) + if len(parts) == 3 and not self.use_seconds: + raise Invalid(self.message('noSeconds', state), value, state) + if (len(parts) == 2 + and self.use_seconds and self.use_seconds != 'optional'): + raise Invalid(self.message('secondsRequired', state), value, state) + if len(parts) == 1: + raise Invalid(self.message('minutesRequired', state), value, state) + try: + hour = int(parts[0]) + except ValueError: + raise Invalid( + self.message('badNumber', state, + number=parts[0], part='hour'), value, state) + if explicit_ampm: + if not 1 <= hour <= 12: + raise Invalid( + self.message('badHour', state, + number=hour, range='1-12'), value, state) + if hour == 12 and offset == 12: + # 12pm == 12 + pass + elif hour == 12 and offset == 0: + # 12am == 0 + hour = 0 + else: + hour += offset + else: + if not 0 <= hour < 24: + raise Invalid( + self.message('badHour', state, + number=hour, range='0-23'), value, state) + try: + minute = int(parts[1]) + except ValueError: + raise Invalid( + self.message('badNumber', state, + number=parts[1], part='minute'), value, state) + if not 0 <= minute < 60: + raise Invalid( + self.message('badMinute', state, number=minute), + value, state) + if len(parts) == 3: + try: + second = int(parts[2]) + except ValueError: + raise Invalid( + self.message('badNumber', state, + number=parts[2], part='second'), value, state) + if not 0 <= second < 60: + raise Invalid( + self.message('badSecond', state, number=second), + value, state) + else: + second = None + if second is None: + return (hour, minute) + else: + return (hour, minute, second) + + def _convert_from_python(self, value, state): + if isinstance(value, str): + return value + if hasattr(value, 'hour'): + hour, minute = value.hour, value.minute + second = value.second + elif len(value) == 3: + hour, minute, second = value + elif len(value) == 2: + hour, minute = value + second = 0 + ampm = '' + if (self.use_ampm == 'optional' and self.prefer_ampm) or ( + self.use_ampm and self.use_ampm != 'optional'): + ampm = 'am' + if hour > 12: + hour -= 12 + ampm = 'pm' + elif hour == 12: + ampm = 'pm' + elif hour == 0: + hour = 12 + if self.use_seconds: + return '%i:%02i:%02i%s' % (hour, minute, second, ampm) + else: + return '%i:%02i%s' % (hour, minute, ampm) + + +def PostalCode(*kw, **kwargs): + deprecation_warning("please use formencode.national.USPostalCode") + from formencode.national import USPostalCode + return USPostalCode(*kw, **kwargs) + + +class StripField(FancyValidator): + """ + Take a field from a dictionary, removing the key from the dictionary. + + ``name`` is the key. The field value and a new copy of the dictionary + with that field removed are returned. + + >>> StripField('test').to_python({'a': 1, 'test': 2}) + (2, {'a': 1}) + >>> StripField('test').to_python({}) + Traceback (most recent call last): + ... + Invalid: The name 'test' is missing + + """ + + __unpackargs__ = ('name',) + + messages = dict( + missing=_('The name %(name)s is missing')) + + def _convert_to_python(self, valueDict, state): + v = valueDict.copy() + try: + field = v.pop(self.name) + except KeyError: + raise Invalid( + self.message('missing', state, name=repr(self.name)), + valueDict, state) + return field, v + + def is_empty(self, value): + # empty dictionaries don't really apply here + return False + + +class StringBool(FancyValidator): # originally from TurboGears 1 + """ + Converts a string to a boolean. + + Values like 'true' and 'false' are considered True and False, + respectively; anything in ``true_values`` is true, anything in + ``false_values`` is false, case-insensitive). The first item of + those lists is considered the preferred form. + + :: + + >>> s = StringBool() + >>> s.to_python('yes'), s.to_python('no') + (True, False) + >>> s.to_python(1), s.to_python('N') + (True, False) + >>> s.to_python('ye') + Traceback (most recent call last): + ... + Invalid: Value should be 'true' or 'false' + """ + + true_values = ['true', 't', 'yes', 'y', 'on', '1'] + false_values = ['false', 'f', 'no', 'n', 'off', '0'] + + messages = dict( + string=_('Value should be %(true)r or %(false)r')) + + def _convert_to_python(self, value, state): + if isinstance(value, str): + value = value.strip().lower() + if value in self.true_values: + return True + if not value or value in self.false_values: + return False + raise Invalid( + self.message('string', state, + true=self.true_values[0], false=self.false_values[0]), + value, state) + return bool(value) + + def _convert_from_python(self, value, state): + return (self.true_values if value else self.false_values)[0] + +# Should deprecate: +StringBoolean = StringBool + + +class SignedString(FancyValidator): + """ + Encodes a string into a signed string, and base64 encodes both the + signature string and a random nonce. + + It is up to you to provide a secret, and to keep the secret handy + and consistent. + """ + + messages = dict( + malformed=_('Value does not contain a signature'), + badsig=_('Signature is not correct')) + + secret = None + nonce_length = 4 + + def _convert_to_python(self, value, state): + global sha1 + if not sha1: + from hashlib import sha1 + assert self.secret is not None, "You must give a secret" + parts = value.split(None, 1) + if not parts or len(parts) == 1: + raise Invalid(self.message('malformed', state), value, state) + sig, rest = parts + sig = sig.decode('base64') + rest = rest.decode('base64') + nonce = rest[:self.nonce_length] + rest = rest[self.nonce_length:] + expected = sha1(str(self.secret) + nonce + rest).digest() + if expected != sig: + raise Invalid(self.message('badsig', state), value, state) + return rest + + def _convert_from_python(self, value, state): + global sha1 + if not sha1: + from hashlib import sha1 + nonce = self.make_nonce() + value = str(value) + digest = sha1(self.secret + nonce + value).digest() + return self.encode(digest) + ' ' + self.encode(nonce + value) + + def encode(self, value): + return value.encode('base64').strip().replace('\n', '') + + def make_nonce(self): + global random + if not random: + import random + return ''.join(chr(random.randrange(256)) + for _i in range(self.nonce_length)) + + +class IPAddress(FancyValidator): + """ + Formencode validator to check whether a string is a correct IP address. + + Examples:: + + >>> ip = IPAddress() + >>> ip.to_python('127.0.0.1') + '127.0.0.1' + >>> ip.to_python('299.0.0.1') + Traceback (most recent call last): + ... + Invalid: The octets must be within the range of 0-255 (not '299') + >>> ip.to_python('192.168.0.1/1') + Traceback (most recent call last): + ... + Invalid: Please enter a valid IP address (a.b.c.d) + >>> ip.to_python('asdf') + Traceback (most recent call last): + ... + Invalid: Please enter a valid IP address (a.b.c.d) + """ + + messages = dict( + badFormat=_('Please enter a valid IP address (a.b.c.d)'), + leadingZeros=_('The octets must not have leading zeros'), + illegalOctets=_('The octets must be within the range of 0-255' + ' (not %(octet)r)')) + + leading_zeros = False + + def _validate_python(self, value, state=None): + try: + if not value: + raise ValueError + octets = value.split('.', 5) + # Only 4 octets? + if len(octets) != 4: + raise ValueError + # Correct octets? + for octet in octets: + if octet.startswith('0') and octet != '0': + if not self.leading_zeros: + raise Invalid( + self.message('leadingZeros', state), value, state) + # strip zeros so this won't be an octal number + octet = octet.lstrip('0') + if not 0 <= int(octet) < 256: + raise Invalid( + self.message('illegalOctets', state, octet=octet), + value, state) + # Splitting faild: wrong syntax + except ValueError: + raise Invalid(self.message('badFormat', state), value, state) + + +class CIDR(IPAddress): + """ + Formencode validator to check whether a string is in correct CIDR + notation (IP address, or IP address plus /mask). + + Examples:: + + >>> cidr = CIDR() + >>> cidr.to_python('127.0.0.1') + '127.0.0.1' + >>> cidr.to_python('299.0.0.1') + Traceback (most recent call last): + ... + Invalid: The octets must be within the range of 0-255 (not '299') + >>> cidr.to_python('192.168.0.1/1') + Traceback (most recent call last): + ... + Invalid: The network size (bits) must be within the range of 8-32 (not '1') + >>> cidr.to_python('asdf') + Traceback (most recent call last): + ... + Invalid: Please enter a valid IP address (a.b.c.d) or IP network (a.b.c.d/e) + """ + + messages = dict(IPAddress._messages, + badFormat=_('Please enter a valid IP address (a.b.c.d)' + ' or IP network (a.b.c.d/e)'), + illegalBits=_('The network size (bits) must be within the range' + ' of 8-32 (not %(bits)r)')) + + def _validate_python(self, value, state): + try: + # Split into octets and bits + if '/' in value: # a.b.c.d/e + addr, bits = value.split('/') + else: # a.b.c.d + addr, bits = value, 32 + # Use IPAddress validator to validate the IP part + IPAddress._validate_python(self, addr, state) + # Bits (netmask) correct? + if not 8 <= int(bits) <= 32: + raise Invalid( + self.message('illegalBits', state, bits=bits), + value, state) + # Splitting faild: wrong syntax + except ValueError: + raise Invalid(self.message('badFormat', state), value, state) + + +class MACAddress(FancyValidator): + """ + Formencode validator to check whether a string is a correct hardware + (MAC) address. + + Examples:: + + >>> mac = MACAddress() + >>> mac.to_python('aa:bb:cc:dd:ee:ff') + 'aabbccddeeff' + >>> mac.to_python('aa:bb:cc:dd:ee:ff:e') + Traceback (most recent call last): + ... + Invalid: A MAC address must contain 12 digits and A-F; the value you gave has 13 characters + >>> mac.to_python('aa:bb:cc:dd:ee:fx') + Traceback (most recent call last): + ... + Invalid: MAC addresses may only contain 0-9 and A-F (and optionally :), not 'x' + >>> MACAddress(add_colons=True).to_python('aabbccddeeff') + 'aa:bb:cc:dd:ee:ff' + """ + + strip = True + valid_characters = '0123456789abcdefABCDEF' + add_colons = False + + messages = dict( + badLength=_('A MAC address must contain 12 digits and A-F;' + ' the value you gave has %(length)s characters'), + badCharacter=_('MAC addresses may only contain 0-9 and A-F' + ' (and optionally :), not %(char)r')) + + def _convert_to_python(self, value, state): + address = value.replace(':', '').lower() # remove colons + if len(address) != 12: + raise Invalid( + self.message('badLength', state, + length=len(address)), address, state) + for char in address: + if char not in self.valid_characters: + raise Invalid( + self.message('badCharacter', state, + char=char), address, state) + if self.add_colons: + address = '%s:%s:%s:%s:%s:%s' % ( + address[0:2], address[2:4], address[4:6], + address[6:8], address[8:10], address[10:12]) + return address + + _convert_from_python = _convert_to_python + + +class FormValidator(FancyValidator): + """ + A FormValidator is something that can be chained with a Schema. + + Unlike normal chaining the FormValidator can validate forms that + aren't entirely valid. + + The important method is .validate(), of course. It gets passed a + dictionary of the (processed) values from the form. If you have + .validate_partial_form set to True, then it will get the incomplete + values as well -- check with the "in" operator if the form was able + to process any particular field. + + Anyway, .validate() should return a string or a dictionary. If a + string, it's an error message that applies to the whole form. If + not, then it should be a dictionary of fieldName: errorMessage. + The special key "form" is the error message for the form as a whole + (i.e., a string is equivalent to {"form": string}). + + Returns None on no errors. + """ + + validate_partial_form = False + + validate_partial_python = None + validate_partial_other = None + + def is_empty(self, value): + return False + + def field_is_empty(self, value): + return is_empty(value) + + +class RequireIfMissing(FormValidator): + """ + Require one field based on another field being present or missing. + + This validator is applied to a form, not an individual field (usually + using a Schema's ``pre_validators`` or ``chained_validators``) and is + available under both names ``RequireIfMissing`` and ``RequireIfPresent``. + + If you provide a ``missing`` value (a string key name) then + if that field is missing the field must be entered. + This gives you an either/or situation. + + If you provide a ``present`` value (another string key name) then + if that field is present, the required field must also be present. + + :: + + >>> from formencode import validators + >>> v = validators.RequireIfPresent('phone_type', present='phone') + >>> v.to_python(dict(phone_type='', phone='510 420 4577')) + Traceback (most recent call last): + ... + Invalid: You must give a value for phone_type + >>> v.to_python(dict(phone='')) + {'phone': ''} + + Note that if you have a validator on the optionally-required + field, you should probably use ``if_missing=None``. This way you + won't get an error from the Schema about a missing value. For example:: + + class PhoneInput(Schema): + phone = PhoneNumber() + phone_type = String(if_missing=None) + chained_validators = [RequireIfPresent('phone_type', present='phone')] + """ + + # Field that potentially is required: + required = None + # If this field is missing, then it is required: + missing = None + # If this field is present, then it is required: + present = None + + __unpackargs__ = ('required',) + + def _convert_to_python(self, value_dict, state): + is_empty = self.field_is_empty + if is_empty(value_dict.get(self.required)) and ( + (self.missing and is_empty(value_dict.get(self.missing))) or + (self.present and not is_empty(value_dict.get(self.present)))): + raise Invalid( + _('You must give a value for %s') % self.required, + value_dict, state, + error_dict={self.required: + Invalid(self.message('empty', state), + value_dict.get(self.required), state)}) + return value_dict + +RequireIfPresent = RequireIfMissing + +class RequireIfMatching(FormValidator): + """ + Require a list of fields based on the value of another field. + + This validator is applied to a form, not an individual field (usually + using a Schema's ``pre_validators`` or ``chained_validators``). + + You provide a field name, an expected value and a list of required fields + (a list of string key names). If the value of the field, if present, + matches the value of ``expected_value``, then the validator will raise an + ``Invalid`` exception for every field in ``required_fields`` that is + missing. + + :: + + >>> from formencode import validators + >>> v = validators.RequireIfMatching('phone_type', expected_value='mobile', required_fields=['mobile']) + >>> v.to_python(dict(phone_type='mobile')) + Traceback (most recent call last): + ... + formencode.api.Invalid: You must give a value for mobile + >>> v.to_python(dict(phone_type='someothervalue')) + {'phone_type': 'someothervalue'} + """ + + # Field that we will check for its value: + field = None + # Value that the field shall have + expected_value = None + # If this field is present, then these fields are required: + required_fields = [] + + __unpackargs__ = ('field', 'expected_value') + + def _convert_to_python(self, value_dict, state): + is_empty = self.field_is_empty + + if self.field in value_dict and value_dict.get(self.field) == self.expected_value: + for required_field in self.required_fields: + if required_field not in value_dict or is_empty(value_dict.get(required_field)): + raise Invalid( + _('You must give a value for %s') % required_field, + value_dict, state, + error_dict={required_field: + Invalid(self.message('empty', state), + value_dict.get(required_field), state)}) + return value_dict + +class FieldsMatch(FormValidator): + """ + Tests that the given fields match, i.e., are identical. Useful + for password+confirmation fields. Pass the list of field names in + as `field_names`. + + :: + + >>> f = FieldsMatch('pass', 'conf') + >>> sorted(f.to_python({'pass': 'xx', 'conf': 'xx'}).items()) + [('conf', 'xx'), ('pass', 'xx')] + >>> f.to_python({'pass': 'xx', 'conf': 'yy'}) + Traceback (most recent call last): + ... + Invalid: conf: Fields do not match + """ + + show_match = False + field_names = None + validate_partial_form = True + + __unpackargs__ = ('*', 'field_names') + + messages = dict( + invalid=_('Fields do not match (should be %(match)s)'), + invalidNoMatch=_('Fields do not match'), + notDict=_('Fields should be a dictionary')) + + def __init__(self, *args, **kw): + super(FieldsMatch, self).__init__(*args, **kw) + if len(self.field_names) < 2: + raise TypeError('FieldsMatch() requires at least two field names') + + def validate_partial(self, field_dict, state): + for name in self.field_names: + if name not in field_dict: + return + self._validate_python(field_dict, state) + + def _validate_python(self, field_dict, state): + try: + ref = field_dict[self.field_names[0]] + except TypeError: + # Generally because field_dict isn't a dict + raise Invalid(self.message('notDict', state), field_dict, state) + except KeyError: + ref = '' + errors = {} + for name in self.field_names[1:]: + if field_dict.get(name, '') != ref: + if self.show_match: + errors[name] = self.message('invalid', state, + match=ref) + else: + errors[name] = self.message('invalidNoMatch', state) + if errors: + error_list = sorted(errors.items()) + error_message = '
\n'.join( + '%s: %s' % (name, value) for name, value in error_list) + raise Invalid(error_message, field_dict, state, error_dict=errors) + + +class CreditCardValidator(FormValidator): + """ + Checks that credit card numbers are valid (if not real). + + You pass in the name of the field that has the credit card + type and the field with the credit card number. The credit + card type should be one of "visa", "mastercard", "amex", + "dinersclub", "discover", "jcb". + + You must check the expiration date yourself (there is no + relation between CC number/types and expiration dates). + + :: + + >>> cc = CreditCardValidator() + >>> sorted(cc.to_python({'ccType': 'visa', 'ccNumber': '4111111111111111'}).items()) + [('ccNumber', '4111111111111111'), ('ccType', 'visa')] + >>> cc.to_python({'ccType': 'visa', 'ccNumber': '411111111111111'}) + Traceback (most recent call last): + ... + Invalid: ccNumber: You did not enter a valid number of digits + >>> cc.to_python({'ccType': 'visa', 'ccNumber': '411111111111112'}) + Traceback (most recent call last): + ... + Invalid: ccNumber: You did not enter a valid number of digits + >>> cc().to_python({}) + Traceback (most recent call last): + ... + Invalid: The field ccType is missing + """ + + validate_partial_form = True + + cc_type_field = 'ccType' + cc_number_field = 'ccNumber' + + __unpackargs__ = ('cc_type_field', 'cc_number_field') + + messages = dict( + notANumber=_('Please enter only the number, no other characters'), + badLength=_('You did not enter a valid number of digits'), + invalidNumber=_('That number is not valid'), + missing_key=_('The field %(key)s is missing')) + + def validate_partial(self, field_dict, state): + if not field_dict.get(self.cc_type_field, None) \ + or not field_dict.get(self.cc_number_field, None): + return None + self._validate_python(field_dict, state) + + def _validate_python(self, field_dict, state): + errors = self._validateReturn(field_dict, state) + if errors: + error_list = sorted(errors.items()) + raise Invalid( + '
\n'.join('%s: %s' % (name, value) + for name, value in error_list), + field_dict, state, error_dict=errors) + + def _validateReturn(self, field_dict, state): + for field in self.cc_type_field, self.cc_number_field: + if field not in field_dict: + raise Invalid( + self.message('missing_key', state, key=field), + field_dict, state) + ccType = field_dict[self.cc_type_field].lower().strip() + number = field_dict[self.cc_number_field].strip() + number = number.replace(' ', '') + number = number.replace('-', '') + try: + int(number) + except ValueError: + return {self.cc_number_field: self.message('notANumber', state)} + assert ccType in self._cardInfo, ( + "I can't validate that type of credit card") + foundValid = False + validLength = False + for prefix, length in self._cardInfo[ccType]: + if len(number) == length: + validLength = True + if number.startswith(prefix): + foundValid = True + break + if not validLength: + return {self.cc_number_field: self.message('badLength', state)} + if not foundValid: + return {self.cc_number_field: self.message('invalidNumber', state)} + if not self._validateMod10(number): + return {self.cc_number_field: self.message('invalidNumber', state)} + return None + + def _validateMod10(self, s): + """Check string with the mod 10 algorithm (aka "Luhn formula").""" + checksum, factor = 0, 1 + for c in reversed(s): + for c in str(factor * int(c)): + checksum += int(c) + factor = 3 - factor + return checksum % 10 == 0 + + _cardInfo = { + "visa": [('4', 16), + ('4', 13)], + "mastercard": [('51', 16), + ('52', 16), + ('53', 16), + ('54', 16), + ('55', 16)], + "discover": [('6011', 16)], + "amex": [('34', 15), + ('37', 15)], + "dinersclub": [('300', 14), + ('301', 14), + ('302', 14), + ('303', 14), + ('304', 14), + ('305', 14), + ('36', 14), + ('38', 14)], + "jcb": [('3', 16), + ('2131', 15), + ('1800', 15)], + } + + +class CreditCardExpires(FormValidator): + """ + Checks that credit card expiration date is valid relative to + the current date. + + You pass in the name of the field that has the credit card + expiration month and the field with the credit card expiration + year. + + :: + + >>> ed = CreditCardExpires() + >>> sorted(ed.to_python({'ccExpiresMonth': '11', 'ccExpiresYear': '2250'}).items()) + [('ccExpiresMonth', '11'), ('ccExpiresYear', '2250')] + >>> ed.to_python({'ccExpiresMonth': '10', 'ccExpiresYear': '2005'}) + Traceback (most recent call last): + ... + Invalid: ccExpiresMonth: Invalid Expiration Date
+ ccExpiresYear: Invalid Expiration Date + """ + + validate_partial_form = True + + cc_expires_month_field = 'ccExpiresMonth' + cc_expires_year_field = 'ccExpiresYear' + + __unpackargs__ = ('cc_expires_month_field', 'cc_expires_year_field') + + datetime_module = None + + messages = dict( + notANumber=_('Please enter numbers only for month and year'), + invalidNumber=_('Invalid Expiration Date')) + + def validate_partial(self, field_dict, state): + if not field_dict.get(self.cc_expires_month_field, None) \ + or not field_dict.get(self.cc_expires_year_field, None): + return None + self._validate_python(field_dict, state) + + def _validate_python(self, field_dict, state): + errors = self._validateReturn(field_dict, state) + if errors: + error_list = sorted(errors.items()) + raise Invalid( + '
\n'.join('%s: %s' % (name, value) + for name, value in error_list), + field_dict, state, error_dict=errors) + + def _validateReturn(self, field_dict, state): + ccExpiresMonth = str(field_dict[self.cc_expires_month_field]).strip() + ccExpiresYear = str(field_dict[self.cc_expires_year_field]).strip() + + try: + ccExpiresMonth = int(ccExpiresMonth) + ccExpiresYear = int(ccExpiresYear) + dt_mod = import_datetime(self.datetime_module) + now = datetime_now(dt_mod) + today = datetime_makedate(dt_mod, now.year, now.month, now.day) + next_month = ccExpiresMonth % 12 + 1 + next_month_year = ccExpiresYear + if next_month == 1: + next_month_year += 1 + expires_date = datetime_makedate( + dt_mod, next_month_year, next_month, 1) + assert expires_date > today + except ValueError: + return {self.cc_expires_month_field: + self.message('notANumber', state), + self.cc_expires_year_field: + self.message('notANumber', state)} + except AssertionError: + return {self.cc_expires_month_field: + self.message('invalidNumber', state), + self.cc_expires_year_field: + self.message('invalidNumber', state)} + + +class CreditCardSecurityCode(FormValidator): + """ + Checks that credit card security code has the correct number + of digits for the given credit card type. + + You pass in the name of the field that has the credit card + type and the field with the credit card security code. + + :: + + >>> code = CreditCardSecurityCode() + >>> sorted(code.to_python({'ccType': 'visa', 'ccCode': '111'}).items()) + [('ccCode', '111'), ('ccType', 'visa')] + >>> code.to_python({'ccType': 'visa', 'ccCode': '1111'}) + Traceback (most recent call last): + ... + Invalid: ccCode: Invalid credit card security code length + """ + + validate_partial_form = True + + cc_type_field = 'ccType' + cc_code_field = 'ccCode' + + __unpackargs__ = ('cc_type_field', 'cc_code_field') + + messages = dict( + notANumber=_('Please enter numbers only for credit card security code'), + badLength=_('Invalid credit card security code length')) + + def validate_partial(self, field_dict, state): + if (not field_dict.get(self.cc_type_field, None) + or not field_dict.get(self.cc_code_field, None)): + return None + self._validate_python(field_dict, state) + + def _validate_python(self, field_dict, state): + errors = self._validateReturn(field_dict, state) + if errors: + error_list = sorted(errors.items()) + raise Invalid( + '
\n'.join('%s: %s' % (name, value) + for name, value in error_list), + field_dict, state, error_dict=errors) + + def _validateReturn(self, field_dict, state): + ccType = str(field_dict[self.cc_type_field]).strip() + ccCode = str(field_dict[self.cc_code_field]).strip() + try: + int(ccCode) + except ValueError: + return {self.cc_code_field: self.message('notANumber', state)} + length = self._cardInfo[ccType] + if len(ccCode) != length: + return {self.cc_code_field: self.message('badLength', state)} + + # key = credit card type, value = length of security code + _cardInfo = dict(visa=3, mastercard=3, discover=3, amex=4) + + +def validators(): + """Return the names of all validators in this module.""" + return [name for name, value in globals().items() + if isinstance(value, type) and issubclass(value, Validator)] + +__all__ = ['Invalid'] + validators() + From 9c300f1b0250618124bf539d4e616ba40b2a1cf4 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 1 Feb 2019 02:17:04 +0300 Subject: [PATCH 195/509] Python 3.7 --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 0ebca65b..8802c9f8 100755 --- a/setup.py +++ b/setup.py @@ -49,6 +49,7 @@ "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", "Topic :: Database", "Topic :: Database :: Front-Ends", "Topic :: Software Development :: Libraries :: Python Modules", From f62927aeba372c25cf8dd9fb62a3c8c664a42925 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 1 Feb 2019 02:17:16 +0300 Subject: [PATCH 196/509] Tests: Require pytest < 5.0 for Python 2.7 --- devscripts/requirements/requirements_tests.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devscripts/requirements/requirements_tests.txt b/devscripts/requirements/requirements_tests.txt index 8e890d81..ae7bbd9a 100644 --- a/devscripts/requirements/requirements_tests.txt +++ b/devscripts/requirements/requirements_tests.txt @@ -1,4 +1,4 @@ -r requirements.txt -pytest +pytest < 5.0 pytest-cov From ac1e0a9c90126523b6b4d4b82f5783eecb03d620 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 1 Feb 2019 02:40:54 +0300 Subject: [PATCH 197/509] Style: Fix flake8 error E117 over-indented --- sqlobject/sqlite/sqliteconnection.py | 12 ++++++------ sqlobject/tests/test_views.py | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/sqlobject/sqlite/sqliteconnection.py b/sqlobject/sqlite/sqliteconnection.py index db83eee1..024b01c6 100644 --- a/sqlobject/sqlite/sqliteconnection.py +++ b/sqlobject/sqlite/sqliteconnection.py @@ -39,14 +39,14 @@ def __init__(self, filename, autoCommit=1, **kw): continue try: if driver in ('sqlite2', 'pysqlite2'): - from pysqlite2 import dbapi2 as sqlite - self.using_sqlite2 = True + from pysqlite2 import dbapi2 as sqlite + self.using_sqlite2 = True elif driver == 'sqlite3': - import sqlite3 as sqlite - self.using_sqlite2 = True + import sqlite3 as sqlite + self.using_sqlite2 = True elif driver in ('sqlite', 'sqlite1'): - import sqlite - self.using_sqlite2 = False + import sqlite + self.using_sqlite2 = False else: raise ValueError( 'Unknown SQLite driver "%s", ' diff --git a/sqlobject/tests/test_views.py b/sqlobject/tests/test_views.py index 08f44aba..44ed0457 100644 --- a/sqlobject/tests/test_views.py +++ b/sqlobject/tests/test_views.py @@ -97,7 +97,7 @@ def testAliasOverride(): def checkAttr(cls, id, attr, value): - assert getattr(cls.get(id), attr) == value + assert getattr(cls.get(id), attr) == value def testGetVPC(): From 928cf63ac5742258e3789f876392eeac52b2bc45 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 2 Feb 2019 18:51:06 +0300 Subject: [PATCH 198/509] Release 3.7.1 --- ANNOUNCE.rst | 39 +++++++++++++++++++++++---------------- README.rst | 2 +- devscripts/build-all-docs | 2 +- docs/News.rst | 5 +++++ setup.cfg | 5 ----- sqlobject/__version__.py | 8 ++++---- 6 files changed, 34 insertions(+), 27 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index d0fdf39e..cab716cb 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,28 +1,35 @@ Hello! -I'm pleased to announce version 3.8.0a1, the first alpha of the upcoming -release of branch 3.8 of SQLObject. +I'm pleased to announce version 3.7.1, the first bugfix release of branch +3.7 of SQLObject. -I'm pleased to announce version 3.8.0a2, the second alpha of the upcoming -release of branch 3.8 of SQLObject. -I'm pleased to announce version 3.8.0b1, the first beta of the upcoming -release of branch 3.8 of SQLObject. +What's new in SQLObject +======================= -I'm pleased to announce version 3.8.0rc1, the first release candidate -of the upcoming release of branch 3.8 of SQLObject. +Contributor for this release is Neil Muller. -I'm pleased to announce version 3.8.0, the first stable release of branch -3.8 of SQLObject. +Bug fixes +--------- -I'm pleased to announce version 3.8.1, the first bugfix release of branch -3.8 of SQLObject. +* Fixed a unicode problem in the latest mysqlclient. +Documentation +------------- -What's new in SQLObject -======================= +* Exclude sqlmeta members from some of the api docs. + The inclusion of of these sqlmeta members in these files breaks + reproducible builds. -Contributor for this release is Neil Muller. +Development +----------- + +* Source code was made flake8-clean using the latest flake8. + +CI +-- + +* Run tests with Python 3.7. For a more complete list, please see the news: http://sqlobject.org/News.html @@ -54,7 +61,7 @@ Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Download: -https://pypi.org/project/SQLObject/3.8.0a0.dev20180606/ +https://pypi.org/project/SQLObject/3.7.1/ News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 3e96729c..13c8ff2a 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,4 @@ -SQLObject 3.8.0 +SQLObject 3.7.1 =============== Thanks for looking at SQLObject. SQLObject is an object-relational diff --git a/devscripts/build-all-docs b/devscripts/build-all-docs index 233c0680..3f905287 100755 --- a/devscripts/build-all-docs +++ b/devscripts/build-all-docs @@ -11,7 +11,7 @@ cd "$PROG_DIR" && PROG_DIR="`pwd`" && cd "$PROG_DIR"/SQLObject && -build_docs 3.7.0 && +build_docs 3.7.1 && build_docs master devel && rm -rf docs/html && diff --git a/docs/News.rst b/docs/News.rst index 7d1d9466..1b968833 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,11 @@ News SQLObject 3.8.0 (master) ======================== +SQLObject 3.7.1 +=============== + +Released 2 Feb 2019. + Bug fixes --------- diff --git a/setup.cfg b/setup.cfg index af28274e..2b534b3c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -4,11 +4,6 @@ universal = 1 [easy_install] optimize = 2 -[egg_info] -tag_build = -tag_date = 0 -tag_svn_revision = 0 - [flake8] exclude = .git,.tox,docs/europython/*.py,validators.py # E305: expected 2 blank lines after class or function definition, found 1 diff --git a/sqlobject/__version__.py b/sqlobject/__version__.py index a21e936c..6e6740f7 100644 --- a/sqlobject/__version__.py +++ b/sqlobject/__version__.py @@ -1,8 +1,8 @@ -version = '3.8.0' +version = '3.7.1' major = 3 -minor = 8 -micro = 0 -release_level = 'dev' +minor = 7 +micro = 1 +release_level = 'final' serial = 0 version_info = (major, minor, micro, release_level, serial) From 1bb8e3a7fe61d7065ac77395713b5ea003aa1233 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 2 Feb 2019 18:59:51 +0300 Subject: [PATCH 199/509] Prepare for the next release [skip ci] --- ANNOUNCE.rst | 39 ++++++++++++++++----------------------- README.rst | 2 +- setup.cfg | 5 +++++ 3 files changed, 22 insertions(+), 24 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index cab716cb..84b0dcbe 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,35 +1,28 @@ Hello! -I'm pleased to announce version 3.7.1, the first bugfix release of branch -3.7 of SQLObject. +I'm pleased to announce version 3.8.0a1, the first alpha of the upcoming +release of branch 3.8 of SQLObject. +I'm pleased to announce version 3.8.0a2, the second alpha of the upcoming +release of branch 3.8 of SQLObject. -What's new in SQLObject -======================= - -Contributor for this release is Neil Muller. - -Bug fixes ---------- +I'm pleased to announce version 3.8.0b1, the first beta of the upcoming +release of branch 3.8 of SQLObject. -* Fixed a unicode problem in the latest mysqlclient. +I'm pleased to announce version 3.8.0rc1, the first release candidate +of the upcoming release of branch 3.8 of SQLObject. -Documentation -------------- +I'm pleased to announce version 3.8.0, the first stable release of branch +3.8 of SQLObject. -* Exclude sqlmeta members from some of the api docs. - The inclusion of of these sqlmeta members in these files breaks - reproducible builds. +I'm pleased to announce version 3.8.1, the first bugfix release of branch +3.8 of SQLObject. -Development ------------ -* Source code was made flake8-clean using the latest flake8. - -CI --- +What's new in SQLObject +======================= -* Run tests with Python 3.7. +Contributors for this release are For a more complete list, please see the news: http://sqlobject.org/News.html @@ -61,7 +54,7 @@ Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Download: -https://pypi.org/project/SQLObject/3.7.1/ +https://pypi.org/project/SQLObject/3.8.0a0.dev20190202/ News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 13c8ff2a..3e96729c 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,4 @@ -SQLObject 3.7.1 +SQLObject 3.8.0 =============== Thanks for looking at SQLObject. SQLObject is an object-relational diff --git a/setup.cfg b/setup.cfg index 2b534b3c..af28274e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -4,6 +4,11 @@ universal = 1 [easy_install] optimize = 2 +[egg_info] +tag_build = +tag_date = 0 +tag_svn_revision = 0 + [flake8] exclude = .git,.tox,docs/europython/*.py,validators.py # E305: expected 2 blank lines after class or function definition, found 1 From 1d4a2891843bd4c35b27ff6491d606cb00bbcc32 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 2 Feb 2019 23:35:42 +0300 Subject: [PATCH 200/509] Build(release): Skip exiting files at PyPI [skip ci] --- devscripts/release | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devscripts/release b/devscripts/release index 9dcff1a2..a329be3e 100755 --- a/devscripts/release +++ b/devscripts/release @@ -24,5 +24,5 @@ if [ "$state" = final ]; then ../sftp-frs fi && -twine upload dist/* && +twine upload --skip-existing dist/* && exec rm -rf build dist docs/html SQLObject.egg-info From 430bb09733f96084463e24ec132200df0bfebee7 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 3 Feb 2019 21:52:38 +0300 Subject: [PATCH 201/509] CI: Require pip < 19.1 for Python 2.7 and 3.4 --- .travis.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index d78da315..26512db5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -175,7 +175,7 @@ before_install: sudo chmod 644 /var/lib/firebird/create_test_db; fi -install: travis_retry pip install --upgrade pip setuptools tox coveralls codecov ppu +install: travis_retry pip install --upgrade "pip < 19.1" setuptools tox coveralls codecov ppu script: tox diff --git a/appveyor.yml b/appveyor.yml index 8530db41..dc63324e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -162,7 +162,7 @@ install: - "SET TOXPYTHON=%PYTHON_HOME%\\python.exe" - "python --version" - "python -c \"import struct; print(struct.calcsize('P') * 8)\"" - - "python -m pip install --upgrade pip setuptools" + - "python -m pip install --upgrade \"pip < 19.1\" setuptools" - "pip install --upgrade \"tox < 3.1\" ppu" - "pip --version" # List ODBC drivers From c021e99dfde5794d3cee318bb9b93e0a05dfbff6 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 7 Feb 2019 08:54:42 +0300 Subject: [PATCH 202/509] Tests: Remove devscripts/run-*; we have been using tox [skip ci] --- devscripts/run-all-tests | 13 ------------- devscripts/run-all-tests-ALL | 4 ---- devscripts/run-all-tests-pgsql | 2 -- devscripts/run-all-tests-sqlite | 2 -- devscripts/run-tests | 22 ---------------------- devscripts/run-tests-mysql-connector | 5 ----- devscripts/run-tests-mysqlclient | 5 ----- devscripts/run-tests-mysqldb | 5 ----- devscripts/run-tests-oursql | 5 ----- devscripts/run-tests-pg8000 | 5 ----- devscripts/run-tests-pgsql | 5 ----- devscripts/run-tests-pygresql | 5 ----- devscripts/run-tests-pymysql | 5 ----- devscripts/run-tests-pypostgresql | 5 ----- devscripts/run-tests-sqlite | 2 -- devscripts/run-tests-sqlite-memory | 2 -- 16 files changed, 92 deletions(-) delete mode 100755 devscripts/run-all-tests delete mode 100755 devscripts/run-all-tests-ALL delete mode 100755 devscripts/run-all-tests-pgsql delete mode 100755 devscripts/run-all-tests-sqlite delete mode 100755 devscripts/run-tests delete mode 100755 devscripts/run-tests-mysql-connector delete mode 100755 devscripts/run-tests-mysqlclient delete mode 100755 devscripts/run-tests-mysqldb delete mode 100755 devscripts/run-tests-oursql delete mode 100755 devscripts/run-tests-pg8000 delete mode 100755 devscripts/run-tests-pgsql delete mode 100755 devscripts/run-tests-pygresql delete mode 100755 devscripts/run-tests-pymysql delete mode 100755 devscripts/run-tests-pypostgresql delete mode 100755 devscripts/run-tests-sqlite delete mode 100755 devscripts/run-tests-sqlite-memory diff --git a/devscripts/run-all-tests b/devscripts/run-all-tests deleted file mode 100755 index 2e67aaa9..00000000 --- a/devscripts/run-all-tests +++ /dev/null @@ -1,13 +0,0 @@ -#! /bin/sh - -cd "`dirname \"$0\"`"/SQLObject && -SO_DIR="`dirname $0`" - -for py_ver in 2.7 3.4 3.5 3.6 3.7; do - echo "---------- PYTHON $py_ver "$1" ----------" - "$SO_DIR"/cleanup && - PY_VER=$py_ver "$SO_DIR"/run-tests-"$1" \ - sqlobject/tests/test_*.py sqlobject/inheritance/tests/test_*.py \ - sqlobject/versioning/test/test_*.py || exit 1 -done -echo "---------- 'DONE!' ----------" diff --git a/devscripts/run-all-tests-ALL b/devscripts/run-all-tests-ALL deleted file mode 100755 index 1d2d813c..00000000 --- a/devscripts/run-all-tests-ALL +++ /dev/null @@ -1,4 +0,0 @@ -#! /bin/sh - -"`dirname $0`"/run-all-tests-sqlite && -exec "`dirname $0`"/run-all-tests-pgsql diff --git a/devscripts/run-all-tests-pgsql b/devscripts/run-all-tests-pgsql deleted file mode 100755 index 283ee0c2..00000000 --- a/devscripts/run-all-tests-pgsql +++ /dev/null @@ -1,2 +0,0 @@ -#! /bin/sh -exec "`dirname $0`"/run-all-tests pgsql diff --git a/devscripts/run-all-tests-sqlite b/devscripts/run-all-tests-sqlite deleted file mode 100755 index ffa4ba59..00000000 --- a/devscripts/run-all-tests-sqlite +++ /dev/null @@ -1,2 +0,0 @@ -#! /bin/sh -exec "`dirname $0`"/run-all-tests sqlite diff --git a/devscripts/run-tests b/devscripts/run-tests deleted file mode 100755 index b81141da..00000000 --- a/devscripts/run-tests +++ /dev/null @@ -1,22 +0,0 @@ -#! /bin/sh - -START_DIR="`pwd`" -CWD="$START_DIR" - -while [ ! -f setup.py -a "$CWD" != / ]; do - cd .. && CWD="`pwd`" || exit 1 -done -if [ ! -f setup.py ]; then - echo "Cannot find setup.py, abort" >&2 - exit 1 -fi -SO_DIR="$CWD" - -PYTHONPATH="$CWD" -export PYTHONPATH - -TESTDB_URI="$1" -shift - -cd "$START_DIR" && -exec python"$PY_VER" `which pytest` $PYTEST_OPTIONS -D "$TESTDB_URI" "$@" diff --git a/devscripts/run-tests-mysql-connector b/devscripts/run-tests-mysql-connector deleted file mode 100755 index d9ed8177..00000000 --- a/devscripts/run-tests-mysql-connector +++ /dev/null @@ -1,5 +0,0 @@ -#! /bin/sh - -mysql -e 'create database sqlobject_test;' -"`dirname \"$0\"`/run-tests" 'mysql://localhost/sqlobject_test?driver=connector&charset=utf8&debug=1' "$@" -mysql -e 'drop database sqlobject_test;' diff --git a/devscripts/run-tests-mysqlclient b/devscripts/run-tests-mysqlclient deleted file mode 100755 index c99ca61c..00000000 --- a/devscripts/run-tests-mysqlclient +++ /dev/null @@ -1,5 +0,0 @@ -#! /bin/sh - -mysql -e 'create database sqlobject_test;' -"`dirname \"$0\"`/run-tests" 'mysql://localhost/sqlobject_test?driver=mysqldb&charset=utf8&debug=1' "$@" -mysql -e 'drop database sqlobject_test;' diff --git a/devscripts/run-tests-mysqldb b/devscripts/run-tests-mysqldb deleted file mode 100755 index 65b7e7e2..00000000 --- a/devscripts/run-tests-mysqldb +++ /dev/null @@ -1,5 +0,0 @@ -#! /bin/sh - -mysql -e 'create database sqlobject_test;' -"`dirname \"$0\"`/run-tests" 'mysql://localhost/sqlobject_test?driver=mysqldb&debug=1' "$@" -mysql -e 'drop database sqlobject_test;' diff --git a/devscripts/run-tests-oursql b/devscripts/run-tests-oursql deleted file mode 100755 index d01dfd61..00000000 --- a/devscripts/run-tests-oursql +++ /dev/null @@ -1,5 +0,0 @@ -#! /bin/sh - -mysql -e 'create database sqlobject_test;' -"`dirname \"$0\"`/run-tests" 'mysql://localhost/sqlobject_test?driver=oursql&charset=utf8&debug=1' "$@" -mysql -e 'drop database sqlobject_test;' diff --git a/devscripts/run-tests-pg8000 b/devscripts/run-tests-pg8000 deleted file mode 100755 index 751f8981..00000000 --- a/devscripts/run-tests-pg8000 +++ /dev/null @@ -1,5 +0,0 @@ -#! /bin/sh - -createdb -E utf-8 -l en_US.UTF-8 -T template0 test && -"`dirname \"$0\"`/run-tests" 'postgres:/var/run/postgresql/.s.PGSQL.5432/test?driver=pg8000&charset=utf-8&debug=1' "$@" -exec dropdb test diff --git a/devscripts/run-tests-pgsql b/devscripts/run-tests-pgsql deleted file mode 100755 index 38144bdb..00000000 --- a/devscripts/run-tests-pgsql +++ /dev/null @@ -1,5 +0,0 @@ -#! /bin/sh - -createdb -E utf-8 -l en_US.UTF-8 -T template0 test && -"`dirname \"$0\"`/run-tests" 'postgres:/test?driver=psycopg&charset=utf-8&debug=1' "$@" -exec dropdb test diff --git a/devscripts/run-tests-pygresql b/devscripts/run-tests-pygresql deleted file mode 100755 index 72072e8b..00000000 --- a/devscripts/run-tests-pygresql +++ /dev/null @@ -1,5 +0,0 @@ -#! /bin/sh - -createdb -E utf-8 -l en_US.UTF-8 -T template0 test && -"`dirname \"$0\"`/run-tests" 'postgres:/var/run/postgresql/test?driver=pygresql&charset=utf-8&debug=1' "$@" -exec dropdb test diff --git a/devscripts/run-tests-pymysql b/devscripts/run-tests-pymysql deleted file mode 100755 index 2000db18..00000000 --- a/devscripts/run-tests-pymysql +++ /dev/null @@ -1,5 +0,0 @@ -#! /bin/sh - -mysql -e 'create database sqlobject_test;' -"`dirname \"$0\"`/run-tests" 'mysql://localhost/sqlobject_test?driver=pymysql&charset=utf8&debug=1' "$@" -mysql -e 'drop database sqlobject_test;' diff --git a/devscripts/run-tests-pypostgresql b/devscripts/run-tests-pypostgresql deleted file mode 100755 index 614950fa..00000000 --- a/devscripts/run-tests-pypostgresql +++ /dev/null @@ -1,5 +0,0 @@ -#! /bin/sh - -createdb -E utf-8 -l en_US.UTF-8 -T template0 test && -"`dirname \"$0\"`/run-tests" 'postgres:/var/run/postgresql/.s.PGSQL.5432/test?driver=pypostgresql&charset=utf-8&debug=1' "$@" -exec dropdb test diff --git a/devscripts/run-tests-sqlite b/devscripts/run-tests-sqlite deleted file mode 100755 index b200a678..00000000 --- a/devscripts/run-tests-sqlite +++ /dev/null @@ -1,2 +0,0 @@ -#! /bin/sh -exec "`dirname \"$0\"`/run-tests" "sqlite:/tmp/test-sqlite.sqdb?debug=1" "$@" diff --git a/devscripts/run-tests-sqlite-memory b/devscripts/run-tests-sqlite-memory deleted file mode 100755 index 850229bf..00000000 --- a/devscripts/run-tests-sqlite-memory +++ /dev/null @@ -1,2 +0,0 @@ -#! /bin/sh -exec "`dirname \"$0\"`/run-tests" 'sqlite:/:memory:?debug=1&check_same_thread=' "$@" From 463502a84c3540addbd47c4f0110430f0c42ea20 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 7 Feb 2019 09:06:12 +0300 Subject: [PATCH 203/509] Build(devscripts): Run the scripts directly from devscripts/ subdir [skip ci] --- devscripts/BRANCH-CHECKLIST | 12 ++++++------ devscripts/RELEASE-CHECKLIST | 36 ++++++++++++++++++------------------ devscripts/build-all-docs | 7 +++---- devscripts/build-docs | 3 +-- devscripts/cleanup | 2 +- devscripts/flake8/run | 2 +- devscripts/publish-docs | 2 +- devscripts/release | 6 +++--- devscripts/setup | 2 +- 9 files changed, 35 insertions(+), 37 deletions(-) diff --git a/devscripts/BRANCH-CHECKLIST b/devscripts/BRANCH-CHECKLIST index 0357e27d..da9c16ac 100644 --- a/devscripts/BRANCH-CHECKLIST +++ b/devscripts/BRANCH-CHECKLIST @@ -1,8 +1,8 @@ 0. Run full test suite in master. Continue if all tests passed. -1. If the branching point is master run ../branch $NEW_BRANCH. If it's -not master run ../branch $NEW_BRANCH $TREEISH, where $TREEISH is -a branch, a commit id or a tag. +1. If the branching point is master run devscripts/branch $NEW_BRANCH. If + it's not master run devscripts/branch $NEW_BRANCH $TREEISH, where + $TREEISH is a branch, a commit id or a tag. 1a. The script creates a new branch and calls editor; edit README.rst, __version__.py and News.rst in the branch - set version. In @@ -20,11 +20,11 @@ a branch, a commit id or a tag. 2. To deprecate a version of Python edit files ANNOUNCE.rst, README.rst, devscripts/release, devscripts/setup, docs/News.rst, docs/SQLObject.rst, - docs/TODO.rst, requirements.txt, setup.py, sqlobject/main.py, - tox.ini in master. Edit metadata at SourceForge. + docs/TODO.rst, requirements.txt, setup.py, sqlobject/main.py, tox.ini in + master. Edit metadata at SourceForge. 3. Do a null-merge from the new branch to the higher branch or the master. -4. Run ../push-all to push all branches and tags to the public +4. Run devscripts/push-all to push all branches and tags to the public repositories. diff --git a/devscripts/RELEASE-CHECKLIST b/devscripts/RELEASE-CHECKLIST index e6949c4d..e85de5e2 100644 --- a/devscripts/RELEASE-CHECKLIST +++ b/devscripts/RELEASE-CHECKLIST @@ -4,8 +4,8 @@ 1. Check out the release branch. If it is a stable release - edit docs/News.rst to set release date. Commit. -2. If release branch is not master - run ../prerelease $NEW_TAG; if it's - master - run ../prerelease $NEW_TAG master. +2. If release branch is not master - run devscripts/prerelease $NEW_TAG; if + it's master - run devscripts/prerelease $NEW_TAG master. The script checks out the release branch and calls editor; update version, the list of contributors, the list of changes and download @@ -24,28 +24,28 @@ 3. If it's not master - null-merge to the next higher branch. -4. If release branch is not master - run ../prerelease-tag $NEW_TAG; if - it's master - run ../prerelease-tag $NEW_TAG master. This checks out - the release branch and creates the new tag at the head of the release - branch. +4. If release branch is not master - run devscripts/prerelease-tag + $NEW_TAG; if it's master - run devscripts/prerelease-tag $NEW_TAG + master. This checks out the release branch and creates the new tag at + the head of the release branch. -5. Run ../release. This generates and uploads new archives to PyPI and - if it is a stable release - uploads archives and release announcement - (ANNOUNCE.rst) to SourceForge. +5. Run devscripts/release. This generates and uploads new archives to PyPI + and if it is a stable release - uploads archives and release + announcement (ANNOUNCE.rst) to SourceForge. 6. Move old releases at SourceForge to subdirectory OldFiles. -7. Run ../push-all in the development repository to push all branches - and tags to the public repositories. +7. Run devscripts/push-all in the development repository to push all + branches and tags to the public repositories. -8. Run ../postrelease. The script restores ANNOUNCE.rst and setup.cfg - from the previous commit (HEAD~). It calls editor; update next version, - remove the list of contributors and the list of changes, edit download - URL in ANNOUNCE.rst. Edit README.rst and docs/News.rst - add new - version. +8. Run devscripts/postrelease. The script restores ANNOUNCE.rst and + setup.cfg from the previous commit (HEAD~). It calls editor; update next + version, remove the list of contributors and the list of changes, edit + download URL in ANNOUNCE.rst. Edit README.rst and docs/News.rst - add + new version. -9. Generate new docs using ./build-all-docs. Upload docs using - ./publish-docs. +9. Generate new docs using devscripts/build-all-docs. Upload docs using + devscripts/publish-docs. 10. Send announcement to the SQLObject mailing list. For a stable release send announcements to python, python-announce and python-db diff --git a/devscripts/build-all-docs b/devscripts/build-all-docs index 3f905287..746018a3 100755 --- a/devscripts/build-all-docs +++ b/devscripts/build-all-docs @@ -2,15 +2,14 @@ build_docs() { git checkout "$1" && - ../build-docs && + devscripts/build-docs && rsync -ahP --del --exclude=/robots.txt docs/html/ ../SQLObject-docs/"$2"/ } -PROG_DIR="`dirname \"$0\"`" && -cd "$PROG_DIR" && +cd "`dirname \"$0\"`" && PROG_DIR="`pwd`" && -cd "$PROG_DIR"/SQLObject && +cd .. && build_docs 3.7.1 && build_docs master devel && rm -rf docs/html && diff --git a/devscripts/build-docs b/devscripts/build-docs index 8f9895bd..dcd94d87 100755 --- a/devscripts/build-docs +++ b/devscripts/build-docs @@ -1,5 +1,4 @@ #! /bin/sh -cd "`dirname \"$0\"`"/SQLObject && -cd docs && +cd "`dirname \"$0\"`"/../docs && exec ./rebuild diff --git a/devscripts/cleanup b/devscripts/cleanup index 19fdb46f..77e348b3 100755 --- a/devscripts/cleanup +++ b/devscripts/cleanup @@ -1,5 +1,5 @@ #! /bin/sh -cd "`dirname $0`" && +cd "`dirname $0`"/../.. && find . \( -name \*.orig -o -name \*.rej -o -name \*.tmp -o -name \*.log \) -type f -delete && exec rm -f /tmp/test-sqlite.sqdb* diff --git a/devscripts/flake8/run b/devscripts/flake8/run index 2000dd6d..ee82ca24 100755 --- a/devscripts/flake8/run +++ b/devscripts/flake8/run @@ -1,5 +1,5 @@ #! /bin/sh -flake8 ../SQLObject | sort >all-results && +flake8 ../.. | sort >all-results && awk '{print $2}' all-results | sort | uniq -c | sort -k 1,1nr -k 2,2 >sort-by-lines diff --git a/devscripts/publish-docs b/devscripts/publish-docs index 1ecdc505..f69df594 100755 --- a/devscripts/publish-docs +++ b/devscripts/publish-docs @@ -1,5 +1,5 @@ #! /bin/sh -cd "`dirname \"$0\"`"/SQLObject-docs && chmod -R a+rX . && +cd "`dirname \"$0\"`"/../../SQLObject-docs && chmod -R a+rX . && exec rsync -hlrtP4 --del . \ web.sourceforge.net:/home/project-web/sqlobject/htdocs/ diff --git a/devscripts/release b/devscripts/release index a329be3e..35154c95 100755 --- a/devscripts/release +++ b/devscripts/release @@ -1,11 +1,11 @@ #! /bin/sh -cd "`dirname \"$0\"`"/SQLObject && +cd "`dirname \"$0\"`"/.. && umask 022 && chmod -R a+rX . && set-commit-date.py && -../build-docs && +devscripts/build-docs && python setup.py build_py && python setup.py build --executable '/usr/bin/env python' && @@ -21,7 +21,7 @@ split_tag $version if [ "$state" = final ]; then rsync -ahP4 dist/* frs.sourceforge.net:/home/frs/project/sqlobject/sqlobject/"$version"/ && rsync -ahP4 ANNOUNCE.rst frs.sourceforge.net:/home/frs/project/sqlobject/sqlobject/"$version"/README.rst || exit 1 - ../sftp-frs + devscripts/sftp-frs fi && twine upload --skip-existing dist/* && diff --git a/devscripts/setup b/devscripts/setup index c85aae00..04ed1b78 100755 --- a/devscripts/setup +++ b/devscripts/setup @@ -1,7 +1,7 @@ #! /bin/sh umask 022 # -rwxr-xr-x -cd "`dirname \"$0\"`"/SQLObject && +cd "`dirname \"$0\"`"/.. && for py_ver in 2.7 3.4 3.5 3.6 3.7; do python$py_ver -m pip install --install-option=-O2 --upgrade . From 362e10795e5a589be9342498f4bd79820a9de836 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 7 Feb 2019 16:44:52 +0300 Subject: [PATCH 204/509] Build(setup.py): Use `importlib` instead of deprecated `imp` for Python 3.4+ --- setup.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 8802c9f8..8ef5c811 100755 --- a/setup.py +++ b/setup.py @@ -1,8 +1,24 @@ #!/usr/bin/env python -from imp import load_source from os.path import abspath, dirname, join from setuptools import setup +import sys + +if sys.version_info[:2] == (2, 7): + from imp import load_source + +elif sys.version_info >= (3, 4): + from importlib.machinery import SourceFileLoader + import types + + def load_source(fullname, path): + loader = SourceFileLoader(fullname, path) + loaded = types.ModuleType(loader.name) + loader.exec_module(loaded) + return loaded + +else: + raise ImportError("SQLObject requires Python 2.7 or 3.4+") versionpath = join(abspath(dirname(__file__)), "sqlobject", "__version__.py") sqlobject_version = load_source("sqlobject_version", versionpath) From d7ce8c4ae274bfc08e711f8a6f840252758f930b Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 7 Feb 2019 17:24:16 +0300 Subject: [PATCH 205/509] CI(travis): remove deprecated `sudo` keyword --- .travis.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 26512db5..4f375a4f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,9 +4,6 @@ branches: only: - master -# Prefer docker container with setuid/sudo -sudo: required - language: python python: From 8cf109f4bc7084e6a177a4c4893c3cc90c4c8d95 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 11 Feb 2019 23:01:12 +0300 Subject: [PATCH 206/509] Feat(compat): Use imp for Python 2, importlib for Python 3 The code in `sqlobject/compat.py` is still outdated and should be updated for Python 3.5. --- sqlobject/compat.py | 19 +++++++++++++++++++ sqlobject/tests/test_compat.py | 10 ++++++++++ sqlobject/util/moduleloader.py | 13 ++----------- 3 files changed, 31 insertions(+), 11 deletions(-) create mode 100644 sqlobject/tests/test_compat.py diff --git a/sqlobject/compat.py b/sqlobject/compat.py index 18aba9d0..a5a379c6 100644 --- a/sqlobject/compat.py +++ b/sqlobject/compat.py @@ -1,3 +1,4 @@ +import os import sys import types @@ -29,3 +30,21 @@ def __new__(cls, name, this_bases, d): unicode_type = str class_types = (type,) buffer_type = memoryview + +if PY2: + import imp + + def load_module_from_file(base_name, module_name, filename): + fp, pathname, stuff = imp.find_module( + base_name, [os.path.dirname(filename)]) + try: + module = imp.load_module(module_name, fp, pathname, stuff) + finally: + fp.close() + return module +else: + import importlib.util + + def load_module_from_file(base_name, module_name, filename): + specs = importlib.util.spec_from_file_location(module_name, filename) + return specs.loader.load_module() diff --git a/sqlobject/tests/test_compat.py b/sqlobject/tests/test_compat.py new file mode 100644 index 00000000..3b5fc653 --- /dev/null +++ b/sqlobject/tests/test_compat.py @@ -0,0 +1,10 @@ +from sqlobject.compat import load_module_from_file + + +def test_load_module_from_path(): + module = load_module_from_file( + 'test_compat', 'sqlobject.tests.test_compat', __file__ + ) + assert module.__file__ == __file__ + assert module.__name__ == 'sqlobject.tests.test_compat' + assert module.__package__ == 'sqlobject.tests' diff --git a/sqlobject/util/moduleloader.py b/sqlobject/util/moduleloader.py index bbb8d0c6..ee7fb2ef 100644 --- a/sqlobject/util/moduleloader.py +++ b/sqlobject/util/moduleloader.py @@ -1,6 +1,6 @@ -import imp import os import sys +from sqlobject.compat import load_module_from_file def load_module(module_name): @@ -24,7 +24,6 @@ def load_module_from_name(filename, module_name): % (os.path.dirname(filename), e)) f.write('#\n') f.close() - fp = None if module_name in sys.modules: return sys.modules[module_name] if '.' in module_name: @@ -33,12 +32,4 @@ def load_module_from_name(filename, module_name): load_module_from_name(os.path.dirname(filename), parent_name) else: base_name = module_name - fp = None - try: - fp, pathname, stuff = imp.find_module( - base_name, [os.path.dirname(filename)]) - module = imp.load_module(module_name, fp, pathname, stuff) - finally: - if fp is not None: - fp.close() - return module + return load_module_from_file(base_name, module_name, filename) From 1ba34efb82000764682764a21a7becc2e86e8360 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 18 Feb 2019 21:06:56 +0300 Subject: [PATCH 207/509] Build(setup): Use exec[file] to get version from __version__.py Use exec[file] instead of imp/importlib. --- setup.py | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/setup.py b/setup.py index 8ef5c811..c31573bd 100755 --- a/setup.py +++ b/setup.py @@ -4,25 +4,18 @@ from setuptools import setup import sys +versionpath = join(abspath(dirname(__file__)), 'sqlobject', '__version__.py') +sqlobject_version = {} + if sys.version_info[:2] == (2, 7): - from imp import load_source + execfile(versionpath, sqlobject_version) elif sys.version_info >= (3, 4): - from importlib.machinery import SourceFileLoader - import types - - def load_source(fullname, path): - loader = SourceFileLoader(fullname, path) - loaded = types.ModuleType(loader.name) - loader.exec_module(loaded) - return loaded + exec(open(versionpath, 'rU').read(), sqlobject_version) else: raise ImportError("SQLObject requires Python 2.7 or 3.4+") -versionpath = join(abspath(dirname(__file__)), "sqlobject", "__version__.py") -sqlobject_version = load_source("sqlobject_version", versionpath) - subpackages = ['firebird', 'include', 'include.tests', 'inheritance', 'inheritance.tests', 'manager', 'maxdb', 'mysql', 'mssql', 'postgres', 'rdbhost', @@ -31,7 +24,7 @@ def load_source(fullname, path): setup( name="SQLObject", - version=sqlobject_version.version, + version=sqlobject_version['version'], description="Object-Relational Manager, aka database wrapper", long_description="""\ SQLObject is a popular *Object Relational Manager* for providing an @@ -76,12 +69,12 @@ def load_source(fullname, path): maintainer_email="phd@phdru.name", url="http://sqlobject.org/", download_url="https://pypi.org/project/SQLObject/%s/" % - sqlobject_version.version, + sqlobject_version['version'], project_urls={ 'Homepage': 'http://sqlobject.org/', 'Development docs': 'http://sqlobject.org/devel/', 'Download': 'https://pypi.org/project/SQLObject/%s/' % - sqlobject_version.version, + sqlobject_version['version'], 'Github repo': 'https://github.com/sqlobject', 'Issue tracker': 'https://github.com/sqlobject/sqlobject/issues', 'SourceForge project': 'https://sourceforge.net/projects/sqlobject/', From 46c236d21fad78824a6ff1505c188316e3247a6b Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 18 Feb 2019 21:31:34 +0300 Subject: [PATCH 208/509] Style(setup): Fix flake8 F821 undefined name `execfile` under Python 3 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index c31573bd..9e5a9543 100755 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ sqlobject_version = {} if sys.version_info[:2] == (2, 7): - execfile(versionpath, sqlobject_version) + execfile(versionpath, sqlobject_version) # noqa: F821 'execfile' Py3 elif sys.version_info >= (3, 4): exec(open(versionpath, 'rU').read(), sqlobject_version) From f542e4e1ae3c047a124922ca90df755d50f907d1 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 25 Feb 2019 19:35:49 +0300 Subject: [PATCH 209/509] Docs,tests: Limit Sphinx and pytest versions for Python 2.7 and 3.4 --- devscripts/requirements/requirements_docs.txt | 3 ++- devscripts/requirements/requirements_tests.txt | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/devscripts/requirements/requirements_docs.txt b/devscripts/requirements/requirements_docs.txt index 94d38eb8..e36ba634 100644 --- a/devscripts/requirements/requirements_docs.txt +++ b/devscripts/requirements/requirements_docs.txt @@ -1,3 +1,4 @@ -r requirements.txt -Sphinx +Sphinx < 2.0; python_version == '2.7' or python_version == '3.4' +Sphinx; python_version >= '3.5' diff --git a/devscripts/requirements/requirements_tests.txt b/devscripts/requirements/requirements_tests.txt index ae7bbd9a..9d647535 100644 --- a/devscripts/requirements/requirements_tests.txt +++ b/devscripts/requirements/requirements_tests.txt @@ -1,4 +1,5 @@ -r requirements.txt -pytest < 5.0 +pytest < 5.0; python_version == '2.7' or python_version == '3.4' +pytest; python_version >= '3.5' pytest-cov From 8fd31c32bd420f19cf02e64088436d82e936aaab Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 25 Feb 2019 21:25:30 +0300 Subject: [PATCH 210/509] CI: Remove branch limitations --- .travis.yml | 6 ------ appveyor.yml | 8 -------- 2 files changed, 14 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4f375a4f..a2627249 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,3 @@ -# Only test master and pull requests; skip tags. -# Other branches can allow themselves. -branches: - only: - - master - language: python python: diff --git a/appveyor.yml b/appveyor.yml index dc63324e..953cc8ac 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -3,14 +3,6 @@ # and Michael Sverdlik's appveyor-utils (https://github.com/cloudify-cosmo/appveyor-utils) version: '{branch}-{build}' -# Only test master and pull requests; skip tags. -# Other branches can allow themselves. -branches: - only: - - master -skip_branch_with_pr: false -skip_tags: true - cache: - '%LOCALAPPDATA%\pip\Cache' From dc3ff012c220b6ee44a0ede7b467de4c0f5167b8 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 25 Feb 2019 22:54:38 +0300 Subject: [PATCH 211/509] Tests(tox): Use easy_install to install mxDateTime Use `easy_install` to install `egenix-mx-base` eggs directly from downloads.egenix.com. --- tox.ini | 109 +++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 81 insertions(+), 28 deletions(-) diff --git a/tox.ini b/tox.ini index 0af7ecbe..dc17448c 100644 --- a/tox.ini +++ b/tox.ini @@ -17,7 +17,6 @@ commands = {envpython} -c "import struct; print(struct.calcsize('P') * 8)" deps = -rdevscripts/requirements/requirements_tests.txt - py27: egenix-mx-base mysqldb: mysql-python mysqlclient: mysqlclient mysql-connector: mysql-connector <= 2.2.2 @@ -55,7 +54,9 @@ commands = mysql -uroot -e 'drop database sqlobject_test;' [testenv:py27-mysqldb] -commands = {[mysqldb]commands} +commands = + easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base + {[mysqldb]commands} [mysqlclient] commands = @@ -86,7 +87,9 @@ commands = mysql -uroot -e 'drop database sqlobject_test;' [testenv:py27-mysql-connector] -commands = {[mysql-connector]commands} +commands = + easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base + {[mysql-connector]commands} [testenv:py34-mysql-connector] commands = {[mysql-connector]commands} @@ -109,7 +112,9 @@ commands = mysql -uroot -e 'drop database sqlobject_test;' [testenv:py27-mysql-oursql] -commands = {[oursql]commands} +commands = + easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base + {[oursql]commands} [testenv:py34-mysql-oursql3] commands = {[oursql]commands} @@ -132,7 +137,9 @@ commands = mysql -uroot -e 'drop database sqlobject_test;' [testenv:py27-pymysql] -commands = {[pymysql]commands} +commands = + easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base + {[pymysql]commands} [testenv:py34-pymysql] commands = {[pymysql]commands} @@ -156,7 +163,9 @@ commands = mysql -uroot -e 'drop database sqlobject_test;' [testenv:py27-mysql-pyodbc] -commands = {[mysql-pyodbc]commands} +commands = + easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base + {[mysql-pyodbc]commands} [testenv:py34-mysql-pyodbc] commands = {[mysql-pyodbc]commands} @@ -179,7 +188,9 @@ commands = mysql -uroot -e 'drop database sqlobject_test;' [testenv:py27-mysql-pypyodbc] -commands = {[mysql-pypyodbc]commands} +commands = + easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base + {[mysql-pypyodbc]commands} [testenv:py34-mysql-pypyodbc] commands = {[mysql-pypyodbc]commands} @@ -203,7 +214,9 @@ commands = dropdb -U postgres -w sqlobject_test [testenv:py27-postgres-psycopg] -commands = {[psycopg]commands} +commands = + easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base + {[psycopg]commands} [testenv:py34-postgres-psycopg] commands = {[psycopg]commands} @@ -226,7 +239,9 @@ commands = dropdb -U postgres -w sqlobject_test [testenv:py27-postgres-pygresql] -commands = {[pygresql]commands} +commands = + easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base + {[pygresql]commands} [testenv:py34-postgres-pygresql] commands = {[pygresql]commands} @@ -269,7 +284,9 @@ commands = dropdb -U postgres -w sqlobject_test [testenv:py27-postgres-pg8000] -commands = {[pg8000]commands} +commands = + easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base + {[pg8000]commands} [testenv:py34-postgres-pg8000] commands = {[pg8000]commands} @@ -293,7 +310,9 @@ commands = dropdb -U postgres -w sqlobject_test [testenv:py27-postgres-pyodbc] -commands = {[postgres-pyodbc]commands} +commands = + easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base + {[postgres-pyodbc]commands} [testenv:py34-postgres-pyodbc] commands = {[postgres-pyodbc]commands} @@ -316,7 +335,9 @@ commands = dropdb -U postgres -w sqlobject_test [testenv:py27-postgres-pypyodbc] -commands = {[postgres-pypyodbc]commands} +commands = + easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base + {[postgres-pypyodbc]commands} [testenv:py34-postgres-pypyodbc] commands = {[postgres-pypyodbc]commands} @@ -340,7 +361,9 @@ commands = rm -f /tmp/sqlobject_test.sqdb [testenv:py27-sqlite] -commands = {[sqlite]commands} +commands = + easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base + {[sqlite]commands} [testenv:py34-sqlite] commands = {[sqlite]commands} @@ -360,7 +383,9 @@ commands = pytest --cov=sqlobject -D sqlite:/:memory:?debug=1 [testenv:py27-sqlite-memory] -commands = {[sqlite-memory]commands} +commands = + easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base + {[sqlite-memory]commands} [testenv:py34-sqlite-memory] commands = {[sqlite-memory]commands} @@ -384,7 +409,9 @@ commands = sudo rm -f /tmp/test.fdb [testenv:py27-firebird-fdb] -commands = {[fdb]commands} +commands = + easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base + {[fdb]commands} [testenv:py34-firebird-fdb] commands = {[fdb]commands} @@ -407,7 +434,9 @@ commands = sudo rm -f /tmp/test.fdb [testenv:py27-firebirdsql] -commands = {[firebirdsql]commands} +commands = + easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base + {[firebirdsql]commands} [testenv:py34-firebirdsql] commands = {[firebirdsql]commands} @@ -450,7 +479,9 @@ commands = [testenv:py27-mssql-pyodbc-w32] platform = win32 -commands = {[mssql-pyodbc-w32]commands} +commands = + easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base + {[mssql-pyodbc-w32]commands} [testenv:py34-mssql-pyodbc-w32] platform = win32 @@ -481,7 +512,9 @@ commands = [testenv:py27-mysql-connector-w32] platform = win32 -commands = {[mysql-connector-w32]commands} +commands = + easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base + {[mysql-connector-w32]commands} [testenv:py34-mysql-connector-w32] platform = win32 @@ -512,7 +545,9 @@ commands = [testenv:py27-pymysql-w32] platform = win32 -commands = {[pymysql-w32]commands} +commands = + easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base + {[pymysql-w32]commands} [testenv:py34-pymysql-w32] platform = win32 @@ -544,7 +579,9 @@ commands = [testenv:py27-mysql-pyodbc-w32] platform = win32 -commands = {[mysql-pyodbc-w32]commands} +commands = + easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base + {[mysql-pyodbc-w32]commands} [testenv:py34-mysql-pyodbc-w32] platform = win32 @@ -576,7 +613,9 @@ commands = [testenv:py27-mysql-pypyodbc-w32] platform = win32 -commands = {[mysql-pypyodbc-w32]commands} +commands = + easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base + {[mysql-pypyodbc-w32]commands} [testenv:py34-mysql-pypyodbc-w32] platform = win32 @@ -607,7 +646,9 @@ commands = [testenv:py27-postgres-psycopg-w32] platform = win32 -commands = {[psycopg-w32]commands} +commands = + easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base + {[psycopg-w32]commands} [testenv:py34-postgres-psycopg-w32] platform = win32 @@ -638,7 +679,9 @@ commands = [testenv:py27-postgres-pygresql-w32] platform = win32 -commands = {[pygresql-w32]commands} +commands = + easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base + {[pygresql-w32]commands} [testenv:py34-postgres-pygresql-w32] platform = win32 @@ -696,7 +739,9 @@ commands = [testenv:py27-postgres-pg8000-w32] platform = win32 -commands = {[pg8000-w32]commands} +commands = + easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base + {[pg8000-w32]commands} [testenv:py34-postgres-pg8000-w32] platform = win32 @@ -728,7 +773,9 @@ commands = [testenv:py27-postgres-pyodbc-w32] platform = win32 -commands = {[postgres-pyodbc-w32]commands} +commands = + easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base + {[postgres-pyodbc-w32]commands} [testenv:py34-postgres-pyodbc-w32] platform = win32 @@ -760,7 +807,9 @@ commands = [testenv:py27-postgres-pypyodbc-w32] platform = win32 -commands = {[postgres-pypyodbc-w32]commands} +commands = + easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base + {[postgres-pypyodbc-w32]commands} [testenv:py34-postgres-pypyodbc-w32] platform = win32 @@ -788,7 +837,9 @@ commands = [testenv:py27-sqlite-w32] platform = win32 -commands = {[sqlite-w32]commands} +commands = + easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base + {[sqlite-w32]commands} [testenv:py34-sqlite-w32] platform = win32 @@ -816,7 +867,9 @@ commands = [testenv:py27-sqlite-memory-w32] platform = win32 -commands = {[sqlite-memory-w32]commands} +commands = + easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base + {[sqlite-memory-w32]commands} [testenv:py34-sqlite-memory-w32] platform = win32 From 570cf8d5a43d4a6aeacaa4f1ebb6e92f09d35fbb Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 27 Feb 2019 00:36:46 +0300 Subject: [PATCH 212/509] Tests: Fix DeprecationWarning from pytest.raises(..., "code") --- sqlobject/tests/test_select.py | 6 +++--- sqlobject/tests/test_select_through.py | 3 ++- sqlobject/tests/test_transactions.py | 5 +++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/sqlobject/tests/test_select.py b/sqlobject/tests/test_select.py index 41ef0efd..3a0055ea 100644 --- a/sqlobject/tests/test_select.py +++ b/sqlobject/tests/test_select.py @@ -108,10 +108,10 @@ def test_select_getOne(): assert IterTest.selectBy(name='a').getOne() == a assert IterTest.select(IterTest.q.name == 'b').getOne() == b assert IterTest.selectBy(name='c').getOne(None) is None - raises(SQLObjectNotFound, 'IterTest.selectBy(name="c").getOne()') + raises(SQLObjectNotFound, IterTest.selectBy(name="c").getOne) IterTest(name='b') - raises(SQLObjectIntegrityError, 'IterTest.selectBy(name="b").getOne()') - raises(SQLObjectIntegrityError, 'IterTest.selectBy(name="b").getOne(None)') + raises(SQLObjectIntegrityError, IterTest.selectBy(name="b").getOne) + raises(SQLObjectIntegrityError, IterTest.selectBy(name="b").getOne, None) def test_selectBy(): diff --git a/sqlobject/tests/test_select_through.py b/sqlobject/tests/test_select_through.py index b043a031..4852a349 100644 --- a/sqlobject/tests/test_select_through.py +++ b/sqlobject/tests/test_select_through.py @@ -40,7 +40,8 @@ def setup_module(mod): def testBadRef(): - pytest.raises(AttributeError, 'threes[0].throughTo.four') + with pytest.raises(AttributeError): + threes[0].throughTo.four def testThroughFK(): diff --git a/sqlobject/tests/test_transactions.py b/sqlobject/tests/test_transactions.py index b9ac5006..56ce7f8e 100644 --- a/sqlobject/tests/test_transactions.py +++ b/sqlobject/tests/test_transactions.py @@ -109,8 +109,9 @@ def test_transaction_delete(close=False): bOutID = bOutInst.id # noqa: bOutID is used in the string code below trans.commit(close=close) assert bOut.count() == 0 - raises(SQLObjectNotFound, "SOTestSOTrans.get(bOutID)") - raises(SQLObjectNotFound, "bOutInst.name") + raises(SQLObjectNotFound, SOTestSOTrans.get, bOutID) + with raises(SQLObjectNotFound): + bOutInst.name finally: trans.rollback() connection.autoCommit = True From be130c38f1ea2f31965345a537157124b6875dca Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 2 Mar 2019 20:57:22 +0300 Subject: [PATCH 213/509] Refactor(compat.py): Rename `stuff` to `description` --- sqlobject/compat.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sqlobject/compat.py b/sqlobject/compat.py index a5a379c6..72d696f4 100644 --- a/sqlobject/compat.py +++ b/sqlobject/compat.py @@ -35,10 +35,10 @@ def __new__(cls, name, this_bases, d): import imp def load_module_from_file(base_name, module_name, filename): - fp, pathname, stuff = imp.find_module( + fp, pathname, description = imp.find_module( base_name, [os.path.dirname(filename)]) try: - module = imp.load_module(module_name, fp, pathname, stuff) + module = imp.load_module(module_name, fp, pathname, description) finally: fp.close() return module From ed64be0ed032055b0a6613fe3051d83a74ded566 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 2 Apr 2019 02:38:37 +0300 Subject: [PATCH 214/509] CI: At Travis run tests with oursql driver updated for Python 3.7 --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index a2627249..acd3e873 100644 --- a/.travis.yml +++ b/.travis.yml @@ -51,6 +51,9 @@ matrix: env: TOXENV=py35-mysql-oursql3 - python: "3.6" env: TOXENV=py36-mysql-oursql3 + - python: "3.7" + dist: xenial + env: TOXENV=py37-mysql-oursql3 - python: "2.7" env: TOXENV=py27-pymysql - python: "3.4" From 4325abbc7b9362f9edbf23fa08cafcf208c06bf9 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sun, 21 Apr 2019 20:12:40 +0200 Subject: [PATCH 215/509] Usage of augmented assignment statements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Source code like “var = var + …” was specified at some places so far. Use augmented assignment statements instead because they are succinct and can be more efficient. https://docs.python.org/3/reference/simple_stmts.html#augmented-assignment-statements Signed-off-by: Markus Elfring --- sqlobject/col.py | 9 ++++----- sqlobject/dbconnection.py | 8 ++++---- sqlobject/joins.py | 4 ++-- sqlobject/tests/test_select.py | 2 +- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/sqlobject/col.py b/sqlobject/col.py index 81195393..a22fb666 100644 --- a/sqlobject/col.py +++ b/sqlobject/col.py @@ -733,9 +733,9 @@ def addSQLAttrs(self, str): if self.length and self.length >= 1: _ret = "%s(%d)" % (_ret, self.length) if self.unsigned: - _ret = _ret + " UNSIGNED" + _ret += " UNSIGNED" if self.zerofill: - _ret = _ret + " ZEROFILL" + _ret += " ZEROFILL" return _ret def _sqlType(self): @@ -1092,9 +1092,8 @@ def maxdbCreateSQL(self): sql = ' '.join([fidName, self._maxdbType()]) tName = other.sqlmeta.table idName = self.refColumn or other.sqlmeta.idName - sql = sql + ',' + '\n' - sql = sql + 'FOREIGN KEY (%s) REFERENCES %s(%s)' % (fidName, tName, - idName) + sql += ',\nFOREIGN KEY (%s) REFERENCES %s(%s)' % (fidName, tName, + idName) return sql def maxdbCreateReferenceConstraint(self): diff --git a/sqlobject/dbconnection.py b/sqlobject/dbconnection.py index fbff4576..8e096391 100644 --- a/sqlobject/dbconnection.py +++ b/sqlobject/dbconnection.py @@ -108,8 +108,8 @@ def oldUri(self): auth = getattr(self, 'user', '') or '' if auth: if self.password: - auth = auth + ':' + self.password - auth = auth + '@' + auth += ':' + self.password + auth += '@' else: assert not getattr(self, 'password', None), ( 'URIs cannot express passwords without usernames') @@ -129,8 +129,8 @@ def uri(self): if auth: auth = quote(auth) if self.password: - auth = auth + ':' + quote(self.password) - auth = auth + '@' + auth += ':' + quote(self.password) + auth += '@' else: assert not getattr(self, 'password', None), ( 'URIs cannot express passwords without usernames') diff --git a/sqlobject/joins.py b/sqlobject/joins.py index afb0f881..e2c835a6 100644 --- a/sqlobject/joins.py +++ b/sqlobject/joins.py @@ -170,9 +170,9 @@ def __init__(self, addRemoveName=None, **kw): if not self.joinMethodName: name = self.otherClassName[0].lower() + self.otherClassName[1:] if name.endswith('s'): - name = name + "es" + name += "es" else: - name = name + "s" + name += "s" self.joinMethodName = name if addRemoveName: self.addRemoveName = addRemoveName diff --git a/sqlobject/tests/test_select.py b/sqlobject/tests/test_select.py index 3a0055ea..12677063 100644 --- a/sqlobject/tests/test_select.py +++ b/sqlobject/tests/test_select.py @@ -66,7 +66,7 @@ def test_04_indexed_ended_by_exception(): try: while 1: all[count] - count = count + 1 + count += 1 # Stop the test if it's gone on too long if count > len(names): break From 85bae29d1727980a682e9d59cd5254ded573add3 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 22 Apr 2019 19:35:38 +0300 Subject: [PATCH 216/509] Fix(pgconnection): Adapt Postgres exception handling to `psycopg2` 2.8 In the recent `psycopg2` errors are in `psycopg2.errors` module. --- docs/News.rst | 10 ++++++++-- sqlobject/postgres/pgconnection.py | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index 1b968833..dade2cbf 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,8 +5,14 @@ News .. contents:: Contents: :backlinks: none -SQLObject 3.8.0 (master) -======================== +SQLObject (master) +================== + +Minor features +-------------- + +* Adapt Postgres exception handling to ``psycopg2`` version ``2.8``: + in the recent ``psycopg2`` errors are in ``psycopg2.errors`` module. SQLObject 3.7.1 =============== diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index 8dd1db58..afe81333 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -11,7 +11,7 @@ class ErrorMessage(str): def __new__(cls, e, append_msg=''): obj = str.__new__(cls, e.args[0] + append_msg) - if e.__module__ == 'psycopg2': + if hasattr(e, 'pgcode'): # psycopg2 or psycopg2.errors obj.code = getattr(e, 'pgcode', None) obj.error = getattr(e, 'pgerror', None) else: From bebfdf9512ca6cdf94a3724dc2625a2288246945 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 22 Apr 2019 19:45:45 +0300 Subject: [PATCH 217/509] Build(devscripts): Remove docs/_build/html on branch change [skip ci] --- devscripts/git-hooks/post-checkout | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devscripts/git-hooks/post-checkout b/devscripts/git-hooks/post-checkout index 2bd5be00..40f7bd71 100755 --- a/devscripts/git-hooks/post-checkout +++ b/devscripts/git-hooks/post-checkout @@ -13,7 +13,7 @@ if [ "$new_branch" = 1 ]; then for d in sqlobject/include/pydispatch sqlobject/include/tests; do if [ "`echo $d/*`" = "$d/*" ]; then rm -rf $d; fi done && - rm -rf docs/html + rm -rf docs/_build/html docs/html fi && python -m compileall -q -x '\.tox/.+' . && From 113a4505fa59ef69672fc8c250fa7821151b41cc Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 22 Apr 2019 20:51:30 +0300 Subject: [PATCH 218/509] Docs(Authors): Add Markus Elfring [skip ci] --- docs/Authors.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Authors.rst b/docs/Authors.rst index 92f936ea..65834b4c 100644 --- a/docs/Authors.rst +++ b/docs/Authors.rst @@ -37,6 +37,7 @@ Contributions have been made by: * Shailesh Mungikar * Michael S. Root * Scott Stahl +* Markus Elfring * Oleg Broytman .. image:: https://sourceforge.net/sflogo.php?group_id=74338&type=10 From c3f99e59301513e39f53b4e1b2b3c8c30e18ad78 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 29 Apr 2019 19:08:05 +0300 Subject: [PATCH 219/509] Feat: Remove RdbhostConnection David Keeney and rdbhost seem to be unavailable since 2017. [skip ci] --- README.rst | 2 +- docs/Authors.rst | 1 - docs/News.rst | 3 + .../sqlobject.rdbhost.rdbhostconnection.rst | 7 --- docs/api/sqlobject.rdbhost.rst | 15 ----- setup.py | 4 +- sqlobject/.coveragerc | 1 - sqlobject/conftest.py | 1 - sqlobject/converters.py | 8 +-- sqlobject/dbconnection.py | 1 - sqlobject/rdbhost/__init__.py | 8 --- sqlobject/rdbhost/rdbhostconnection.py | 61 ------------------- sqlobject/sqlbuilder.py | 3 +- sqlobject/tests/dbtest.py | 4 +- sqlobject/tests/test_auto.py | 15 +---- 15 files changed, 14 insertions(+), 120 deletions(-) delete mode 100644 docs/api/sqlobject.rdbhost.rdbhostconnection.rst delete mode 100644 docs/api/sqlobject.rdbhost.rst delete mode 100644 sqlobject/rdbhost/__init__.py delete mode 100644 sqlobject/rdbhost/rdbhostconnection.py diff --git a/README.rst b/README.rst index 3e96729c..92962cf6 100644 --- a/README.rst +++ b/README.rst @@ -7,7 +7,7 @@ classes, and your rows in Python instances. It currently supports MySQL through the `MySQLdb` package, PostgreSQL through the `psycopg` package, SQLite, Firebird, MaxDB (SAP DB), MS SQL, -Sybase and Rdbhost. Python 2.7 or 3.4+ is required. +and Sybase. Python 2.7 or 3.4+ is required. For more information please see the documentation in ``_, or online at http://sqlobject.org/ diff --git a/docs/Authors.rst b/docs/Authors.rst index 65834b4c..9f1c6fe5 100644 --- a/docs/Authors.rst +++ b/docs/Authors.rst @@ -22,7 +22,6 @@ Contributions have been made by: * Dan Pascu * Diez B. Roggisch * Christopher Singley -* David Keeney * Daniel Fetchinson * Neil Muller * Petr Jakes diff --git a/docs/News.rst b/docs/News.rst index dade2cbf..af4ce644 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -14,6 +14,9 @@ Minor features * Adapt Postgres exception handling to ``psycopg2`` version ``2.8``: in the recent ``psycopg2`` errors are in ``psycopg2.errors`` module. +* Removed RdbhostConnection: David Keeney and rdbhost seem to be unavailable + since 2017. + SQLObject 3.7.1 =============== diff --git a/docs/api/sqlobject.rdbhost.rdbhostconnection.rst b/docs/api/sqlobject.rdbhost.rdbhostconnection.rst deleted file mode 100644 index 016d0e66..00000000 --- a/docs/api/sqlobject.rdbhost.rdbhostconnection.rst +++ /dev/null @@ -1,7 +0,0 @@ -sqlobject\.rdbhost\.rdbhostconnection module -============================================ - -.. automodule:: sqlobject.rdbhost.rdbhostconnection - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/api/sqlobject.rdbhost.rst b/docs/api/sqlobject.rdbhost.rst deleted file mode 100644 index c4f57c87..00000000 --- a/docs/api/sqlobject.rdbhost.rst +++ /dev/null @@ -1,15 +0,0 @@ -sqlobject\.rdbhost package -========================== - -.. automodule:: sqlobject.rdbhost - :members: - :undoc-members: - :show-inheritance: - -Submodules ----------- - -.. toctree:: - - sqlobject.rdbhost.rdbhostconnection - diff --git a/setup.py b/setup.py index 9e5a9543..ca58f2eb 100755 --- a/setup.py +++ b/setup.py @@ -18,7 +18,7 @@ subpackages = ['firebird', 'include', 'include.tests', 'inheritance', 'inheritance.tests', - 'manager', 'maxdb', 'mysql', 'mssql', 'postgres', 'rdbhost', + 'manager', 'maxdb', 'mysql', 'mssql', 'postgres', 'sqlite', 'sybase', 'tests', 'util', 'versioning', 'versioning.test'] @@ -164,7 +164,7 @@ It currently supports MySQL through the `MySQLdb` package, PostgreSQL through the `psycopg` package, SQLite, Firebird, MaxDB (SAP DB), MS SQL -Sybase and Rdbhost. Python 2.7 or 3.4+ is required. +and Sybase. Python 2.7 or 3.4+ is required. Where is SQLObject diff --git a/sqlobject/.coveragerc b/sqlobject/.coveragerc index c49e277b..b4c9dee6 100644 --- a/sqlobject/.coveragerc +++ b/sqlobject/.coveragerc @@ -3,7 +3,6 @@ omit = firebird/*.py maxdb/*.py mssql/*.py - rdbhost/*.py sybase/*.py tests/test_boundattributes.py tests/test_paste.py diff --git a/sqlobject/conftest.py b/sqlobject/conftest.py index af39c6ff..3673168c 100644 --- a/sqlobject/conftest.py +++ b/sqlobject/conftest.py @@ -16,7 +16,6 @@ 'dbm': 'dbm:///data', 'postgres': 'postgres:///test', 'postgresql': 'postgres:///test', - 'rdbhost': 'rdhbost://role:authcode@www.rdbhost.com/', 'pygresql': 'pygresql://localhost/test', 'sqlite': 'sqlite:/:memory:', 'sybase': 'sybase://test:test123@sybase/test?autoCommit=0', diff --git a/sqlobject/converters.py b/sqlobject/converters.py index 5f4a7c93..19b90d07 100644 --- a/sqlobject/converters.py +++ b/sqlobject/converters.py @@ -84,14 +84,14 @@ def StringLikeConverter(value, db): elif isinstance(value, buffer_type): value = str(value) - if db in ('mysql', 'postgres', 'rdbhost'): + if db in ('mysql', 'postgres'): for orig, repl in sqlStringReplace: value = value.replace(orig, repl) elif db in ('sqlite', 'firebird', 'sybase', 'maxdb', 'mssql'): value = value.replace("'", "''") else: assert 0, "Database %s unknown" % db - if db in ('postgres', 'rdbhost') and ('\\' in value): + if (db == 'postgres') and ('\\' in value): return "E'%s'" % value return "'%s'" % value @@ -125,7 +125,7 @@ def LongConverter(value, db): def BoolConverter(value, db): - if db in ('postgres', 'rdbhost'): + if db == 'postgres': if value: return "'t'" else: @@ -237,7 +237,7 @@ def sqlrepr(obj, db=None): def quote_str(s, db): - if db in ('postgres', 'rdbhost') and ('\\' in s): + if (db == 'postgres') and ('\\' in s): return "E'%s'" % s return "'%s'" % s diff --git a/sqlobject/dbconnection.py b/sqlobject/dbconnection.py index 8e096391..0b9fd02d 100644 --- a/sqlobject/dbconnection.py +++ b/sqlobject/dbconnection.py @@ -1124,6 +1124,5 @@ def dbConnectionForScheme(self, scheme): from . import mssql # noqa from . import mysql # noqa from . import postgres # noqa -from . import rdbhost # noqa from . import sqlite # noqa from . import sybase # noqa diff --git a/sqlobject/rdbhost/__init__.py b/sqlobject/rdbhost/__init__.py deleted file mode 100644 index 588c6a84..00000000 --- a/sqlobject/rdbhost/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -from sqlobject.dbconnection import registerConnection - - -def builder(): - from . import rdbhostconnection - return rdbhostconnection.RdbhostConnection - -registerConnection(['rdbhost'], builder) diff --git a/sqlobject/rdbhost/rdbhostconnection.py b/sqlobject/rdbhost/rdbhostconnection.py deleted file mode 100644 index 25200e90..00000000 --- a/sqlobject/rdbhost/rdbhostconnection.py +++ /dev/null @@ -1,61 +0,0 @@ -""" -This module written by David Keeney, 2009, 2010 - -Released under the LGPL for use with the SQLObject ORM library. -""" - -from sqlobject.dbconnection import DBAPI -from sqlobject.postgres.pgconnection import PostgresConnection - - -class RdbhostConnection(PostgresConnection): - - supportTransactions = False - dbName = 'rdbhost' - schemes = [dbName] - - def __init__(self, dsn=None, host=None, port=None, db=None, - user=None, password=None, unicodeCols=False, **kw): - from rdbhdb import rdbhdb as rdb - # monkey patch % escaping into Cursor._execute - old_execute = getattr(rdb.Cursor, '_execute') - setattr(rdb.Cursor, '_old_execute', old_execute) - - def _execute(self, query, *args): - assert not any([a for a in args]) - query = query.replace('%', '%%') - self._old_execute(query, (), (), ()) - setattr(rdb.Cursor, '_execute', _execute) - - self.module = rdb - self.user = user - self.host = host - self.port = port - self.db = db - self.password = password - self.dsn_dict = dsn_dict = {} - self.use_dsn = dsn is not None - if host: - dsn_dict["host"] = host - if user: - dsn_dict["role"] = user - if password: - dsn_dict["authcode"] = password - if dsn is None: - dsn = [] - if db: - dsn.append('dbname=%s' % db) - if user: - dsn.append('user=%s' % user) - if password: - dsn.append('password=%s' % password) - if host: - dsn.append('host=%s' % host) - if port: - dsn.append('port=%d' % port) - dsn = ' '.join(dsn) - self.dsn = dsn - self.unicodeCols = unicodeCols - self.schema = kw.pop('schema', None) - self.dbEncoding = 'utf-8' - DBAPI.__init__(self, **kw) diff --git a/sqlobject/sqlbuilder.py b/sqlobject/sqlbuilder.py index 5178c73d..cc6696b5 100644 --- a/sqlobject/sqlbuilder.py +++ b/sqlobject/sqlbuilder.py @@ -1092,7 +1092,7 @@ def __sqlrepr__(self, db): def _quote_like_special(s, db): - if db in ('postgres', 'rdbhost'): + if db == 'postgres': escape = r'\\' else: escape = '\\' @@ -1433,7 +1433,6 @@ class RLIKE(LIKE): 'maxdb': 'RLIKE', 'mysql': 'RLIKE', 'postgres': '~', - 'rdbhost': '~', 'sqlite': 'REGEXP' } diff --git a/sqlobject/tests/dbtest.py b/sqlobject/tests/dbtest.py index b1cf6e4b..6c0c8463 100644 --- a/sqlobject/tests/dbtest.py +++ b/sqlobject/tests/dbtest.py @@ -33,7 +33,7 @@ def test_featureX(): pytest.skip("Doesn't support featureX") """ supportsMatrix = { - '-blobData': 'mssql rdbhost', + '-blobData': 'mssql', '-decimalColumn': 'mssql', '-dropTableCascade': 'sybase mssql mysql', '-emptyTable': 'mssql', @@ -43,7 +43,7 @@ def test_featureX(): '+memorydb': 'sqlite', '+rlike': 'mysql postgres sqlite', '+schema': 'postgres', - '-transactions': 'mysql rdbhost', + '-transactions': 'mysql', } diff --git a/sqlobject/tests/test_auto.py b/sqlobject/tests/test_auto.py index 1b66821e..ee4967ab 100644 --- a/sqlobject/tests/test_auto.py +++ b/sqlobject/tests/test_auto.py @@ -117,19 +117,6 @@ class TestAuto: ) """ - rdbhostCreate = """ - CREATE TABLE auto_test ( - auto_id SERIAL PRIMARY KEY, - first_name VARCHAR(100), - last_name VARCHAR(200) NOT NULL, - age INT DEFAULT 0, - created VARCHAR(40) NOT NULL, - happy char(1) DEFAULT 'Y' NOT NULL, - long_field TEXT, - wannahavefun BOOL DEFAULT FALSE NOT NULL - ) - """ - sqliteCreate = """ CREATE TABLE auto_test ( auto_id INTEGER PRIMARY KEY AUTOINCREMENT , @@ -177,7 +164,7 @@ class TestAuto: DROP TABLE auto_test """ - sqliteDrop = sybaseDrop = mssqlDrop = rdbhostDrop = postgresDrop + sqliteDrop = sybaseDrop = mssqlDrop = postgresDrop def setup_method(self, meth): conn = getConnection() From b2b8dcffb2123e1cdffd87602e8a533321db23e2 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 29 Apr 2019 19:11:38 +0300 Subject: [PATCH 220/509] Docs(API): Regenerate API docs [skip ci] --- docs/api/sqlobject.boundattributes.rst | 4 ++-- docs/api/sqlobject.cache.rst | 4 ++-- docs/api/sqlobject.classregistry.rst | 4 ++-- docs/api/sqlobject.col.rst | 4 ++-- docs/api/sqlobject.compat.rst | 4 ++-- docs/api/sqlobject.conftest.rst | 4 ++-- docs/api/sqlobject.constraints.rst | 4 ++-- docs/api/sqlobject.converters.rst | 4 ++-- docs/api/sqlobject.dbconnection.rst | 4 ++-- docs/api/sqlobject.dberrors.rst | 4 ++-- docs/api/sqlobject.declarative.rst | 4 ++-- docs/api/sqlobject.events.rst | 4 ++-- docs/api/sqlobject.firebird.firebirdconnection.rst | 4 ++-- docs/api/sqlobject.firebird.rst | 4 ++-- docs/api/sqlobject.include.hashcol.rst | 4 ++-- docs/api/sqlobject.include.rst | 4 ++-- docs/api/sqlobject.include.tests.rst | 4 ++-- docs/api/sqlobject.include.tests.test_hashcol.rst | 5 ++--- docs/api/sqlobject.index.rst | 4 ++-- docs/api/sqlobject.inheritance.iteration.rst | 4 ++-- docs/api/sqlobject.inheritance.rst | 4 ++-- docs/api/sqlobject.inheritance.tests.rst | 4 ++-- docs/api/sqlobject.inheritance.tests.test_aggregates.rst | 5 ++--- docs/api/sqlobject.inheritance.tests.test_asdict.rst | 5 ++--- .../sqlobject.inheritance.tests.test_deep_inheritance.rst | 5 ++--- .../sqlobject.inheritance.tests.test_destroy_cascade.rst | 5 ++--- docs/api/sqlobject.inheritance.tests.test_foreignKey.rst | 5 ++--- docs/api/sqlobject.inheritance.tests.test_indexes.rst | 5 ++--- docs/api/sqlobject.inheritance.tests.test_inheritance.rst | 5 ++--- .../sqlobject.inheritance.tests.test_inheritance_tree.rst | 5 ++--- docs/api/sqlobject.joins.rst | 4 ++-- docs/api/sqlobject.main.rst | 4 ++-- docs/api/sqlobject.manager.command.rst | 5 ++--- docs/api/sqlobject.manager.rst | 4 ++-- docs/api/sqlobject.maxdb.maxdbconnection.rst | 4 ++-- docs/api/sqlobject.maxdb.rst | 4 ++-- docs/api/sqlobject.mssql.mssqlconnection.rst | 4 ++-- docs/api/sqlobject.mssql.rst | 4 ++-- docs/api/sqlobject.mysql.mysqlconnection.rst | 4 ++-- docs/api/sqlobject.mysql.rst | 4 ++-- docs/api/sqlobject.postgres.pgconnection.rst | 4 ++-- docs/api/sqlobject.postgres.rst | 4 ++-- docs/api/sqlobject.rst | 1 - docs/api/sqlobject.sqlbuilder.rst | 4 ++-- docs/api/sqlobject.sqlite.rst | 4 ++-- docs/api/sqlobject.sqlite.sqliteconnection.rst | 4 ++-- docs/api/sqlobject.sresults.rst | 4 ++-- docs/api/sqlobject.styles.rst | 4 ++-- docs/api/sqlobject.sybase.rst | 4 ++-- docs/api/sqlobject.sybase.sybaseconnection.rst | 4 ++-- docs/api/sqlobject.tests.dbtest.rst | 4 ++-- docs/api/sqlobject.tests.rst | 5 +++-- docs/api/sqlobject.tests.test_ForeignKey.rst | 5 ++--- docs/api/sqlobject.tests.test_NoneValuedResultItem.rst | 5 ++--- docs/api/sqlobject.tests.test_SQLMultipleJoin.rst | 5 ++--- docs/api/sqlobject.tests.test_SQLRelatedJoin.rst | 5 ++--- docs/api/sqlobject.tests.test_SingleJoin.rst | 5 ++--- docs/api/sqlobject.tests.test_aggregates.rst | 5 ++--- docs/api/sqlobject.tests.test_aliases.rst | 5 ++--- docs/api/sqlobject.tests.test_asdict.rst | 5 ++--- docs/api/sqlobject.tests.test_auto.rst | 5 ++--- docs/api/sqlobject.tests.test_basic.rst | 5 ++--- docs/api/sqlobject.tests.test_blob.rst | 5 ++--- docs/api/sqlobject.tests.test_boundattributes.rst | 4 ++-- docs/api/sqlobject.tests.test_cache.rst | 5 ++--- docs/api/sqlobject.tests.test_class_hash.rst | 5 ++--- docs/api/sqlobject.tests.test_columns_order.rst | 5 ++--- docs/api/sqlobject.tests.test_combining_joins.rst | 5 ++--- docs/api/sqlobject.tests.test_comparison.rst | 4 ++-- docs/api/sqlobject.tests.test_compat.rst | 7 +++++++ docs/api/sqlobject.tests.test_complex_sorting.rst | 5 ++--- docs/api/sqlobject.tests.test_constraints.rst | 4 ++-- docs/api/sqlobject.tests.test_converters.rst | 4 ++-- docs/api/sqlobject.tests.test_create_drop.rst | 5 ++--- docs/api/sqlobject.tests.test_csvexport.rst | 5 ++--- docs/api/sqlobject.tests.test_csvimport.rst | 4 ++-- docs/api/sqlobject.tests.test_cyclic_reference.rst | 5 ++--- docs/api/sqlobject.tests.test_datetime.rst | 5 ++--- docs/api/sqlobject.tests.test_decimal.rst | 5 ++--- docs/api/sqlobject.tests.test_declarative.rst | 4 ++-- docs/api/sqlobject.tests.test_default_style.rst | 4 ++-- docs/api/sqlobject.tests.test_delete.rst | 5 ++--- docs/api/sqlobject.tests.test_distinct.rst | 5 ++--- docs/api/sqlobject.tests.test_empty.rst | 4 ++-- docs/api/sqlobject.tests.test_enum.rst | 5 ++--- docs/api/sqlobject.tests.test_events.rst | 5 ++--- docs/api/sqlobject.tests.test_exceptions.rst | 5 ++--- docs/api/sqlobject.tests.test_expire.rst | 5 ++--- docs/api/sqlobject.tests.test_groupBy.rst | 5 ++--- docs/api/sqlobject.tests.test_identity.rst | 5 ++--- docs/api/sqlobject.tests.test_indexes.rst | 5 ++--- docs/api/sqlobject.tests.test_inheritance.rst | 5 ++--- docs/api/sqlobject.tests.test_joins.rst | 5 ++--- docs/api/sqlobject.tests.test_joins_conditional.rst | 5 ++--- docs/api/sqlobject.tests.test_jsonbcol.rst | 5 ++--- docs/api/sqlobject.tests.test_jsoncol.rst | 5 ++--- docs/api/sqlobject.tests.test_lazy.rst | 5 ++--- docs/api/sqlobject.tests.test_md5.rst | 4 ++-- docs/api/sqlobject.tests.test_mysql.rst | 4 ++-- docs/api/sqlobject.tests.test_new_joins.rst | 5 ++--- docs/api/sqlobject.tests.test_parse_uri.rst | 4 ++-- docs/api/sqlobject.tests.test_paste.rst | 5 ++--- docs/api/sqlobject.tests.test_perConnection.rst | 5 ++--- docs/api/sqlobject.tests.test_pickle.rst | 5 ++--- docs/api/sqlobject.tests.test_picklecol.rst | 5 ++--- docs/api/sqlobject.tests.test_postgres.rst | 5 ++--- docs/api/sqlobject.tests.test_reparent_sqlmeta.rst | 5 ++--- docs/api/sqlobject.tests.test_schema.rst | 5 ++--- docs/api/sqlobject.tests.test_select.rst | 5 ++--- docs/api/sqlobject.tests.test_select_through.rst | 5 ++--- docs/api/sqlobject.tests.test_setters.rst | 5 ++--- docs/api/sqlobject.tests.test_slice.rst | 5 ++--- docs/api/sqlobject.tests.test_sorting.rst | 5 ++--- docs/api/sqlobject.tests.test_sqlbuilder.rst | 5 ++--- docs/api/sqlobject.tests.test_sqlbuilder_dbspecific.rst | 5 ++--- docs/api/sqlobject.tests.test_sqlbuilder_importproxy.rst | 4 ++-- .../sqlobject.tests.test_sqlbuilder_joins_instances.rst | 5 ++--- docs/api/sqlobject.tests.test_sqlite.rst | 5 ++--- docs/api/sqlobject.tests.test_sqlmeta_idName.rst | 4 ++-- docs/api/sqlobject.tests.test_sqlobject_admin.rst | 5 ++--- docs/api/sqlobject.tests.test_string_id.rst | 5 ++--- docs/api/sqlobject.tests.test_style.rst | 5 ++--- docs/api/sqlobject.tests.test_subqueries.rst | 5 ++--- docs/api/sqlobject.tests.test_transactions.rst | 5 ++--- docs/api/sqlobject.tests.test_unicode.rst | 5 ++--- docs/api/sqlobject.tests.test_uuidcol.rst | 5 ++--- docs/api/sqlobject.tests.test_validation.rst | 5 ++--- docs/api/sqlobject.tests.test_views.rst | 5 ++--- docs/api/sqlobject.util.csvexport.rst | 4 ++-- docs/api/sqlobject.util.csvimport.rst | 4 ++-- docs/api/sqlobject.util.moduleloader.rst | 4 ++-- docs/api/sqlobject.util.rst | 4 ++-- docs/api/sqlobject.util.threadinglocal.rst | 4 ++-- docs/api/sqlobject.versioning.rst | 4 ++-- docs/api/sqlobject.versioning.test.rst | 4 ++-- docs/api/sqlobject.versioning.test.test_version.rst | 5 ++--- docs/api/sqlobject.views.rst | 4 ++-- docs/api/sqlobject.wsgi_middleware.rst | 4 ++-- 138 files changed, 280 insertions(+), 346 deletions(-) create mode 100644 docs/api/sqlobject.tests.test_compat.rst diff --git a/docs/api/sqlobject.boundattributes.rst b/docs/api/sqlobject.boundattributes.rst index ebc0ab5a..1518f8da 100644 --- a/docs/api/sqlobject.boundattributes.rst +++ b/docs/api/sqlobject.boundattributes.rst @@ -1,5 +1,5 @@ -sqlobject\.boundattributes module -================================= +sqlobject.boundattributes module +================================ .. automodule:: sqlobject.boundattributes :members: diff --git a/docs/api/sqlobject.cache.rst b/docs/api/sqlobject.cache.rst index 657e1e86..6c74d5be 100644 --- a/docs/api/sqlobject.cache.rst +++ b/docs/api/sqlobject.cache.rst @@ -1,5 +1,5 @@ -sqlobject\.cache module -======================= +sqlobject.cache module +====================== .. automodule:: sqlobject.cache :members: diff --git a/docs/api/sqlobject.classregistry.rst b/docs/api/sqlobject.classregistry.rst index 80ed01a7..08824917 100644 --- a/docs/api/sqlobject.classregistry.rst +++ b/docs/api/sqlobject.classregistry.rst @@ -1,5 +1,5 @@ -sqlobject\.classregistry module -=============================== +sqlobject.classregistry module +============================== .. automodule:: sqlobject.classregistry :members: diff --git a/docs/api/sqlobject.col.rst b/docs/api/sqlobject.col.rst index 4c649dc9..5282fc2f 100644 --- a/docs/api/sqlobject.col.rst +++ b/docs/api/sqlobject.col.rst @@ -1,5 +1,5 @@ -sqlobject\.col module -===================== +sqlobject.col module +==================== .. automodule:: sqlobject.col :members: diff --git a/docs/api/sqlobject.compat.rst b/docs/api/sqlobject.compat.rst index 4191c0cf..cdb4f6dd 100644 --- a/docs/api/sqlobject.compat.rst +++ b/docs/api/sqlobject.compat.rst @@ -1,5 +1,5 @@ -sqlobject\.compat module -======================== +sqlobject.compat module +======================= .. automodule:: sqlobject.compat :members: diff --git a/docs/api/sqlobject.conftest.rst b/docs/api/sqlobject.conftest.rst index e29d059d..8e564281 100644 --- a/docs/api/sqlobject.conftest.rst +++ b/docs/api/sqlobject.conftest.rst @@ -1,5 +1,5 @@ -sqlobject\.conftest module -========================== +sqlobject.conftest module +========================= .. automodule:: sqlobject.conftest :members: diff --git a/docs/api/sqlobject.constraints.rst b/docs/api/sqlobject.constraints.rst index 88a736b3..ad39272b 100644 --- a/docs/api/sqlobject.constraints.rst +++ b/docs/api/sqlobject.constraints.rst @@ -1,5 +1,5 @@ -sqlobject\.constraints module -============================= +sqlobject.constraints module +============================ .. automodule:: sqlobject.constraints :members: diff --git a/docs/api/sqlobject.converters.rst b/docs/api/sqlobject.converters.rst index 38f7777f..82b5cff7 100644 --- a/docs/api/sqlobject.converters.rst +++ b/docs/api/sqlobject.converters.rst @@ -1,5 +1,5 @@ -sqlobject\.converters module -============================ +sqlobject.converters module +=========================== .. automodule:: sqlobject.converters :members: diff --git a/docs/api/sqlobject.dbconnection.rst b/docs/api/sqlobject.dbconnection.rst index 6ab39d10..6a6adc35 100644 --- a/docs/api/sqlobject.dbconnection.rst +++ b/docs/api/sqlobject.dbconnection.rst @@ -1,5 +1,5 @@ -sqlobject\.dbconnection module -============================== +sqlobject.dbconnection module +============================= .. automodule:: sqlobject.dbconnection :members: diff --git a/docs/api/sqlobject.dberrors.rst b/docs/api/sqlobject.dberrors.rst index e8be2dbf..3035746a 100644 --- a/docs/api/sqlobject.dberrors.rst +++ b/docs/api/sqlobject.dberrors.rst @@ -1,5 +1,5 @@ -sqlobject\.dberrors module -========================== +sqlobject.dberrors module +========================= .. automodule:: sqlobject.dberrors :members: diff --git a/docs/api/sqlobject.declarative.rst b/docs/api/sqlobject.declarative.rst index f89a88b4..9cc7e9bd 100644 --- a/docs/api/sqlobject.declarative.rst +++ b/docs/api/sqlobject.declarative.rst @@ -1,5 +1,5 @@ -sqlobject\.declarative module -============================= +sqlobject.declarative module +============================ .. automodule:: sqlobject.declarative :members: diff --git a/docs/api/sqlobject.events.rst b/docs/api/sqlobject.events.rst index 18ddcc78..8c33239d 100644 --- a/docs/api/sqlobject.events.rst +++ b/docs/api/sqlobject.events.rst @@ -1,5 +1,5 @@ -sqlobject\.events module -======================== +sqlobject.events module +======================= .. automodule:: sqlobject.events :members: diff --git a/docs/api/sqlobject.firebird.firebirdconnection.rst b/docs/api/sqlobject.firebird.firebirdconnection.rst index e517e981..6fdf26e9 100644 --- a/docs/api/sqlobject.firebird.firebirdconnection.rst +++ b/docs/api/sqlobject.firebird.firebirdconnection.rst @@ -1,5 +1,5 @@ -sqlobject\.firebird\.firebirdconnection module -============================================== +sqlobject.firebird.firebirdconnection module +============================================ .. automodule:: sqlobject.firebird.firebirdconnection :members: diff --git a/docs/api/sqlobject.firebird.rst b/docs/api/sqlobject.firebird.rst index a1f5b0ae..78cec9ae 100644 --- a/docs/api/sqlobject.firebird.rst +++ b/docs/api/sqlobject.firebird.rst @@ -1,5 +1,5 @@ -sqlobject\.firebird package -=========================== +sqlobject.firebird package +========================== .. automodule:: sqlobject.firebird :members: diff --git a/docs/api/sqlobject.include.hashcol.rst b/docs/api/sqlobject.include.hashcol.rst index 7abe8d54..76396aa4 100644 --- a/docs/api/sqlobject.include.hashcol.rst +++ b/docs/api/sqlobject.include.hashcol.rst @@ -1,5 +1,5 @@ -sqlobject\.include\.hashcol module -================================== +sqlobject.include.hashcol module +================================ .. automodule:: sqlobject.include.hashcol :members: diff --git a/docs/api/sqlobject.include.rst b/docs/api/sqlobject.include.rst index aebc9e47..62086bfc 100644 --- a/docs/api/sqlobject.include.rst +++ b/docs/api/sqlobject.include.rst @@ -1,5 +1,5 @@ -sqlobject\.include package -========================== +sqlobject.include package +========================= .. automodule:: sqlobject.include :members: diff --git a/docs/api/sqlobject.include.tests.rst b/docs/api/sqlobject.include.tests.rst index 0bf1f136..e17b4def 100644 --- a/docs/api/sqlobject.include.tests.rst +++ b/docs/api/sqlobject.include.tests.rst @@ -1,5 +1,5 @@ -sqlobject\.include\.tests package -================================= +sqlobject.include.tests package +=============================== .. automodule:: sqlobject.include.tests :members: diff --git a/docs/api/sqlobject.include.tests.test_hashcol.rst b/docs/api/sqlobject.include.tests.test_hashcol.rst index 2ec99027..5289acd7 100644 --- a/docs/api/sqlobject.include.tests.test_hashcol.rst +++ b/docs/api/sqlobject.include.tests.test_hashcol.rst @@ -1,8 +1,7 @@ -sqlobject\.include\.tests\.test\_hashcol module -=============================================== +sqlobject.include.tests.test\_hashcol module +============================================ .. automodule:: sqlobject.include.tests.test_hashcol :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.index.rst b/docs/api/sqlobject.index.rst index c2facd02..bc96433c 100644 --- a/docs/api/sqlobject.index.rst +++ b/docs/api/sqlobject.index.rst @@ -1,5 +1,5 @@ -sqlobject\.index module -======================= +sqlobject.index module +====================== .. automodule:: sqlobject.index :members: diff --git a/docs/api/sqlobject.inheritance.iteration.rst b/docs/api/sqlobject.inheritance.iteration.rst index b6318065..0e9538f8 100644 --- a/docs/api/sqlobject.inheritance.iteration.rst +++ b/docs/api/sqlobject.inheritance.iteration.rst @@ -1,5 +1,5 @@ -sqlobject\.inheritance\.iteration module -======================================== +sqlobject.inheritance.iteration module +====================================== .. automodule:: sqlobject.inheritance.iteration :members: diff --git a/docs/api/sqlobject.inheritance.rst b/docs/api/sqlobject.inheritance.rst index 5d9dae4c..7ab19a77 100644 --- a/docs/api/sqlobject.inheritance.rst +++ b/docs/api/sqlobject.inheritance.rst @@ -1,5 +1,5 @@ -sqlobject\.inheritance package -============================== +sqlobject.inheritance package +============================= .. automodule:: sqlobject.inheritance :members: diff --git a/docs/api/sqlobject.inheritance.tests.rst b/docs/api/sqlobject.inheritance.tests.rst index c29cbc40..994c85ab 100644 --- a/docs/api/sqlobject.inheritance.tests.rst +++ b/docs/api/sqlobject.inheritance.tests.rst @@ -1,5 +1,5 @@ -sqlobject\.inheritance\.tests package -===================================== +sqlobject.inheritance.tests package +=================================== .. automodule:: sqlobject.inheritance.tests :members: diff --git a/docs/api/sqlobject.inheritance.tests.test_aggregates.rst b/docs/api/sqlobject.inheritance.tests.test_aggregates.rst index 15fa5afd..58a2944d 100644 --- a/docs/api/sqlobject.inheritance.tests.test_aggregates.rst +++ b/docs/api/sqlobject.inheritance.tests.test_aggregates.rst @@ -1,8 +1,7 @@ -sqlobject\.inheritance\.tests\.test\_aggregates module -====================================================== +sqlobject.inheritance.tests.test\_aggregates module +=================================================== .. automodule:: sqlobject.inheritance.tests.test_aggregates :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.inheritance.tests.test_asdict.rst b/docs/api/sqlobject.inheritance.tests.test_asdict.rst index c24c5114..6a33dce2 100644 --- a/docs/api/sqlobject.inheritance.tests.test_asdict.rst +++ b/docs/api/sqlobject.inheritance.tests.test_asdict.rst @@ -1,8 +1,7 @@ -sqlobject\.inheritance\.tests\.test\_asdict module -================================================== +sqlobject.inheritance.tests.test\_asdict module +=============================================== .. automodule:: sqlobject.inheritance.tests.test_asdict :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.inheritance.tests.test_deep_inheritance.rst b/docs/api/sqlobject.inheritance.tests.test_deep_inheritance.rst index eb1661dd..5447d0bd 100644 --- a/docs/api/sqlobject.inheritance.tests.test_deep_inheritance.rst +++ b/docs/api/sqlobject.inheritance.tests.test_deep_inheritance.rst @@ -1,8 +1,7 @@ -sqlobject\.inheritance\.tests\.test\_deep\_inheritance module -============================================================= +sqlobject.inheritance.tests.test\_deep\_inheritance module +========================================================== .. automodule:: sqlobject.inheritance.tests.test_deep_inheritance :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.inheritance.tests.test_destroy_cascade.rst b/docs/api/sqlobject.inheritance.tests.test_destroy_cascade.rst index 3504fe65..8b9b7069 100644 --- a/docs/api/sqlobject.inheritance.tests.test_destroy_cascade.rst +++ b/docs/api/sqlobject.inheritance.tests.test_destroy_cascade.rst @@ -1,8 +1,7 @@ -sqlobject\.inheritance\.tests\.test\_destroy\_cascade module -============================================================ +sqlobject.inheritance.tests.test\_destroy\_cascade module +========================================================= .. automodule:: sqlobject.inheritance.tests.test_destroy_cascade :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.inheritance.tests.test_foreignKey.rst b/docs/api/sqlobject.inheritance.tests.test_foreignKey.rst index b6e28aa5..68059887 100644 --- a/docs/api/sqlobject.inheritance.tests.test_foreignKey.rst +++ b/docs/api/sqlobject.inheritance.tests.test_foreignKey.rst @@ -1,8 +1,7 @@ -sqlobject\.inheritance\.tests\.test\_foreignKey module -====================================================== +sqlobject.inheritance.tests.test\_foreignKey module +=================================================== .. automodule:: sqlobject.inheritance.tests.test_foreignKey :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.inheritance.tests.test_indexes.rst b/docs/api/sqlobject.inheritance.tests.test_indexes.rst index bb2e3f7b..cda20165 100644 --- a/docs/api/sqlobject.inheritance.tests.test_indexes.rst +++ b/docs/api/sqlobject.inheritance.tests.test_indexes.rst @@ -1,8 +1,7 @@ -sqlobject\.inheritance\.tests\.test\_indexes module -=================================================== +sqlobject.inheritance.tests.test\_indexes module +================================================ .. automodule:: sqlobject.inheritance.tests.test_indexes :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,indexDefinitions diff --git a/docs/api/sqlobject.inheritance.tests.test_inheritance.rst b/docs/api/sqlobject.inheritance.tests.test_inheritance.rst index 0c186b0a..7af4fc40 100644 --- a/docs/api/sqlobject.inheritance.tests.test_inheritance.rst +++ b/docs/api/sqlobject.inheritance.tests.test_inheritance.rst @@ -1,8 +1,7 @@ -sqlobject\.inheritance\.tests\.test\_inheritance module -======================================================= +sqlobject.inheritance.tests.test\_inheritance module +==================================================== .. automodule:: sqlobject.inheritance.tests.test_inheritance :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.inheritance.tests.test_inheritance_tree.rst b/docs/api/sqlobject.inheritance.tests.test_inheritance_tree.rst index b56d0474..31cea2e6 100644 --- a/docs/api/sqlobject.inheritance.tests.test_inheritance_tree.rst +++ b/docs/api/sqlobject.inheritance.tests.test_inheritance_tree.rst @@ -1,8 +1,7 @@ -sqlobject\.inheritance\.tests\.test\_inheritance\_tree module -============================================================= +sqlobject.inheritance.tests.test\_inheritance\_tree module +========================================================== .. automodule:: sqlobject.inheritance.tests.test_inheritance_tree :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.joins.rst b/docs/api/sqlobject.joins.rst index c864c429..70e43b04 100644 --- a/docs/api/sqlobject.joins.rst +++ b/docs/api/sqlobject.joins.rst @@ -1,5 +1,5 @@ -sqlobject\.joins module -======================= +sqlobject.joins module +====================== .. automodule:: sqlobject.joins :members: diff --git a/docs/api/sqlobject.main.rst b/docs/api/sqlobject.main.rst index 5f8c4b8e..b4de5566 100644 --- a/docs/api/sqlobject.main.rst +++ b/docs/api/sqlobject.main.rst @@ -1,5 +1,5 @@ -sqlobject\.main module -====================== +sqlobject.main module +===================== .. automodule:: sqlobject.main :members: diff --git a/docs/api/sqlobject.manager.command.rst b/docs/api/sqlobject.manager.command.rst index be4a0073..bae2b682 100644 --- a/docs/api/sqlobject.manager.command.rst +++ b/docs/api/sqlobject.manager.command.rst @@ -1,8 +1,7 @@ -sqlobject\.manager\.command module -================================== +sqlobject.manager.command module +================================ .. automodule:: sqlobject.manager.command :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.manager.rst b/docs/api/sqlobject.manager.rst index 2b3387c6..3a8c8a81 100644 --- a/docs/api/sqlobject.manager.rst +++ b/docs/api/sqlobject.manager.rst @@ -1,5 +1,5 @@ -sqlobject\.manager package -========================== +sqlobject.manager package +========================= .. automodule:: sqlobject.manager :members: diff --git a/docs/api/sqlobject.maxdb.maxdbconnection.rst b/docs/api/sqlobject.maxdb.maxdbconnection.rst index c2cae465..1a6490ea 100644 --- a/docs/api/sqlobject.maxdb.maxdbconnection.rst +++ b/docs/api/sqlobject.maxdb.maxdbconnection.rst @@ -1,5 +1,5 @@ -sqlobject\.maxdb\.maxdbconnection module -======================================== +sqlobject.maxdb.maxdbconnection module +====================================== .. automodule:: sqlobject.maxdb.maxdbconnection :members: diff --git a/docs/api/sqlobject.maxdb.rst b/docs/api/sqlobject.maxdb.rst index 1ca83a35..d591970e 100644 --- a/docs/api/sqlobject.maxdb.rst +++ b/docs/api/sqlobject.maxdb.rst @@ -1,5 +1,5 @@ -sqlobject\.maxdb package -======================== +sqlobject.maxdb package +======================= .. automodule:: sqlobject.maxdb :members: diff --git a/docs/api/sqlobject.mssql.mssqlconnection.rst b/docs/api/sqlobject.mssql.mssqlconnection.rst index d3121122..ffcc0023 100644 --- a/docs/api/sqlobject.mssql.mssqlconnection.rst +++ b/docs/api/sqlobject.mssql.mssqlconnection.rst @@ -1,5 +1,5 @@ -sqlobject\.mssql\.mssqlconnection module -======================================== +sqlobject.mssql.mssqlconnection module +====================================== .. automodule:: sqlobject.mssql.mssqlconnection :members: diff --git a/docs/api/sqlobject.mssql.rst b/docs/api/sqlobject.mssql.rst index 84c45418..7e622693 100644 --- a/docs/api/sqlobject.mssql.rst +++ b/docs/api/sqlobject.mssql.rst @@ -1,5 +1,5 @@ -sqlobject\.mssql package -======================== +sqlobject.mssql package +======================= .. automodule:: sqlobject.mssql :members: diff --git a/docs/api/sqlobject.mysql.mysqlconnection.rst b/docs/api/sqlobject.mysql.mysqlconnection.rst index 224601ef..3e5a9ef8 100644 --- a/docs/api/sqlobject.mysql.mysqlconnection.rst +++ b/docs/api/sqlobject.mysql.mysqlconnection.rst @@ -1,5 +1,5 @@ -sqlobject\.mysql\.mysqlconnection module -======================================== +sqlobject.mysql.mysqlconnection module +====================================== .. automodule:: sqlobject.mysql.mysqlconnection :members: diff --git a/docs/api/sqlobject.mysql.rst b/docs/api/sqlobject.mysql.rst index e244266d..7e69a9e2 100644 --- a/docs/api/sqlobject.mysql.rst +++ b/docs/api/sqlobject.mysql.rst @@ -1,5 +1,5 @@ -sqlobject\.mysql package -======================== +sqlobject.mysql package +======================= .. automodule:: sqlobject.mysql :members: diff --git a/docs/api/sqlobject.postgres.pgconnection.rst b/docs/api/sqlobject.postgres.pgconnection.rst index 3880e511..854104d5 100644 --- a/docs/api/sqlobject.postgres.pgconnection.rst +++ b/docs/api/sqlobject.postgres.pgconnection.rst @@ -1,5 +1,5 @@ -sqlobject\.postgres\.pgconnection module -======================================== +sqlobject.postgres.pgconnection module +====================================== .. automodule:: sqlobject.postgres.pgconnection :members: diff --git a/docs/api/sqlobject.postgres.rst b/docs/api/sqlobject.postgres.rst index 5decb52a..ad93e75d 100644 --- a/docs/api/sqlobject.postgres.rst +++ b/docs/api/sqlobject.postgres.rst @@ -1,5 +1,5 @@ -sqlobject\.postgres package -=========================== +sqlobject.postgres package +========================== .. automodule:: sqlobject.postgres :members: diff --git a/docs/api/sqlobject.rst b/docs/api/sqlobject.rst index 1695715e..2711347b 100644 --- a/docs/api/sqlobject.rst +++ b/docs/api/sqlobject.rst @@ -19,7 +19,6 @@ Subpackages sqlobject.mssql sqlobject.mysql sqlobject.postgres - sqlobject.rdbhost sqlobject.sqlite sqlobject.sybase sqlobject.tests diff --git a/docs/api/sqlobject.sqlbuilder.rst b/docs/api/sqlobject.sqlbuilder.rst index 4c49ca06..bd21c086 100644 --- a/docs/api/sqlobject.sqlbuilder.rst +++ b/docs/api/sqlobject.sqlbuilder.rst @@ -1,5 +1,5 @@ -sqlobject\.sqlbuilder module -============================ +sqlobject.sqlbuilder module +=========================== .. automodule:: sqlobject.sqlbuilder :members: diff --git a/docs/api/sqlobject.sqlite.rst b/docs/api/sqlobject.sqlite.rst index 8afe099e..f62364ef 100644 --- a/docs/api/sqlobject.sqlite.rst +++ b/docs/api/sqlobject.sqlite.rst @@ -1,5 +1,5 @@ -sqlobject\.sqlite package -========================= +sqlobject.sqlite package +======================== .. automodule:: sqlobject.sqlite :members: diff --git a/docs/api/sqlobject.sqlite.sqliteconnection.rst b/docs/api/sqlobject.sqlite.sqliteconnection.rst index 37e64745..0ce1763a 100644 --- a/docs/api/sqlobject.sqlite.sqliteconnection.rst +++ b/docs/api/sqlobject.sqlite.sqliteconnection.rst @@ -1,5 +1,5 @@ -sqlobject\.sqlite\.sqliteconnection module -========================================== +sqlobject.sqlite.sqliteconnection module +======================================== .. automodule:: sqlobject.sqlite.sqliteconnection :members: diff --git a/docs/api/sqlobject.sresults.rst b/docs/api/sqlobject.sresults.rst index 7b18b85f..690de42e 100644 --- a/docs/api/sqlobject.sresults.rst +++ b/docs/api/sqlobject.sresults.rst @@ -1,5 +1,5 @@ -sqlobject\.sresults module -========================== +sqlobject.sresults module +========================= .. automodule:: sqlobject.sresults :members: diff --git a/docs/api/sqlobject.styles.rst b/docs/api/sqlobject.styles.rst index f5238168..04aeb8c8 100644 --- a/docs/api/sqlobject.styles.rst +++ b/docs/api/sqlobject.styles.rst @@ -1,5 +1,5 @@ -sqlobject\.styles module -======================== +sqlobject.styles module +======================= .. automodule:: sqlobject.styles :members: diff --git a/docs/api/sqlobject.sybase.rst b/docs/api/sqlobject.sybase.rst index 84e1fc2a..b5d5aef8 100644 --- a/docs/api/sqlobject.sybase.rst +++ b/docs/api/sqlobject.sybase.rst @@ -1,5 +1,5 @@ -sqlobject\.sybase package -========================= +sqlobject.sybase package +======================== .. automodule:: sqlobject.sybase :members: diff --git a/docs/api/sqlobject.sybase.sybaseconnection.rst b/docs/api/sqlobject.sybase.sybaseconnection.rst index b684c94a..3cdf4c02 100644 --- a/docs/api/sqlobject.sybase.sybaseconnection.rst +++ b/docs/api/sqlobject.sybase.sybaseconnection.rst @@ -1,5 +1,5 @@ -sqlobject\.sybase\.sybaseconnection module -========================================== +sqlobject.sybase.sybaseconnection module +======================================== .. automodule:: sqlobject.sybase.sybaseconnection :members: diff --git a/docs/api/sqlobject.tests.dbtest.rst b/docs/api/sqlobject.tests.dbtest.rst index 617ef7f7..b6fb5132 100644 --- a/docs/api/sqlobject.tests.dbtest.rst +++ b/docs/api/sqlobject.tests.dbtest.rst @@ -1,5 +1,5 @@ -sqlobject\.tests\.dbtest module -=============================== +sqlobject.tests.dbtest module +============================= .. automodule:: sqlobject.tests.dbtest :members: diff --git a/docs/api/sqlobject.tests.rst b/docs/api/sqlobject.tests.rst index e7a409ce..6cf2f130 100644 --- a/docs/api/sqlobject.tests.rst +++ b/docs/api/sqlobject.tests.rst @@ -1,5 +1,5 @@ -sqlobject\.tests package -======================== +sqlobject.tests package +======================= .. automodule:: sqlobject.tests :members: @@ -29,6 +29,7 @@ Submodules sqlobject.tests.test_columns_order sqlobject.tests.test_combining_joins sqlobject.tests.test_comparison + sqlobject.tests.test_compat sqlobject.tests.test_complex_sorting sqlobject.tests.test_constraints sqlobject.tests.test_converters diff --git a/docs/api/sqlobject.tests.test_ForeignKey.rst b/docs/api/sqlobject.tests.test_ForeignKey.rst index 1ca6c9d7..c495f8b9 100644 --- a/docs/api/sqlobject.tests.test_ForeignKey.rst +++ b/docs/api/sqlobject.tests.test_ForeignKey.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_ForeignKey module -========================================= +sqlobject.tests.test\_ForeignKey module +======================================= .. automodule:: sqlobject.tests.test_ForeignKey :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_NoneValuedResultItem.rst b/docs/api/sqlobject.tests.test_NoneValuedResultItem.rst index bac55967..35ee6435 100644 --- a/docs/api/sqlobject.tests.test_NoneValuedResultItem.rst +++ b/docs/api/sqlobject.tests.test_NoneValuedResultItem.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_NoneValuedResultItem module -=================================================== +sqlobject.tests.test\_NoneValuedResultItem module +================================================= .. automodule:: sqlobject.tests.test_NoneValuedResultItem :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_SQLMultipleJoin.rst b/docs/api/sqlobject.tests.test_SQLMultipleJoin.rst index a7473fbd..7ae46d52 100644 --- a/docs/api/sqlobject.tests.test_SQLMultipleJoin.rst +++ b/docs/api/sqlobject.tests.test_SQLMultipleJoin.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_SQLMultipleJoin module -============================================== +sqlobject.tests.test\_SQLMultipleJoin module +============================================ .. automodule:: sqlobject.tests.test_SQLMultipleJoin :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_SQLRelatedJoin.rst b/docs/api/sqlobject.tests.test_SQLRelatedJoin.rst index e1813011..e12f1f55 100644 --- a/docs/api/sqlobject.tests.test_SQLRelatedJoin.rst +++ b/docs/api/sqlobject.tests.test_SQLRelatedJoin.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_SQLRelatedJoin module -============================================= +sqlobject.tests.test\_SQLRelatedJoin module +=========================================== .. automodule:: sqlobject.tests.test_SQLRelatedJoin :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_SingleJoin.rst b/docs/api/sqlobject.tests.test_SingleJoin.rst index 7f4179da..80f8907c 100644 --- a/docs/api/sqlobject.tests.test_SingleJoin.rst +++ b/docs/api/sqlobject.tests.test_SingleJoin.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_SingleJoin module -========================================= +sqlobject.tests.test\_SingleJoin module +======================================= .. automodule:: sqlobject.tests.test_SingleJoin :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_aggregates.rst b/docs/api/sqlobject.tests.test_aggregates.rst index 117aadde..283cea6f 100644 --- a/docs/api/sqlobject.tests.test_aggregates.rst +++ b/docs/api/sqlobject.tests.test_aggregates.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_aggregates module -========================================= +sqlobject.tests.test\_aggregates module +======================================= .. automodule:: sqlobject.tests.test_aggregates :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_aliases.rst b/docs/api/sqlobject.tests.test_aliases.rst index d96edd13..fa46a461 100644 --- a/docs/api/sqlobject.tests.test_aliases.rst +++ b/docs/api/sqlobject.tests.test_aliases.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_aliases module -====================================== +sqlobject.tests.test\_aliases module +==================================== .. automodule:: sqlobject.tests.test_aliases :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_asdict.rst b/docs/api/sqlobject.tests.test_asdict.rst index b316c7ef..e1550441 100644 --- a/docs/api/sqlobject.tests.test_asdict.rst +++ b/docs/api/sqlobject.tests.test_asdict.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_asdict module -===================================== +sqlobject.tests.test\_asdict module +=================================== .. automodule:: sqlobject.tests.test_asdict :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_auto.rst b/docs/api/sqlobject.tests.test_auto.rst index 9c23284c..6d578d5e 100644 --- a/docs/api/sqlobject.tests.test_auto.rst +++ b/docs/api/sqlobject.tests.test_auto.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_auto module -=================================== +sqlobject.tests.test\_auto module +================================= .. automodule:: sqlobject.tests.test_auto :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_basic.rst b/docs/api/sqlobject.tests.test_basic.rst index 549436dd..40235ecf 100644 --- a/docs/api/sqlobject.tests.test_basic.rst +++ b/docs/api/sqlobject.tests.test_basic.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_basic module -==================================== +sqlobject.tests.test\_basic module +================================== .. automodule:: sqlobject.tests.test_basic :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_blob.rst b/docs/api/sqlobject.tests.test_blob.rst index 798a66c0..1d01d512 100644 --- a/docs/api/sqlobject.tests.test_blob.rst +++ b/docs/api/sqlobject.tests.test_blob.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_blob module -=================================== +sqlobject.tests.test\_blob module +================================= .. automodule:: sqlobject.tests.test_blob :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_boundattributes.rst b/docs/api/sqlobject.tests.test_boundattributes.rst index ec672dfb..47d9e2b1 100644 --- a/docs/api/sqlobject.tests.test_boundattributes.rst +++ b/docs/api/sqlobject.tests.test_boundattributes.rst @@ -1,5 +1,5 @@ -sqlobject\.tests\.test\_boundattributes module -============================================== +sqlobject.tests.test\_boundattributes module +============================================ .. automodule:: sqlobject.tests.test_boundattributes :members: diff --git a/docs/api/sqlobject.tests.test_cache.rst b/docs/api/sqlobject.tests.test_cache.rst index 3e01991e..69f05823 100644 --- a/docs/api/sqlobject.tests.test_cache.rst +++ b/docs/api/sqlobject.tests.test_cache.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_cache module -==================================== +sqlobject.tests.test\_cache module +================================== .. automodule:: sqlobject.tests.test_cache :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_class_hash.rst b/docs/api/sqlobject.tests.test_class_hash.rst index 076937ab..f25b66b6 100644 --- a/docs/api/sqlobject.tests.test_class_hash.rst +++ b/docs/api/sqlobject.tests.test_class_hash.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_class\_hash module -========================================== +sqlobject.tests.test\_class\_hash module +======================================== .. automodule:: sqlobject.tests.test_class_hash :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_columns_order.rst b/docs/api/sqlobject.tests.test_columns_order.rst index 6187c32d..c48cf7c0 100644 --- a/docs/api/sqlobject.tests.test_columns_order.rst +++ b/docs/api/sqlobject.tests.test_columns_order.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_columns\_order module -============================================= +sqlobject.tests.test\_columns\_order module +=========================================== .. automodule:: sqlobject.tests.test_columns_order :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_combining_joins.rst b/docs/api/sqlobject.tests.test_combining_joins.rst index 7b30db09..e1961a80 100644 --- a/docs/api/sqlobject.tests.test_combining_joins.rst +++ b/docs/api/sqlobject.tests.test_combining_joins.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_combining\_joins module -=============================================== +sqlobject.tests.test\_combining\_joins module +============================================= .. automodule:: sqlobject.tests.test_combining_joins :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_comparison.rst b/docs/api/sqlobject.tests.test_comparison.rst index e54aacc3..02127b7b 100644 --- a/docs/api/sqlobject.tests.test_comparison.rst +++ b/docs/api/sqlobject.tests.test_comparison.rst @@ -1,5 +1,5 @@ -sqlobject\.tests\.test\_comparison module -========================================= +sqlobject.tests.test\_comparison module +======================================= .. automodule:: sqlobject.tests.test_comparison :members: diff --git a/docs/api/sqlobject.tests.test_compat.rst b/docs/api/sqlobject.tests.test_compat.rst new file mode 100644 index 00000000..e37cb543 --- /dev/null +++ b/docs/api/sqlobject.tests.test_compat.rst @@ -0,0 +1,7 @@ +sqlobject.tests.test\_compat module +=================================== + +.. automodule:: sqlobject.tests.test_compat + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/api/sqlobject.tests.test_complex_sorting.rst b/docs/api/sqlobject.tests.test_complex_sorting.rst index 570fe23c..2321e963 100644 --- a/docs/api/sqlobject.tests.test_complex_sorting.rst +++ b/docs/api/sqlobject.tests.test_complex_sorting.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_complex\_sorting module -=============================================== +sqlobject.tests.test\_complex\_sorting module +============================================= .. automodule:: sqlobject.tests.test_complex_sorting :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_constraints.rst b/docs/api/sqlobject.tests.test_constraints.rst index d3521779..c967979b 100644 --- a/docs/api/sqlobject.tests.test_constraints.rst +++ b/docs/api/sqlobject.tests.test_constraints.rst @@ -1,5 +1,5 @@ -sqlobject\.tests\.test\_constraints module -========================================== +sqlobject.tests.test\_constraints module +======================================== .. automodule:: sqlobject.tests.test_constraints :members: diff --git a/docs/api/sqlobject.tests.test_converters.rst b/docs/api/sqlobject.tests.test_converters.rst index 4548363b..a6893bda 100644 --- a/docs/api/sqlobject.tests.test_converters.rst +++ b/docs/api/sqlobject.tests.test_converters.rst @@ -1,5 +1,5 @@ -sqlobject\.tests\.test\_converters module -========================================= +sqlobject.tests.test\_converters module +======================================= .. automodule:: sqlobject.tests.test_converters :members: diff --git a/docs/api/sqlobject.tests.test_create_drop.rst b/docs/api/sqlobject.tests.test_create_drop.rst index d7845b9b..fcd3eea5 100644 --- a/docs/api/sqlobject.tests.test_create_drop.rst +++ b/docs/api/sqlobject.tests.test_create_drop.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_create\_drop module -=========================================== +sqlobject.tests.test\_create\_drop module +========================================= .. automodule:: sqlobject.tests.test_create_drop :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_csvexport.rst b/docs/api/sqlobject.tests.test_csvexport.rst index 2935f61d..0927f4f0 100644 --- a/docs/api/sqlobject.tests.test_csvexport.rst +++ b/docs/api/sqlobject.tests.test_csvexport.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_csvexport module -======================================== +sqlobject.tests.test\_csvexport module +====================================== .. automodule:: sqlobject.tests.test_csvexport :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_csvimport.rst b/docs/api/sqlobject.tests.test_csvimport.rst index 56981a8d..f7db4138 100644 --- a/docs/api/sqlobject.tests.test_csvimport.rst +++ b/docs/api/sqlobject.tests.test_csvimport.rst @@ -1,5 +1,5 @@ -sqlobject\.tests\.test\_csvimport module -======================================== +sqlobject.tests.test\_csvimport module +====================================== .. automodule:: sqlobject.tests.test_csvimport :members: diff --git a/docs/api/sqlobject.tests.test_cyclic_reference.rst b/docs/api/sqlobject.tests.test_cyclic_reference.rst index 1cb34572..910421ab 100644 --- a/docs/api/sqlobject.tests.test_cyclic_reference.rst +++ b/docs/api/sqlobject.tests.test_cyclic_reference.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_cyclic\_reference module -================================================ +sqlobject.tests.test\_cyclic\_reference module +============================================== .. automodule:: sqlobject.tests.test_cyclic_reference :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_datetime.rst b/docs/api/sqlobject.tests.test_datetime.rst index b6b42358..87a1b043 100644 --- a/docs/api/sqlobject.tests.test_datetime.rst +++ b/docs/api/sqlobject.tests.test_datetime.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_datetime module -======================================= +sqlobject.tests.test\_datetime module +===================================== .. automodule:: sqlobject.tests.test_datetime :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_decimal.rst b/docs/api/sqlobject.tests.test_decimal.rst index 9e680e3a..86868120 100644 --- a/docs/api/sqlobject.tests.test_decimal.rst +++ b/docs/api/sqlobject.tests.test_decimal.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_decimal module -====================================== +sqlobject.tests.test\_decimal module +==================================== .. automodule:: sqlobject.tests.test_decimal :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_declarative.rst b/docs/api/sqlobject.tests.test_declarative.rst index 097a81fc..a022b0cc 100644 --- a/docs/api/sqlobject.tests.test_declarative.rst +++ b/docs/api/sqlobject.tests.test_declarative.rst @@ -1,5 +1,5 @@ -sqlobject\.tests\.test\_declarative module -========================================== +sqlobject.tests.test\_declarative module +======================================== .. automodule:: sqlobject.tests.test_declarative :members: diff --git a/docs/api/sqlobject.tests.test_default_style.rst b/docs/api/sqlobject.tests.test_default_style.rst index 50868333..5cd86ffe 100644 --- a/docs/api/sqlobject.tests.test_default_style.rst +++ b/docs/api/sqlobject.tests.test_default_style.rst @@ -1,5 +1,5 @@ -sqlobject\.tests\.test\_default\_style module -============================================= +sqlobject.tests.test\_default\_style module +=========================================== .. automodule:: sqlobject.tests.test_default_style :members: diff --git a/docs/api/sqlobject.tests.test_delete.rst b/docs/api/sqlobject.tests.test_delete.rst index 8ee8eb76..508cc86a 100644 --- a/docs/api/sqlobject.tests.test_delete.rst +++ b/docs/api/sqlobject.tests.test_delete.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_delete module -===================================== +sqlobject.tests.test\_delete module +=================================== .. automodule:: sqlobject.tests.test_delete :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_distinct.rst b/docs/api/sqlobject.tests.test_distinct.rst index 5b2b72c6..68080aa3 100644 --- a/docs/api/sqlobject.tests.test_distinct.rst +++ b/docs/api/sqlobject.tests.test_distinct.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_distinct module -======================================= +sqlobject.tests.test\_distinct module +===================================== .. automodule:: sqlobject.tests.test_distinct :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_empty.rst b/docs/api/sqlobject.tests.test_empty.rst index 111994c7..69964d49 100644 --- a/docs/api/sqlobject.tests.test_empty.rst +++ b/docs/api/sqlobject.tests.test_empty.rst @@ -1,5 +1,5 @@ -sqlobject\.tests\.test\_empty module -==================================== +sqlobject.tests.test\_empty module +================================== .. automodule:: sqlobject.tests.test_empty :members: diff --git a/docs/api/sqlobject.tests.test_enum.rst b/docs/api/sqlobject.tests.test_enum.rst index c5c5a0f1..0ae9e483 100644 --- a/docs/api/sqlobject.tests.test_enum.rst +++ b/docs/api/sqlobject.tests.test_enum.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_enum module -=================================== +sqlobject.tests.test\_enum module +================================= .. automodule:: sqlobject.tests.test_enum :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_events.rst b/docs/api/sqlobject.tests.test_events.rst index 78c7b839..7c1b9ef8 100644 --- a/docs/api/sqlobject.tests.test_events.rst +++ b/docs/api/sqlobject.tests.test_events.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_events module -===================================== +sqlobject.tests.test\_events module +=================================== .. automodule:: sqlobject.tests.test_events :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_exceptions.rst b/docs/api/sqlobject.tests.test_exceptions.rst index 45d09fd2..5e440e43 100644 --- a/docs/api/sqlobject.tests.test_exceptions.rst +++ b/docs/api/sqlobject.tests.test_exceptions.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_exceptions module -========================================= +sqlobject.tests.test\_exceptions module +======================================= .. automodule:: sqlobject.tests.test_exceptions :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_expire.rst b/docs/api/sqlobject.tests.test_expire.rst index 26b81f54..614f06ce 100644 --- a/docs/api/sqlobject.tests.test_expire.rst +++ b/docs/api/sqlobject.tests.test_expire.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_expire module -===================================== +sqlobject.tests.test\_expire module +=================================== .. automodule:: sqlobject.tests.test_expire :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_groupBy.rst b/docs/api/sqlobject.tests.test_groupBy.rst index f823fd07..c8f6cc92 100644 --- a/docs/api/sqlobject.tests.test_groupBy.rst +++ b/docs/api/sqlobject.tests.test_groupBy.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_groupBy module -====================================== +sqlobject.tests.test\_groupBy module +==================================== .. automodule:: sqlobject.tests.test_groupBy :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_identity.rst b/docs/api/sqlobject.tests.test_identity.rst index e154f2dc..63716dfb 100644 --- a/docs/api/sqlobject.tests.test_identity.rst +++ b/docs/api/sqlobject.tests.test_identity.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_identity module -======================================= +sqlobject.tests.test\_identity module +===================================== .. automodule:: sqlobject.tests.test_identity :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_indexes.rst b/docs/api/sqlobject.tests.test_indexes.rst index cfe8e4bc..023d8fdb 100644 --- a/docs/api/sqlobject.tests.test_indexes.rst +++ b/docs/api/sqlobject.tests.test_indexes.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_indexes module -====================================== +sqlobject.tests.test\_indexes module +==================================== .. automodule:: sqlobject.tests.test_indexes :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns,indexDefinitions diff --git a/docs/api/sqlobject.tests.test_inheritance.rst b/docs/api/sqlobject.tests.test_inheritance.rst index 369aa4df..a381ee17 100644 --- a/docs/api/sqlobject.tests.test_inheritance.rst +++ b/docs/api/sqlobject.tests.test_inheritance.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_inheritance module -========================================== +sqlobject.tests.test\_inheritance module +======================================== .. automodule:: sqlobject.tests.test_inheritance :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_joins.rst b/docs/api/sqlobject.tests.test_joins.rst index 67ef3475..a0679733 100644 --- a/docs/api/sqlobject.tests.test_joins.rst +++ b/docs/api/sqlobject.tests.test_joins.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_joins module -==================================== +sqlobject.tests.test\_joins module +================================== .. automodule:: sqlobject.tests.test_joins :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_joins_conditional.rst b/docs/api/sqlobject.tests.test_joins_conditional.rst index 8bc28896..ca6fd0b5 100644 --- a/docs/api/sqlobject.tests.test_joins_conditional.rst +++ b/docs/api/sqlobject.tests.test_joins_conditional.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_joins\_conditional module -================================================= +sqlobject.tests.test\_joins\_conditional module +=============================================== .. automodule:: sqlobject.tests.test_joins_conditional :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_jsonbcol.rst b/docs/api/sqlobject.tests.test_jsonbcol.rst index 48eba47e..30f0d54a 100644 --- a/docs/api/sqlobject.tests.test_jsonbcol.rst +++ b/docs/api/sqlobject.tests.test_jsonbcol.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_jsonbcol module -======================================= +sqlobject.tests.test\_jsonbcol module +===================================== .. automodule:: sqlobject.tests.test_jsonbcol :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_jsoncol.rst b/docs/api/sqlobject.tests.test_jsoncol.rst index 18334b2a..bc78a692 100644 --- a/docs/api/sqlobject.tests.test_jsoncol.rst +++ b/docs/api/sqlobject.tests.test_jsoncol.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_jsoncol module -====================================== +sqlobject.tests.test\_jsoncol module +==================================== .. automodule:: sqlobject.tests.test_jsoncol :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_lazy.rst b/docs/api/sqlobject.tests.test_lazy.rst index 34df4cbb..98994362 100644 --- a/docs/api/sqlobject.tests.test_lazy.rst +++ b/docs/api/sqlobject.tests.test_lazy.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_lazy module -=================================== +sqlobject.tests.test\_lazy module +================================= .. automodule:: sqlobject.tests.test_lazy :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_md5.rst b/docs/api/sqlobject.tests.test_md5.rst index 8ea42178..922a8b88 100644 --- a/docs/api/sqlobject.tests.test_md5.rst +++ b/docs/api/sqlobject.tests.test_md5.rst @@ -1,5 +1,5 @@ -sqlobject\.tests\.test\_md5 module -================================== +sqlobject.tests.test\_md5 module +================================ .. automodule:: sqlobject.tests.test_md5 :members: diff --git a/docs/api/sqlobject.tests.test_mysql.rst b/docs/api/sqlobject.tests.test_mysql.rst index 1ac3d767..adb997f9 100644 --- a/docs/api/sqlobject.tests.test_mysql.rst +++ b/docs/api/sqlobject.tests.test_mysql.rst @@ -1,5 +1,5 @@ -sqlobject\.tests\.test\_mysql module -==================================== +sqlobject.tests.test\_mysql module +================================== .. automodule:: sqlobject.tests.test_mysql :members: diff --git a/docs/api/sqlobject.tests.test_new_joins.rst b/docs/api/sqlobject.tests.test_new_joins.rst index 5f751be7..7edf06aa 100644 --- a/docs/api/sqlobject.tests.test_new_joins.rst +++ b/docs/api/sqlobject.tests.test_new_joins.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_new\_joins module -========================================= +sqlobject.tests.test\_new\_joins module +======================================= .. automodule:: sqlobject.tests.test_new_joins :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_parse_uri.rst b/docs/api/sqlobject.tests.test_parse_uri.rst index d5adf4e9..8a7cf626 100644 --- a/docs/api/sqlobject.tests.test_parse_uri.rst +++ b/docs/api/sqlobject.tests.test_parse_uri.rst @@ -1,5 +1,5 @@ -sqlobject\.tests\.test\_parse\_uri module -========================================= +sqlobject.tests.test\_parse\_uri module +======================================= .. automodule:: sqlobject.tests.test_parse_uri :members: diff --git a/docs/api/sqlobject.tests.test_paste.rst b/docs/api/sqlobject.tests.test_paste.rst index 2a284741..dc0fb590 100644 --- a/docs/api/sqlobject.tests.test_paste.rst +++ b/docs/api/sqlobject.tests.test_paste.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_paste module -==================================== +sqlobject.tests.test\_paste module +================================== .. automodule:: sqlobject.tests.test_paste :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_perConnection.rst b/docs/api/sqlobject.tests.test_perConnection.rst index e4d43710..7d4b1781 100644 --- a/docs/api/sqlobject.tests.test_perConnection.rst +++ b/docs/api/sqlobject.tests.test_perConnection.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_perConnection module -============================================ +sqlobject.tests.test\_perConnection module +========================================== .. automodule:: sqlobject.tests.test_perConnection :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_pickle.rst b/docs/api/sqlobject.tests.test_pickle.rst index 6e7cfe33..c44fa27d 100644 --- a/docs/api/sqlobject.tests.test_pickle.rst +++ b/docs/api/sqlobject.tests.test_pickle.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_pickle module -===================================== +sqlobject.tests.test\_pickle module +=================================== .. automodule:: sqlobject.tests.test_pickle :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_picklecol.rst b/docs/api/sqlobject.tests.test_picklecol.rst index 56db3212..7edd7c08 100644 --- a/docs/api/sqlobject.tests.test_picklecol.rst +++ b/docs/api/sqlobject.tests.test_picklecol.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_picklecol module -======================================== +sqlobject.tests.test\_picklecol module +====================================== .. automodule:: sqlobject.tests.test_picklecol :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_postgres.rst b/docs/api/sqlobject.tests.test_postgres.rst index 374a7869..d8082b5c 100644 --- a/docs/api/sqlobject.tests.test_postgres.rst +++ b/docs/api/sqlobject.tests.test_postgres.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_postgres module -======================================= +sqlobject.tests.test\_postgres module +===================================== .. automodule:: sqlobject.tests.test_postgres :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_reparent_sqlmeta.rst b/docs/api/sqlobject.tests.test_reparent_sqlmeta.rst index 2af5978d..8c044b55 100644 --- a/docs/api/sqlobject.tests.test_reparent_sqlmeta.rst +++ b/docs/api/sqlobject.tests.test_reparent_sqlmeta.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_reparent\_sqlmeta module -================================================ +sqlobject.tests.test\_reparent\_sqlmeta module +============================================== .. automodule:: sqlobject.tests.test_reparent_sqlmeta :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_schema.rst b/docs/api/sqlobject.tests.test_schema.rst index 42f80883..9cf3457f 100644 --- a/docs/api/sqlobject.tests.test_schema.rst +++ b/docs/api/sqlobject.tests.test_schema.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_schema module -===================================== +sqlobject.tests.test\_schema module +=================================== .. automodule:: sqlobject.tests.test_schema :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_select.rst b/docs/api/sqlobject.tests.test_select.rst index 0ba89a83..9e63811b 100644 --- a/docs/api/sqlobject.tests.test_select.rst +++ b/docs/api/sqlobject.tests.test_select.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_select module -===================================== +sqlobject.tests.test\_select module +=================================== .. automodule:: sqlobject.tests.test_select :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_select_through.rst b/docs/api/sqlobject.tests.test_select_through.rst index 8c5cdaa1..f0833e2f 100644 --- a/docs/api/sqlobject.tests.test_select_through.rst +++ b/docs/api/sqlobject.tests.test_select_through.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_select\_through module -============================================== +sqlobject.tests.test\_select\_through module +============================================ .. automodule:: sqlobject.tests.test_select_through :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_setters.rst b/docs/api/sqlobject.tests.test_setters.rst index 0bb4d136..f35cfb0e 100644 --- a/docs/api/sqlobject.tests.test_setters.rst +++ b/docs/api/sqlobject.tests.test_setters.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_setters module -====================================== +sqlobject.tests.test\_setters module +==================================== .. automodule:: sqlobject.tests.test_setters :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_slice.rst b/docs/api/sqlobject.tests.test_slice.rst index f0559438..f2819a1b 100644 --- a/docs/api/sqlobject.tests.test_slice.rst +++ b/docs/api/sqlobject.tests.test_slice.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_slice module -==================================== +sqlobject.tests.test\_slice module +================================== .. automodule:: sqlobject.tests.test_slice :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_sorting.rst b/docs/api/sqlobject.tests.test_sorting.rst index 04e1510a..a461b701 100644 --- a/docs/api/sqlobject.tests.test_sorting.rst +++ b/docs/api/sqlobject.tests.test_sorting.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_sorting module -====================================== +sqlobject.tests.test\_sorting module +==================================== .. automodule:: sqlobject.tests.test_sorting :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_sqlbuilder.rst b/docs/api/sqlobject.tests.test_sqlbuilder.rst index e70be201..f71230de 100644 --- a/docs/api/sqlobject.tests.test_sqlbuilder.rst +++ b/docs/api/sqlobject.tests.test_sqlbuilder.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_sqlbuilder module -========================================= +sqlobject.tests.test\_sqlbuilder module +======================================= .. automodule:: sqlobject.tests.test_sqlbuilder :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_sqlbuilder_dbspecific.rst b/docs/api/sqlobject.tests.test_sqlbuilder_dbspecific.rst index b3291a43..47c965c9 100644 --- a/docs/api/sqlobject.tests.test_sqlbuilder_dbspecific.rst +++ b/docs/api/sqlobject.tests.test_sqlbuilder_dbspecific.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_sqlbuilder\_dbspecific module -===================================================== +sqlobject.tests.test\_sqlbuilder\_dbspecific module +=================================================== .. automodule:: sqlobject.tests.test_sqlbuilder_dbspecific :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_sqlbuilder_importproxy.rst b/docs/api/sqlobject.tests.test_sqlbuilder_importproxy.rst index d6c874d1..56eb89fa 100644 --- a/docs/api/sqlobject.tests.test_sqlbuilder_importproxy.rst +++ b/docs/api/sqlobject.tests.test_sqlbuilder_importproxy.rst @@ -1,5 +1,5 @@ -sqlobject\.tests\.test\_sqlbuilder\_importproxy module -====================================================== +sqlobject.tests.test\_sqlbuilder\_importproxy module +==================================================== .. automodule:: sqlobject.tests.test_sqlbuilder_importproxy :members: diff --git a/docs/api/sqlobject.tests.test_sqlbuilder_joins_instances.rst b/docs/api/sqlobject.tests.test_sqlbuilder_joins_instances.rst index d92359b0..ac24093e 100644 --- a/docs/api/sqlobject.tests.test_sqlbuilder_joins_instances.rst +++ b/docs/api/sqlobject.tests.test_sqlbuilder_joins_instances.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_sqlbuilder\_joins\_instances module -=========================================================== +sqlobject.tests.test\_sqlbuilder\_joins\_instances module +========================================================= .. automodule:: sqlobject.tests.test_sqlbuilder_joins_instances :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_sqlite.rst b/docs/api/sqlobject.tests.test_sqlite.rst index 1da10c03..7ef87923 100644 --- a/docs/api/sqlobject.tests.test_sqlite.rst +++ b/docs/api/sqlobject.tests.test_sqlite.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_sqlite module -===================================== +sqlobject.tests.test\_sqlite module +=================================== .. automodule:: sqlobject.tests.test_sqlite :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_sqlmeta_idName.rst b/docs/api/sqlobject.tests.test_sqlmeta_idName.rst index e01eb945..b2954f4c 100644 --- a/docs/api/sqlobject.tests.test_sqlmeta_idName.rst +++ b/docs/api/sqlobject.tests.test_sqlmeta_idName.rst @@ -1,5 +1,5 @@ -sqlobject\.tests\.test\_sqlmeta\_idName module -============================================== +sqlobject.tests.test\_sqlmeta\_idName module +============================================ .. automodule:: sqlobject.tests.test_sqlmeta_idName :members: diff --git a/docs/api/sqlobject.tests.test_sqlobject_admin.rst b/docs/api/sqlobject.tests.test_sqlobject_admin.rst index d76ebc52..517d03ed 100644 --- a/docs/api/sqlobject.tests.test_sqlobject_admin.rst +++ b/docs/api/sqlobject.tests.test_sqlobject_admin.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_sqlobject\_admin module -=============================================== +sqlobject.tests.test\_sqlobject\_admin module +============================================= .. automodule:: sqlobject.tests.test_sqlobject_admin :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_string_id.rst b/docs/api/sqlobject.tests.test_string_id.rst index fbadd05c..28be7463 100644 --- a/docs/api/sqlobject.tests.test_string_id.rst +++ b/docs/api/sqlobject.tests.test_string_id.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_string\_id module -========================================= +sqlobject.tests.test\_string\_id module +======================================= .. automodule:: sqlobject.tests.test_string_id :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_style.rst b/docs/api/sqlobject.tests.test_style.rst index 04722741..df0981a2 100644 --- a/docs/api/sqlobject.tests.test_style.rst +++ b/docs/api/sqlobject.tests.test_style.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_style module -==================================== +sqlobject.tests.test\_style module +================================== .. automodule:: sqlobject.tests.test_style :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_subqueries.rst b/docs/api/sqlobject.tests.test_subqueries.rst index 59b034be..c4ef5395 100644 --- a/docs/api/sqlobject.tests.test_subqueries.rst +++ b/docs/api/sqlobject.tests.test_subqueries.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_subqueries module -========================================= +sqlobject.tests.test\_subqueries module +======================================= .. automodule:: sqlobject.tests.test_subqueries :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_transactions.rst b/docs/api/sqlobject.tests.test_transactions.rst index 940636ca..1c218945 100644 --- a/docs/api/sqlobject.tests.test_transactions.rst +++ b/docs/api/sqlobject.tests.test_transactions.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_transactions module -=========================================== +sqlobject.tests.test\_transactions module +========================================= .. automodule:: sqlobject.tests.test_transactions :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_unicode.rst b/docs/api/sqlobject.tests.test_unicode.rst index cb48d1ad..c90397f9 100644 --- a/docs/api/sqlobject.tests.test_unicode.rst +++ b/docs/api/sqlobject.tests.test_unicode.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_unicode module -====================================== +sqlobject.tests.test\_unicode module +==================================== .. automodule:: sqlobject.tests.test_unicode :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_uuidcol.rst b/docs/api/sqlobject.tests.test_uuidcol.rst index 4ca71612..6ea9226e 100644 --- a/docs/api/sqlobject.tests.test_uuidcol.rst +++ b/docs/api/sqlobject.tests.test_uuidcol.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_uuidcol module -====================================== +sqlobject.tests.test\_uuidcol module +==================================== .. automodule:: sqlobject.tests.test_uuidcol :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_validation.rst b/docs/api/sqlobject.tests.test_validation.rst index 98ccedec..30e3fe04 100644 --- a/docs/api/sqlobject.tests.test_validation.rst +++ b/docs/api/sqlobject.tests.test_validation.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_validation module -========================================= +sqlobject.tests.test\_validation module +======================================= .. automodule:: sqlobject.tests.test_validation :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_views.rst b/docs/api/sqlobject.tests.test_views.rst index 291d57c7..ed828c36 100644 --- a/docs/api/sqlobject.tests.test_views.rst +++ b/docs/api/sqlobject.tests.test_views.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_views module -==================================== +sqlobject.tests.test\_views module +================================== .. automodule:: sqlobject.tests.test_views :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.util.csvexport.rst b/docs/api/sqlobject.util.csvexport.rst index 465bed93..25a3cb86 100644 --- a/docs/api/sqlobject.util.csvexport.rst +++ b/docs/api/sqlobject.util.csvexport.rst @@ -1,5 +1,5 @@ -sqlobject\.util\.csvexport module -================================= +sqlobject.util.csvexport module +=============================== .. automodule:: sqlobject.util.csvexport :members: diff --git a/docs/api/sqlobject.util.csvimport.rst b/docs/api/sqlobject.util.csvimport.rst index 6b19ee8d..415b518c 100644 --- a/docs/api/sqlobject.util.csvimport.rst +++ b/docs/api/sqlobject.util.csvimport.rst @@ -1,5 +1,5 @@ -sqlobject\.util\.csvimport module -================================= +sqlobject.util.csvimport module +=============================== .. automodule:: sqlobject.util.csvimport :members: diff --git a/docs/api/sqlobject.util.moduleloader.rst b/docs/api/sqlobject.util.moduleloader.rst index 9bfeb892..f262edad 100644 --- a/docs/api/sqlobject.util.moduleloader.rst +++ b/docs/api/sqlobject.util.moduleloader.rst @@ -1,5 +1,5 @@ -sqlobject\.util\.moduleloader module -==================================== +sqlobject.util.moduleloader module +================================== .. automodule:: sqlobject.util.moduleloader :members: diff --git a/docs/api/sqlobject.util.rst b/docs/api/sqlobject.util.rst index 2e194f23..9f5c1b38 100644 --- a/docs/api/sqlobject.util.rst +++ b/docs/api/sqlobject.util.rst @@ -1,5 +1,5 @@ -sqlobject\.util package -======================= +sqlobject.util package +====================== .. automodule:: sqlobject.util :members: diff --git a/docs/api/sqlobject.util.threadinglocal.rst b/docs/api/sqlobject.util.threadinglocal.rst index 3511fe17..dddba4d2 100644 --- a/docs/api/sqlobject.util.threadinglocal.rst +++ b/docs/api/sqlobject.util.threadinglocal.rst @@ -1,5 +1,5 @@ -sqlobject\.util\.threadinglocal module -====================================== +sqlobject.util.threadinglocal module +==================================== .. automodule:: sqlobject.util.threadinglocal :members: diff --git a/docs/api/sqlobject.versioning.rst b/docs/api/sqlobject.versioning.rst index 5f8c4d28..852d3e95 100644 --- a/docs/api/sqlobject.versioning.rst +++ b/docs/api/sqlobject.versioning.rst @@ -1,5 +1,5 @@ -sqlobject\.versioning package -============================= +sqlobject.versioning package +============================ .. automodule:: sqlobject.versioning :members: diff --git a/docs/api/sqlobject.versioning.test.rst b/docs/api/sqlobject.versioning.test.rst index f87edc23..6f9ea366 100644 --- a/docs/api/sqlobject.versioning.test.rst +++ b/docs/api/sqlobject.versioning.test.rst @@ -1,5 +1,5 @@ -sqlobject\.versioning\.test package -=================================== +sqlobject.versioning.test package +================================= .. automodule:: sqlobject.versioning.test :members: diff --git a/docs/api/sqlobject.versioning.test.test_version.rst b/docs/api/sqlobject.versioning.test.test_version.rst index 6ddf7722..2f03e9e4 100644 --- a/docs/api/sqlobject.versioning.test.test_version.rst +++ b/docs/api/sqlobject.versioning.test.test_version.rst @@ -1,8 +1,7 @@ -sqlobject\.versioning\.test\.test\_version module -================================================= +sqlobject.versioning.test.test\_version module +============================================== .. automodule:: sqlobject.versioning.test.test_version :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.views.rst b/docs/api/sqlobject.views.rst index ce4b406e..d0a30c58 100644 --- a/docs/api/sqlobject.views.rst +++ b/docs/api/sqlobject.views.rst @@ -1,5 +1,5 @@ -sqlobject\.views module -======================= +sqlobject.views module +====================== .. automodule:: sqlobject.views :members: diff --git a/docs/api/sqlobject.wsgi_middleware.rst b/docs/api/sqlobject.wsgi_middleware.rst index 79bc8727..b0aa884c 100644 --- a/docs/api/sqlobject.wsgi_middleware.rst +++ b/docs/api/sqlobject.wsgi_middleware.rst @@ -1,5 +1,5 @@ -sqlobject\.wsgi\_middleware module -================================== +sqlobject.wsgi\_middleware module +================================= .. automodule:: sqlobject.wsgi_middleware :members: From dffe5e97678ecf0e5f9d71aa141026f34ce151cc Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 1 May 2019 18:50:47 +0300 Subject: [PATCH 221/509] Release 3.7.2 --- ANNOUNCE.rst | 30 +++++++++++------------------- README.rst | 2 +- devscripts/build-all-docs | 2 +- docs/News.rst | 6 ++++-- sqlobject/__version__.py | 4 ++-- 5 files changed, 19 insertions(+), 25 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 84b0dcbe..6ab1d9ad 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,28 +1,20 @@ Hello! -I'm pleased to announce version 3.8.0a1, the first alpha of the upcoming -release of branch 3.8 of SQLObject. - -I'm pleased to announce version 3.8.0a2, the second alpha of the upcoming -release of branch 3.8 of SQLObject. - -I'm pleased to announce version 3.8.0b1, the first beta of the upcoming -release of branch 3.8 of SQLObject. - -I'm pleased to announce version 3.8.0rc1, the first release candidate -of the upcoming release of branch 3.8 of SQLObject. - -I'm pleased to announce version 3.8.0, the first stable release of branch -3.8 of SQLObject. - -I'm pleased to announce version 3.8.1, the first bugfix release of branch -3.8 of SQLObject. +I'm pleased to announce version 3.7.2, the second bugfix release of branch +3.7 of SQLObject. What's new in SQLObject ======================= -Contributors for this release are +Minor features +-------------- + +* Adapt Postgres exception handling to ``psycopg2`` version ``2.8``: + in the recent ``psycopg2`` errors are in ``psycopg2.errors`` module. + +* Removed RdbhostConnection: David Keeney and rdbhost seem to be unavailable + since 2017. For a more complete list, please see the news: http://sqlobject.org/News.html @@ -54,7 +46,7 @@ Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Download: -https://pypi.org/project/SQLObject/3.8.0a0.dev20190202/ +https://pypi.org/project/SQLObject/3.7.2 News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 92962cf6..52213389 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,4 @@ -SQLObject 3.8.0 +SQLObject 3.7.2 =============== Thanks for looking at SQLObject. SQLObject is an object-relational diff --git a/devscripts/build-all-docs b/devscripts/build-all-docs index 746018a3..bcb5c7c7 100755 --- a/devscripts/build-all-docs +++ b/devscripts/build-all-docs @@ -10,7 +10,7 @@ cd "`dirname \"$0\"`" && PROG_DIR="`pwd`" && cd .. && -build_docs 3.7.1 && +build_docs 3.7.2 && build_docs master devel && rm -rf docs/html && diff --git a/docs/News.rst b/docs/News.rst index af4ce644..dce568ef 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,8 +5,10 @@ News .. contents:: Contents: :backlinks: none -SQLObject (master) -================== +SQLObject 3.7.2 +=============== + +Released 1 May 2019. Minor features -------------- diff --git a/sqlobject/__version__.py b/sqlobject/__version__.py index 6e6740f7..52a80488 100644 --- a/sqlobject/__version__.py +++ b/sqlobject/__version__.py @@ -1,8 +1,8 @@ -version = '3.7.1' +version = '3.7.2' major = 3 minor = 7 -micro = 1 +micro = 2 release_level = 'final' serial = 0 version_info = (major, minor, micro, release_level, serial) From ee26d9787b276686f5be9a19229134f3256e24a3 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 1 May 2019 19:01:59 +0300 Subject: [PATCH 222/509] Prepare for the next release --- ANNOUNCE.rst | 30 +++++++++++++++++++----------- README.rst | 4 ++-- docs/News.rst | 3 +++ 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 6ab1d9ad..5cb28861 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,20 +1,28 @@ Hello! -I'm pleased to announce version 3.7.2, the second bugfix release of branch -3.7 of SQLObject. +I'm pleased to announce version 3.8.0a1, the first alpha of the upcoming +release of branch 3.8 of SQLObject. +I'm pleased to announce version 3.8.0a2, the second alpha of the upcoming +release of branch 3.8 of SQLObject. -What's new in SQLObject -======================= +I'm pleased to announce version 3.8.0b1, the first beta of the upcoming +release of branch 3.8 of SQLObject. + +I'm pleased to announce version 3.8.0rc1, the first release candidate +of the upcoming release of branch 3.8 of SQLObject. + +I'm pleased to announce version 3.8.0, the first stable release of branch +3.8 of SQLObject. -Minor features --------------- +I'm pleased to announce version 3.8.1, the first bugfix release of branch +3.8 of SQLObject. -* Adapt Postgres exception handling to ``psycopg2`` version ``2.8``: - in the recent ``psycopg2`` errors are in ``psycopg2.errors`` module. -* Removed RdbhostConnection: David Keeney and rdbhost seem to be unavailable - since 2017. +What's new in SQLObject +======================= + +Contributors for this release are For a more complete list, please see the news: http://sqlobject.org/News.html @@ -46,7 +54,7 @@ Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Download: -https://pypi.org/project/SQLObject/3.7.2 +https://pypi.org/project/SQLObject/3.8.0a0.dev20190501/ News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 52213389..404d1650 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.7.2 -=============== +SQLObject 3.7.3a0 +================= Thanks for looking at SQLObject. SQLObject is an object-relational mapper, i.e., a library that will wrap your database tables in Python diff --git a/docs/News.rst b/docs/News.rst index dce568ef..b2da732e 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,6 +5,9 @@ News .. contents:: Contents: :backlinks: none +SQLObject (master) +================== + SQLObject 3.7.2 =============== From 16925142461dd707162cc23ba57add3794aa4647 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 26 Jun 2019 21:33:23 +0300 Subject: [PATCH 223/509] Build(devscripts): Add `tox-select-envs.cmd` for w32 [skip ci] --- devscripts/tox-select-envs.cmd | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 devscripts/tox-select-envs.cmd diff --git a/devscripts/tox-select-envs.cmd b/devscripts/tox-select-envs.cmd new file mode 100644 index 00000000..2f6fbae4 --- /dev/null +++ b/devscripts/tox-select-envs.cmd @@ -0,0 +1,18 @@ +@echo off +SetLocal EnableDelayedExpansion + +set "pattern=%1" +shift + +set "envs=" +for /f "usebackq" %%e in ( + `tox --listenvs-all ^| find "%pattern%" ^| find "-w32"` +) do ( + if not defined envs (set "envs=%%e") else (set "envs=!envs!,%%e") +) + +if not "%envs%"=="" ( + tox -e "%envs%" %* +) else ( + echo "No environments match %pattern%" >&2 +) From 37ec639c362949356a01a7fb1a8c700178b80237 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 30 Jun 2019 17:10:45 +0300 Subject: [PATCH 224/509] Tests(tox): Refactor `tox-select-envs.cmd` --- devscripts/tox-select-envs.cmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devscripts/tox-select-envs.cmd b/devscripts/tox-select-envs.cmd index 2f6fbae4..4ea6114e 100644 --- a/devscripts/tox-select-envs.cmd +++ b/devscripts/tox-select-envs.cmd @@ -8,7 +8,7 @@ set "envs=" for /f "usebackq" %%e in ( `tox --listenvs-all ^| find "%pattern%" ^| find "-w32"` ) do ( - if not defined envs (set "envs=%%e") else (set "envs=!envs!,%%e") + if defined envs (set "envs=!envs!,%%e") else (set "envs=%%e") ) if not "%envs%"=="" ( From ed65656d57475b9cdcac7fe45a47581b95c4f375 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 30 Jun 2019 17:21:13 +0300 Subject: [PATCH 225/509] Tests(tox): Add dummy tests and unify test names Add dummy tests for `MySQL-python` on Python 3 and for `mysqlclient`/`pypostgresql` on Python 2.7. Unified test names must be structured "python-version" - "database name" - "driver" [-w32]. These tests will be used in refactored `.travis.yml`/`appveyor.yml`. --- tox.ini | 65 +++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 47 insertions(+), 18 deletions(-) diff --git a/tox.ini b/tox.ini index dc17448c..f3f2bfc0 100644 --- a/tox.ini +++ b/tox.ini @@ -58,6 +58,22 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysqldb]commands} +[testenv:py34-mysqldb] +commands = {envpython} -c "print('MySQL-python requires Python 2.7')" +deps = + +[testenv:py35-mysqldb] +commands = {envpython} -c "print('MySQL-python requires Python 2.7')" +deps = + +[testenv:py36-mysqldb] +commands = {envpython} -c "print('MySQL-python requires Python 2.7')" +deps = + +[testenv:py37-mysqldb] +commands = {envpython} -c "print('MySQL-python requires Python 2.7')" +deps = + [mysqlclient] commands = {[testenv]commands} @@ -66,6 +82,10 @@ commands = pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=mysqldb&charset=utf8&debug=1 mysql -uroot -e 'drop database sqlobject_test;' +[testenv:py27-mysqlclient] +commands = {envpython} -c "print('mysqlclient requires Python 3.4+')" +deps = + [testenv:py34-mysqlclient] commands = {[mysqlclient]commands} @@ -136,21 +156,21 @@ commands = pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=pymysql&charset=utf8&debug=1 mysql -uroot -e 'drop database sqlobject_test;' -[testenv:py27-pymysql] +[testenv:py27-mysql-pymysql] commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pymysql]commands} -[testenv:py34-pymysql] +[testenv:py34-mysql-pymysql] commands = {[pymysql]commands} -[testenv:py35-pymysql] +[testenv:py35-mysql-pymysql] commands = {[pymysql]commands} -[testenv:py36-pymysql] +[testenv:py36-mysql-pymysql] commands = {[pymysql]commands} -[testenv:py37-pymysql] +[testenv:py37-mysql-pymysql] commands = {[pymysql]commands} [mysql-pyodbc] @@ -263,16 +283,20 @@ commands = pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test dropdb -U postgres -w sqlobject_test -[testenv:py34-pypostgresql] +[testenv:py27-postgres-pypostgresql] +commands = {envpython} -c "print('pypostgresql requires Python 3.4+')" +deps = + +[testenv:py34-postgres-pypostgresql] commands = {[pypostgresql]commands} -[testenv:py35-pypostgresql] +[testenv:py35-postgres-pypostgresql] commands = {[pypostgresql]commands} -[testenv:py36-pypostgresql] +[testenv:py36-postgres-pypostgresql] commands = {[pypostgresql]commands} -[testenv:py37-pypostgresql] +[testenv:py37-postgres-pypostgresql] commands = {[pypostgresql]commands} [pg8000] @@ -543,25 +567,25 @@ commands = pytest --cov=sqlobject -D "mysql://root:Password12!@localhost/sqlobject_test?driver=pymysql&charset=utf8&debug=1" mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' -[testenv:py27-pymysql-w32] +[testenv:py27-mysql-pymysql-w32] platform = win32 commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pymysql-w32]commands} -[testenv:py34-pymysql-w32] +[testenv:py34-mysql-pymysql-w32] platform = win32 commands = {[pymysql-w32]commands} -[testenv:py35-pymysql-w32] +[testenv:py35-mysql-pymysql-w32] platform = win32 commands = {[pymysql-w32]commands} -[testenv:py36-pymysql-w32] +[testenv:py36-mysql-pymysql-w32] platform = win32 commands = {[pymysql-w32]commands} -[testenv:py37-pymysql-w32] +[testenv:py37-mysql-pymysql-w32] platform = win32 commands = cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" @@ -710,19 +734,24 @@ commands = pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb -U postgres -w sqlobject_test -[testenv:py34-pypostgresql-w32] +[testenv:py27-postgres-pypostgresql-w32] +platform = win32 +commands = {envpython} -c "print('pypostgresql requires Python 3.4+')" +deps = + +[testenv:py34-postgres-pypostgresql-w32] platform = win32 commands = {[pypostgresql-w32]commands} -[testenv:py35-pypostgresql-w32] +[testenv:py35-postgres-pypostgresql-w32] platform = win32 commands = {[pypostgresql-w32]commands} -[testenv:py36-pypostgresql-w32] +[testenv:py36-postgres-pypostgresql-w32] platform = win32 commands = {[pypostgresql-w32]commands} -[testenv:py37-pypostgresql-w32] +[testenv:py37-postgres-pypostgresql-w32] platform = win32 commands = cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" From 9084e6f3a27fcf24e5fd02010319cfacf5a015dc Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 30 Jun 2019 17:52:29 +0300 Subject: [PATCH 226/509] CI: Reduce the number of virtual machines/containers One OS, one DB, one python version, many drivers per VM. --- .travis.yml | 129 +++++++++++--------------------------------------- appveyor.yml | 97 ++++--------------------------------- docs/News.rst | 6 +++ 3 files changed, 43 insertions(+), 189 deletions(-) diff --git a/.travis.yml b/.travis.yml index acd3e873..8fe81bad 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,132 +22,57 @@ addons: matrix: include: - python: "2.7" - env: TOXENV=py27-mysqldb + env: TESTS=py27-mysql - python: "3.4" - env: TOXENV=py34-mysqlclient + env: TESTS=py34-mysql - python: "3.5" - env: TOXENV=py35-mysqlclient + env: TESTS=py35-mysql - python: "3.6" - env: TOXENV=py36-mysqlclient + env: TESTS=py36-mysql - python: "3.7" dist: xenial - env: TOXENV=py37-mysqlclient + env: TESTS=py37-mysql - python: "2.7" - env: TOXENV=py27-mysql-connector + env: TESTS=py27-postgres - python: "3.4" - env: TOXENV=py34-mysql-connector + env: TESTS=py34-postgres - python: "3.5" - env: TOXENV=py35-mysql-connector + env: TESTS=py35-postgres - python: "3.6" - env: TOXENV=py36-mysql-connector + env: TESTS=py36-postgres - python: "3.7" dist: xenial - env: TOXENV=py37-mysql-connector + env: TESTS=py37-postgres - python: "2.7" - env: TOXENV=py27-mysql-oursql + env: TESTS=py27-sqlite - python: "3.4" - env: TOXENV=py34-mysql-oursql3 + env: TESTS=py34-sqlite - python: "3.5" - env: TOXENV=py35-mysql-oursql3 + env: TESTS=py35-sqlite - python: "3.6" - env: TOXENV=py36-mysql-oursql3 + env: TESTS=py36-sqlite - python: "3.7" dist: xenial - env: TOXENV=py37-mysql-oursql3 + env: TESTS=py37-sqlite - python: "2.7" - env: TOXENV=py27-pymysql - - python: "3.4" - env: TOXENV=py34-pymysql - - python: "3.5" - env: TOXENV=py35-pymysql - - python: "3.6" - env: TOXENV=py36-pymysql - - python: "3.7" - dist: xenial - env: TOXENV=py37-pymysql - - python: "2.7" - env: TOXENV=py27-postgres-psycopg - - python: "3.4" - env: TOXENV=py34-postgres-psycopg - - python: "3.5" - env: TOXENV=py35-postgres-psycopg - - python: "3.6" - env: TOXENV=py36-postgres-psycopg - - python: "3.7" - dist: xenial - env: TOXENV=py37-postgres-psycopg - - python: "2.7" - env: TOXENV=py27-postgres-pygresql - - python: "3.4" - env: TOXENV=py34-postgres-pygresql - - python: "3.5" - env: TOXENV=py35-postgres-pygresql - - python: "3.6" - env: TOXENV=py36-postgres-pygresql - - python: "3.7" - dist: xenial - env: TOXENV=py37-postgres-pygresql - - python: "3.4" - env: TOXENV=py34-pypostgresql - - python: "3.5" - env: TOXENV=py35-pypostgresql - - python: "3.6" - env: TOXENV=py36-pypostgresql - - python: "3.7" - dist: xenial - env: TOXENV=py37-pypostgresql - - python: "2.7" - env: TOXENV=py27-postgres-pg8000 - - python: "3.4" - env: TOXENV=py34-postgres-pg8000 - - python: "3.5" - env: TOXENV=py35-postgres-pg8000 - - python: "3.6" - env: TOXENV=py36-postgres-pg8000 - - python: "3.7" - dist: xenial - env: TOXENV=py37-postgres-pg8000 - - python: "2.7" - env: TOXENV=py27-sqlite - - python: "3.4" - env: TOXENV=py34-sqlite - - python: "3.5" - env: TOXENV=py35-sqlite - - python: "3.6" - env: TOXENV=py36-sqlite - - python: "3.7" - dist: xenial - env: TOXENV=py37-sqlite - - python: "2.7" - env: TOXENV=py27-sqlite-memory - - python: "3.4" - env: TOXENV=py34-sqlite-memory - - python: "3.5" - env: TOXENV=py35-sqlite-memory - - python: "3.6" - env: TOXENV=py36-sqlite-memory - - python: "3.7" - dist: xenial - env: TOXENV=py37-sqlite-memory - - python: "2.7" - env: TOXENV=py27-flake8 + env: TESTS=py27-flake8 - python: "3.7" dist: xenial - env: TOXENV=py37-flake8 + env: TESTS=py37-flake8 - python: "2.7" - env: TOXENV=py27-firebird-fdb + env: TESTS=py27-firebird - python: "3.6" - env: TOXENV=py36-firebird-fdb + env: TESTS=py36-firebird - python: "2.7" - env: TOXENV=py27-firebirdsql + env: TESTS=py27-firebird - python: "3.6" - env: TOXENV=py36-firebirdsql + env: TESTS=py36-firebird allow_failures: - - env: TOXENV=py27-firebird-fdb - - env: TOXENV=py36-firebird-fdb - - env: TOXENV=py27-firebirdsql - - env: TOXENV=py36-firebirdsql + - env: TESTS=py27-firebird + - env: TESTS=py36-firebird + - env: TESTS=py27-firebird + - env: TESTS=py36-firebird fast_finish: true @@ -160,7 +85,7 @@ before_install: # to create the test database. # Copied password initializtion from # https://github.com/xdenser/node-firebird-libfbclient/blob/master/.travis.yml - - if [[ $TOXENV = *firebird* ]]; then + - if [[ $TESTS = *firebird* ]]; then sudo sed -i /etc/default/firebird2.5 -e 's/=no/=yes/' && sudo /etc/init.d/firebird2.5-super start && sleep 5 && sudo /bin/bash -c '(export FB_VER="2.5"; export FB_FLAVOUR="super";source /usr/share/firebird2.5-common/functions.sh; writeNewPassword masterkey)' && @@ -171,7 +96,7 @@ before_install: install: travis_retry pip install --upgrade "pip < 19.1" setuptools tox coveralls codecov ppu -script: tox +script: devscripts/tox-select-envs $TESTS after_success: - cd sqlobject diff --git a/appveyor.yml b/appveyor.yml index 953cc8ac..0bd35764 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -25,122 +25,45 @@ environment: CMD_IN_ENV: "cmd /E:ON /V:ON /C .\\run_with_env.cmd" matrix: - - TOXENV: "py27-mysql-connector-w32" + - TESTS: "py27-mysql" PYTHON_ARCH: "32" PYTHON_VERSION: "2.7" PYTHON_HOME: "C:\\Python27" db: mysql - - TOXENV: "py36-mysql-connector-w32" + - TESTS: "py36-mysql" PYTHON_ARCH: "64" PYTHON_VERSION: "3.6" PYTHON_HOME: "C:\\Python36-x64" db: mysql - - TOXENV: "py37-mysql-connector-w32" + - TESTS: "py37-mysql" PYTHON_ARCH: "64" PYTHON_VERSION: "3.7" PYTHON_HOME: "C:\\Python37-x64" db: mysql - - TOXENV: "py27-pymysql-w32" + - TESTS: "py27-postgres" PYTHON_ARCH: "32" PYTHON_VERSION: "2.7" PYTHON_HOME: "C:\\Python27" - db: mysql - - TOXENV: "py36-pymysql-w32" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.6" - PYTHON_HOME: "C:\\Python36-x64" - db: mysql - - TOXENV: "py37-pymysql-w32" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.7" - PYTHON_HOME: "C:\\Python37-x64" - db: mysql - - TOXENV: "py27-postgres-psycopg-w32" - PYTHON_ARCH: "32" - PYTHON_VERSION: "2.7" - PYTHON_HOME: "C:\\Python27" - db: postgresql - - TOXENV: "py36-postgres-psycopg-w32" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.6" - PYTHON_HOME: "C:\\Python36-x64" - db: postgresql - - TOXENV: "py37-postgres-psycopg-w32" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.7" - PYTHON_HOME: "C:\\Python37-x64" - db: postgresql - - TOXENV: "py27-postgres-pygresql-w32" - PYTHON_ARCH: "64" - PYTHON_VERSION: "2.7" - PYTHON_HOME: "C:\\Python27-x64" - db: postgresql - - TOXENV: "py36-postgres-pygresql-w32" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.6" - PYTHON_HOME: "C:\\Python36-x64" - db: postgresql - - TOXENV: "py37-postgres-pygresql-w32" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.7" - PYTHON_HOME: "C:\\Python37-x64" - db: postgresql - - TOXENV: "py36-pypostgresql-w32" - PYTHON_ARCH: "32" - PYTHON_VERSION: "3.6" - PYTHON_HOME: "C:\\Python36" - db: postgresql - - TOXENV: "py37-pypostgresql-w32" - PYTHON_ARCH: "32" - PYTHON_VERSION: "3.7" - PYTHON_HOME: "C:\\Python37" db: postgresql - - TOXENV: "py36-pypostgresql-w32" + - TESTS: "py36-postgres" PYTHON_ARCH: "64" PYTHON_VERSION: "3.6" PYTHON_HOME: "C:\\Python36-x64" db: postgresql - - TOXENV: "py37-pypostgresql-w32" + - TESTS: "py37-postgres" PYTHON_ARCH: "64" PYTHON_VERSION: "3.7" PYTHON_HOME: "C:\\Python37-x64" db: postgresql - - TOXENV: "py27-postgres-pg8000-w32" - PYTHON_ARCH: "32" - PYTHON_VERSION: "2.7" - PYTHON_HOME: "C:\\Python27" - db: postgresql - - TOXENV: "py36-postgres-pg8000-w32" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.6" - PYTHON_HOME: "C:\\Python36-x64" - db: postgresql - - TOXENV: "py37-postgres-pg8000-w32" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.7" - PYTHON_HOME: "C:\\Python37-x64" - db: postgresql - - TOXENV: "py27-sqlite-w32" - PYTHON_ARCH: "32" - PYTHON_VERSION: "2.7" - PYTHON_HOME: "C:\\Python27" - - TOXENV: "py36-sqlite-w32" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.6" - PYTHON_HOME: "C:\\Python36-x64" - - TOXENV: "py37-sqlite-w32" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.7" - PYTHON_HOME: "C:\\Python37-x64" - - TOXENV: "py27-sqlite-memory-w32" + - TESTS: "py27-sqlite" PYTHON_ARCH: "32" PYTHON_VERSION: "2.7" PYTHON_HOME: "C:\\Python27" - - TOXENV: "py36-sqlite-memory-w32" + - TESTS: "py36-sqlite" PYTHON_ARCH: "64" PYTHON_VERSION: "3.6" PYTHON_HOME: "C:\\Python36-x64" - - TOXENV: "py37-sqlite-memory-w32" + - TESTS: "py37-sqlite" PYTHON_ARCH: "64" PYTHON_VERSION: "3.7" PYTHON_HOME: "C:\\Python37-x64" @@ -165,7 +88,7 @@ install: build: false test_script: - - "%CMD_IN_ENV% tox" + - "%CMD_IN_ENV% devscripts\\tox-select-envs %TESTS%" after_test: - "remove-old-files.py -o 180 %LOCALAPPDATA%\\pip\\Cache" diff --git a/docs/News.rst b/docs/News.rst index b2da732e..e57e68c0 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,12 @@ News SQLObject (master) ================== +CI +-- + +* Reduce the number of virtual machines/containers: + one OS, one DB, one python version, many drivers per VM. + SQLObject 3.7.2 =============== From 9d4af66987f77054c307c417dbdd786d6bfb5012 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 30 Jun 2019 18:27:22 +0300 Subject: [PATCH 227/509] Tests(tox): Exclude tests from the list of auto tests Exclude ODBC tests and py27-pygresql. --- devscripts/tox-select-envs | 2 +- devscripts/tox-select-envs.cmd | 2 +- tox.ini | 92 +++++++++++++++++----------------- 3 files changed, 48 insertions(+), 48 deletions(-) diff --git a/devscripts/tox-select-envs b/devscripts/tox-select-envs index 34ff4b2c..f1e9a817 100755 --- a/devscripts/tox-select-envs +++ b/devscripts/tox-select-envs @@ -2,7 +2,7 @@ pattern="$1" shift -envs="`tox --listenvs-all | grep -F $pattern | sed 's/$/,/'`" +envs="`tox --listenvs-all | grep -F $pattern | grep -v 'noauto\|w32' | sed 's/$/,/'`" if [ -n "$envs" ]; then exec tox -e "$envs" "$@" diff --git a/devscripts/tox-select-envs.cmd b/devscripts/tox-select-envs.cmd index 4ea6114e..03d8b4e1 100644 --- a/devscripts/tox-select-envs.cmd +++ b/devscripts/tox-select-envs.cmd @@ -6,7 +6,7 @@ shift set "envs=" for /f "usebackq" %%e in ( - `tox --listenvs-all ^| find "%pattern%" ^| find "-w32"` + `tox --listenvs-all ^| find "%pattern%" ^| find "-w32" ^| find /v "noauto"` ) do ( if defined envs (set "envs=!envs!,%%e") else (set "envs=%%e") ) diff --git a/tox.ini b/tox.ini index f3f2bfc0..7dac706b 100644 --- a/tox.ini +++ b/tox.ini @@ -182,21 +182,21 @@ commands = pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=pyodbc&odbcdrv=MySQL&charset=utf8&debug=1 mysql -uroot -e 'drop database sqlobject_test;' -[testenv:py27-mysql-pyodbc] +[testenv:py27-mysql-pyodbc-noauto] commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pyodbc]commands} -[testenv:py34-mysql-pyodbc] +[testenv:py34-mysql-pyodbc-noauto] commands = {[mysql-pyodbc]commands} -[testenv:py35-mysql-pyodbc] +[testenv:py35-mysql-pyodbc-noauto] commands = {[mysql-pyodbc]commands} -[testenv:py36-mysql-pyodbc] +[testenv:py36-mysql-pyodbc-noauto] commands = {[mysql-pyodbc]commands} -[testenv:py37-mysql-pyodbc] +[testenv:py37-mysql-pyodbc-noauto] commands = {[mysql-pyodbc]commands} [mysql-pypyodbc] @@ -207,21 +207,21 @@ commands = pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=MySQL&charset=utf8&debug=1 mysql -uroot -e 'drop database sqlobject_test;' -[testenv:py27-mysql-pypyodbc] +[testenv:py27-mysql-pypyodbc-noauto] commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pypyodbc]commands} -[testenv:py34-mysql-pypyodbc] +[testenv:py34-mysql-pypyodbc-noauto] commands = {[mysql-pypyodbc]commands} -[testenv:py35-mysql-pypyodbc] +[testenv:py35-mysql-pypyodbc-noauto] commands = {[mysql-pypyodbc]commands} -[testenv:py36-mysql-pypyodbc] +[testenv:py36-mysql-pypyodbc-noauto] commands = {[mysql-pypyodbc]commands} -[testenv:py37-mysql-pypyodbc] +[testenv:py37-mysql-pypyodbc-noauto] commands = {[mysql-pypyodbc]commands} # PostgreSQL test environments @@ -333,21 +333,21 @@ commands = pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=pyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test dropdb -U postgres -w sqlobject_test -[testenv:py27-postgres-pyodbc] +[testenv:py27-postgres-pyodbc-noauto] commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pyodbc]commands} -[testenv:py34-postgres-pyodbc] +[testenv:py34-postgres-pyodbc-noauto] commands = {[postgres-pyodbc]commands} -[testenv:py35-postgres-pyodbc] +[testenv:py35-postgres-pyodbc-noauto] commands = {[postgres-pyodbc]commands} -[testenv:py36-postgres-pyodbc] +[testenv:py36-postgres-pyodbc-noauto] commands = {[postgres-pyodbc]commands} -[testenv:py37-postgres-pyodbc] +[testenv:py37-postgres-pyodbc-noauto] commands = {[postgres-pyodbc]commands} [postgres-pypyodbc] @@ -358,21 +358,21 @@ commands = pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test dropdb -U postgres -w sqlobject_test -[testenv:py27-postgres-pypyodbc] +[testenv:py27-postgres-pypyodbc-noauto] commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pypyodbc]commands} -[testenv:py34-postgres-pypyodbc] +[testenv:py34-postgres-pypyodbc-noauto] commands = {[postgres-pypyodbc]commands} -[testenv:py35-postgres-pypyodbc] +[testenv:py35-postgres-pypyodbc-noauto] commands = {[postgres-pypyodbc]commands} -[testenv:py36-postgres-pypyodbc] +[testenv:py36-postgres-pypyodbc-noauto] commands = {[postgres-pypyodbc]commands} -[testenv:py37-postgres-pypyodbc] +[testenv:py37-postgres-pypyodbc-noauto] commands = {[postgres-pypyodbc]commands} @@ -501,25 +501,25 @@ commands = pytest --cov=sqlobject -D "mssql://sa:Password12!@localhost\SQL2014/sqlobject_test?driver=pyodbc&odbcdrv=SQL%20Server&timeout=30&debug=1" sqlcmd -U sa -P "Password12!" -S .\SQL2014 -Q "DROP DATABASE sqlobject_test" -[testenv:py27-mssql-pyodbc-w32] +[testenv:py27-mssql-pyodbc-noauto-w32] platform = win32 commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mssql-pyodbc-w32]commands} -[testenv:py34-mssql-pyodbc-w32] +[testenv:py34-mssql-pyodbc-noauto-w32] platform = win32 commands = {[mssql-pyodbc-w32]commands} -[testenv:py35-mssql-pyodbc-w32] +[testenv:py35-mssql-pyodbc-noauto-w32] platform = win32 commands = {[mssql-pyodbc-w32]commands} -[testenv:py36-mssql-pyodbc-w32] +[testenv:py36-mssql-pyodbc-noauto-w32] platform = win32 commands = {[mssql-pyodbc-w32]commands} -[testenv:py37-mssql-pyodbc-w32] +[testenv:py37-mssql-pyodbc-noauto-w32] platform = win32 commands = cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" @@ -601,25 +601,25 @@ commands = pytest --cov=sqlobject -D mysql://root:Password12!@localhost/sqlobject_test?driver=pyodbc&odbcdrv=MySQL%20ODBC%205.3%20ANSI%20Driver&charset=utf8&debug=1 mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' -[testenv:py27-mysql-pyodbc-w32] +[testenv:py27-mysql-pyodbc-noauto-w32] platform = win32 commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pyodbc-w32]commands} -[testenv:py34-mysql-pyodbc-w32] +[testenv:py34-mysql-pyodbc-noauto-w32] platform = win32 commands = {[mysql-pyodbc-w32]commands} -[testenv:py35-mysql-pyodbc-w32] +[testenv:py35-mysql-pyodbc-noauto-w32] platform = win32 commands = {[mysql-pyodbc-w32]commands} -[testenv:py36-mysql-pyodbc-w32] +[testenv:py36-mysql-pyodbc-noauto-w32] platform = win32 commands = {[mysql-pyodbc-w32]commands} -[testenv:py37-mysql-pyodbc-w32] +[testenv:py37-mysql-pyodbc-noauto-w32] platform = win32 commands = cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" @@ -635,25 +635,25 @@ commands = pytest --cov=sqlobject -D mysql://root:Password12!@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=MySQL%20ODBC%205.3%20ANSI%20Driver&charset=utf8&debug=1 mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' -[testenv:py27-mysql-pypyodbc-w32] +[testenv:py27-mysql-pypyodbc-noauto-w32] platform = win32 commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pypyodbc-w32]commands} -[testenv:py34-mysql-pypyodbc-w32] +[testenv:py34-mysql-pypyodbc-noauto-w32] platform = win32 commands = {[mysql-pypyodbc-w32]commands} -[testenv:py35-mysql-pypyodbc-w32] +[testenv:py35-mysql-pypyodbc-noauto-w32] platform = win32 commands = {[mysql-pypyodbc-w32]commands} -[testenv:py36-mysql-pypyodbc-w32] +[testenv:py36-mysql-pypyodbc-noauto-w32] platform = win32 commands = {[mysql-pypyodbc-w32]commands} -[testenv:py37-mysql-pypyodbc-w32] +[testenv:py37-mysql-pypyodbc-noauto-w32] platform = win32 commands = cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" @@ -701,7 +701,7 @@ commands = pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb -U postgres -w sqlobject_test -[testenv:py27-postgres-pygresql-w32] +[testenv:py27-postgres-pygresql-noauto-w32] platform = win32 commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base @@ -800,25 +800,25 @@ commands = pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pyodbc&odbcdrv=PostgreSQL%20ANSI%28x64%29&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb -U postgres -w sqlobject_test -[testenv:py27-postgres-pyodbc-w32] +[testenv:py27-postgres-pyodbc-noauto-w32] platform = win32 commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pyodbc-w32]commands} -[testenv:py34-postgres-pyodbc-w32] +[testenv:py34-postgres-pyodbc-noauto-w32] platform = win32 commands = {[postgres-pyodbc-w32]commands} -[testenv:py35-postgres-pyodbc-w32] +[testenv:py35-postgres-pyodbc-noauto-w32] platform = win32 commands = {[postgres-pyodbc-w32]commands} -[testenv:py36-postgres-pyodbc-w32] +[testenv:py36-postgres-pyodbc-noauto-w32] platform = win32 commands = {[postgres-pyodbc-w32]commands} -[testenv:py37-postgres-pyodbc-w32] +[testenv:py37-postgres-pyodbc-noauto-w32] platform = win32 commands = cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" @@ -834,25 +834,25 @@ commands = pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=PostgreSQL%20ANSI%28x64%29&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb -U postgres -w sqlobject_test -[testenv:py27-postgres-pypyodbc-w32] +[testenv:py27-postgres-pypyodbc-noauto-w32] platform = win32 commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pypyodbc-w32]commands} -[testenv:py34-postgres-pypyodbc-w32] +[testenv:py34-postgres-pypyodbc-noauto-w32] platform = win32 commands = {[postgres-pypyodbc-w32]commands} -[testenv:py35-postgres-pypyodbc-w32] +[testenv:py35-postgres-pypyodbc-noauto-w32] platform = win32 commands = {[postgres-pypyodbc-w32]commands} -[testenv:py36-postgres-pypyodbc-w32] +[testenv:py36-postgres-pypyodbc-noauto-w32] platform = win32 commands = {[postgres-pypyodbc-w32]commands} -[testenv:py37-postgres-pypyodbc-w32] +[testenv:py37-postgres-pypyodbc-noauto-w32] platform = win32 commands = cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" From bae4bad96fbff1fdb476ca11e200d4d1a0907083 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 5 Sep 2019 20:02:03 +0300 Subject: [PATCH 228/509] Build: Remove outdated `git-svn` --- .../git-svn/SQLObject-gitignore/.gitignore | 10 ---- .../SQLObject-gitignore/docs/.gitignore | 3 - devscripts/git-svn/svn2git | 55 ------------------- devscripts/git-svn/svn2git-fullhistory | 33 ----------- 4 files changed, 101 deletions(-) delete mode 100644 devscripts/git-svn/SQLObject-gitignore/.gitignore delete mode 100644 devscripts/git-svn/SQLObject-gitignore/docs/.gitignore delete mode 100755 devscripts/git-svn/svn2git delete mode 100755 devscripts/git-svn/svn2git-fullhistory diff --git a/devscripts/git-svn/SQLObject-gitignore/.gitignore b/devscripts/git-svn/SQLObject-gitignore/.gitignore deleted file mode 100644 index 52d4a58a..00000000 --- a/devscripts/git-svn/SQLObject-gitignore/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -*~ -*.tmp -*.pyc -*.pyo -/MANIFEST -/SQLObject.egg-info -/build -/data -/dist -/temp diff --git a/devscripts/git-svn/SQLObject-gitignore/docs/.gitignore b/devscripts/git-svn/SQLObject-gitignore/docs/.gitignore deleted file mode 100644 index 59370209..00000000 --- a/devscripts/git-svn/SQLObject-gitignore/docs/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/*.html -/data.db -/html diff --git a/devscripts/git-svn/svn2git b/devscripts/git-svn/svn2git deleted file mode 100755 index e93e4f6f..00000000 --- a/devscripts/git-svn/svn2git +++ /dev/null @@ -1,55 +0,0 @@ -#! /bin/sh - -if [ -z "$1" ]; then - echo "Usage: $0 svn_url [dir]" >&2 - exit 1 -fi - -url="$1" - -if [ ! -f authors.txt ]; then - echo "Run \"get-authors $1\" first" >&2 - exit 2 -fi - -if [ -z "$2" ]; then - dir="`basename $url`" -else - dir="$2" -fi - -if [ -z "$dir" ]; then - echo "Usage: $0 $url dir" >&2 - exit 1 -fi - -# init + fetch -git svn clone "$url" --authors-file=authors.txt --prefix=svn/ --stdlayout "$dir" && -cd "$dir" && - -# Convert tags and branches - -# See http://blog.jessitron.com/2013/08/converting-from-svn-to-git.html - -git for-each-ref --format="%(refname:short)" refs/remotes/svn | - sed 's#svn/##' | grep -v '^tags' | - while read aBranch; do git branch $aBranch svn/$aBranch || exit 1; done - -# See http://thomasrast.ch/git/git-svn-conversion.html - -git for-each-ref --format="%(refname:short)" refs/remotes/svn/tags/ | -while read tag; do - GIT_COMMITTER_DATE="`git log -1 --pretty=format:\"%ad\" \"$tag\"`" \ - GIT_COMMITTER_EMAIL="`git log -1 --pretty=format:\"%ce\" \"$tag\"`" \ - GIT_COMMITTER_NAME="`git log -1 --pretty=format:\"%cn\" \"$tag\"`" \ - git tag -a -m "`git for-each-ref --format=\"%(contents)\" \"$tag\"`" \ - "`echo \"$tag\" | sed 's#svn/tags/##'`" "$tag" || exit 1 -done - -# preserve authors.txt -cp -p ../authors.txt .git/info && -git config --local --path svn.authorsfile .git/info/authors.txt - -git svn gc && -git gc --aggressive && -echo "Cloned from $url using git-svn" >.git/description diff --git a/devscripts/git-svn/svn2git-fullhistory b/devscripts/git-svn/svn2git-fullhistory deleted file mode 100755 index bc74b897..00000000 --- a/devscripts/git-svn/svn2git-fullhistory +++ /dev/null @@ -1,33 +0,0 @@ -#! /bin/sh - -"`dirname \"$0\"`"/svn2git \ - http://svn.colorstudy.com/SQLObject SQLObject-fullhistory && - -git init --bare SQLObject.git && -cd SQLObject.git && -echo "Bare SQLObject repository" >description && -git fetch ../SQLObject-fullhistory master:master 1.5:1.5 1.6:1.6 1.7:1.7 tag 1.5.0b1 tag 1.5.0rc1 tag 1.5.0 tag 1.5.1 tag 1.5.2 tag 1.6.0a1 tag 1.6.0b1 tag 1.6.0 tag 1.7.0b1 && - -cd .. && -git clone SQLObject.git SQLObject && rm -rf SQLObject.git && -cd SQLObject && git remote rm origin && rmdir .git/refs/remotes/origin && - -echo "Development SQLObject repository" >.git/description && -git branch --track 1.5 origin/1.5 && -git branch --track 1.6 origin/1.6 && -git branch --track 1.7 origin/1.7 && - -# Null merges -git checkout 1.6 && git merge --no-commit -s ours 1.5 && -git checkout HEAD sqlobject/main.py && git commit && - -git checkout 1.7 && git merge --no-commit -s ours 1.6 && -git checkout HEAD sqlobject/col.py && git commit && - -git checkout master && git merge --no-commit -s ours 1.7 && -git checkout HEAD setup.cfg setup.py \ - sqlobject/__version__.py sqlobject/converters.py \ - sqlobject/tests/test_converters.py sqlobject/tests/test_datetime.py && -git commit && - -exec vim .git/config From 26d83fb89b914940892dbecd033707fbfcc8b71e Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 5 Sep 2019 20:54:30 +0300 Subject: [PATCH 229/509] CI(AppVeyor): Move `validators.py` -> `devscripts/CI/` --- validators.py => devscripts/CI/validators.py | 0 tox.ini | 26 ++++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) rename validators.py => devscripts/CI/validators.py (100%) diff --git a/validators.py b/devscripts/CI/validators.py similarity index 100% rename from validators.py rename to devscripts/CI/validators.py diff --git a/tox.ini b/tox.ini index 7dac706b..899295c8 100644 --- a/tox.ini +++ b/tox.ini @@ -522,7 +522,7 @@ commands = {[mssql-pyodbc-w32]commands} [testenv:py37-mssql-pyodbc-noauto-w32] platform = win32 commands = - cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" + cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[mssql-pyodbc-w32]commands} [mysql-connector-w32] @@ -555,7 +555,7 @@ commands = {[mysql-connector-w32]commands} [testenv:py37-mysql-connector-w32] platform = win32 commands = - cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" + cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[mysql-connector-w32]commands} [pymysql-w32] @@ -588,7 +588,7 @@ commands = {[pymysql-w32]commands} [testenv:py37-mysql-pymysql-w32] platform = win32 commands = - cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" + cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[pymysql-w32]commands} [mysql-pyodbc-w32] @@ -622,7 +622,7 @@ commands = {[mysql-pyodbc-w32]commands} [testenv:py37-mysql-pyodbc-noauto-w32] platform = win32 commands = - cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" + cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[mysql-pyodbc-w32]commands} [mysql-pypyodbc-w32] @@ -656,7 +656,7 @@ commands = {[mysql-pypyodbc-w32]commands} [testenv:py37-mysql-pypyodbc-noauto-w32] platform = win32 commands = - cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" + cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[mysql-pypyodbc-w32]commands} [psycopg-w32] @@ -689,7 +689,7 @@ commands = {[psycopg-w32]commands} [testenv:py37-postgres-psycopg-w32] platform = win32 commands = - cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" + cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[psycopg-w32]commands} [pygresql-w32] @@ -722,7 +722,7 @@ commands = {[pygresql-w32]commands} [testenv:py37-postgres-pygresql-w32] platform = win32 commands = - cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" + cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[pygresql-w32]commands} [pypostgresql-w32] @@ -754,7 +754,7 @@ commands = {[pypostgresql-w32]commands} [testenv:py37-postgres-pypostgresql-w32] platform = win32 commands = - cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" + cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[pypostgresql-w32]commands} [pg8000-w32] @@ -787,7 +787,7 @@ commands = {[pg8000-w32]commands} [testenv:py37-postgres-pg8000-w32] platform = win32 commands = - cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" + cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[pg8000-w32]commands} [postgres-pyodbc-w32] @@ -821,7 +821,7 @@ commands = {[postgres-pyodbc-w32]commands} [testenv:py37-postgres-pyodbc-noauto-w32] platform = win32 commands = - cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" + cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[postgres-pyodbc-w32]commands} [postgres-pypyodbc-w32] @@ -855,7 +855,7 @@ commands = {[postgres-pypyodbc-w32]commands} [testenv:py37-postgres-pypyodbc-noauto-w32] platform = win32 commands = - cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" + cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[postgres-pypyodbc-w32]commands} [sqlite-w32] @@ -885,7 +885,7 @@ commands = {[sqlite-w32]commands} [testenv:py37-sqlite-w32] platform = win32 commands = - cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" + cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[sqlite-w32]commands} [sqlite-memory-w32] @@ -915,5 +915,5 @@ commands = {[sqlite-memory-w32]commands} [testenv:py37-sqlite-memory-w32] platform = win32 commands = - cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" + cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[sqlite-memory-w32]commands} From e24b9ed78e3de8016e6f9aafdfa153aa08faa732 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 5 Sep 2019 18:32:17 +0300 Subject: [PATCH 230/509] Refactor: Remove excessive assignment --- sqlobject/main.py | 1 - 1 file changed, 1 deletion(-) diff --git a/sqlobject/main.py b/sqlobject/main.py index 5d9b537a..488b9924 100644 --- a/sqlobject/main.py +++ b/sqlobject/main.py @@ -1621,7 +1621,6 @@ def destroySelf(self): join.joinColumn, self.id) self._connection.query(q) - depends = [] depends = self._SO_depends() for k in depends: # Free related joins From 14d47233fb0d8e0eb4f39c17f0ffce3b907e2910 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 5 Sep 2019 19:14:27 +0300 Subject: [PATCH 231/509] Tests(ForeignKey_cascade): Add tests for cascade deletion --- docs/News.rst | 5 + sqlobject/tests/test_ForeignKey_cascade.py | 125 +++++++++++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 sqlobject/tests/test_ForeignKey_cascade.py diff --git a/docs/News.rst b/docs/News.rst index e57e68c0..a8f949df 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,11 @@ News SQLObject (master) ================== +Tests +----- + +* Add tests for cascade deletion. + CI -- diff --git a/sqlobject/tests/test_ForeignKey_cascade.py b/sqlobject/tests/test_ForeignKey_cascade.py new file mode 100644 index 00000000..d4a10612 --- /dev/null +++ b/sqlobject/tests/test_ForeignKey_cascade.py @@ -0,0 +1,125 @@ +from sqlobject import ForeignKey, SQLObject, StringCol, \ + SQLObjectIntegrityError, SQLObjectNotFound +from sqlobject.tests.dbtest import raises, setupClass + + +class SOTestPerson1(SQLObject): + name = StringCol() + + +class SOTestMessageCascadeTrue(SQLObject): + sender = ForeignKey('SOTestPerson1', cascade=True) + recipient = ForeignKey('SOTestPerson1', cascade=True) + body = StringCol() + + +def test1(): + setupClass([SOTestPerson1, SOTestMessageCascadeTrue]) + + john = SOTestPerson1(name='john') + emily = SOTestPerson1(name='emily') + message = SOTestMessageCascadeTrue( + sender=emily, recipient=john, body='test1' + ) + + SOTestPerson1.delete(emily.id) + john.expire() + message.expire() + + john.sync() + raises(SQLObjectNotFound, emily.sync) + raises(SQLObjectNotFound, message.sync) + + +class SOTestPerson2(SQLObject): + name = StringCol() + + +class SOTestMessageCascadeFalse(SQLObject): + sender = ForeignKey('SOTestPerson2', cascade=False) + recipient = ForeignKey('SOTestPerson2', cascade=False) + body = StringCol() + + +def test2(): + setupClass([SOTestPerson2, SOTestMessageCascadeFalse]) + + john = SOTestPerson2(name='john') + emily = SOTestPerson2(name='emily') + message = SOTestMessageCascadeFalse( + sender=emily, recipient=john, body='test2' + ) + + raises(SQLObjectIntegrityError, SOTestPerson2.delete, emily.id) + john.expire() + emily.expire() + message.expire() + + john.sync() + emily.sync() + message.sync() + + assert message.sender == emily + assert message.recipient == john + + +class SOTestPerson3(SQLObject): + name = StringCol() + + +class SOTestMessageCascadeNull(SQLObject): + sender = ForeignKey('SOTestPerson3', cascade='null') + recipient = ForeignKey('SOTestPerson3', cascade='null') + body = StringCol() + + +def test3(): + setupClass([SOTestPerson3, SOTestMessageCascadeNull]) + + john = SOTestPerson3(name='john') + emily = SOTestPerson3(name='emily') + message = SOTestMessageCascadeNull( + sender=emily, recipient=john, body='test3' + ) + + SOTestPerson3.delete(emily.id) + john.expire() + message.expire() + + john.sync() + message.sync() + raises(SQLObjectNotFound, emily.sync) + + assert message.recipient is None + + # This looks like a bug; `message.sender` here should be None + # assert message.sender is None + + +class SOTestPerson4(SQLObject): + name = StringCol() + + +class SOTestMessageCascadeMixed(SQLObject): + sender = ForeignKey('SOTestPerson4', cascade=True) + recipient = ForeignKey('SOTestPerson4', cascade='null') + body = StringCol() + + +def test4(): + setupClass([SOTestPerson4, SOTestMessageCascadeMixed]) + + john = SOTestPerson4(name='john') + emily = SOTestPerson4(name='emily') + message = SOTestMessageCascadeMixed( + sender=emily, recipient=john, body='test4' + ) + + SOTestPerson4.delete(emily.id) + john.expire() + message.expire() + + john.sync() + + # This is even a nastier bug; `message` was deleted from the DB + # message.sync() From b3d72cd4c4516bddf8bd39550ed8582cf7101eae Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 15 Sep 2019 17:47:31 +0300 Subject: [PATCH 232/509] Tests: Fix calls to `pytest.mark.skipif` Make conditions bool instead of str. --- docs/News.rst | 2 ++ sqlobject/tests/test_boundattributes.py | 4 +++- sqlobject/tests/test_paste.py | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index a8f949df..f1fcf89a 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -13,6 +13,8 @@ Tests * Add tests for cascade deletion. +* Fix calls to ``pytest.mark.skipif`` - make conditions bool instead of str. + CI -- diff --git a/sqlobject/tests/test_boundattributes.py b/sqlobject/tests/test_boundattributes.py index 5ae20152..1453658d 100644 --- a/sqlobject/tests/test_boundattributes.py +++ b/sqlobject/tests/test_boundattributes.py @@ -3,7 +3,9 @@ from sqlobject import boundattributes from sqlobject import declarative -pytestmark = pytest.mark.skipif('True') +pytestmark = pytest.mark.skipif( + True, + reason='The module "boundattributes" and its tests were not finished yet') class SOTestMe(object): diff --git a/sqlobject/tests/test_paste.py b/sqlobject/tests/test_paste.py index 36623093..5cd90298 100644 --- a/sqlobject/tests/test_paste.py +++ b/sqlobject/tests/test_paste.py @@ -5,7 +5,7 @@ try: from sqlobject.wsgi_middleware import make_middleware except ImportError: - pytestmark = pytest.mark.skipif('True') + pytestmark = pytest.mark.skipif(True, reason='These tests require Paste') from .dbtest import getConnection, getConnectionURI, setupClass From 477cff64f80a545db9346770e7cc4378c3413780 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 15 Sep 2019 17:54:31 +0300 Subject: [PATCH 233/509] Tests: Fix module-level calls to `pytest.mark.skip` Add reasons. --- docs/News.rst | 2 ++ sqlobject/tests/test_decimal.py | 2 +- sqlobject/tests/test_mysql.py | 2 +- sqlobject/tests/test_postgres.py | 2 +- sqlobject/tests/test_sqlite.py | 2 +- sqlobject/tests/test_transactions.py | 2 +- 6 files changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index f1fcf89a..a216624b 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -15,6 +15,8 @@ Tests * Fix calls to ``pytest.mark.skipif`` - make conditions bool instead of str. +* Fix module-level calls to ``pytest.mark.skip`` - add reasons. + CI -- diff --git a/sqlobject/tests/test_decimal.py b/sqlobject/tests/test_decimal.py index c7388e0d..06cd2fbe 100644 --- a/sqlobject/tests/test_decimal.py +++ b/sqlobject/tests/test_decimal.py @@ -16,7 +16,7 @@ pass else: if not support_decimal_column: - pytestmark = pytest.mark.skip('') + pytestmark = pytest.mark.skip("These tests require Decimal support") class DecimalTable(SQLObject): diff --git a/sqlobject/tests/test_mysql.py b/sqlobject/tests/test_mysql.py index de4b040b..3d7b9a68 100644 --- a/sqlobject/tests/test_mysql.py +++ b/sqlobject/tests/test_mysql.py @@ -10,7 +10,7 @@ pass else: if connection.dbName != "mysql": - pytestmark = pytest.mark.skip('') + pytestmark = pytest.mark.skip("These tests require MySQL") class SOTestSOListMySQL(SQLObject): diff --git a/sqlobject/tests/test_postgres.py b/sqlobject/tests/test_postgres.py index e656ce78..ab1f9692 100644 --- a/sqlobject/tests/test_postgres.py +++ b/sqlobject/tests/test_postgres.py @@ -16,7 +16,7 @@ pass else: if connection.dbName != "postgres": - pytestmark = pytest.mark.skip('') + pytestmark = pytest.mark.skip("These tests require PostgreSQL") class SOTestSSLMode(SQLObject): diff --git a/sqlobject/tests/test_sqlite.py b/sqlobject/tests/test_sqlite.py index 4e9611a8..5fb070b2 100644 --- a/sqlobject/tests/test_sqlite.py +++ b/sqlobject/tests/test_sqlite.py @@ -16,7 +16,7 @@ pass else: if connection.dbName != "sqlite": - pytestmark = pytest.mark.skip('') + pytestmark = pytest.mark.skip("These tests require SQLite") class SQLiteFactoryTest(SQLObject): diff --git a/sqlobject/tests/test_transactions.py b/sqlobject/tests/test_transactions.py index 56ce7f8e..ee66620b 100644 --- a/sqlobject/tests/test_transactions.py +++ b/sqlobject/tests/test_transactions.py @@ -16,7 +16,7 @@ pass else: if not support_transactions: - pytestmark = pytest.mark.skip('') + pytestmark = pytest.mark.skip("These tests require transactions") class SOTestSOTrans(SQLObject): From a26acf96a3322dedfaf2a2b36b5eaf3d313e0901 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 13 Sep 2019 04:16:10 +0300 Subject: [PATCH 234/509] Fix: Avoid excessive parentheses around `ALL/ANY/SOME()` --- docs/News.rst | 7 +++++++ sqlobject/sqlbuilder.py | 3 ++- sqlobject/tests/test_mysql.py | 16 +++++++++++++++- sqlobject/tests/test_postgres.py | 16 +++++++++++++++- sqlobject/tests/test_sqlbuilder.py | 17 +++++++++++++++-- 5 files changed, 54 insertions(+), 5 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index a216624b..3ca56b08 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,11 +8,18 @@ News SQLObject (master) ================== +Bug fixes +--------- + +* Avoid excessive parentheses around ``ALL/ANY/SOME()``. + Tests ----- * Add tests for cascade deletion. +* Add tests for ``sqlbuilder.ALL/ANY/SOME()``. + * Fix calls to ``pytest.mark.skipif`` - make conditions bool instead of str. * Fix module-level calls to ``pytest.mark.skip`` - add reasons. diff --git a/sqlobject/sqlbuilder.py b/sqlobject/sqlbuilder.py index cc6696b5..d6c2e619 100644 --- a/sqlobject/sqlbuilder.py +++ b/sqlobject/sqlbuilder.py @@ -308,7 +308,8 @@ def __sqlrepr__(self, db): s2 = sqlrepr(self.expr2, db) if s1[0] != '(' and s1 != 'NULL': s1 = '(' + s1 + ')' - if s2[0] != '(' and s2 != 'NULL': + if s2[0] != '(' and s2 != 'NULL' and \ + not isinstance(self.expr2, Subquery): s2 = '(' + s2 + ')' return "(%s %s %s)" % (s1, self.op, s2) diff --git a/sqlobject/tests/test_mysql.py b/sqlobject/tests/test_mysql.py index 3d7b9a68..5f41bd96 100644 --- a/sqlobject/tests/test_mysql.py +++ b/sqlobject/tests/test_mysql.py @@ -1,5 +1,6 @@ import pytest -from sqlobject import SQLObject +from sqlobject import SQLObject, IntCol +from sqlobject.sqlbuilder import Select, ANY from sqlobject.tests.dbtest import getConnection, setupClass @@ -24,3 +25,16 @@ def test_list_databases(): def test_list_tables(): setupClass(SOTestSOListMySQL) assert SOTestSOListMySQL.sqlmeta.table in connection.listTables() + + +class SOTestANY(SQLObject): + value = IntCol() + + +def test_ANY(): + setupClass(SOTestANY) + SOTestANY(value=10) + SOTestANY(value=20) + SOTestANY(value=30) + assert len(list(SOTestANY.select( + SOTestANY.q.value > ANY(Select([SOTestANY.q.value]))))) == 2 diff --git a/sqlobject/tests/test_postgres.py b/sqlobject/tests/test_postgres.py index ab1f9692..dbe62c04 100644 --- a/sqlobject/tests/test_postgres.py +++ b/sqlobject/tests/test_postgres.py @@ -1,6 +1,7 @@ import os import pytest -from sqlobject import SQLObject, StringCol +from sqlobject import SQLObject, StringCol, IntCol +from sqlobject.sqlbuilder import Select, SOME from sqlobject.tests.dbtest import getConnection, setupClass @@ -56,3 +57,16 @@ def test_list_databases(): def test_list_tables(): setupClass(SOTestSOList) assert SOTestSOList.sqlmeta.table in connection.listTables() + + +class SOTestSOME(SQLObject): + value = IntCol() + + +def test_SOME(): + setupClass(SOTestSOME) + SOTestSOME(value=10) + SOTestSOME(value=20) + SOTestSOME(value=30) + assert len(list(SOTestSOME.select( + SOTestSOME.q.value > SOME(Select([SOTestSOME.q.value]))))) == 2 diff --git a/sqlobject/tests/test_sqlbuilder.py b/sqlobject/tests/test_sqlbuilder.py index 1d2c8501..5b9d3b41 100644 --- a/sqlobject/tests/test_sqlbuilder.py +++ b/sqlobject/tests/test_sqlbuilder.py @@ -1,7 +1,7 @@ from sqlobject import IntCol, SQLObject, StringCol from sqlobject.compat import PY2 -from sqlobject.sqlbuilder import AND, CONCAT, Delete, Insert, SQLOp, Select, \ - Union, Update, const, func, sqlrepr +from sqlobject.sqlbuilder import AND, ANY, CONCAT, Delete, Insert, \ + SQLConstant, SQLOp, Select, Union, Update, const, func, sqlrepr from sqlobject.tests.dbtest import getConnection, raises, setupClass @@ -119,3 +119,16 @@ def test_CONCAT(): if not PY2 and not isinstance(result, str): result = result.decode('ascii') assert result == "test-suffix" + + +def test_ANY(): + setupClass(SOTestSQLBuilder) + + select = Select( + [SOTestSQLBuilder.q.name], + SQLConstant("'value'") == ANY(SOTestSQLBuilder.q.so_value), + ) + + assert sqlrepr(select, 'mysql') == \ + "SELECT so_test_sql_builder.name FROM so_test_sql_builder " \ + "WHERE (('value') = ANY (so_test_sql_builder.so_value))" From ff5a94f43b4e221e9ae5986eea824fb642d309c0 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 22 Sep 2019 03:47:42 +0300 Subject: [PATCH 235/509] Fix escape sequences `'\%'` -> `'\\%'` --- docs/News.rst | 2 ++ sqlobject/tests/test_converters.py | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index 3ca56b08..23c6f888 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -24,6 +24,8 @@ Tests * Fix module-level calls to ``pytest.mark.skip`` - add reasons. +* Fix escape sequences ``'\%'`` -> ``'\\%'``. + CI -- diff --git a/sqlobject/tests/test_converters.py b/sqlobject/tests/test_converters.py index 0468a75c..a064c69f 100644 --- a/sqlobject/tests/test_converters.py +++ b/sqlobject/tests/test_converters.py @@ -262,8 +262,8 @@ def test_timedelta(): def test_quote_unquote_str(): assert quote_str('test%', 'postgres') == "'test%'" assert quote_str('test%', 'sqlite') == "'test%'" - assert quote_str('test\%', 'postgres') == "E'test\\%'" - assert quote_str('test\\%', 'sqlite') == "'test\%'" + assert quote_str('test\\%', 'postgres') == "E'test\\%'" + assert quote_str('test\\%', 'sqlite') == "'test\\%'" assert unquote_str("'test%'") == 'test%' assert unquote_str("'test\\%'") == 'test\\%' assert unquote_str("E'test\\%'") == 'test\\%' From aa0af590862607300b0e4a695fcc6516d903a926 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 22 Sep 2019 03:50:35 +0300 Subject: [PATCH 236/509] Fix sqlite test under Python 3.7+ at AppVeyor --- docs/News.rst | 2 ++ sqlobject/tests/test_sqlite.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/News.rst b/docs/News.rst index 23c6f888..e8d7d991 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -32,6 +32,8 @@ CI * Reduce the number of virtual machines/containers: one OS, one DB, one python version, many drivers per VM. +* Fix sqlite test under Python 3.7+ at AppVeyor. + SQLObject 3.7.2 =============== diff --git a/sqlobject/tests/test_sqlite.py b/sqlobject/tests/test_sqlite.py index 5fb070b2..2ec1d422 100644 --- a/sqlobject/tests/test_sqlite.py +++ b/sqlobject/tests/test_sqlite.py @@ -140,7 +140,7 @@ def test_memorydb(): def test_list_databases(): - assert connection.listDatabases() == ['main'] + assert 'main' in connection.listDatabases() def test_list_tables(): From 6c54d9a0009d50a9859d2fa0b76103e2992a17de Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 22 Sep 2019 15:51:56 +0300 Subject: [PATCH 237/509] Docs(News): SQLObject 3.7.3 released 22 Sep 2019 --- docs/News.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/News.rst b/docs/News.rst index e8d7d991..d24ad0ac 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,11 @@ News SQLObject (master) ================== +SQLObject 3.7.3 +=============== + +Released 22 Sep 2019. + Bug fixes --------- From f31a1bc9c70cb0b1504b70d1dacd4ef18dc8cfb7 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 22 Sep 2019 15:59:34 +0300 Subject: [PATCH 238/509] Release 3.7.3 --- ANNOUNCE.rst | 41 +++++++++++++++++++++++++-------------- README.rst | 4 ++-- devscripts/build-all-docs | 2 +- sqlobject/__version__.py | 4 ++-- 4 files changed, 31 insertions(+), 20 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 5cb28861..67323a9d 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,26 +1,37 @@ Hello! -I'm pleased to announce version 3.8.0a1, the first alpha of the upcoming -release of branch 3.8 of SQLObject. +I'm pleased to announce version 3.7.3, a bugfix release of branch +3.7 of SQLObject. -I'm pleased to announce version 3.8.0a2, the second alpha of the upcoming -release of branch 3.8 of SQLObject. -I'm pleased to announce version 3.8.0b1, the first beta of the upcoming -release of branch 3.8 of SQLObject. +What's new in SQLObject +======================= -I'm pleased to announce version 3.8.0rc1, the first release candidate -of the upcoming release of branch 3.8 of SQLObject. +Bug fixes +--------- -I'm pleased to announce version 3.8.0, the first stable release of branch -3.8 of SQLObject. +* Avoid excessive parentheses around ``ALL/ANY/SOME()``. -I'm pleased to announce version 3.8.1, the first bugfix release of branch -3.8 of SQLObject. +Tests +----- +* Add tests for cascade deletion. -What's new in SQLObject -======================= +* Add tests for ``sqlbuilder.ALL/ANY/SOME()``. + +* Fix calls to ``pytest.mark.skipif`` - make conditions bool instead of str. + +* Fix module-level calls to ``pytest.mark.skip`` - add reasons. + +* Fix escape sequences ``'\%'`` -> ``'\\%'``. + +CI +-- + +* Reduce the number of virtual machines/containers: + one OS, one DB, one python version, many drivers per VM. + +* Fix sqlite test under Python 3.7+ at AppVeyor. Contributors for this release are @@ -54,7 +65,7 @@ Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Download: -https://pypi.org/project/SQLObject/3.8.0a0.dev20190501/ +https://pypi.org/project/SQLObject/3.7.3 News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 404d1650..4348085e 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.7.3a0 -================= +SQLObject 3.7.3 +=============== Thanks for looking at SQLObject. SQLObject is an object-relational mapper, i.e., a library that will wrap your database tables in Python diff --git a/devscripts/build-all-docs b/devscripts/build-all-docs index bcb5c7c7..65231745 100755 --- a/devscripts/build-all-docs +++ b/devscripts/build-all-docs @@ -10,7 +10,7 @@ cd "`dirname \"$0\"`" && PROG_DIR="`pwd`" && cd .. && -build_docs 3.7.2 && +build_docs 3.7.3 && build_docs master devel && rm -rf docs/html && diff --git a/sqlobject/__version__.py b/sqlobject/__version__.py index 52a80488..0d929919 100644 --- a/sqlobject/__version__.py +++ b/sqlobject/__version__.py @@ -1,8 +1,8 @@ -version = '3.7.2' +version = '3.7.3' major = 3 minor = 7 -micro = 2 +micro = 3 release_level = 'final' serial = 0 version_info = (major, minor, micro, release_level, serial) From d53e4f7d2110daa53c86c8c78e401f590da95a5a Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 22 Sep 2019 16:08:24 +0300 Subject: [PATCH 239/509] Prepare for the next release [skip ci] --- ANNOUNCE.rst | 41 +++++++++++++++-------------------------- README.rst | 4 ++-- 2 files changed, 17 insertions(+), 28 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 67323a9d..5cb28861 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,37 +1,26 @@ Hello! -I'm pleased to announce version 3.7.3, a bugfix release of branch -3.7 of SQLObject. +I'm pleased to announce version 3.8.0a1, the first alpha of the upcoming +release of branch 3.8 of SQLObject. +I'm pleased to announce version 3.8.0a2, the second alpha of the upcoming +release of branch 3.8 of SQLObject. -What's new in SQLObject -======================= - -Bug fixes ---------- - -* Avoid excessive parentheses around ``ALL/ANY/SOME()``. - -Tests ------ +I'm pleased to announce version 3.8.0b1, the first beta of the upcoming +release of branch 3.8 of SQLObject. -* Add tests for cascade deletion. +I'm pleased to announce version 3.8.0rc1, the first release candidate +of the upcoming release of branch 3.8 of SQLObject. -* Add tests for ``sqlbuilder.ALL/ANY/SOME()``. +I'm pleased to announce version 3.8.0, the first stable release of branch +3.8 of SQLObject. -* Fix calls to ``pytest.mark.skipif`` - make conditions bool instead of str. +I'm pleased to announce version 3.8.1, the first bugfix release of branch +3.8 of SQLObject. -* Fix module-level calls to ``pytest.mark.skip`` - add reasons. -* Fix escape sequences ``'\%'`` -> ``'\\%'``. - -CI --- - -* Reduce the number of virtual machines/containers: - one OS, one DB, one python version, many drivers per VM. - -* Fix sqlite test under Python 3.7+ at AppVeyor. +What's new in SQLObject +======================= Contributors for this release are @@ -65,7 +54,7 @@ Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Download: -https://pypi.org/project/SQLObject/3.7.3 +https://pypi.org/project/SQLObject/3.8.0a0.dev20190501/ News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 4348085e..9f09e511 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.7.3 -=============== +SQLObject 3.8.0a0 +================= Thanks for looking at SQLObject. SQLObject is an object-relational mapper, i.e., a library that will wrap your database tables in Python From 351ac9230a1cb13ebeeddae9ab6b7b8c1dda1191 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 28 Sep 2019 20:24:53 +0300 Subject: [PATCH 240/509] Fix a bug working with microseconds in `Time` columns --- docs/News.rst | 5 +++++ sqlobject/col.py | 6 +++++- sqlobject/mysql/mysqlconnection.py | 5 ----- sqlobject/tests/dbtest.py | 6 +----- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index d24ad0ac..abb141b2 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,11 @@ News SQLObject (master) ================== +Bug fixes +--------- + +* Fixed a bug working with microseconds in Time columns. + SQLObject 3.7.3 =============== diff --git a/sqlobject/col.py b/sqlobject/col.py index a22fb666..56752f40 100644 --- a/sqlobject/col.py +++ b/sqlobject/col.py @@ -1505,7 +1505,11 @@ def to_python(self, value, state): raise validators.Invalid( "the value for the TimeCol '%s' must has days=0, " "it has days=%d" % (self.name, value.days), value, state) - return datetime.time(*time.gmtime(value.seconds)[3:6]) + print("[DEBUG1]:", value.microseconds) + return datetime.time( + *time.gmtime(value.seconds)[3:6], + microsecond=value.microseconds + ) value = super(TimeValidator, self).to_python(value, state) if isinstance(value, datetime.datetime): value = value.time() diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index 2d7afa58..00cc3d65 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -1,5 +1,3 @@ -import os - from sqlobject import col, dberrors from sqlobject.compat import PY2 from sqlobject.dbconnection import DBAPI @@ -482,9 +480,6 @@ def server_version(self): def can_use_microseconds(self): if self._can_use_microseconds is not None: return self._can_use_microseconds - if os.environ.get('APPVEYOR') or os.environ.get('TRAVIS'): - self._can_use_microseconds = False - return False server_version = self.server_version() if server_version is None: return None diff --git a/sqlobject/tests/dbtest.py b/sqlobject/tests/dbtest.py index 6c0c8463..c7c8b0ea 100644 --- a/sqlobject/tests/dbtest.py +++ b/sqlobject/tests/dbtest.py @@ -120,11 +120,7 @@ def getConnectionURI(): if 'sphinx' not in sys.modules: print("Could not open database: %s" % e, file=sys.stderr) else: - if (connection.dbName == 'firebird') \ - or ( - (connection.dbName == 'mysql') - and ((os.environ.get('APPVEYOR')) or (os.environ.get('TRAVIS'))) - ): + if (connection.dbName == 'firebird'): use_microseconds(False) From 701fb3c7268fc96ab54c243feed58a4f7614403c Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 28 Sep 2019 20:25:23 +0300 Subject: [PATCH 241/509] Tests: Allow to run `flake8` under any Python version --- tox.ini | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tox.ini b/tox.ini index 899295c8..fb7ab87f 100644 --- a/tox.ini +++ b/tox.ini @@ -483,6 +483,30 @@ commands = {[testenv]commands} flake8 . +[testenv:py34-flake8] +changedir = ./ +deps = + flake8 +commands = + {[testenv]commands} + flake8 . + +[testenv:py35-flake8] +changedir = ./ +deps = + flake8 +commands = + {[testenv]commands} + flake8 . + +[testenv:py36-flake8] +changedir = ./ +deps = + flake8 +commands = + {[testenv]commands} + flake8 . + [testenv:py37-flake8] changedir = ./ deps = From f9822e7a2ad3558402dec8a552107b7328da938a Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 28 Sep 2019 20:31:39 +0300 Subject: [PATCH 242/509] Feat(sqlite): Add driver `supersqlite` --- docs/News.rst | 6 ++++++ docs/SQLObject.rst | 21 +++++++++++---------- docs/download.rst | 7 ++++++- setup.py | 1 + sqlobject/sqlite/sqliteconnection.py | 11 ++++++++--- tox.ini | 26 ++++++++++++++++++++++++++ 6 files changed, 58 insertions(+), 14 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index abb141b2..d795a697 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,12 @@ News SQLObject (master) ================== +Features +-------- + +* Add driver ``supersqlite``. Not all tests are passing + so the driver isn't added to the list of default drivers. + Bug fixes --------- diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index 46d820ee..9504c1a2 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -48,14 +48,14 @@ Requirements Currently SQLObject supports MySQL_ via MySQLdb_ aka MySQL-python (called mysqlclient_ for Python 3), `MySQL Connector`_, oursql_, PyMySQL_, PyODBC_ -and PyPyODBC_. For PostgreSQL_ psycopg2_ is recommended; -PyGreSQL_, py-postgresql_ and pg8000_ are supported; SQLite_ has a -built-in driver or PySQLite_. Firebird_ is supported via fdb_ or -kinterbasdb_; pyfirebirdsql_ is supported but has problems. `MAX DB`_ -(also known as SAP DB) is supported via sapdb_. Sybase via Sybase_. `MSSQL -Server`_ via pymssql_ (+ FreeTDS_) or adodbapi_ (Win32). PyODBC_ and -PyPyODBC_ are supported for MySQL, PostgreSQL and MSSQL but have -problems (not all tests passed). +and PyPyODBC_. For PostgreSQL_ psycopg2_ is recommended; PyGreSQL_, +py-postgresql_ and pg8000_ are supported; SQLite_ has a built-in driver, +PySQLite_ or supersqlite_. Firebird_ is supported via fdb_ or kinterbasdb_; +pyfirebirdsql_ is supported but has problems. `MAX DB`_ (also known as SAP +DB) is supported via sapdb_. Sybase via Sybase_. `MSSQL Server`_ via +pymssql_ (+ FreeTDS_) or adodbapi_ (Win32). PyODBC_ and PyPyODBC_ are +supported for MySQL, PostgreSQL and MSSQL but have problems (not all tests +passed). .. _MySQL: https://www.mysql.com/ .. _MySQLdb: https://sourceforge.net/projects/mysql-python/ @@ -70,6 +70,7 @@ problems (not all tests passed). .. _pg8000: https://pypi.org/project/pg8000/ .. _SQLite: https://sqlite.org/ .. _PySQLite: https://github.com/ghaering/pysqlite +.. _supersqlite: https://github.com/plasticityai/supersqlite .. _Firebird: http://www.firebirdsql.org/en/python-driver/ .. _fdb: http://www.firebirdsql.org/en/devel-python-driver/ .. _kinterbasdb: http://kinterbasdb.sourceforge.net/ @@ -1857,8 +1858,8 @@ multi-threaded environment. The user can choose a DB API driver for SQLite by using a ``driver`` parameter in DB URI or SQLiteConnection that can be a comma-separated list of driver names. Possible drivers are: ``pysqlite2`` (alias ``sqlite2``), -``sqlite3``, ``sqlite`` (alias ``sqlite1``). Default is to test pysqlite2, -sqlite3 and sqlite in that order. +``sqlite3``, ``sqlite`` (alias ``sqlite1``), ``supersqlite``. Default is to +test supersqlite, pysqlite2, sqlite3 and sqlite in that order. Connection-specific parameters are: ``encoding``, ``mode``, ``timeout``, ``check_same_thread``, ``use_table_info``. diff --git a/docs/download.rst b/docs/download.rst index 1d9e5467..0126343b 100644 --- a/docs/download.rst +++ b/docs/download.rst @@ -76,10 +76,15 @@ PostgreSQL psycopg2 psycopg postgres postgresql (synonyms for psycopg2) pygresql pypostgresql py-postgresql pg8000 +SQLite +^^^^^^ + +sqlite pysqlite supersqlite + The rest ^^^^^^^^ -sapdb sqlite (pysqlite) sybase +sapdb sybase Repositories ------------ diff --git a/setup.py b/setup.py index ca58f2eb..0af8a294 100755 --- a/setup.py +++ b/setup.py @@ -131,6 +131,7 @@ # 'sapdb': ['sapdb'], 'sqlite': ['pysqlite'], + 'supersqlite': ['supersqlite'], 'sybase': ['Sybase'], }, ) diff --git a/sqlobject/sqlite/sqliteconnection.py b/sqlobject/sqlite/sqliteconnection.py index 024b01c6..06cf3c43 100644 --- a/sqlobject/sqlite/sqliteconnection.py +++ b/sqlobject/sqlite/sqliteconnection.py @@ -32,13 +32,17 @@ class SQLiteConnection(DBAPI): schemes = [dbName] def __init__(self, filename, autoCommit=1, **kw): - drivers = kw.pop('driver', None) or 'pysqlite2,sqlite3,sqlite' + drivers = kw.pop('driver', None) or \ + 'supersqlite,pysqlite2,sqlite3,sqlite' for driver in drivers.split(','): driver = driver.strip() if not driver: continue try: - if driver in ('sqlite2', 'pysqlite2'): + if driver == 'supersqlite': + from supersqlite import sqlite3 as sqlite + self.using_sqlite2 = True + elif driver in ('sqlite2', 'pysqlite2'): from pysqlite2 import dbapi2 as sqlite self.using_sqlite2 = True elif driver == 'sqlite3': @@ -50,7 +54,8 @@ def __init__(self, filename, autoCommit=1, **kw): else: raise ValueError( 'Unknown SQLite driver "%s", ' - 'expected pysqlite2, sqlite3 or sqlite' % driver) + 'expected supersqlite, pysqlite2, sqlite3 ' + 'or sqlite' % driver) except ImportError: pass else: diff --git a/tox.ini b/tox.ini index fb7ab87f..65b21476 100644 --- a/tox.ini +++ b/tox.ini @@ -29,6 +29,7 @@ deps = postgres-pg8000: git+https://github.com/sqlobject/pg8000.git@getuser#egg=pg8000 pyodbc: pyodbc pypyodbc: pypyodbc + supersqlite: supersqlite firebird-fdb: fdb firebirdsql: firebirdsql passenv = CI TRAVIS TRAVIS_* APPVEYOR DISTUTILS_USE_SDK MSSdk INCLUDE LIB PGPASSWORD WINDIR @@ -423,6 +424,31 @@ commands = {[sqlite-memory]commands} [testenv:py37-sqlite-memory] commands = {[sqlite-memory]commands} +[sqlite-supersqlite] +commands = + {[testenv]commands} + -rm -f /tmp/sqlobject_test.sqdb + -pytest --cov=sqlobject -D sqlite:///tmp/sqlobject_test.sqdb?driver=supersqlite&debug=1 + rm -f /tmp/sqlobject_test.sqdb + +[testenv:py27-sqlite-supersqlite] +commands = + easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base + {[sqlite-supersqlite]commands} + +[testenv:py34-sqlite-supersqlite] +commands = {[sqlite-supersqlite]commands} + +[testenv:py35-sqlite-supersqlite] +commands = {[sqlite-supersqlite]commands} + +[testenv:py36-sqlite-supersqlite] +commands = {[sqlite-supersqlite]commands} + +[testenv:py37-sqlite-supersqlite] +commands = {[sqlite-supersqlite]commands} + + # Firebird database test environments [fdb] commands = From 852bded59e5c7da4e118d6b54c1097f8a32fcf67 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 29 Sep 2019 19:00:52 +0300 Subject: [PATCH 243/509] Fix a bug in cascade deletion/nullification --- docs/News.rst | 2 + sqlobject/col.py | 9 ++++- sqlobject/main.py | 47 +++++++++++++--------- sqlobject/tests/test_ForeignKey_cascade.py | 35 +++++++++++++--- 4 files changed, 67 insertions(+), 26 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index d795a697..5b63bba6 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -17,6 +17,8 @@ Features Bug fixes --------- +* Fixed a bug in cascade deletion/nullification. + * Fixed a bug working with microseconds in Time columns. SQLObject 3.7.3 diff --git a/sqlobject/col.py b/sqlobject/col.py index 56752f40..be8571cd 100644 --- a/sqlobject/col.py +++ b/sqlobject/col.py @@ -170,8 +170,13 @@ def __init__(self, # True: a CASCADE constraint is generated # False: a RESTRICT constraint is generated # 'null': a SET NULL trigger is generated - if isinstance(cascade, str): - assert cascade == 'null', ( + if not isinstance(cascade, (bool, string_type, type(None))): + raise TypeError( + 'Expected cascade to be True, False, None or "null", ' + "(you gave: %r %r)" % (type(cascade), cascade) + ) + if isinstance(cascade, str) and (cascade != 'null'): + raise ValueError( "The only string value allowed for cascade is 'null' " "(you gave: %r)" % cascade) self.cascade = cascade diff --git a/sqlobject/main.py b/sqlobject/main.py index 488b9924..827db2cd 100644 --- a/sqlobject/main.py +++ b/sqlobject/main.py @@ -1639,36 +1639,45 @@ def destroySelf(self): continue query = [] - delete = setnull = restrict = False + restrict = False for _col in cols: + query.append(getattr(k.q, _col.name) == self.id) if _col.cascade is False: # Found a restriction restrict = True - query.append(getattr(k.q, _col.name) == self.id) + query = sqlbuilder.OR(*query) + results = k.select(query, connection=self._connection) + if restrict and results.count(): + # Restrictions only apply if there are + # matching records on the related table + raise SQLObjectIntegrityError( + "Tried to delete %s::%s but " + "table %s has a restriction against it" % + (klass.__name__, self.id, k.__name__)) + + setnull = {} + for _col in cols: if _col.cascade == 'null': - setnull = _col.name - elif _col.cascade: + setnull[_col.name] = None + if setnull: + for row in results: + clear = {} + for name in setnull: + if getattr(row, name) == self.id: + clear[name] = None + row.set(**clear) + + delete = False + for _col in cols: + if _col.cascade is True: delete = True assert delete or setnull or restrict, ( "Class %s depends on %s accoriding to " "findDependantColumns, but this seems inaccurate" % (k, klass)) - query = sqlbuilder.OR(*query) - results = k.select(query, connection=self._connection) - if restrict: - if results.count(): - # Restrictions only apply if there are - # matching records on the related table - raise SQLObjectIntegrityError( - "Tried to delete %s::%s but " - "table %s has a restriction against it" % - (klass.__name__, self.id, k.__name__)) - else: + if delete: for row in results: - if delete: - row.destroySelf() - else: - row.set(**{setnull: None}) + row.destroySelf() self.sqlmeta._obsolete = True self._connection._SO_delete(self) diff --git a/sqlobject/tests/test_ForeignKey_cascade.py b/sqlobject/tests/test_ForeignKey_cascade.py index d4a10612..e8942b58 100644 --- a/sqlobject/tests/test_ForeignKey_cascade.py +++ b/sqlobject/tests/test_ForeignKey_cascade.py @@ -90,10 +90,17 @@ def test3(): message.sync() raises(SQLObjectNotFound, emily.sync) - assert message.recipient is None + assert message.sender is None + assert message.recipient == john - # This looks like a bug; `message.sender` here should be None - # assert message.sender is None + SOTestPerson3.delete(john.id) + john.expire() + message.expire() + + message.sync() + raises(SQLObjectNotFound, john.sync) + + assert message.recipient is None class SOTestPerson4(SQLObject): @@ -120,6 +127,24 @@ def test4(): message.expire() john.sync() + raises(SQLObjectNotFound, message.sync) + - # This is even a nastier bug; `message` was deleted from the DB - # message.sync() +def test5(): + setupClass([SOTestPerson4, SOTestMessageCascadeMixed]) + + john = SOTestPerson4(name='john') + emily = SOTestPerson4(name='emily') + message = SOTestMessageCascadeMixed( + sender=emily, recipient=john, body='test5' + ) + + john.destroySelf() + emily.expire() + message.expire() + + emily.sync() + message.sync() + + assert message.recipient is None + assert message.sender == emily From 596704cd6be8970c26b200df32cfa335c0d2bf50 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 30 Sep 2019 23:00:22 +0300 Subject: [PATCH 244/509] Feat(sqlbuilder): Improve sqlrepr'ing `ALL/ANY/SOME()` --- docs/News.rst | 6 ++++++ sqlobject/sqlbuilder.py | 2 ++ sqlobject/tests/test_sqlbuilder.py | 4 ++-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index 5b63bba6..425aa1af 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -14,6 +14,12 @@ Features * Add driver ``supersqlite``. Not all tests are passing so the driver isn't added to the list of default drivers. +Minor features +-------------- + +* Improve sqlrepr'ing ``ALL/ANY/SOME()``: always put the expression + at the right side of the comparison operation. + Bug fixes --------- diff --git a/sqlobject/sqlbuilder.py b/sqlobject/sqlbuilder.py index d6c2e619..844ab9ea 100644 --- a/sqlobject/sqlbuilder.py +++ b/sqlobject/sqlbuilder.py @@ -300,6 +300,8 @@ def tablesUsedSet(obj, db): class SQLOp(SQLExpression): def __init__(self, op, expr1, expr2): self.op = op.upper() + if isinstance(expr1, Subquery): + expr1, expr2 = expr2, expr1 self.expr1 = expr1 self.expr2 = expr2 diff --git a/sqlobject/tests/test_sqlbuilder.py b/sqlobject/tests/test_sqlbuilder.py index 5b9d3b41..1b198fc2 100644 --- a/sqlobject/tests/test_sqlbuilder.py +++ b/sqlobject/tests/test_sqlbuilder.py @@ -1,7 +1,7 @@ from sqlobject import IntCol, SQLObject, StringCol from sqlobject.compat import PY2 from sqlobject.sqlbuilder import AND, ANY, CONCAT, Delete, Insert, \ - SQLConstant, SQLOp, Select, Union, Update, const, func, sqlrepr + SQLOp, Select, Union, Update, const, func, sqlrepr from sqlobject.tests.dbtest import getConnection, raises, setupClass @@ -126,7 +126,7 @@ def test_ANY(): select = Select( [SOTestSQLBuilder.q.name], - SQLConstant("'value'") == ANY(SOTestSQLBuilder.q.so_value), + 'value' == ANY(SOTestSQLBuilder.q.so_value), ) assert sqlrepr(select, 'mysql') == \ From cdf61fad45dc594f28ebb2b56ae0adc931f615f1 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 1 Nov 2019 17:51:52 +0300 Subject: [PATCH 245/509] CI: Run tests with Python 3.8 at Travis CI Add Python 3.8 to `setup.py` and `devscripts/setup`. --- .travis.yml | 13 +++++- devscripts/setup | 2 +- docs/News.rst | 5 ++ setup.py | 1 + tox.ini | 118 ++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 135 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8fe81bad..a674f2d7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,6 +32,9 @@ matrix: - python: "3.7" dist: xenial env: TESTS=py37-mysql + - python: "3.8" + dist: xenial + env: TESTS=py38-mysql - python: "2.7" env: TESTS=py27-postgres - python: "3.4" @@ -43,6 +46,9 @@ matrix: - python: "3.7" dist: xenial env: TESTS=py37-postgres + - python: "3.8" + dist: xenial + env: TESTS=py38-postgres - python: "2.7" env: TESTS=py27-sqlite - python: "3.4" @@ -54,11 +60,14 @@ matrix: - python: "3.7" dist: xenial env: TESTS=py37-sqlite + - python: "3.8" + dist: xenial + env: TESTS=py38-sqlite - python: "2.7" env: TESTS=py27-flake8 - - python: "3.7" + - python: "3.8" dist: xenial - env: TESTS=py37-flake8 + env: TESTS=py38-flake8 - python: "2.7" env: TESTS=py27-firebird - python: "3.6" diff --git a/devscripts/setup b/devscripts/setup index 04ed1b78..3c12824d 100755 --- a/devscripts/setup +++ b/devscripts/setup @@ -3,7 +3,7 @@ umask 022 # -rwxr-xr-x cd "`dirname \"$0\"`"/.. && -for py_ver in 2.7 3.4 3.5 3.6 3.7; do +for py_ver in 2.7 3.4 3.5 3.6 3.7 3.8; do python$py_ver -m pip install --install-option=-O2 --upgrade . done && diff --git a/docs/News.rst b/docs/News.rst index 425aa1af..24ad6612 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -27,6 +27,11 @@ Bug fixes * Fixed a bug working with microseconds in Time columns. +CI +-- + +* Run tests with Python 3.8 at Travis CI. + SQLObject 3.7.3 =============== diff --git a/setup.py b/setup.py index 0af8a294..d85791d3 100755 --- a/setup.py +++ b/setup.py @@ -59,6 +59,7 @@ "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", "Topic :: Database", "Topic :: Database :: Front-Ends", "Topic :: Software Development :: Libraries :: Python Modules", diff --git a/tox.ini b/tox.ini index 65b21476..9be1d8bc 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 2.0 -envlist = py{27,34,35,36,37}-sqlite{,-memory},py{27,37}-flake8 +envlist = py{27,34,35,36,37,38}-sqlite{,-memory},py{27,38}-flake8 # Base test environment settings [testenv] @@ -12,6 +12,7 @@ basepython = py35: {env:TOXPYTHON:python3.5} py36: {env:TOXPYTHON:python3.6} py37: {env:TOXPYTHON:python3.7} + py38: {env:TOXPYTHON:python3.8} commands = {envpython} --version {envpython} -c "import struct; print(struct.calcsize('P') * 8)" @@ -75,6 +76,10 @@ deps = commands = {envpython} -c "print('MySQL-python requires Python 2.7')" deps = +[testenv:py38-mysqldb] +commands = {envpython} -c "print('MySQL-python requires Python 2.7')" +deps = + [mysqlclient] commands = {[testenv]commands} @@ -99,6 +104,9 @@ commands = {[mysqlclient]commands} [testenv:py37-mysqlclient] commands = {[mysqlclient]commands} +[testenv:py38-mysqlclient] +commands = {[mysqlclient]commands} + [mysql-connector] commands = {[testenv]commands} @@ -124,6 +132,9 @@ commands = {[mysql-connector]commands} [testenv:py37-mysql-connector] commands = {[mysql-connector]commands} +[testenv:py38-mysql-connector] +commands = {[mysql-connector]commands} + [oursql] commands = {[testenv]commands} @@ -149,6 +160,9 @@ commands = {[oursql]commands} [testenv:py37-mysql-oursql3] commands = {[oursql]commands} +[testenv:py38-mysql-oursql3] +commands = {[oursql]commands} + [pymysql] commands = {[testenv]commands} @@ -174,6 +188,9 @@ commands = {[pymysql]commands} [testenv:py37-mysql-pymysql] commands = {[pymysql]commands} +[testenv:py38-mysql-pymysql] +commands = {[pymysql]commands} + [mysql-pyodbc] commands = {[testenv]commands} @@ -200,6 +217,9 @@ commands = {[mysql-pyodbc]commands} [testenv:py37-mysql-pyodbc-noauto] commands = {[mysql-pyodbc]commands} +[testenv:py38-mysql-pyodbc-noauto] +commands = {[mysql-pyodbc]commands} + [mysql-pypyodbc] commands = {[testenv]commands} @@ -225,6 +245,9 @@ commands = {[mysql-pypyodbc]commands} [testenv:py37-mysql-pypyodbc-noauto] commands = {[mysql-pypyodbc]commands} +[testenv:py38-mysql-pypyodbc-noauto] +commands = {[mysql-pypyodbc]commands} + # PostgreSQL test environments [psycopg] commands = @@ -251,6 +274,9 @@ commands = {[psycopg]commands} [testenv:py37-postgres-psycopg] commands = {[psycopg]commands} +[testenv:py38-postgres-psycopg] +commands = {[psycopg]commands} + [pygresql] commands = {[testenv]commands} @@ -276,6 +302,9 @@ commands = {[pygresql]commands} [testenv:py37-postgres-pygresql] commands = {[pygresql]commands} +[testenv:py38-postgres-pygresql] +commands = {[pygresql]commands} + [pypostgresql] commands = {[testenv]commands} @@ -300,6 +329,9 @@ commands = {[pypostgresql]commands} [testenv:py37-postgres-pypostgresql] commands = {[pypostgresql]commands} +[testenv:py38-postgres-pypostgresql] +commands = {[pypostgresql]commands} + [pg8000] commands = {[testenv]commands} @@ -325,6 +357,9 @@ commands = {[pg8000]commands} [testenv:py37-postgres-pg8000] commands = {[pg8000]commands} +[testenv:py38-postgres-pg8000] +commands = {[pg8000]commands} + [postgres-pyodbc] commands = {[testenv]commands} @@ -351,6 +386,9 @@ commands = {[postgres-pyodbc]commands} [testenv:py37-postgres-pyodbc-noauto] commands = {[postgres-pyodbc]commands} +[testenv:py38-postgres-pyodbc-noauto] +commands = {[postgres-pyodbc]commands} + [postgres-pypyodbc] commands = {[testenv]commands} @@ -376,6 +414,9 @@ commands = {[postgres-pypyodbc]commands} [testenv:py37-postgres-pypyodbc-noauto] commands = {[postgres-pypyodbc]commands} +[testenv:py38-postgres-pypyodbc-noauto] +commands = {[postgres-pypyodbc]commands} + # SQLite test environments [sqlite] @@ -402,6 +443,9 @@ commands = {[sqlite]commands} [testenv:py37-sqlite] commands = {[sqlite]commands} +[testenv:py38-sqlite] +commands = {[sqlite]commands} + [sqlite-memory] commands = {[testenv]commands} @@ -424,6 +468,9 @@ commands = {[sqlite-memory]commands} [testenv:py37-sqlite-memory] commands = {[sqlite-memory]commands} +[testenv:py38-sqlite-memory] +commands = {[sqlite-memory]commands} + [sqlite-supersqlite] commands = {[testenv]commands} @@ -448,6 +495,9 @@ commands = {[sqlite-supersqlite]commands} [testenv:py37-sqlite-supersqlite] commands = {[sqlite-supersqlite]commands} +[testenv:py38-sqlite-supersqlite] +commands = {[sqlite-supersqlite]commands} + # Firebird database test environments [fdb] @@ -475,6 +525,9 @@ commands = {[fdb]commands} [testenv:py37-firebird-fdb] commands = {[fdb]commands} +[testenv:py38-firebird-fdb] +commands = {[fdb]commands} + [firebirdsql] commands = {[testenv]commands} @@ -500,6 +553,9 @@ commands = {[firebirdsql]commands} [testenv:py37-firebirdsql] commands = {[firebirdsql]commands} +[testenv:py38-firebirdsql] +commands = {[firebirdsql]commands} + # Special test environments [testenv:py27-flake8] changedir = ./ @@ -541,6 +597,14 @@ commands = {[testenv]commands} flake8 . +[testenv:py38-flake8] +changedir = ./ +deps = + flake8 +commands = + {[testenv]commands} + flake8 . + # Windows testing [mssql-pyodbc-w32] platform = win32 @@ -575,6 +639,10 @@ commands = cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[mssql-pyodbc-w32]commands} +[testenv:py38-mssql-pyodbc-noauto-w32] +platform = win32 +commands = {[mssql-pyodbc-w32]commands} + [mysql-connector-w32] platform = win32 commands = @@ -608,6 +676,10 @@ commands = cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[mysql-connector-w32]commands} +[testenv:py38-mysql-connector-w32] +platform = win32 +commands = {[mysql-connector-w32]commands} + [pymysql-w32] platform = win32 commands = @@ -641,6 +713,10 @@ commands = cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[pymysql-w32]commands} +[testenv:py38-mysql-pymysql-w32] +platform = win32 +commands = {[pymysql-w32]commands} + [mysql-pyodbc-w32] platform = win32 commands = @@ -675,6 +751,10 @@ commands = cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[mysql-pyodbc-w32]commands} +[testenv:py38-mysql-pyodbc-noauto-w32] +platform = win32 +commands = {[mysql-pyodbc-w32]commands} + [mysql-pypyodbc-w32] platform = win32 commands = @@ -709,6 +789,10 @@ commands = cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[mysql-pypyodbc-w32]commands} +[testenv:py38-mysql-pypyodbc-noauto-w32] +platform = win32 +commands = {[mysql-pypyodbc-w32]commands} + [psycopg-w32] platform = win32 commands = @@ -742,6 +826,10 @@ commands = cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[psycopg-w32]commands} +[testenv:py38-postgres-psycopg-w32] +platform = win32 +commands = {[psycopg-w32]commands} + [pygresql-w32] platform = win32 commands = @@ -775,6 +863,10 @@ commands = cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[pygresql-w32]commands} +[testenv:py38-postgres-pygresql-w32] +platform = win32 +commands = {[pygresql-w32]commands} + [pypostgresql-w32] platform = win32 commands = @@ -807,6 +899,10 @@ commands = cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[pypostgresql-w32]commands} +[testenv:py38-postgres-pypostgresql-w32] +platform = win32 +commands = {[pypostgresql-w32]commands} + [pg8000-w32] platform = win32 commands = @@ -840,6 +936,10 @@ commands = cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[pg8000-w32]commands} +[testenv:py38-postgres-pg8000-w32] +platform = win32 +commands = {[pg8000-w32]commands} + [postgres-pyodbc-w32] platform = win32 commands = @@ -874,6 +974,10 @@ commands = cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[postgres-pyodbc-w32]commands} +[testenv:py38-postgres-pyodbc-noauto-w32] +platform = win32 +commands = {[postgres-pyodbc-w32]commands} + [postgres-pypyodbc-w32] platform = win32 commands = @@ -908,6 +1012,10 @@ commands = cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[postgres-pypyodbc-w32]commands} +[testenv:py38-postgres-pypyodbc-noauto-w32] +platform = win32 +commands = {[postgres-pypyodbc-w32]commands} + [sqlite-w32] platform = win32 commands = @@ -938,6 +1046,10 @@ commands = cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[sqlite-w32]commands} +[testenv:py38-sqlite-w32] +platform = win32 +commands = {[sqlite-w32]commands} + [sqlite-memory-w32] platform = win32 commands = @@ -967,3 +1079,7 @@ platform = win32 commands = cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[sqlite-memory-w32]commands} + +[testenv:py38-sqlite-memory-w32] +platform = win32 +commands = {[sqlite-memory-w32]commands} From 83fd61d2d8ef1231291fee1aa650af6f58098342 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 14 Nov 2019 20:23:05 +0300 Subject: [PATCH 246/509] Fix(postgres): Fix a bug in `PostgresConnection.columnsFromSchema` PostgreSQL 12 removed outdated catalog attribute `pg_catalog.pg_attrdef.adsrc`. --- docs/News.rst | 4 ++++ sqlobject/postgres/pgconnection.py | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/News.rst b/docs/News.rst index 24ad6612..a68b7395 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -25,6 +25,10 @@ Bug fixes * Fixed a bug in cascade deletion/nullification. +* Fixed a bug in ``PostgresConnection.columnsFromSchema``: + PostgreSQL 12 removed outdated catalog attribute + ``pg_catalog.pg_attrdef.adsrc``. + * Fixed a bug working with microseconds in Time columns. CI diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index afe81333..85a50945 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -353,7 +353,8 @@ def columnsFromSchema(self, tableName, soClass): colQuery = """ SELECT a.attname, pg_catalog.format_type(a.atttypid, a.atttypmod), a.attnotnull, - (SELECT substring(d.adsrc for 128) FROM pg_catalog.pg_attrdef d + (SELECT substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid) for 128) + FROM pg_catalog.pg_attrdef d WHERE d.adrelid=a.attrelid AND d.adnum = a.attnum) FROM pg_catalog.pg_attribute a WHERE a.attrelid =%s::regclass From 0e6ca33cc343ac7910bee9c34a0a33d0d9d3a192 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 21 Nov 2019 15:43:25 +0300 Subject: [PATCH 247/509] Tests(tox-select-envs.cmd): Exit the batch with an error [skip ci] --- devscripts/tox-select-envs.cmd | 1 + 1 file changed, 1 insertion(+) diff --git a/devscripts/tox-select-envs.cmd b/devscripts/tox-select-envs.cmd index 03d8b4e1..1aa15195 100644 --- a/devscripts/tox-select-envs.cmd +++ b/devscripts/tox-select-envs.cmd @@ -15,4 +15,5 @@ if not "%envs%"=="" ( tox -e "%envs%" %* ) else ( echo "No environments match %pattern%" >&2 + exit /b 1 ) From b0b1c9c3610f9b52ea80c815a93cf49241081497 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 7 Dec 2019 20:27:56 +0300 Subject: [PATCH 248/509] Release 3.8.0 --- ANNOUNCE.rst | 45 +++++++++++++++++++++++++-------------- README.rst | 4 ++-- devscripts/build-all-docs | 2 +- docs/News.rst | 6 ++++-- sqlobject/__version__.py | 6 +++--- 5 files changed, 39 insertions(+), 24 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 5cb28861..fe822ef1 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,28 +1,41 @@ Hello! -I'm pleased to announce version 3.8.0a1, the first alpha of the upcoming -release of branch 3.8 of SQLObject. +I'm pleased to announce version 3.8.0, the first stable release of branch +3.8 of SQLObject. -I'm pleased to announce version 3.8.0a2, the second alpha of the upcoming -release of branch 3.8 of SQLObject. -I'm pleased to announce version 3.8.0b1, the first beta of the upcoming -release of branch 3.8 of SQLObject. +What's new in SQLObject +======================= -I'm pleased to announce version 3.8.0rc1, the first release candidate -of the upcoming release of branch 3.8 of SQLObject. +Features +-------- -I'm pleased to announce version 3.8.0, the first stable release of branch -3.8 of SQLObject. +* Add driver ``supersqlite``. Not all tests are passing + so the driver isn't added to the list of default drivers. -I'm pleased to announce version 3.8.1, the first bugfix release of branch -3.8 of SQLObject. +Minor features +-------------- +* Improve sqlrepr'ing ``ALL/ANY/SOME()``: always put the expression + at the right side of the comparison operation. -What's new in SQLObject -======================= +Bug fixes +--------- + +* Fixed a bug in cascade deletion/nullification. + +* Fixed a bug in ``PostgresConnection.columnsFromSchema``: + PostgreSQL 12 removed outdated catalog attribute + ``pg_catalog.pg_attrdef.adsrc``. + +* Fixed a bug working with microseconds in Time columns. + +CI +-- + +* Run tests with Python 3.8 at Travis CI. -Contributors for this release are +Contributors for this release are Andrew Trusty, Marco Sirabella and darix. For a more complete list, please see the news: http://sqlobject.org/News.html @@ -54,7 +67,7 @@ Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Download: -https://pypi.org/project/SQLObject/3.8.0a0.dev20190501/ +https://pypi.org/project/SQLObject/3.8.0 News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 9f09e511..92962cf6 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.8.0a0 -================= +SQLObject 3.8.0 +=============== Thanks for looking at SQLObject. SQLObject is an object-relational mapper, i.e., a library that will wrap your database tables in Python diff --git a/devscripts/build-all-docs b/devscripts/build-all-docs index 65231745..349c6ed8 100755 --- a/devscripts/build-all-docs +++ b/devscripts/build-all-docs @@ -10,7 +10,7 @@ cd "`dirname \"$0\"`" && PROG_DIR="`pwd`" && cd .. && -build_docs 3.7.3 && +build_docs 3.8.0 && build_docs master devel && rm -rf docs/html && diff --git a/docs/News.rst b/docs/News.rst index a68b7395..9012621b 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,8 +5,10 @@ News .. contents:: Contents: :backlinks: none -SQLObject (master) -================== +SQLObject 3.8.0 +=============== + +Released 7 Dec 2019. Features -------- diff --git a/sqlobject/__version__.py b/sqlobject/__version__.py index 0d929919..763a4a41 100644 --- a/sqlobject/__version__.py +++ b/sqlobject/__version__.py @@ -1,8 +1,8 @@ -version = '3.7.3' +version = '3.8.0' major = 3 -minor = 7 -micro = 3 +minor = 8 +micro = 0 release_level = 'final' serial = 0 version_info = (major, minor, micro, release_level, serial) From 0783e77bcfe6511483f864ebb152d306d858758f Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 7 Dec 2019 20:41:37 +0300 Subject: [PATCH 249/509] Prepare for the next release [skip ci] --- ANNOUNCE.rst | 45 ++++++++++++++++----------------------------- README.rst | 2 +- docs/News.rst | 3 +++ 3 files changed, 20 insertions(+), 30 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index fe822ef1..38444044 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,41 +1,28 @@ Hello! -I'm pleased to announce version 3.8.0, the first stable release of branch -3.8 of SQLObject. - - -What's new in SQLObject -======================= - -Features --------- +I'm pleased to announce version 3.8.1a1, the first alpha of the upcoming +release of branch 3.8 of SQLObject. -* Add driver ``supersqlite``. Not all tests are passing - so the driver isn't added to the list of default drivers. +I'm pleased to announce version 3.8.1a2, the second alpha of the upcoming +release of branch 3.8 of SQLObject. -Minor features --------------- +I'm pleased to announce version 3.8.1b1, the first beta of the upcoming +release of branch 3.8 of SQLObject. -* Improve sqlrepr'ing ``ALL/ANY/SOME()``: always put the expression - at the right side of the comparison operation. +I'm pleased to announce version 3.8.1rc1, the first release candidate +of the upcoming release of branch 3.8 of SQLObject. -Bug fixes ---------- - -* Fixed a bug in cascade deletion/nullification. - -* Fixed a bug in ``PostgresConnection.columnsFromSchema``: - PostgreSQL 12 removed outdated catalog attribute - ``pg_catalog.pg_attrdef.adsrc``. +I'm pleased to announce version 3.8.0, the first stable release of branch +3.8 of SQLObject. -* Fixed a bug working with microseconds in Time columns. +I'm pleased to announce version 3.8.1, the first bugfix release of branch +3.8 of SQLObject. -CI --- -* Run tests with Python 3.8 at Travis CI. +What's new in SQLObject +======================= -Contributors for this release are Andrew Trusty, Marco Sirabella and darix. +Contributors for this release are For a more complete list, please see the news: http://sqlobject.org/News.html @@ -67,7 +54,7 @@ Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Download: -https://pypi.org/project/SQLObject/3.8.0 +https://pypi.org/project/SQLObject/3.8.1a0.dev20191208/ News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 92962cf6..88ecfac9 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,4 @@ -SQLObject 3.8.0 +SQLObject 3.8.1 =============== Thanks for looking at SQLObject. SQLObject is an object-relational diff --git a/docs/News.rst b/docs/News.rst index 9012621b..089f671e 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,6 +5,9 @@ News .. contents:: Contents: :backlinks: none +SQLObject (master) +================== + SQLObject 3.8.0 =============== From a92401156915a9b82553c7202566cc11d647cb0f Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 25 Feb 2020 23:20:18 +0300 Subject: [PATCH 250/509] CI(Travis): Set default OS to `linux`, dist to `xenial` Default dist is `xenial` anyway. --- .travis.yml | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index a674f2d7..7a6a950e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,7 @@ +os: linux + +dist: xenial + language: python python: @@ -30,10 +34,8 @@ matrix: - python: "3.6" env: TESTS=py36-mysql - python: "3.7" - dist: xenial env: TESTS=py37-mysql - python: "3.8" - dist: xenial env: TESTS=py38-mysql - python: "2.7" env: TESTS=py27-postgres @@ -44,10 +46,8 @@ matrix: - python: "3.6" env: TESTS=py36-postgres - python: "3.7" - dist: xenial env: TESTS=py37-postgres - python: "3.8" - dist: xenial env: TESTS=py38-postgres - python: "2.7" env: TESTS=py27-sqlite @@ -58,15 +58,12 @@ matrix: - python: "3.6" env: TESTS=py36-sqlite - python: "3.7" - dist: xenial env: TESTS=py37-sqlite - python: "3.8" - dist: xenial env: TESTS=py38-sqlite - python: "2.7" env: TESTS=py27-flake8 - python: "3.8" - dist: xenial env: TESTS=py38-flake8 - python: "2.7" env: TESTS=py27-firebird From df601fd23785c2be0d36492d6b8710f66c24cc58 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 26 Feb 2020 00:36:46 +0300 Subject: [PATCH 251/509] CI(Travis): Remove duplicate Firebird tests --- .travis.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7a6a950e..1d54f6b8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -69,16 +69,10 @@ matrix: env: TESTS=py27-firebird - python: "3.6" env: TESTS=py36-firebird - - python: "2.7" - env: TESTS=py27-firebird - - python: "3.6" - env: TESTS=py36-firebird allow_failures: - env: TESTS=py27-firebird - env: TESTS=py36-firebird - - env: TESTS=py27-firebird - - env: TESTS=py36-firebird fast_finish: true From 0252ba226b81eedbaba6d1d169d1c692632f17fe Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 26 Feb 2020 00:37:29 +0300 Subject: [PATCH 252/509] CI(AppVeyor): Run tests with Python 3.8 --- appveyor.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/appveyor.yml b/appveyor.yml index 0bd35764..4d2f86b4 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -40,6 +40,11 @@ environment: PYTHON_VERSION: "3.7" PYTHON_HOME: "C:\\Python37-x64" db: mysql + - TESTS: "py38-mysql" + PYTHON_ARCH: "64" + PYTHON_VERSION: "3.8" + PYTHON_HOME: "C:\\Python38-x64" + db: mysql - TESTS: "py27-postgres" PYTHON_ARCH: "32" PYTHON_VERSION: "2.7" @@ -55,6 +60,11 @@ environment: PYTHON_VERSION: "3.7" PYTHON_HOME: "C:\\Python37-x64" db: postgresql + - TESTS: "py38-postgres" + PYTHON_ARCH: "64" + PYTHON_VERSION: "3.8" + PYTHON_HOME: "C:\\Python38-x64" + db: postgresql - TESTS: "py27-sqlite" PYTHON_ARCH: "32" PYTHON_VERSION: "2.7" @@ -67,6 +77,10 @@ environment: PYTHON_ARCH: "64" PYTHON_VERSION: "3.7" PYTHON_HOME: "C:\\Python37-x64" + - TESTS: "py38-sqlite" + PYTHON_ARCH: "64" + PYTHON_VERSION: "3.8" + PYTHON_HOME: "C:\\Python38-x64" matrix: fast_finish: true From ab6bfb9b2246bff936a2ec6e3efa746c499f0824 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 26 Feb 2020 00:37:49 +0300 Subject: [PATCH 253/509] Tests(tox): Refactor the list of environments --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 9be1d8bc..41619f20 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 2.0 -envlist = py{27,34,35,36,37,38}-sqlite{,-memory},py{27,38}-flake8 +envlist = py27,py3{4,5,6,7,8}-sqlite{,-memory},py{27,38}-flake8 # Base test environment settings [testenv] From 04f9060c15c0ca1fcf0d82ce03d10e458958ed11 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 28 Feb 2020 15:10:33 +0300 Subject: [PATCH 254/509] Limit `setuptools<44` for Python 2.7 --- .travis.yml | 2 +- appveyor.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1d54f6b8..1e4feb51 100644 --- a/.travis.yml +++ b/.travis.yml @@ -94,7 +94,7 @@ before_install: sudo chmod 644 /var/lib/firebird/create_test_db; fi -install: travis_retry pip install --upgrade "pip < 19.1" setuptools tox coveralls codecov ppu +install: travis_retry pip install --upgrade "pip<19.1" "setuptools<44" tox coveralls codecov ppu script: devscripts/tox-select-envs $TESTS diff --git a/appveyor.yml b/appveyor.yml index 4d2f86b4..778e9f51 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -91,8 +91,8 @@ install: - "SET TOXPYTHON=%PYTHON_HOME%\\python.exe" - "python --version" - "python -c \"import struct; print(struct.calcsize('P') * 8)\"" - - "python -m pip install --upgrade \"pip < 19.1\" setuptools" - - "pip install --upgrade \"tox < 3.1\" ppu" + - "python -m pip install --upgrade \"pip<19.1\" \"setuptools<44\"" + - "pip install --upgrade \"tox<3.1\" ppu" - "pip --version" # List ODBC drivers - ps: Get-OdbcDriver -Platform 32-bit | Select-Object -ExpandProperty Name From 7b0bab102f7c80333ade797341846c177020adb7 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 4 May 2020 21:36:48 +0300 Subject: [PATCH 255/509] Tests(tox): Delete SQLite database under w32 --- tox.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/tox.ini b/tox.ini index 41619f20..7de2551d 100644 --- a/tox.ini +++ b/tox.ini @@ -1021,6 +1021,7 @@ platform = win32 commands = {[testenv]commands} pytest --cov=sqlobject -D sqlite:/C:/projects/sqlobject/sqlobject_test.sqdb?debug=1 + cmd /c "del C:\projects\sqlobject\sqlobject_test.sqdb" [testenv:py27-sqlite-w32] platform = win32 From 0266ac96332b82b768afd8344f8a6a2ea8fe1ef2 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 4 May 2020 21:38:06 +0300 Subject: [PATCH 256/509] Tests: Add `test-sqlobject.cmd` --- devscripts/test-sqlobject.cmd | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 devscripts/test-sqlobject.cmd diff --git a/devscripts/test-sqlobject.cmd b/devscripts/test-sqlobject.cmd new file mode 100644 index 00000000..53b7cab5 --- /dev/null +++ b/devscripts/test-sqlobject.cmd @@ -0,0 +1,16 @@ +@echo off + +SetLocal EnableDelayedExpansion +set SavePATH=%PATH% + +for %%V in (27 34 35 36 37 38) do ( + for %%s in (32 64) do ( + set PATH=C:\Python%%V-%%s;C:\Python%%V-%%s\Scripts;!SavePATH! + set TOXPYTHON=C:\Python%%V-%%s\python.exe + !TOXPYTHON! -m tox -e "py%%V-sqlite{-memory,}-w32" + if !ERRORLEVEL! EQU 0 (echo Ok) else (echo Error && goto Quit) + ) +) + +:Quit +set PATH=%SavePATH% From eb00dff007fb8e16d4ebebae6860f305ae4cf54b Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 6 May 2020 23:22:39 +0300 Subject: [PATCH 257/509] CI: pip<21 for Python 2.7 --- .travis.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1e4feb51..e1760350 100644 --- a/.travis.yml +++ b/.travis.yml @@ -94,7 +94,7 @@ before_install: sudo chmod 644 /var/lib/firebird/create_test_db; fi -install: travis_retry pip install --upgrade "pip<19.1" "setuptools<44" tox coveralls codecov ppu +install: travis_retry pip install --upgrade "pip<21" "setuptools<44" tox coveralls codecov ppu script: devscripts/tox-select-envs $TESTS diff --git a/appveyor.yml b/appveyor.yml index 778e9f51..e5f00a6e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -91,7 +91,7 @@ install: - "SET TOXPYTHON=%PYTHON_HOME%\\python.exe" - "python --version" - "python -c \"import struct; print(struct.calcsize('P') * 8)\"" - - "python -m pip install --upgrade \"pip<19.1\" \"setuptools<44\"" + - "python -m pip install --upgrade \"pip<21\" \"setuptools<44\"" - "pip install --upgrade \"tox<3.1\" ppu" - "pip --version" # List ODBC drivers From 51d38936203e9f1881d60efe63cee694216ff0f7 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 22 Jun 2020 03:31:51 +0300 Subject: [PATCH 258/509] Fix(col.TimeValidator): Remove debug print --- sqlobject/col.py | 1 - 1 file changed, 1 deletion(-) diff --git a/sqlobject/col.py b/sqlobject/col.py index be8571cd..9bbde2a6 100644 --- a/sqlobject/col.py +++ b/sqlobject/col.py @@ -1510,7 +1510,6 @@ def to_python(self, value, state): raise validators.Invalid( "the value for the TimeCol '%s' must has days=0, " "it has days=%d" % (self.name, value.days), value, state) - print("[DEBUG1]:", value.microseconds) return datetime.time( *time.gmtime(value.seconds)[3:6], microsecond=value.microseconds From 7b2279dec80985a485976f6a0a264bd0d021e06e Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 22 Jun 2020 18:48:59 +0300 Subject: [PATCH 259/509] Fix `PyGreSQL` version for Python 3.4 --- devscripts/requirements/requirements_pygresql.txt | 2 ++ docs/News.rst | 5 +++++ tox.ini | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 devscripts/requirements/requirements_pygresql.txt diff --git a/devscripts/requirements/requirements_pygresql.txt b/devscripts/requirements/requirements_pygresql.txt new file mode 100644 index 00000000..ea4052ca --- /dev/null +++ b/devscripts/requirements/requirements_pygresql.txt @@ -0,0 +1,2 @@ +pygresql<5.2; python_version == '3.4' +pygresql; python_version != '3.4' diff --git a/docs/News.rst b/docs/News.rst index 089f671e..374899ce 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,11 @@ News SQLObject (master) ================== +Tests +----- + +* Fix ``PyGreSQL`` version for Python 3.4. + SQLObject 3.8.0 =============== diff --git a/tox.ini b/tox.ini index 7de2551d..1a21ebb5 100644 --- a/tox.ini +++ b/tox.ini @@ -25,7 +25,7 @@ deps = mysql-oursql3: git+https://github.com/sqlobject/oursql.git@py3k#egg=oursql pymysql: pymysql postgres-psycopg: psycopg2-binary - postgres-pygresql: pygresql + pygresql: -rdevscripts/requirements/requirements_pygresql.txt pypostgresql: git+https://github.com/sqlobject/py-postgresql.git@fix_w32#egg=pypostgresql postgres-pg8000: git+https://github.com/sqlobject/pg8000.git@getuser#egg=pg8000 pyodbc: pyodbc From f25602178eab6e148be25cdf87ba4bd5744d0838 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 22 Jun 2020 18:51:22 +0300 Subject: [PATCH 260/509] Style: Fix `flake8` E741 ambiguous variable name 'l' --- sqlobject/constraints.py | 4 ++-- sqlobject/manager/command.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sqlobject/constraints.py b/sqlobject/constraints.py index 9241579f..1b8bd0fe 100644 --- a/sqlobject/constraints.py +++ b/sqlobject/constraints.py @@ -51,8 +51,8 @@ def isBool(obj, col, value): class InList: - def __init__(self, l): - self.list = l + def __init__(self, _l): + self.list = _l def __call__(self, obj, col, value): if value not in self.list: diff --git a/sqlobject/manager/command.py b/sqlobject/manager/command.py index e9891d91..fc8db834 100755 --- a/sqlobject/manager/command.py +++ b/sqlobject/manager/command.py @@ -1095,8 +1095,8 @@ def update_db(self, version, conn): connection=conn) def strip_comments(self, sql): - lines = [l for l in sql.splitlines() - if not l.strip().startswith('--')] + lines = [_l for _l in sql.splitlines() + if not _l.strip().startswith('--')] return '\n'.join(lines) def base_dir(self): From dfedb4e3f88f71b17b96559cb89080e4c1c967bb Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 22 Jun 2020 18:53:06 +0300 Subject: [PATCH 261/509] Style: Fix `flake8` warnings E124 closing bracket does not match visual indentation E128 continuation line under-indented for visual indent --- sqlobject/dbconnection.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sqlobject/dbconnection.py b/sqlobject/dbconnection.py index 0b9fd02d..e3de62e8 100644 --- a/sqlobject/dbconnection.py +++ b/sqlobject/dbconnection.py @@ -1071,9 +1071,9 @@ def registerConnection(self, schemes, builder): def registerConnectionInstance(self, inst): if inst.name: assert (inst.name not in self.instanceNames - or self.instanceNames[inst.name] is cls # noqa - ), ("A instance has already been registered " - "with the name %s" % inst.name) + or self.instanceNames[inst.name] is cls # noqa + ), ("A instance has already been registered " + "with the name %s" % inst.name) assert inst.name.find(':') == -1, \ "You cannot include ':' " \ "in your class names (%r)" % cls.name # noqa From 551063155c71b177345fc5cfb8bcbd238aa17eac Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 22 Jun 2020 23:08:26 +0300 Subject: [PATCH 262/509] CI(AppVeyor): Ignore errors with `PyGreSQL` --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 1a21ebb5..51855a57 100644 --- a/tox.ini +++ b/tox.ini @@ -836,7 +836,7 @@ commands = {[testenv]commands} -dropdb -U postgres -w sqlobject_test createdb -U postgres -w sqlobject_test - pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + -pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb -U postgres -w sqlobject_test [testenv:py27-postgres-pygresql-noauto-w32] From 7b85a599c0989780aed68feed24c2ebef8d5c9f9 Mon Sep 17 00:00:00 2001 From: Neil Date: Fri, 21 Aug 2020 13:42:15 +0200 Subject: [PATCH 263/509] Use conf.py options to exclude sqlmeta options This aims to fix the same issue as in #147, but fixing the problem that genapi docs will override the rst files and lose the exclusions. --- docs/conf.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/conf.py b/docs/conf.py index f8272ab1..b6e460e3 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -35,6 +35,11 @@ 'sphinx.ext.viewcode', ] +# Exclude uninformative members from the api docs +autodoc_default_options = { + 'exclude-members': 'columnDefinitions,columnList,columns,indexDefinitions' +} + # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] From a2d90177d185c9c1f6ed6b2425e35262fa70ad18 Mon Sep 17 00:00:00 2001 From: Neil Date: Sat, 22 Aug 2020 08:41:31 +0200 Subject: [PATCH 264/509] Rerun genapidocs and new & updated files --- docs/api/sqlobject.tests.rst | 1 + docs/api/sqlobject.tests.test_ForeignKey_cascade.rst | 7 +++++++ 2 files changed, 8 insertions(+) create mode 100644 docs/api/sqlobject.tests.test_ForeignKey_cascade.rst diff --git a/docs/api/sqlobject.tests.rst b/docs/api/sqlobject.tests.rst index 6cf2f130..fcab4e81 100644 --- a/docs/api/sqlobject.tests.rst +++ b/docs/api/sqlobject.tests.rst @@ -13,6 +13,7 @@ Submodules sqlobject.tests.dbtest sqlobject.tests.test_ForeignKey + sqlobject.tests.test_ForeignKey_cascade sqlobject.tests.test_NoneValuedResultItem sqlobject.tests.test_SQLMultipleJoin sqlobject.tests.test_SQLRelatedJoin diff --git a/docs/api/sqlobject.tests.test_ForeignKey_cascade.rst b/docs/api/sqlobject.tests.test_ForeignKey_cascade.rst new file mode 100644 index 00000000..cbe1c448 --- /dev/null +++ b/docs/api/sqlobject.tests.test_ForeignKey_cascade.rst @@ -0,0 +1,7 @@ +sqlobject.tests.test\_ForeignKey\_cascade module +================================================ + +.. automodule:: sqlobject.tests.test_ForeignKey_cascade + :members: + :undoc-members: + :show-inheritance: From cb7575ab2050260311e6ace0226917dfdeb3dfbc Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 1 Oct 2020 18:00:14 +0300 Subject: [PATCH 265/509] Release 3.8.1 --- ANNOUNCE.rst | 33 +++++++++++++++++---------------- devscripts/build-all-docs | 2 +- docs/News.rst | 16 ++++++++++++++-- sqlobject/__version__.py | 4 ++-- 4 files changed, 34 insertions(+), 21 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 38444044..5cfb5180 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,28 +1,29 @@ Hello! -I'm pleased to announce version 3.8.1a1, the first alpha of the upcoming -release of branch 3.8 of SQLObject. +I'm pleased to announce version 3.8.1, the first bugfix release of branch +3.8 of SQLObject. -I'm pleased to announce version 3.8.1a2, the second alpha of the upcoming -release of branch 3.8 of SQLObject. -I'm pleased to announce version 3.8.1b1, the first beta of the upcoming -release of branch 3.8 of SQLObject. +What's new in SQLObject +======================= -I'm pleased to announce version 3.8.1rc1, the first release candidate -of the upcoming release of branch 3.8 of SQLObject. +The contributor for this release is Neil Muller. -I'm pleased to announce version 3.8.0, the first stable release of branch -3.8 of SQLObject. +Documentation +------------- -I'm pleased to announce version 3.8.1, the first bugfix release of branch -3.8 of SQLObject. +* Use conf.py options to exclude sqlmeta options. +Tests +----- -What's new in SQLObject -======================= +* Fix ``PyGreSQL`` version for Python 3.4. + +CI +-- + +* Run tests with Python 3.8 at AppVeyor. -Contributors for this release are For a more complete list, please see the news: http://sqlobject.org/News.html @@ -54,7 +55,7 @@ Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Download: -https://pypi.org/project/SQLObject/3.8.1a0.dev20191208/ +https://pypi.org/project/SQLObject/3.8.1 News and changes: http://sqlobject.org/News.html diff --git a/devscripts/build-all-docs b/devscripts/build-all-docs index 349c6ed8..4eab6205 100755 --- a/devscripts/build-all-docs +++ b/devscripts/build-all-docs @@ -10,7 +10,7 @@ cd "`dirname \"$0\"`" && PROG_DIR="`pwd`" && cd .. && -build_docs 3.8.0 && +build_docs 3.8.1 && build_docs master devel && rm -rf docs/html && diff --git a/docs/News.rst b/docs/News.rst index 374899ce..291954fe 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,14 +5,26 @@ News .. contents:: Contents: :backlinks: none -SQLObject (master) -================== +SQLObject 3.8.1 +=============== + +Released 2020 Oct 01. + +Documentation +------------- + +* Use conf.py options to exclude sqlmeta options. Tests ----- * Fix ``PyGreSQL`` version for Python 3.4. +CI +-- + +* Run tests with Python 3.8 at AppVeyor. + SQLObject 3.8.0 =============== diff --git a/sqlobject/__version__.py b/sqlobject/__version__.py index 763a4a41..579bdd6a 100644 --- a/sqlobject/__version__.py +++ b/sqlobject/__version__.py @@ -1,8 +1,8 @@ -version = '3.8.0' +version = '3.8.1' major = 3 minor = 8 -micro = 0 +micro = 1 release_level = 'final' serial = 0 version_info = (major, minor, micro, release_level, serial) From 270dd73d1d0a6db0abc453bf74743189151d8a08 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 1 Oct 2020 18:19:49 +0300 Subject: [PATCH 266/509] Prepare for the next release --- ANNOUNCE.rst | 32 ++++++++++++++------------------ README.rst | 4 ++-- docs/News.rst | 3 +++ 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 5cfb5180..9beb8c90 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,29 +1,25 @@ Hello! -I'm pleased to announce version 3.8.1, the first bugfix release of branch -3.8 of SQLObject. - - -What's new in SQLObject -======================= +I'm pleased to announce version 3.8.1a1, the first alpha of the upcoming +release of branch 3.8 of SQLObject. -The contributor for this release is Neil Muller. +I'm pleased to announce version 3.8.1a2, the second alpha of the upcoming +release of branch 3.8 of SQLObject. -Documentation -------------- +I'm pleased to announce version 3.8.1b1, the first beta of the upcoming +release of branch 3.8 of SQLObject. -* Use conf.py options to exclude sqlmeta options. +I'm pleased to announce version 3.8.1rc1, the first release candidate +of the upcoming release of branch 3.8 of SQLObject. -Tests ------ - -* Fix ``PyGreSQL`` version for Python 3.4. +I'm pleased to announce version 3.8.2, the first bugfix release of branch +3.8 of SQLObject. -CI --- -* Run tests with Python 3.8 at AppVeyor. +What's new in SQLObject +======================= +Contributors for this release are For a more complete list, please see the news: http://sqlobject.org/News.html @@ -55,7 +51,7 @@ Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Download: -https://pypi.org/project/SQLObject/3.8.1 +https://pypi.org/project/SQLObject/3.8.2a0.dev20201001/ News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 88ecfac9..a0f632de 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.8.1 -=============== +SQLObject 3.8.2a0 +================= Thanks for looking at SQLObject. SQLObject is an object-relational mapper, i.e., a library that will wrap your database tables in Python diff --git a/docs/News.rst b/docs/News.rst index 291954fe..dc57777a 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,6 +5,9 @@ News .. contents:: Contents: :backlinks: none +SQLObject (master) +================== + SQLObject 3.8.1 =============== From 5a9174719f50e03caec767209b239fd0e2caf5c6 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 20 Nov 2020 17:30:41 +0300 Subject: [PATCH 267/509] Tests,CI: Run tests with Python 3.9 at Travis and AppVeyor --- .travis.yml | 6 +++ appveyor.yml | 16 +++++++ docs/News.rst | 5 +++ tox.ini | 118 +++++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 144 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e1760350..9f03a84f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -37,6 +37,8 @@ matrix: env: TESTS=py37-mysql - python: "3.8" env: TESTS=py38-mysql + - python: "3.9" + env: TESTS=py39-mysql - python: "2.7" env: TESTS=py27-postgres - python: "3.4" @@ -49,6 +51,8 @@ matrix: env: TESTS=py37-postgres - python: "3.8" env: TESTS=py38-postgres + - python: "3.9" + env: TESTS=py39-postgres - python: "2.7" env: TESTS=py27-sqlite - python: "3.4" @@ -61,6 +65,8 @@ matrix: env: TESTS=py37-sqlite - python: "3.8" env: TESTS=py38-sqlite + - python: "3.9" + env: TESTS=py39-sqlite - python: "2.7" env: TESTS=py27-flake8 - python: "3.8" diff --git a/appveyor.yml b/appveyor.yml index e5f00a6e..be97e213 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -3,6 +3,8 @@ # and Michael Sverdlik's appveyor-utils (https://github.com/cloudify-cosmo/appveyor-utils) version: '{branch}-{build}' +image: Visual Studio 2019 + cache: - '%LOCALAPPDATA%\pip\Cache' @@ -45,6 +47,11 @@ environment: PYTHON_VERSION: "3.8" PYTHON_HOME: "C:\\Python38-x64" db: mysql + - TESTS: "py39-mysql" + PYTHON_ARCH: "64" + PYTHON_VERSION: "3.9" + PYTHON_HOME: "C:\\Python39-x64" + db: mysql - TESTS: "py27-postgres" PYTHON_ARCH: "32" PYTHON_VERSION: "2.7" @@ -65,6 +72,11 @@ environment: PYTHON_VERSION: "3.8" PYTHON_HOME: "C:\\Python38-x64" db: postgresql + - TESTS: "py39-postgres" + PYTHON_ARCH: "64" + PYTHON_VERSION: "3.9" + PYTHON_HOME: "C:\\Python39-x64" + db: postgresql - TESTS: "py27-sqlite" PYTHON_ARCH: "32" PYTHON_VERSION: "2.7" @@ -81,6 +93,10 @@ environment: PYTHON_ARCH: "64" PYTHON_VERSION: "3.8" PYTHON_HOME: "C:\\Python38-x64" + - TESTS: "py39-sqlite" + PYTHON_ARCH: "64" + PYTHON_VERSION: "3.9" + PYTHON_HOME: "C:\\Python39-x64" matrix: fast_finish: true diff --git a/docs/News.rst b/docs/News.rst index dc57777a..fcab0d42 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,11 @@ News SQLObject (master) ================== +CI +-- + +* Run tests with Python 3.9 at Travis and AppVeyor. + SQLObject 3.8.1 =============== diff --git a/tox.ini b/tox.ini index 51855a57..c84ffcf6 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 2.0 -envlist = py27,py3{4,5,6,7,8}-sqlite{,-memory},py{27,38}-flake8 +envlist = py27,py3{4,5,6,7,8}-sqlite{,-memory},py{27,39}-flake8 # Base test environment settings [testenv] @@ -13,6 +13,7 @@ basepython = py36: {env:TOXPYTHON:python3.6} py37: {env:TOXPYTHON:python3.7} py38: {env:TOXPYTHON:python3.8} + py39: {env:TOXPYTHON:python3.9} commands = {envpython} --version {envpython} -c "import struct; print(struct.calcsize('P') * 8)" @@ -80,6 +81,10 @@ deps = commands = {envpython} -c "print('MySQL-python requires Python 2.7')" deps = +[testenv:py39-mysqldb] +commands = {envpython} -c "print('MySQL-python requires Python 2.7')" +deps = + [mysqlclient] commands = {[testenv]commands} @@ -107,6 +112,9 @@ commands = {[mysqlclient]commands} [testenv:py38-mysqlclient] commands = {[mysqlclient]commands} +[testenv:py39-mysqlclient] +commands = {[mysqlclient]commands} + [mysql-connector] commands = {[testenv]commands} @@ -135,6 +143,9 @@ commands = {[mysql-connector]commands} [testenv:py38-mysql-connector] commands = {[mysql-connector]commands} +[testenv:py39-mysql-connector] +commands = {[mysql-connector]commands} + [oursql] commands = {[testenv]commands} @@ -163,6 +174,9 @@ commands = {[oursql]commands} [testenv:py38-mysql-oursql3] commands = {[oursql]commands} +[testenv:py39-mysql-oursql3] +commands = {[oursql]commands} + [pymysql] commands = {[testenv]commands} @@ -191,6 +205,9 @@ commands = {[pymysql]commands} [testenv:py38-mysql-pymysql] commands = {[pymysql]commands} +[testenv:py39-mysql-pymysql] +commands = {[pymysql]commands} + [mysql-pyodbc] commands = {[testenv]commands} @@ -220,6 +237,9 @@ commands = {[mysql-pyodbc]commands} [testenv:py38-mysql-pyodbc-noauto] commands = {[mysql-pyodbc]commands} +[testenv:py39-mysql-pyodbc-noauto] +commands = {[mysql-pyodbc]commands} + [mysql-pypyodbc] commands = {[testenv]commands} @@ -248,6 +268,9 @@ commands = {[mysql-pypyodbc]commands} [testenv:py38-mysql-pypyodbc-noauto] commands = {[mysql-pypyodbc]commands} +[testenv:py39-mysql-pypyodbc-noauto] +commands = {[mysql-pypyodbc]commands} + # PostgreSQL test environments [psycopg] commands = @@ -277,6 +300,9 @@ commands = {[psycopg]commands} [testenv:py38-postgres-psycopg] commands = {[psycopg]commands} +[testenv:py39-postgres-psycopg] +commands = {[psycopg]commands} + [pygresql] commands = {[testenv]commands} @@ -305,6 +331,9 @@ commands = {[pygresql]commands} [testenv:py38-postgres-pygresql] commands = {[pygresql]commands} +[testenv:py39-postgres-pygresql] +commands = {[pygresql]commands} + [pypostgresql] commands = {[testenv]commands} @@ -332,6 +361,9 @@ commands = {[pypostgresql]commands} [testenv:py38-postgres-pypostgresql] commands = {[pypostgresql]commands} +[testenv:py39-postgres-pypostgresql] +commands = {[pypostgresql]commands} + [pg8000] commands = {[testenv]commands} @@ -360,6 +392,9 @@ commands = {[pg8000]commands} [testenv:py38-postgres-pg8000] commands = {[pg8000]commands} +[testenv:py39-postgres-pg8000] +commands = {[pg8000]commands} + [postgres-pyodbc] commands = {[testenv]commands} @@ -389,6 +424,9 @@ commands = {[postgres-pyodbc]commands} [testenv:py38-postgres-pyodbc-noauto] commands = {[postgres-pyodbc]commands} +[testenv:py39-postgres-pyodbc-noauto] +commands = {[postgres-pyodbc]commands} + [postgres-pypyodbc] commands = {[testenv]commands} @@ -417,6 +455,9 @@ commands = {[postgres-pypyodbc]commands} [testenv:py38-postgres-pypyodbc-noauto] commands = {[postgres-pypyodbc]commands} +[testenv:py39-postgres-pypyodbc-noauto] +commands = {[postgres-pypyodbc]commands} + # SQLite test environments [sqlite] @@ -446,6 +487,9 @@ commands = {[sqlite]commands} [testenv:py38-sqlite] commands = {[sqlite]commands} +[testenv:py39-sqlite] +commands = {[sqlite]commands} + [sqlite-memory] commands = {[testenv]commands} @@ -471,6 +515,9 @@ commands = {[sqlite-memory]commands} [testenv:py38-sqlite-memory] commands = {[sqlite-memory]commands} +[testenv:py39-sqlite-memory] +commands = {[sqlite-memory]commands} + [sqlite-supersqlite] commands = {[testenv]commands} @@ -498,6 +545,9 @@ commands = {[sqlite-supersqlite]commands} [testenv:py38-sqlite-supersqlite] commands = {[sqlite-supersqlite]commands} +[testenv:py39-sqlite-supersqlite] +commands = {[sqlite-supersqlite]commands} + # Firebird database test environments [fdb] @@ -528,6 +578,9 @@ commands = {[fdb]commands} [testenv:py38-firebird-fdb] commands = {[fdb]commands} +[testenv:py39-firebird-fdb] +commands = {[fdb]commands} + [firebirdsql] commands = {[testenv]commands} @@ -556,6 +609,9 @@ commands = {[firebirdsql]commands} [testenv:py38-firebirdsql] commands = {[firebirdsql]commands} +[testenv:py39-firebirdsql] +commands = {[firebirdsql]commands} + # Special test environments [testenv:py27-flake8] changedir = ./ @@ -605,6 +661,14 @@ commands = {[testenv]commands} flake8 . +[testenv:py39-flake8] +changedir = ./ +deps = + flake8 +commands = + {[testenv]commands} + flake8 . + # Windows testing [mssql-pyodbc-w32] platform = win32 @@ -643,6 +707,10 @@ commands = platform = win32 commands = {[mssql-pyodbc-w32]commands} +[testenv:py39-mssql-pyodbc-noauto-w32] +platform = win32 +commands = {[mssql-pyodbc-w32]commands} + [mysql-connector-w32] platform = win32 commands = @@ -680,6 +748,10 @@ commands = platform = win32 commands = {[mysql-connector-w32]commands} +[testenv:py39-mysql-connector-w32] +platform = win32 +commands = {[mysql-connector-w32]commands} + [pymysql-w32] platform = win32 commands = @@ -717,6 +789,10 @@ commands = platform = win32 commands = {[pymysql-w32]commands} +[testenv:py39-mysql-pymysql-w32] +platform = win32 +commands = {[pymysql-w32]commands} + [mysql-pyodbc-w32] platform = win32 commands = @@ -755,6 +831,10 @@ commands = platform = win32 commands = {[mysql-pyodbc-w32]commands} +[testenv:py39-mysql-pyodbc-noauto-w32] +platform = win32 +commands = {[mysql-pyodbc-w32]commands} + [mysql-pypyodbc-w32] platform = win32 commands = @@ -793,6 +873,10 @@ commands = platform = win32 commands = {[mysql-pypyodbc-w32]commands} +[testenv:py39-mysql-pypyodbc-noauto-w32] +platform = win32 +commands = {[mysql-pypyodbc-w32]commands} + [psycopg-w32] platform = win32 commands = @@ -830,6 +914,10 @@ commands = platform = win32 commands = {[psycopg-w32]commands} +[testenv:py39-postgres-psycopg-w32] +platform = win32 +commands = {[psycopg-w32]commands} + [pygresql-w32] platform = win32 commands = @@ -867,6 +955,10 @@ commands = platform = win32 commands = {[pygresql-w32]commands} +[testenv:py39-postgres-pygresql-w32] +platform = win32 +commands = {[pygresql-w32]commands} + [pypostgresql-w32] platform = win32 commands = @@ -903,6 +995,10 @@ commands = platform = win32 commands = {[pypostgresql-w32]commands} +[testenv:py39-postgres-pypostgresql-w32] +platform = win32 +commands = {[pypostgresql-w32]commands} + [pg8000-w32] platform = win32 commands = @@ -940,6 +1036,10 @@ commands = platform = win32 commands = {[pg8000-w32]commands} +[testenv:py39-postgres-pg8000-w32] +platform = win32 +commands = {[pg8000-w32]commands} + [postgres-pyodbc-w32] platform = win32 commands = @@ -978,6 +1078,10 @@ commands = platform = win32 commands = {[postgres-pyodbc-w32]commands} +[testenv:py39-postgres-pyodbc-noauto-w32] +platform = win32 +commands = {[postgres-pyodbc-w32]commands} + [postgres-pypyodbc-w32] platform = win32 commands = @@ -1016,6 +1120,10 @@ commands = platform = win32 commands = {[postgres-pypyodbc-w32]commands} +[testenv:py39-postgres-pypyodbc-noauto-w32] +platform = win32 +commands = {[postgres-pypyodbc-w32]commands} + [sqlite-w32] platform = win32 commands = @@ -1051,6 +1159,10 @@ commands = platform = win32 commands = {[sqlite-w32]commands} +[testenv:py39-sqlite-w32] +platform = win32 +commands = {[sqlite-w32]commands} + [sqlite-memory-w32] platform = win32 commands = @@ -1084,3 +1196,7 @@ commands = [testenv:py38-sqlite-memory-w32] platform = win32 commands = {[sqlite-memory-w32]commands} + +[testenv:py39-sqlite-memory-w32] +platform = win32 +commands = {[sqlite-memory-w32]commands} From f2e34acc8dd32ef00f28275c4bca044e9ca03d05 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 21 Nov 2020 15:53:13 +0300 Subject: [PATCH 268/509] CI: Turn off `fast_finish` --- .travis.yml | 2 -- appveyor.yml | 3 --- 2 files changed, 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9f03a84f..71cc4c2b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -80,8 +80,6 @@ matrix: - env: TESTS=py27-firebird - env: TESTS=py36-firebird - fast_finish: true - before_install: # Start the firebird database server. # We use firebird-super, so there's none of the inetd configuration diff --git a/appveyor.yml b/appveyor.yml index be97e213..cdb6cfe4 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -98,9 +98,6 @@ environment: PYTHON_VERSION: "3.9" PYTHON_HOME: "C:\\Python39-x64" -matrix: - fast_finish: true - install: # Ensure we use the right python version - "SET PATH=%PYTHON_HOME%;%PYTHON_HOME%\\Scripts;C:\\Program Files\\MySQL\\MySQL Server 5.7\\bin;C:\\Program Files\\PostgreSQL\\9.5\\bin;%PATH%" From a80792d2a52980ddc644c728f4c968f2015dd2d7 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 21 Nov 2020 18:38:40 +0300 Subject: [PATCH 269/509] CI(AppVeyor): Use `PostgreSQL` 9.6 --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index cdb6cfe4..537ec564 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -100,7 +100,7 @@ environment: install: # Ensure we use the right python version - - "SET PATH=%PYTHON_HOME%;%PYTHON_HOME%\\Scripts;C:\\Program Files\\MySQL\\MySQL Server 5.7\\bin;C:\\Program Files\\PostgreSQL\\9.5\\bin;%PATH%" + - "SET PATH=%PYTHON_HOME%;%PYTHON_HOME%\\Scripts;C:\\Program Files\\MySQL\\MySQL Server 5.7\\bin;C:\\Program Files\\PostgreSQL\\9.6\\bin;%PATH%" - "SET TOXPYTHON=%PYTHON_HOME%\\python.exe" - "python --version" - "python -c \"import struct; print(struct.calcsize('P') * 8)\"" From 7ccfeb89506ef301ec11253d3fed550e39ab6278 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 21 Nov 2020 19:07:12 +0300 Subject: [PATCH 270/509] Tests: Clear microseconds It seems MySQL at AppVeyor rounds seconds if microseconds > 0.5 sec. --- sqlobject/tests/test_datetime.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlobject/tests/test_datetime.py b/sqlobject/tests/test_datetime.py index 58c43f99..df9bbc3a 100644 --- a/sqlobject/tests/test_datetime.py +++ b/sqlobject/tests/test_datetime.py @@ -24,7 +24,7 @@ class DateTime1(SQLObject): def test_dateTime(): setupClass(DateTime1) - _now = datetime.now() + _now = datetime.now().replace(microsecond=0) dt1 = DateTime1(col1=_now, col2=_now, col3=_now.time()) assert isinstance(dt1.col1, datetime) From 470c8f43e956d34a500e18d9fe428c16927cabd2 Mon Sep 17 00:00:00 2001 From: "Michael S. Root" Date: Thu, 3 Sep 2020 14:14:00 +0300 Subject: [PATCH 271/509] Update for JSON column and functions Refs: #159. --- sqlobject/col.py | 57 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/sqlobject/col.py b/sqlobject/col.py index 9bbde2a6..6fda37f6 100644 --- a/sqlobject/col.py +++ b/sqlobject/col.py @@ -2008,11 +2008,68 @@ def createValidators(self): return [JSONValidator(name=self.name)] + \ super(SOJSONCol, self).createValidators() + def _sqlType(self): + return 'JSON' + class JSONCol(StringCol): baseClass = SOJSONCol +############################################# +# +# Added by Tippett +# + +# +# Convenience stuff Monkey-Patched onto sqlbuilder.SQLObjectField, +# so you can do: +# +# Table.q.column.json_extract("key") == value +# Table.q.column.json_contains("item") +# Table.q.column.json_length("key") +# +# instead of +# +# func.JSON_EXTRACT(Table.q.column, '$.key') == value +# func.JSON_CONTAINS(Table.q.column, json.dumps("item")) +# func.JSON_LENGTH(Table.q.column, '$.key') +# + +def _json_extract(col, key, path=None): + """ + """ + assert isinstance(col.column, SOJSONCol), \ + "{!r} is not a JSONCol".format(col) + if path is None: + return sqlbuilder.func.JSON_EXTRACT(col, '$.%s' % key) + else: + return sqlbuilder.func.JSON_EXTRACT(col, '$.%s' % key, path) + + +def _json_contains(col, value, path=None): + assert isinstance(col.column, SOJSONCol), \ + "{!r} is not a JSONCol".format(col) + if path is None: + return sqlbuilder.func.JSON_CONTAINS(col, json.dumps(value)) + else: + return sqlbuilder.func.JSON_CONTAINS(col, json.dumps(value), path) + + +def _json_length(col, path=None): + assert isinstance(col.column, SOJSONCol), \ + "{!r} is not a JSONCol".format(col) + if path is None: + return sqlbuilder.func.JSON_LENGTH(col) + else: + return sqlbuilder.func.JSON_LENGTH(col, path) + + +sqlbuilder.SQLObjectField.json_extract = _json_extract +sqlbuilder.SQLObjectField.json_contains = _json_contains +sqlbuilder.SQLObjectField.json_length = _json_length + + def pushKey(kw, name, value): if name not in kw: kw[name] = value From ac96456b98cbb0e95a3bdafab263d3f59e7d8e77 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 13 Sep 2020 16:15:32 +0300 Subject: [PATCH 272/509] Feat(mysql): Check if the server allows to use JSON functions Refs: #159. --- sqlobject/mysql/mysqlconnection.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index 00cc3d65..16bd4b0f 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -148,6 +148,8 @@ def __init__(self, db, user, password='', host='localhost', port=0, **kw): self._server_version = None self._can_use_microseconds = None + self._can_use_json_funcs = None + DBAPI.__init__(self, **kw) @classmethod @@ -490,3 +492,17 @@ def can_use_microseconds(self): can_use_microseconds = (server_version >= (5, 6, 4)) self._can_use_microseconds = can_use_microseconds return can_use_microseconds + + def can_use_json_funcs(self): + if self._can_use_json_funcs is not None: + return self._can_use_json_funcs + server_version = self.server_version() + if server_version is None: + return None + server_version, db_tag = server_version + if db_tag == "MariaDB": + can_use_json_funcs = (server_version >= (10, 2, 7)) + else: # MySQL + can_use_json_funcs = (server_version >= (5, 7, 0)) + self._can_use_json_funcs = can_use_json_funcs + return can_use_json_funcs From 6d5d0c200b8428b009a35d8f4c5912413e5db7c6 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 13 Sep 2020 16:17:01 +0300 Subject: [PATCH 273/509] Test(mysql/json): Test JSON functions Refs: #159. --- sqlobject/tests/test_jsoncol.py | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/sqlobject/tests/test_jsoncol.py b/sqlobject/tests/test_jsoncol.py index 1a120cda..52bb354e 100644 --- a/sqlobject/tests/test_jsoncol.py +++ b/sqlobject/tests/test_jsoncol.py @@ -1,3 +1,4 @@ +import pytest from sqlobject import SQLObject, JSONCol from sqlobject.tests.dbtest import setupClass @@ -18,17 +19,38 @@ class JSONTest(SQLObject): u"unicode", u"unicode'with'apostrophes", u"unicode\"with\"quotes", ], u"unicode", u"unicode'with'apostrophes", u"unicode\"with\"quotes", + {'test': 'Test'}, ) -def test_JSONCol(): +def _setup(): setupClass(JSONTest) for _id, test_data in enumerate(_json_test_data): - json = JSONTest(id=_id + 1, json=test_data) + JSONTest(id=_id + 1, json=test_data) + +def test_JSONCol(): + _setup() JSONTest._connection.cache.clear() for _id, test_data in enumerate(_json_test_data): json = JSONTest.get(_id + 1) assert json.json == test_data + + +def test_JSONCol_funcs(): + connection = JSONTest._connection + if not hasattr(connection, 'can_use_json_funcs') \ + or not connection.can_use_json_funcs(): + pytest.skip( + "The database doesn't support JSON functions; " + "JSON functions are supported by MariaDB since version 10.2.7 " + "and by MySQL since version 5.7.") + _setup() + + rows = list( + JSONTest.select(JSONTest.q.json.json_extract('test') == 'Test') + ) + assert len(rows) == 1 + assert rows[0].json == {'test': 'Test'} From 3a4e35f61d6779c555032b8fd70dddef1dcec7f0 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 20 Nov 2020 17:13:17 +0300 Subject: [PATCH 274/509] Fix(col): Fix `JSONValidator` Refs: #159. --- sqlobject/col.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sqlobject/col.py b/sqlobject/col.py index 6fda37f6..8c4118ed 100644 --- a/sqlobject/col.py +++ b/sqlobject/col.py @@ -1978,11 +1978,13 @@ class JsonbCol(Col): baseClass = SOJsonbCol -class JSONValidator(StringValidator): +class JSONValidator(SOValidator): def to_python(self, value, state): if value is None: return None + if isinstance(value, (bool, int, float, long, dict, list)): + return value if isinstance(value, string_type): return json.loads(value) raise validators.Invalid( @@ -2005,8 +2007,7 @@ def from_python(self, value, state): class SOJSONCol(SOStringCol): def createValidators(self): - return [JSONValidator(name=self.name)] + \ - super(SOJSONCol, self).createValidators() + return [JSONValidator(name=self.name)] def _sqlType(self): return 'JSON' From 48b1521d3fd55fb1bd968d6fdd34656e471004b1 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 24 Nov 2020 18:43:16 +0300 Subject: [PATCH 275/509] Python 3.9 is supported --- devscripts/setup | 2 +- setup.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/devscripts/setup b/devscripts/setup index 3c12824d..e28d6765 100755 --- a/devscripts/setup +++ b/devscripts/setup @@ -3,7 +3,7 @@ umask 022 # -rwxr-xr-x cd "`dirname \"$0\"`"/.. && -for py_ver in 2.7 3.4 3.5 3.6 3.7 3.8; do +for py_ver in 2.7 3.4 3.5 3.6 3.7 3.8 3.9; do python$py_ver -m pip install --install-option=-O2 --upgrade . done && diff --git a/setup.py b/setup.py index d85791d3..58cd1d0f 100755 --- a/setup.py +++ b/setup.py @@ -60,6 +60,7 @@ "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", "Topic :: Database", "Topic :: Database :: Front-Ends", "Topic :: Software Development :: Libraries :: Python Modules", From 1b9aff1e6983b4e3f708933884333d8cc93512ec Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 28 Nov 2020 16:30:37 +0300 Subject: [PATCH 276/509] Fix(col): Comment out `SOJSONCol._sqlType()` Doesn't work, especially with Postgres. Refs: #159. --- docs/SQLObject.rst | 3 ++- sqlobject/col.py | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index 9504c1a2..c3f19576 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -1244,7 +1244,8 @@ different types of columns, when SQLObject creates your tables. `JSONCol`: A universal json column that converts simple Python objects (None, bool, int, float, long, dict, list, str/unicode to/from JSON using - json.dumps/loads. A subclass of StringCol. + json.dumps/loads. A subclass of StringCol. Requires ``VARCHAR``/``TEXT`` + columns at backends, doesn't work with ``JSON`` columns. `PickleCol`: An extension of BLOBCol; this column can store/retrieve any Python object; diff --git a/sqlobject/col.py b/sqlobject/col.py index 8c4118ed..c5bd2968 100644 --- a/sqlobject/col.py +++ b/sqlobject/col.py @@ -2009,8 +2009,9 @@ class SOJSONCol(SOStringCol): def createValidators(self): return [JSONValidator(name=self.name)] - def _sqlType(self): - return 'JSON' + # Doesn't work, especially with Postgres + # def _sqlType(self): + # return 'JSON' class JSONCol(StringCol): From ed106ef2c461ea31387f9597d6f17d934c3eebd0 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 28 Nov 2020 16:43:13 +0300 Subject: [PATCH 277/509] Docs(News): Add `JSONCol` [skip ci] --- docs/News.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/News.rst b/docs/News.rst index fcab0d42..aee1f6e3 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,14 @@ News SQLObject (master) ================== +Features +-------- + +* Add ``JSONCol``: a universal json column that converts simple Python objects + (None, bool, int, float, long, dict, list, str/unicode to/from JSON using + json.dumps/loads. A subclass of StringCol. Requires ``VARCHAR``/``TEXT`` + columns at backends, doesn't work with ``JSON`` columns. + CI -- From 3635f444399c34e256dba87687e6ab657e85447a Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 29 Nov 2020 04:11:11 +0300 Subject: [PATCH 278/509] Tests(tox): Add `py39-sqlite` to the default list of environments --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index c84ffcf6..f0fc2b23 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 2.0 -envlist = py27,py3{4,5,6,7,8}-sqlite{,-memory},py{27,39}-flake8 +envlist = py27,py3{4,5,6,7,8,9}-sqlite{,-memory},py{27,39}-flake8 # Base test environment settings [testenv] From b6d0201febccc7895e398b548d8c2f60e8ead1d1 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 11 Dec 2020 16:47:03 +0300 Subject: [PATCH 279/509] Feat(DateTime): Drop support for very old version of `mxDateTime` Drop support for very old version of `mxDateTime` without `mx.` namespace. Refs: #161. --- docs/News.rst | 3 +++ sqlobject/col.py | 31 ++++++++++++++++--------------- sqlobject/converters.py | 33 ++++++++++++++++----------------- 3 files changed, 35 insertions(+), 32 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index aee1f6e3..1842d1a0 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -16,6 +16,9 @@ Features json.dumps/loads. A subclass of StringCol. Requires ``VARCHAR``/``TEXT`` columns at backends, doesn't work with ``JSON`` columns. +* Drop support for very old version of ``mxDateTime`` + without ``mx.`` namespace. + CI -- diff --git a/sqlobject/col.py b/sqlobject/col.py index c5bd2968..80745a24 100644 --- a/sqlobject/col.py +++ b/sqlobject/col.py @@ -46,27 +46,28 @@ try: from mx import DateTime except ImportError: - try: - # old version of mxDateTime, - # or Zope's Version if we're running with Zope - import DateTime - except ImportError: - mxdatetime_available = False - else: - mxdatetime_available = True + mxdatetime_available = False else: mxdatetime_available = True +try: + # DateTime from Zope + import DateTime +except ImportError: + zope_datetime_available = False +else: + zope_datetime_available = True + DATETIME_IMPLEMENTATION = "datetime" MXDATETIME_IMPLEMENTATION = "mxDateTime" -if mxdatetime_available: - if hasattr(DateTime, "Time"): - DateTimeType = type(DateTime.now()) - TimeType = type(DateTime.Time()) - else: # Zope - DateTimeType = type(DateTime.DateTime()) - TimeType = type(DateTime.DateTime.Time(DateTime.DateTime())) +if mxdatetime_available and hasattr(DateTime, "Time"): + DateTimeType = type(DateTime.now()) + TimeType = type(DateTime.Time()) + +elif zope_datetime_available: + DateTimeType = type(DateTime.DateTime()) + TimeType = type(DateTime.DateTime.Time(DateTime.DateTime())) __all__ = ["datetime_available", "mxdatetime_available", "default_datetime_implementation", "DATETIME_IMPLEMENTATION"] diff --git a/sqlobject/converters.py b/sqlobject/converters.py index 19b90d07..b79695fa 100644 --- a/sqlobject/converters.py +++ b/sqlobject/converters.py @@ -16,13 +16,11 @@ try: - from mx.DateTime import DateTimeType, DateTimeDeltaType + from mx.DateTime import DateTimeType as mxDateTimeType, \ + DateTimeDeltaType as mxDateTimeDeltaType except ImportError: - try: - from DateTime import DateTimeType, DateTimeDeltaType - except ImportError: - DateTimeType = None - DateTimeDeltaType = None + mxDateTimeType = None + mxDateTimeDeltaType = None try: import Sybase @@ -144,17 +142,6 @@ def FloatConverter(value, db): registerConverter(float, FloatConverter) -if DateTimeType: - def mxDateTimeConverter(value, db): - return "'%s'" % value.strftime("%Y-%m-%d %H:%M:%S") - - registerConverter(DateTimeType, mxDateTimeConverter) - - def mxTimeConverter(value, db): - return "'%s'" % value.strftime("%H:%M:%S") - - registerConverter(DateTimeDeltaType, mxTimeConverter) - def NoneConverter(value, db): return "NULL" @@ -209,6 +196,18 @@ def TimeConverterMS(value, db): registerConverter(datetime.time, TimeConverterMS) +if mxDateTimeType: + def mxDateTimeConverter(value, db): + return "'%s'" % value.strftime("%Y-%m-%d %H:%M:%S") + + registerConverter(mxDateTimeType, mxDateTimeConverter) + + def mxTimeConverter(value, db): + return "'%s'" % value.strftime("%H:%M:%S") + + registerConverter(mxDateTimeDeltaType, mxTimeConverter) + + def DecimalConverter(value, db): return value.to_eng_string() From e7b379f442a5aa8071076fd3438e9a56c0fb8eed Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 11 Dec 2020 17:08:07 +0300 Subject: [PATCH 280/509] Feat(DateTime): Extend/fix support for `DateTime` from `Zope` Refs: #161. --- devscripts/requirements/requirements.txt | 3 + docs/News.rst | 2 + sqlobject/col.py | 143 +++++++++++++++++++---- sqlobject/converters.py | 14 +++ sqlobject/tests/test_datetime.py | 37 ++++-- 5 files changed, 169 insertions(+), 30 deletions(-) diff --git a/devscripts/requirements/requirements.txt b/devscripts/requirements/requirements.txt index b8113c5c..f77d60a2 100644 --- a/devscripts/requirements/requirements.txt +++ b/devscripts/requirements/requirements.txt @@ -1,5 +1,8 @@ --install-option=-O2 +# DateTime from Zope +DateTime + FormEncode >= 1.1.1, != 1.3.0; python_version >= '2.7' and python_version < '3.0' FormEncode >= 1.3.1; python_version >= '3.4' PyDispatcher >= 2.0.4 diff --git a/docs/News.rst b/docs/News.rst index 1842d1a0..e9d02920 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -16,6 +16,8 @@ Features json.dumps/loads. A subclass of StringCol. Requires ``VARCHAR``/``TEXT`` columns at backends, doesn't work with ``JSON`` columns. +* Extend/fix support for ``DateTime`` from ``Zope``. + * Drop support for very old version of ``mxDateTime`` without ``mx.`` namespace. diff --git a/sqlobject/col.py b/sqlobject/col.py index 80745a24..cf9705de 100644 --- a/sqlobject/col.py +++ b/sqlobject/col.py @@ -44,7 +44,7 @@ datetime_available = True try: - from mx import DateTime + from mx import DateTime as mxDateTime except ImportError: mxdatetime_available = False else: @@ -52,7 +52,7 @@ try: # DateTime from Zope - import DateTime + import DateTime as zopeDateTime except ImportError: zope_datetime_available = False else: @@ -60,14 +60,14 @@ DATETIME_IMPLEMENTATION = "datetime" MXDATETIME_IMPLEMENTATION = "mxDateTime" +ZOPE_DATETIME_IMPLEMENTATION = "zopeDateTime" -if mxdatetime_available and hasattr(DateTime, "Time"): - DateTimeType = type(DateTime.now()) - TimeType = type(DateTime.Time()) +if mxdatetime_available and hasattr(mxDateTime, "Time"): + mxDateTimeType = type(mxDateTime.now()) + mxTimeType = type(mxDateTime.Time()) -elif zope_datetime_available: - DateTimeType = type(DateTime.DateTime()) - TimeType = type(DateTime.DateTime.Time(DateTime.DateTime())) +if zope_datetime_available: + zopeDateTimeType = type(zopeDateTime.DateTime()) __all__ = ["datetime_available", "mxdatetime_available", "default_datetime_implementation", "DATETIME_IMPLEMENTATION"] @@ -75,6 +75,9 @@ if mxdatetime_available: __all__.append("MXDATETIME_IMPLEMENTATION") +if zope_datetime_available: + __all__.append("ZOPE_DATETIME_IMPLEMENTATION") + default_datetime_implementation = DATETIME_IMPLEMENTATION if not PY2: @@ -1257,7 +1260,7 @@ def to_python(self, value, state): datetime.time, sqlbuilder.SQLExpression)): return value if mxdatetime_available: - if isinstance(value, DateTimeType): + if isinstance(value, mxDateTimeType): # convert mxDateTime instance to datetime if (self.format.find("%H") >= 0) or \ (self.format.find("%T")) >= 0: @@ -1267,13 +1270,23 @@ def to_python(self, value, state): int(value.second)) else: return datetime.date(value.year, value.month, value.day) - elif isinstance(value, TimeType): + elif isinstance(value, mxTimeType): # convert mxTime instance to time if self.format.find("%d") >= 0: return datetime.timedelta(seconds=value.seconds) else: return datetime.time(value.hour, value.minute, int(value.second)) + if zope_datetime_available: + if isinstance(value, zopeDateTimeType): + # convert zopeDateTime instance to datetime + if (self.format.find("%H") >= 0) or \ + (self.format.find("%T")) >= 0: + return datetime.datetime( + value.year(), value.month(), value.day(), + value.hour(), value.minute(), int(value.second())) + else: + return datetime.date(value.year, value.month, value.day) try: if self.format.find(".%f") >= 0: if '.' in value: @@ -1315,23 +1328,30 @@ def to_python(self, value, state): if value is None: return None if isinstance(value, - (DateTimeType, TimeType, sqlbuilder.SQLExpression)): + (mxDateTimeType, mxTimeType, + sqlbuilder.SQLExpression)): return value if isinstance(value, datetime.datetime): - return DateTime.DateTime(value.year, value.month, value.day, - value.hour, value.minute, - value.second) + return mxDateTime.DateTime(value.year, value.month, value.day, + value.hour, value.minute, + value.second) elif isinstance(value, datetime.date): - return DateTime.Date(value.year, value.month, value.day) + return mxDateTime.Date(value.year, value.month, value.day) elif isinstance(value, datetime.time): - return DateTime.Time(value.hour, value.minute, value.second) + return mxDateTime.Time(value.hour, value.minute, value.second) elif isinstance(value, datetime.timedelta): if value.days: raise validators.Invalid( "the value for the TimeCol '%s' must has days=0, " "it has days=%d" % (self.name, value.days), value, state) - return DateTime.Time(seconds=value.seconds) + return mxDateTime.Time(seconds=value.seconds) + if zope_datetime_available: + if isinstance(value, zopeDateTimeType): + # convert zopeDateTime instance to mxdatetime + return mxDateTime.DateTime( + value.year(), value.month(), value.day(), + value.hour(), value.minute(), int(value.second())) try: if self.format.find(".%f") >= 0: if '.' in value: @@ -1347,9 +1367,9 @@ def to_python(self, value, state): else: value += '.0' value = datetime.datetime.strptime(value, self.format) - return DateTime.DateTime(value.year, value.month, value.day, - value.hour, value.minute, - value.second) + return mxDateTime.DateTime(value.year, value.month, value.day, + value.hour, value.minute, + value.second) except Exception: raise validators.Invalid( "expected a date/time string of the '%s' format " @@ -1361,7 +1381,8 @@ def from_python(self, value, state): if value is None: return None if isinstance(value, - (DateTimeType, TimeType, sqlbuilder.SQLExpression)): + (mxDateTimeType, mxTimeType, + sqlbuilder.SQLExpression)): return value if hasattr(value, "strftime"): return value.strftime(self.format) @@ -1371,6 +1392,76 @@ def from_python(self, value, state): self.name, type(value), value), value, state) +if zope_datetime_available: + class ZopeDateTimeValidator(validators.DateValidator): + def to_python(self, value, state): + if value is None: + return None + if isinstance(value, + (zopeDateTimeType, sqlbuilder.SQLExpression)): + return value + if isinstance(value, datetime.datetime): + return zopeDateTime.DateTime( + value.year, value.month, value.day, + value.hour, value.minute, value.second) + elif isinstance(value, datetime.date): + return zopeDateTime.DateTime( + value.year, value.month, value.day) + elif isinstance(value, datetime.time): + return zopeDateTime.DateTime( + value.hour, value.minute, value.second) + elif isinstance(value, datetime.timedelta): + if value.days: + raise validators.Invalid( + "the value for the TimeCol '%s' must has days=0, " + "it has days=%d" % (self.name, value.days), + value, state) + return zopeDateTime.DateTime(seconds=value.seconds) + if mxdatetime_available: + if isinstance(value, mxDateTimeType): + # convert mxDateTime instance to zopeDateTime + return zopeDateTime.DateTime( + value.year, value.month, value.day, + value.hour, value.minute, value.second) + try: + if self.format.find(".%f") >= 0: + if '.' in value: + _value = value.split('.') + microseconds = _value[-1] + _l = len(microseconds) + if _l < 6: + _value[-1] = microseconds + '0' * (6 - _l) + elif _l > 6: + _value[-1] = microseconds[:6] + if _l != 6: + value = '.'.join(_value) + else: + value += '.0' + value = datetime.datetime.strptime(value, self.format) + return zopeDateTime.DateTime( + value.year, value.month, value.day, + value.hour, value.minute, value.second) + except Exception: + raise validators.Invalid( + "expected a date/time string of the '%s' format " + "in the DateTimeCol '%s', got %s %r instead" % ( + self.format, self.name, type(value), value), + value, state) + + def from_python(self, value, state): + if value is None: + return None + if isinstance(value, + (zopeDateTimeType, sqlbuilder.SQLExpression)): + return value + if hasattr(value, "strftime"): + return value.strftime(self.format) + raise validators.Invalid( + "expected a zopeDateTime in the DateTimeCol '%s', " + "got %s %r instead" % ( + self.name, type(value), value), value, state) + + class SODateTimeCol(SOCol): datetimeFormat = '%Y-%m-%d %H:%M:%S.%f' @@ -1386,6 +1477,8 @@ def createValidators(self): validatorClass = DateTimeValidator elif default_datetime_implementation == MXDATETIME_IMPLEMENTATION: validatorClass = MXDateTimeValidator + elif default_datetime_implementation == ZOPE_DATETIME_IMPLEMENTATION: + validatorClass = ZopeDateTimeValidator if default_datetime_implementation: _validators.insert(0, validatorClass(name=self.name, format=self.datetimeFormat)) @@ -1427,7 +1520,9 @@ def now(): if default_datetime_implementation == DATETIME_IMPLEMENTATION: return datetime.datetime.now() elif default_datetime_implementation == MXDATETIME_IMPLEMENTATION: - return DateTime.now() + return mxDateTime.now() + elif default_datetime_implementation == ZOPE_DATETIME_IMPLEMENTATION: + return zopeDateTime.DateTimr() else: assert 0, ("No datetime implementation available " "(DATETIME_IMPLEMENTATION=%r)" @@ -1468,6 +1563,8 @@ def createValidators(self): validatorClass = DateValidator elif default_datetime_implementation == MXDATETIME_IMPLEMENTATION: validatorClass = MXDateTimeValidator + elif default_datetime_implementation == ZOPE_DATETIME_IMPLEMENTATION: + validatorClass = ZopeDateTimeValidator if default_datetime_implementation: _validators.insert(0, validatorClass(name=self.name, format=self.dateFormat)) @@ -1538,6 +1635,8 @@ def createValidators(self): validatorClass = TimeValidator elif default_datetime_implementation == MXDATETIME_IMPLEMENTATION: validatorClass = MXDateTimeValidator + elif default_datetime_implementation == ZOPE_DATETIME_IMPLEMENTATION: + validatorClass = ZopeDateTimeValidator if default_datetime_implementation: _validators.insert(0, validatorClass(name=self.name, format=self.timeFormat)) diff --git a/sqlobject/converters.py b/sqlobject/converters.py index b79695fa..fa6ea1c0 100644 --- a/sqlobject/converters.py +++ b/sqlobject/converters.py @@ -22,6 +22,13 @@ mxDateTimeType = None mxDateTimeDeltaType = None +try: + from DateTime import DateTime as zopeDateTime +except ImportError: + zopeDateTimeType = None +else: + zopeDateTimeType = type(zopeDateTime()) + try: import Sybase NumericType = Sybase.NumericType @@ -208,6 +215,13 @@ def mxTimeConverter(value, db): registerConverter(mxDateTimeDeltaType, mxTimeConverter) +if zopeDateTimeType: + def zopeDateTimeConverter(value, db): + return "'%s'" % value.strftime("%Y-%m-%d %H:%M:%S") + + registerConverter(zopeDateTimeType, zopeDateTimeConverter) + + def DecimalConverter(value, db): return value.to_eng_string() diff --git a/sqlobject/tests/test_datetime.py b/sqlobject/tests/test_datetime.py index df9bbc3a..06ce1ae6 100644 --- a/sqlobject/tests/test_datetime.py +++ b/sqlobject/tests/test_datetime.py @@ -3,8 +3,9 @@ from sqlobject import SQLObject from sqlobject import col -from sqlobject.col import DATETIME_IMPLEMENTATION, DateCol, DateTimeCol, \ - MXDATETIME_IMPLEMENTATION, TimeCol, mxdatetime_available, use_microseconds +from sqlobject.col import DateCol, DateTimeCol, TimeCol, use_microseconds, \ + DATETIME_IMPLEMENTATION, MXDATETIME_IMPLEMENTATION, mxdatetime_available, \ + ZOPE_DATETIME_IMPLEMENTATION, zope_datetime_available from sqlobject.tests.dbtest import getConnection, setupClass @@ -82,7 +83,7 @@ def test_microseconds(): if mxdatetime_available: col.default_datetime_implementation = MXDATETIME_IMPLEMENTATION - from mx.DateTime import now, Time + from mx.DateTime import now as mx_now, Time as mxTime dateFormat = None # use default try: @@ -104,11 +105,11 @@ class DateTime2(SQLObject): def test_mxDateTime(): setupClass(DateTime2) - _now = now() + _now = mx_now() dt2 = DateTime2(col1=_now, col2=_now.pydate(), - col3=Time(_now.hour, _now.minute, _now.second)) + col3=mxTime(_now.hour, _now.minute, _now.second)) - assert isinstance(dt2.col1, col.DateTimeType) + assert isinstance(dt2.col1, col.mxDateTimeType) assert dt2.col1.year == _now.year assert dt2.col1.month == _now.month assert dt2.col1.day == _now.day @@ -116,7 +117,7 @@ def test_mxDateTime(): assert dt2.col1.minute == _now.minute assert dt2.col1.second == int(_now.second) - assert isinstance(dt2.col2, col.DateTimeType) + assert isinstance(dt2.col2, col.mxDateTimeType) assert dt2.col2.year == _now.year assert dt2.col2.month == _now.month assert dt2.col2.day == _now.day @@ -124,7 +125,27 @@ def test_mxDateTime(): assert dt2.col2.minute == 0 assert dt2.col2.second == 0 - assert isinstance(dt2.col3, (col.DateTimeType, col.TimeType)) + assert isinstance(dt2.col3, (col.mxDateTimeType, col.mxTimeType)) assert dt2.col3.hour == _now.hour assert dt2.col3.minute == _now.minute assert dt2.col3.second == int(_now.second) + +if zope_datetime_available: + col.default_datetime_implementation = ZOPE_DATETIME_IMPLEMENTATION + from DateTime import DateTime as zopeDateTime + + class DateTime3(SQLObject): + col1 = DateTimeCol() + + def test_ZopeDateTime(): + setupClass(DateTime3) + _now = zopeDateTime() + dt3 = DateTime3(col1=_now) + + assert isinstance(dt3.col1, col.zopeDateTimeType) + assert dt3.col1.year() == _now.year() + assert dt3.col1.month() == _now.month() + assert dt3.col1.day() == _now.day() + assert dt3.col1.hour() == _now.hour() + assert dt3.col1.minute() == _now.minute() + assert int(dt3.col1.second()) == int(_now.second()) From 11247f12ca31106288caf51fdf2cb1b2de92dd6b Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 13 Dec 2020 02:31:05 +0300 Subject: [PATCH 281/509] Test(devscripts/test-sqlobject.cmd): Run tests with Python 3.9 [skip ci] --- devscripts/test-sqlobject.cmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devscripts/test-sqlobject.cmd b/devscripts/test-sqlobject.cmd index 53b7cab5..97846d80 100644 --- a/devscripts/test-sqlobject.cmd +++ b/devscripts/test-sqlobject.cmd @@ -3,7 +3,7 @@ SetLocal EnableDelayedExpansion set SavePATH=%PATH% -for %%V in (27 34 35 36 37 38) do ( +for %%V in (27 34 35 36 37 38 39) do ( for %%s in (32 64) do ( set PATH=C:\Python%%V-%%s;C:\Python%%V-%%s\Scripts;!SavePATH! set TOXPYTHON=C:\Python%%V-%%s\python.exe From 805632876ff07142ed0f71b4b557a878e805d370 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 12 Dec 2020 19:16:02 +0300 Subject: [PATCH 282/509] Feat(mysql): Support `mariadb` --- .travis.yml | 8 ++++ appveyor.yml | 20 ++++++++ docs/News.rst | 5 ++ docs/SQLObject.rst | 26 ++++++----- sqlobject/mysql/mysqlconnection.py | 38 +++++++++++---- tox.ini | 75 ++++++++++++++++++++++++++++++ 6 files changed, 152 insertions(+), 20 deletions(-) diff --git a/.travis.yml b/.travis.yml index 71cc4c2b..c5e810fa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -39,6 +39,14 @@ matrix: env: TESTS=py38-mysql - python: "3.9" env: TESTS=py39-mysql + - python: "3.6" + env: TESTS=py36-mariadb + - python: "3.7" + env: TESTS=py37-mariadb + - python: "3.8" + env: TESTS=py38-mariadb + - python: "3.9" + env: TESTS=py39-mariadb - python: "2.7" env: TESTS=py27-postgres - python: "3.4" diff --git a/appveyor.yml b/appveyor.yml index 537ec564..84c56d4d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -52,6 +52,26 @@ environment: PYTHON_VERSION: "3.9" PYTHON_HOME: "C:\\Python39-x64" db: mysql + - TESTS: "py36-mariadb" + PYTHON_ARCH: "64" + PYTHON_VERSION: "3.6" + PYTHON_HOME: "C:\\Python36-x64" + db: mysql + - TESTS: "py37-mariadb" + PYTHON_ARCH: "64" + PYTHON_VERSION: "3.7" + PYTHON_HOME: "C:\\Python37-x64" + db: mysql + - TESTS: "py38-mariadb" + PYTHON_ARCH: "64" + PYTHON_VERSION: "3.8" + PYTHON_HOME: "C:\\Python38-x64" + db: mysql + - TESTS: "py39-mariadb" + PYTHON_ARCH: "64" + PYTHON_VERSION: "3.9" + PYTHON_HOME: "C:\\Python39-x64" + db: mysql - TESTS: "py27-postgres" PYTHON_ARCH: "32" PYTHON_VERSION: "2.7" diff --git a/docs/News.rst b/docs/News.rst index e9d02920..253ef84b 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -21,6 +21,11 @@ Features * Drop support for very old version of ``mxDateTime`` without ``mx.`` namespace. +Drivers +------- + +* Support ``mariadb``. + CI -- diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index c3f19576..ddbe2c5d 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -46,23 +46,25 @@ used with the same query syntax. Requirements ============ -Currently SQLObject supports MySQL_ via MySQLdb_ aka MySQL-python (called -mysqlclient_ for Python 3), `MySQL Connector`_, oursql_, PyMySQL_, PyODBC_ -and PyPyODBC_. For PostgreSQL_ psycopg2_ is recommended; PyGreSQL_, -py-postgresql_ and pg8000_ are supported; SQLite_ has a built-in driver, -PySQLite_ or supersqlite_. Firebird_ is supported via fdb_ or kinterbasdb_; -pyfirebirdsql_ is supported but has problems. `MAX DB`_ (also known as SAP -DB) is supported via sapdb_. Sybase via Sybase_. `MSSQL Server`_ via -pymssql_ (+ FreeTDS_) or adodbapi_ (Win32). PyODBC_ and PyPyODBC_ are -supported for MySQL, PostgreSQL and MSSQL but have problems (not all tests -passed). +Currently SQLObject supports MySQL_ and MariaDB_ via MySQLdb_ aka +MySQL-python (called mysqlclient_ for Python 3), `MySQL Connector`_, +oursql_, PyMySQL_, `mariadb connector`_, PyODBC_ and PyPyODBC_. For +PostgreSQL_ psycopg2_ is recommended; PyGreSQL_, py-postgresql_ and pg8000_ +are supported; SQLite_ has a built-in driver, PySQLite_ or supersqlite_. +Firebird_ is supported via fdb_ or kinterbasdb_; pyfirebirdsql_ is +supported but has problems. `MAX DB`_ (also known as SAP DB) is supported +via sapdb_. Sybase via Sybase_. `MSSQL Server`_ via pymssql_ (+ FreeTDS_) +or adodbapi_ (Win32). PyODBC_ and PyPyODBC_ are supported for MySQL, +PostgreSQL and MSSQL but have problems (not all tests passed). .. _MySQL: https://www.mysql.com/ +.. _MariaDB: https://mariadb.org/ .. _MySQLdb: https://sourceforge.net/projects/mysql-python/ .. _mysqlclient: https://pypi.org/project/mysqlclient/ .. _`MySQL Connector`: https://pypi.org/project/mysql-connector/ .. _oursql: https://github.com/python-oursql/oursql .. _PyMySQL: https://github.com/PyMySQL/PyMySQL/ +.. _mariadb connector: https://pypi.org/project/mariadb/ .. _PostgreSQL: https://postgresql.org .. _psycopg2: http://initd.org/psycopg/ .. _PyGreSQL: http://www.pygresql.org/ @@ -1788,8 +1790,8 @@ MySQLConnection supports all the features, though MySQL only supports transactions_ when using the InnoDB backend; SQLObject can explicitly define the backend using ``sqlmeta.createSQL``. -Supported drivers are ``mysqldb``, ``connector``, ``oursql`` and -``pymysql``, ``pyodbc``, ``pypyodbc`` or ``odbc`` (try ``pyodbc`` and +Supported drivers are ``mysqldb``, ``connector``, ``oursql``, ``pymysql`` +and ``mariadb``, ``pyodbc``, ``pypyodbc`` or ``odbc`` (try ``pyodbc`` and ``pypyodbc``); defualt is ``mysqldb``. diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index 16bd4b0f..95d6b58e 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -5,7 +5,10 @@ class ErrorMessage(str): def __new__(cls, e, append_msg=''): - obj = str.__new__(cls, e.args[1] + append_msg) + if len(e.args) > 1: + obj = str.__new__(cls, e.args[1] + append_msg) + else: + obj = str.__new__(cls, append_msg) try: obj.code = int(e.args[0]) except ValueError: @@ -70,6 +73,9 @@ def __init__(self, db, user, password='', host='localhost', port=0, **kw): oursql.errnos['CR_SERVER_GONE_ERROR'] self.CR_SERVER_LOST = oursql.errnos['CR_SERVER_LOST'] self.ER_DUP_ENTRY = oursql.errnos['ER_DUP_ENTRY'] + elif driver == 'mariadb': + import mariadb + self.module = mariadb elif driver == 'pyodbc': import pyodbc self.module = pyodbc @@ -86,7 +92,7 @@ def __init__(self, db, user, password='', host='localhost', port=0, **kw): raise ValueError( 'Unknown MySQL driver "%s", ' 'expected mysqldb, connector, ' - 'oursql, pymysql, ' + 'oursql, pymysql, mariadb, ' 'odbc, pyodbc or pypyodbc' % driver) except ImportError: pass @@ -125,21 +131,26 @@ def __init__(self, db, user, password='', host='localhost', port=0, **kw): self.dbEncoding = None self.driver = driver + if driver in ('mariadb', 'odbc', 'pyodbc', 'pypyodbc'): + self.CR_SERVER_GONE_ERROR = 2006 + self.CR_SERVER_LOST = 2013 + self.ER_DUP_ENTRY = '23000' + if driver in ('odbc', 'pyodbc', 'pypyodbc'): self.make_odbc_conn_str(kw.pop('odbcdrv', 'MySQL ODBC 5.3 ANSI Driver'), db, host, port, user, password ) - self.CR_SERVER_GONE_ERROR = 2006 - self.CR_SERVER_LOST = 2013 - self.ER_DUP_ENTRY = '23000' - elif self.driver == 'oursql': + elif driver == 'oursql': if "use_unicode" not in self.kw: self.kw["use_unicode"] = not PY2 # oursql doesn't implement ping(True) yet self.kw["autoreconnect"] = True + elif driver == 'mariadb': + self.kw.pop("charset", None) + global mysql_Bin if not PY2 and mysql_Bin is None: mysql_Bin = self.module.Binary @@ -179,7 +190,13 @@ def character_set_name(self): conn = self.module.connect( host=self.host, port=self.port, db=self.db, user=self.user, passwd=self.password, **self.kw) - if self.driver != 'oursql': + if self.driver == 'mariadb': + # Attempt to reconnect. + # This setting is persistent due to ``auto_reconnect``. + # mariadb doesn't implement ping(True) + conn.auto_reconnect = True + conn.ping() + elif self.driver != 'oursql': # Attempt to reconnect. This setting is persistent. conn.ping(True) except self.module.OperationalError as e: @@ -229,7 +246,7 @@ def _executeRetry(self, conn, cursor, query): self.printDebug(conn, query, 'QueryR') dbEncoding = self.dbEncoding if dbEncoding and not isinstance(query, bytes) and ( - self.driver in ('mysqldb', 'connector', 'oursql')): + self.driver in ('mysqldb', 'connector', 'oursql', 'mariadb')): query = query.encode(dbEncoding, 'surrogateescape') # When a server connection is lost and a query is attempted, most of # the time the query will raise a SERVER_LOST exception, then at the @@ -263,6 +280,9 @@ def _executeRetry(self, conn, cursor, query): msg = ErrorMessage(e) if e.args[0] == self.ER_DUP_ENTRY: raise dberrors.DuplicateEntryError(msg) + elif isinstance(e.args[0], str) \ + and e.args[0].startswith('Duplicate'): + raise dberrors.DuplicateEntryError(msg) else: raise dberrors.IntegrityError(msg) except self.module.InternalError as e: @@ -345,6 +365,8 @@ def tableExists(self, tableName): except dberrors.ProgrammingError as e: if e.args[0].code in (1146, '42S02'): # ER_NO_SUCH_TABLE return False + if self.driver == 'mariadb': + return False raise def addColumn(self, tableName, column): diff --git a/tox.ini b/tox.ini index f0fc2b23..e8893f32 100644 --- a/tox.ini +++ b/tox.ini @@ -25,6 +25,7 @@ deps = mysql-oursql: git+https://github.com/sqlobject/oursql.git@master#egg=oursql mysql-oursql3: git+https://github.com/sqlobject/oursql.git@py3k#egg=oursql pymysql: pymysql + mariadb: mariadb postgres-psycopg: psycopg2-binary pygresql: -rdevscripts/requirements/requirements_pygresql.txt pypostgresql: git+https://github.com/sqlobject/py-postgresql.git@fix_w32#egg=pypostgresql @@ -208,6 +209,38 @@ commands = {[pymysql]commands} [testenv:py39-mysql-pymysql] commands = {[pymysql]commands} +[mariadb] +commands = + {[testenv]commands} + -mysql -uroot -e 'drop database sqlobject_test;' + mysql -uroot -e 'create database sqlobject_test;' + pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=mariadb&charset=utf8&debug=1 + mysql -uroot -e 'drop database sqlobject_test;' + +[testenv:py27-mariadb] +commands = {envpython} -c "print('mariadb requires Python 3.6+')" +deps = + +[testenv:py34-mariadb] +commands = {envpython} -c "print('mariadb requires Python 3.6+')" +deps = + +[testenv:py35-mariadb] +commands = {envpython} -c "print('mariadb requires Python 3.6+')" +deps = + +[testenv:py36-mariadb] +commands = {[mariadb]commands} + +[testenv:py37-mariadb] +commands = {[mariadb]commands} + +[testenv:py38-mariadb] +commands = {[mariadb]commands} + +[testenv:py39-mariadb] +commands = {[mariadb]commands} + [mysql-pyodbc] commands = {[testenv]commands} @@ -793,6 +826,48 @@ commands = {[pymysql-w32]commands} platform = win32 commands = {[pymysql-w32]commands} +[mariadb-w32] +platform = win32 +commands = + {[testenv]commands} + -mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' + mysql -u root "-pPassword12!" -e 'create database sqlobject_test;' + pytest --cov=sqlobject -D "mysql://root:Password12!@localhost/sqlobject_test?driver=mariadb&charset=utf8&debug=1" + mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' + +[testenv:py27-mariadb-w32] +platform = win32 +commands = {envpython} -c "print('mariadb requires Python 3.6+')" +deps = + +[testenv:py34-mariadb-w32] +platform = win32 +commands = {envpython} -c "print('mariadb requires Python 3.6+')" +deps = + +[testenv:py35-mariadb-w32] +platform = win32 +commands = {envpython} -c "print('mariadb requires Python 3.6+')" +deps = + +[testenv:py36-mariadb-w32] +platform = win32 +commands = {[mariadb-w32]commands} + +[testenv:py37-mariadb-w32] +platform = win32 +commands = + cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" + {[mariadb-w32]commands} + +[testenv:py38-mariadb-w32] +platform = win32 +commands = {[mariadb-w32]commands} + +[testenv:py39-mariadb-w32] +platform = win32 +commands = {[mariadb-w32]commands} + [mysql-pyodbc-w32] platform = win32 commands = From fb39c1809498fbb93e5e6dbf23391b8aaaa7efc0 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 13 Dec 2020 15:38:49 +0300 Subject: [PATCH 283/509] CI(Travis): Install mysql-compatible development files Install MariaDB mysql-compatible development files to compile mysql drivers. --- .travis.yml | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index c5e810fa..9fddebe6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,13 +14,6 @@ services: - postgres addons: - apt: - packages: - - python-egenix-mxdatetime - - python-mysqldb - - python-psycopg2 - - python3-psycopg2 - - firebird2.5-super postgresql: "9.4" matrix: @@ -41,12 +34,16 @@ matrix: env: TESTS=py39-mysql - python: "3.6" env: TESTS=py36-mariadb + dist: focal - python: "3.7" env: TESTS=py37-mariadb + dist: focal - python: "3.8" env: TESTS=py38-mariadb + dist: focal - python: "3.9" env: TESTS=py39-mariadb + dist: focal - python: "2.7" env: TESTS=py27-postgres - python: "3.4" @@ -89,7 +86,20 @@ matrix: - env: TESTS=py36-firebird before_install: - # Start the firebird database server. + # Install version-specific dependencies + - if [[ $TESTS = py27-* ]]; then + sudo apt-get --quiet --yes install python-egenix-mxdatetime python-mysqldb python-psycopg2; + fi + - if [[ $TESTS = py3*-* ]]; then + sudo apt-get --quiet --yes install python3-mysqldb python3-psycopg2; + fi + # Install MariaDB mysql-compatible development files to compile mysql drivers + - if [[ $TESTS = py3[6789]-mysql ]]; then + sudo apt-get --quiet --yes install libmysqlclient-dev; + elif [[ $TESTS = py3[6789]-mariadb ]]; then + sudo apt-get --quiet --yes install libmariadb-dev-compat; + fi + # Install and start the firebird database server. # We use firebird-super, so there's none of the inetd configuration # required by firebird-classic. # We also create a test user for the firebird test and @@ -98,6 +108,7 @@ before_install: # Copied password initializtion from # https://github.com/xdenser/node-firebird-libfbclient/blob/master/.travis.yml - if [[ $TESTS = *firebird* ]]; then + sudo apt-get --quiet --yes install firebird2.5-super && sudo sed -i /etc/default/firebird2.5 -e 's/=no/=yes/' && sudo /etc/init.d/firebird2.5-super start && sleep 5 && sudo /bin/bash -c '(export FB_VER="2.5"; export FB_FLAVOUR="super";source /usr/share/firebird2.5-common/functions.sh; writeNewPassword masterkey)' && From ed8dd808114faace25c01ead78ae83f2ca09ceb9 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 14 Dec 2020 00:55:57 +0300 Subject: [PATCH 284/509] Test(tox): Skip tests with `mysql-connector` and `oursql` On newer Ubuntu (`focal`) they exhibit problems. Need investigation. --- tox.ini | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/tox.ini b/tox.ini index e8893f32..5fd8c596 100644 --- a/tox.ini +++ b/tox.ini @@ -124,27 +124,27 @@ commands = pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=connector&charset=utf8&debug=1 mysql -uroot -e 'drop database sqlobject_test;' -[testenv:py27-mysql-connector] +[testenv:py27-mysql-connector-noauto] commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-connector]commands} -[testenv:py34-mysql-connector] +[testenv:py34-mysql-connector-noauto] commands = {[mysql-connector]commands} -[testenv:py35-mysql-connector] +[testenv:py35-mysql-connector-noauto] commands = {[mysql-connector]commands} -[testenv:py36-mysql-connector] +[testenv:py36-mysql-connector-noauto] commands = {[mysql-connector]commands} -[testenv:py37-mysql-connector] +[testenv:py37-mysql-connector-noauto] commands = {[mysql-connector]commands} -[testenv:py38-mysql-connector] +[testenv:py38-mysql-connector-noauto] commands = {[mysql-connector]commands} -[testenv:py39-mysql-connector] +[testenv:py39-mysql-connector-noauto] commands = {[mysql-connector]commands} [oursql] @@ -155,27 +155,27 @@ commands = pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=oursql&charset=utf8&debug=1 mysql -uroot -e 'drop database sqlobject_test;' -[testenv:py27-mysql-oursql] +[testenv:py27-mysql-oursql-noauto] commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[oursql]commands} -[testenv:py34-mysql-oursql3] +[testenv:py34-mysql-oursql3-noauto] commands = {[oursql]commands} -[testenv:py35-mysql-oursql3] +[testenv:py35-mysql-oursql3-noauto] commands = {[oursql]commands} -[testenv:py36-mysql-oursql3] +[testenv:py36-mysql-oursql3-noauto] commands = {[oursql]commands} -[testenv:py37-mysql-oursql3] +[testenv:py37-mysql-oursql3-noauto] commands = {[oursql]commands} -[testenv:py38-mysql-oursql3] +[testenv:py38-mysql-oursql3-noauto] commands = {[oursql]commands} -[testenv:py39-mysql-oursql3] +[testenv:py39-mysql-oursql3-noauto] commands = {[oursql]commands} [pymysql] From 27239030fc3098b9653b036f8f95cb17460bcd71 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 14 Dec 2020 01:14:16 +0300 Subject: [PATCH 285/509] Test(tox): Do not restore `validators.py` It seems we no longer need the hack at AppVeyor. --- devscripts/CI/validators.py | 3089 ----------------------------------- tox.ini | 56 +- 2 files changed, 14 insertions(+), 3131 deletions(-) delete mode 100644 devscripts/CI/validators.py diff --git a/devscripts/CI/validators.py b/devscripts/CI/validators.py deleted file mode 100644 index 233d5dd5..00000000 --- a/devscripts/CI/validators.py +++ /dev/null @@ -1,3089 +0,0 @@ -## FormEncode, a Form processor -## Copyright (C) 2003, Ian Bicking - -""" -Validator/Converters for use with FormEncode. -""" - -import cgi -import locale -import re -import warnings -from encodings import idna - -try: # import dnspython - import dns.resolver - import dns.exception -except (IOError, ImportError): - have_dns = False -else: - have_dns = True - - -# These are only imported when needed -httplib = None -random = None -sha1 = None -socket = None -urlparse = None - -from .api import (FancyValidator, Identity, Invalid, NoDefault, Validator, - deprecation_warning, is_empty) - -assert Identity and Invalid and NoDefault # silence unused import warnings - -# Dummy i18n translation function, nothing is translated here. -# Instead this is actually done in api.message. -# The surrounding _('string') of the strings is only for extracting -# the strings automatically. -# If you run pygettext with this source comment this function out temporarily. -_ = lambda s: s - - -############################################################ -## Utility methods -############################################################ - -# These all deal with accepting both datetime and mxDateTime modules and types -datetime_module = None -mxDateTime_module = None - - -def import_datetime(module_type): - global datetime_module, mxDateTime_module - module_type = module_type.lower() if module_type else 'datetime' - if module_type == 'datetime': - if datetime_module is None: - import datetime as datetime_module - return datetime_module - elif module_type == 'mxdatetime': - if mxDateTime_module is None: - from mx import DateTime as mxDateTime_module - return mxDateTime_module - else: - raise ImportError('Invalid datetime module %r' % module_type) - - -def datetime_now(module): - if module.__name__ == 'datetime': - return module.datetime.now() - else: - return module.now() - - -def datetime_makedate(module, year, month, day): - if module.__name__ == 'datetime': - return module.date(year, month, day) - else: - try: - return module.DateTime(year, month, day) - except module.RangeError as e: - raise ValueError(str(e)) - - -def datetime_time(module): - if module.__name__ == 'datetime': - return module.time - else: - return module.Time - - -def datetime_isotime(module): - if module.__name__ == 'datetime': - return module.time.isoformat - else: - return module.ISO.Time - - -############################################################ -## Wrapper Validators -############################################################ - -class ConfirmType(FancyValidator): - """ - Confirms that the input/output is of the proper type. - - Uses the parameters: - - subclass: - The class or a tuple of classes; the item must be an instance - of the class or a subclass. - type: - A type or tuple of types (or classes); the item must be of - the exact class or type. Subclasses are not allowed. - - Examples:: - - >>> cint = ConfirmType(subclass=int) - >>> cint.to_python(True) - True - >>> cint.to_python('1') - Traceback (most recent call last): - ... - Invalid: '1' is not a subclass of - >>> cintfloat = ConfirmType(subclass=(float, int)) - >>> cintfloat.to_python(1.0), cintfloat.from_python(1.0) - (1.0, 1.0) - >>> cintfloat.to_python(1), cintfloat.from_python(1) - (1, 1) - >>> cintfloat.to_python(None) - Traceback (most recent call last): - ... - Invalid: None is not a subclass of one of the types , - >>> cint2 = ConfirmType(type=int) - >>> cint2(accept_python=False).from_python(True) - Traceback (most recent call last): - ... - Invalid: True must be of the type - """ - - accept_iterator = True - - subclass = None - type = None - - messages = dict( - subclass=_('%(object)r is not a subclass of %(subclass)s'), - inSubclass=_('%(object)r is not a subclass of one of the types %(subclassList)s'), - inType=_('%(object)r must be one of the types %(typeList)s'), - type=_('%(object)r must be of the type %(type)s')) - - def __init__(self, *args, **kw): - FancyValidator.__init__(self, *args, **kw) - if self.subclass: - if isinstance(self.subclass, list): - self.subclass = tuple(self.subclass) - elif not isinstance(self.subclass, tuple): - self.subclass = (self.subclass,) - self._validate_python = self.confirm_subclass - if self.type: - if isinstance(self.type, list): - self.type = tuple(self.type) - elif not isinstance(self.type, tuple): - self.type = (self.type,) - self._validate_python = self.confirm_type - - def confirm_subclass(self, value, state): - if not isinstance(value, self.subclass): - if len(self.subclass) == 1: - msg = self.message('subclass', state, object=value, - subclass=self.subclass[0]) - else: - subclass_list = ', '.join(map(str, self.subclass)) - msg = self.message('inSubclass', state, object=value, - subclassList=subclass_list) - raise Invalid(msg, value, state) - - def confirm_type(self, value, state): - for t in self.type: - if type(value) is t: - break - else: - if len(self.type) == 1: - msg = self.message('type', state, object=value, - type=self.type[0]) - else: - msg = self.message('inType', state, object=value, - typeList=', '.join(map(str, self.type))) - raise Invalid(msg, value, state) - return value - - def is_empty(self, value): - return False - - -class Wrapper(FancyValidator): - """ - Used to convert functions to validator/converters. - - You can give a simple function for `_convert_to_python`, - `_convert_from_python`, `_validate_python` or `_validate_other`. - If that function raises an exception, the value is considered invalid. - Whatever value the function returns is considered the converted value. - - Unlike validators, the `state` argument is not used. Functions - like `int` can be used here, that take a single argument. - - Note that as Wrapper will generate a FancyValidator, empty - values (those who pass ``FancyValidator.is_empty)`` will return ``None``. - To override this behavior you can use ``Wrapper(empty_value=callable)``. - For example passing ``Wrapper(empty_value=lambda val: val)`` will return - the value itself when is considered empty. - - Examples:: - - >>> def downcase(v): - ... return v.lower() - >>> wrap = Wrapper(convert_to_python=downcase) - >>> wrap.to_python('This') - 'this' - >>> wrap.from_python('This') - 'This' - >>> wrap.to_python('') is None - True - >>> wrap2 = Wrapper( - ... convert_from_python=downcase, empty_value=lambda value: value) - >>> wrap2.from_python('This') - 'this' - >>> wrap2.to_python('') - '' - >>> wrap2.from_python(1) - Traceback (most recent call last): - ... - Invalid: 'int' object has no attribute 'lower' - >>> wrap3 = Wrapper(validate_python=int) - >>> wrap3.to_python('1') - '1' - >>> wrap3.to_python('a') # doctest: +ELLIPSIS - Traceback (most recent call last): - ... - Invalid: invalid literal for int()... - """ - - func_convert_to_python = None - func_convert_from_python = None - func_validate_python = None - func_validate_other = None - - _deprecated_methods = ( - ('func_to_python', 'func_convert_to_python'), - ('func_from_python', 'func_convert_from_python')) - - def __init__(self, *args, **kw): - # allow old method names as parameters - if 'to_python' in kw and 'convert_to_python' not in kw: - kw['convert_to_python'] = kw.pop('to_python') - if 'from_python' in kw and 'convert_from_python' not in kw: - kw['convert_from_python'] = kw.pop('from_python') - for n in ('convert_to_python', 'convert_from_python', - 'validate_python', 'validate_other'): - if n in kw: - kw['func_%s' % n] = kw.pop(n) - FancyValidator.__init__(self, *args, **kw) - self._convert_to_python = self.wrap(self.func_convert_to_python) - self._convert_from_python = self.wrap(self.func_convert_from_python) - self._validate_python = self.wrap(self.func_validate_python) - self._validate_other = self.wrap(self.func_validate_other) - - def wrap(self, func): - if not func: - return None - - def result(value, state, func=func): - try: - return func(value) - except Exception as e: - raise Invalid(str(e), value, state) - - return result - - -class Constant(FancyValidator): - """ - This converter converts everything to the same thing. - - I.e., you pass in the constant value when initializing, then all - values get converted to that constant value. - - This is only really useful for funny situations, like:: - - # Any evaluates sub validators in reverse order for to_python - fromEmailValidator = Any( - Constant('unknown@localhost'), - Email()) - - In this case, the if the email is not valid - ``'unknown@localhost'`` will be used instead. Of course, you - could use ``if_invalid`` instead. - - Examples:: - - >>> Constant('X').to_python('y') - 'X' - """ - - __unpackargs__ = ('value',) - - def _convert_to_python(self, value, state): - return self.value - - _convert_from_python = _convert_to_python - - -############################################################ -## Normal validators -############################################################ - -class MaxLength(FancyValidator): - """ - Invalid if the value is longer than `maxLength`. Uses len(), - so it can work for strings, lists, or anything with length. - - Examples:: - - >>> max5 = MaxLength(5) - >>> max5.to_python('12345') - '12345' - >>> max5.from_python('12345') - '12345' - >>> max5.to_python('123456') - Traceback (most recent call last): - ... - Invalid: Enter a value less than 5 characters long - >>> max5(accept_python=False).from_python('123456') - Traceback (most recent call last): - ... - Invalid: Enter a value less than 5 characters long - >>> max5.to_python([1, 2, 3]) - [1, 2, 3] - >>> max5.to_python([1, 2, 3, 4, 5, 6]) - Traceback (most recent call last): - ... - Invalid: Enter a value less than 5 characters long - >>> max5.to_python(5) - Traceback (most recent call last): - ... - Invalid: Invalid value (value with length expected) - """ - - __unpackargs__ = ('maxLength',) - - messages = dict( - tooLong=_('Enter a value less than %(maxLength)i characters long'), - invalid=_('Invalid value (value with length expected)')) - - def _validate_python(self, value, state): - try: - if value and len(value) > self.maxLength: - raise Invalid( - self.message('tooLong', state, - maxLength=self.maxLength), value, state) - else: - return None - except TypeError: - raise Invalid( - self.message('invalid', state), value, state) - - -class MinLength(FancyValidator): - """ - Invalid if the value is shorter than `minlength`. Uses len(), so - it can work for strings, lists, or anything with length. Note - that you **must** use ``not_empty=True`` if you don't want to - accept empty values -- empty values are not tested for length. - - Examples:: - - >>> min5 = MinLength(5) - >>> min5.to_python('12345') - '12345' - >>> min5.from_python('12345') - '12345' - >>> min5.to_python('1234') - Traceback (most recent call last): - ... - Invalid: Enter a value at least 5 characters long - >>> min5(accept_python=False).from_python('1234') - Traceback (most recent call last): - ... - Invalid: Enter a value at least 5 characters long - >>> min5.to_python([1, 2, 3, 4, 5]) - [1, 2, 3, 4, 5] - >>> min5.to_python([1, 2, 3]) - Traceback (most recent call last): - ... - Invalid: Enter a value at least 5 characters long - >>> min5.to_python(5) - Traceback (most recent call last): - ... - Invalid: Invalid value (value with length expected) - - """ - - __unpackargs__ = ('minLength',) - - messages = dict( - tooShort=_('Enter a value at least %(minLength)i characters long'), - invalid=_('Invalid value (value with length expected)')) - - def _validate_python(self, value, state): - try: - if len(value) < self.minLength: - raise Invalid( - self.message('tooShort', state, - minLength=self.minLength), value, state) - except TypeError: - raise Invalid( - self.message('invalid', state), value, state) - - -class NotEmpty(FancyValidator): - """ - Invalid if value is empty (empty string, empty list, etc). - - Generally for objects that Python considers false, except zero - which is not considered invalid. - - Examples:: - - >>> ne = NotEmpty(messages=dict(empty='enter something')) - >>> ne.to_python('') - Traceback (most recent call last): - ... - Invalid: enter something - >>> ne.to_python(0) - 0 - """ - not_empty = True - - messages = dict( - empty=_('Please enter a value')) - - def _validate_python(self, value, state): - if value == 0: - # This isn't "empty" for this definition. - return value - if not value: - raise Invalid(self.message('empty', state), value, state) - - -class Empty(FancyValidator): - """ - Invalid unless the value is empty. Use cleverly, if at all. - - Examples:: - - >>> Empty.to_python(0) - Traceback (most recent call last): - ... - Invalid: You cannot enter a value here - """ - - messages = dict( - notEmpty=_('You cannot enter a value here')) - - def _validate_python(self, value, state): - if value or value == 0: - raise Invalid(self.message('notEmpty', state), value, state) - - -class Regex(FancyValidator): - """ - Invalid if the value doesn't match the regular expression `regex`. - - The regular expression can be a compiled re object, or a string - which will be compiled for you. - - Use strip=True if you want to strip the value before validation, - and as a form of conversion (often useful). - - Examples:: - - >>> cap = Regex(r'^[A-Z]+$') - >>> cap.to_python('ABC') - 'ABC' - - Note that ``.from_python()`` calls (in general) do not validate - the input:: - - >>> cap.from_python('abc') - 'abc' - >>> cap(accept_python=False).from_python('abc') - Traceback (most recent call last): - ... - Invalid: The input is not valid - >>> cap.to_python(1) - Traceback (most recent call last): - ... - Invalid: The input must be a string (not a : 1) - >>> Regex(r'^[A-Z]+$', strip=True).to_python(' ABC ') - 'ABC' - >>> Regex(r'this', regexOps=('I',)).to_python('THIS') - 'THIS' - """ - - regexOps = () - strip = False - regex = None - - __unpackargs__ = ('regex',) - - messages = dict( - invalid=_('The input is not valid')) - - def __init__(self, *args, **kw): - FancyValidator.__init__(self, *args, **kw) - if isinstance(self.regex, str): - ops = 0 - assert not isinstance(self.regexOps, str), ( - "regexOps should be a list of options from the re module " - "(names, or actual values)") - for op in self.regexOps: - if isinstance(op, str): - ops |= getattr(re, op) - else: - ops |= op - self.regex = re.compile(self.regex, ops) - - def _validate_python(self, value, state): - self.assert_string(value, state) - if self.strip and isinstance(value, str): - value = value.strip() - if not self.regex.search(value): - raise Invalid(self.message('invalid', state), value, state) - - def _convert_to_python(self, value, state): - if self.strip and isinstance(value, str): - return value.strip() - return value - - -class PlainText(Regex): - """ - Test that the field contains only letters, numbers, underscore, - and the hyphen. Subclasses Regex. - - Examples:: - - >>> PlainText.to_python('_this9_') - '_this9_' - >>> PlainText.from_python(' this ') - ' this ' - >>> PlainText(accept_python=False).from_python(' this ') - Traceback (most recent call last): - ... - Invalid: Enter only letters, numbers, or _ (underscore) - >>> PlainText(strip=True).to_python(' this ') - 'this' - >>> PlainText(strip=True).from_python(' this ') - 'this' - """ - - regex = r"^[a-zA-Z_\-0-9]*$" - - messages = dict( - invalid=_('Enter only letters, numbers, or _ (underscore)')) - - -class OneOf(FancyValidator): - """ - Tests that the value is one of the members of a given list. - - If ``testValueList=True``, then if the input value is a list or - tuple, all the members of the sequence will be checked (i.e., the - input must be a subset of the allowed values). - - Use ``hideList=True`` to keep the list of valid values out of the - error message in exceptions. - - Examples:: - - >>> oneof = OneOf([1, 2, 3]) - >>> oneof.to_python(1) - 1 - >>> oneof.to_python(4) - Traceback (most recent call last): - ... - Invalid: Value must be one of: 1; 2; 3 (not 4) - >>> oneof(testValueList=True).to_python([2, 3, [1, 2, 3]]) - [2, 3, [1, 2, 3]] - >>> oneof.to_python([2, 3, [1, 2, 3]]) - Traceback (most recent call last): - ... - Invalid: Value must be one of: 1; 2; 3 (not [2, 3, [1, 2, 3]]) - """ - - list = None - testValueList = False - hideList = False - - __unpackargs__ = ('list',) - - messages = dict( - invalid=_('Invalid value'), - notIn=_('Value must be one of: %(items)s (not %(value)r)')) - - def _validate_python(self, value, state): - if self.testValueList and isinstance(value, (list, tuple)): - for v in value: - self._validate_python(v, state) - else: - if not value in self.list: - if self.hideList: - raise Invalid(self.message('invalid', state), value, state) - else: - try: - items = '; '.join(map(str, self.list)) - except UnicodeError: - items = '; '.join(map(str, self.list)) - raise Invalid( - self.message('notIn', state, - items=items, value=value), value, state) - - @property - def accept_iterator(self): - return self.testValueList - - -class DictConverter(FancyValidator): - """ - Converts values based on a dictionary which has values as keys for - the resultant values. - - If ``allowNull`` is passed, it will not balk if a false value - (e.g., '' or None) is given (it will return None in these cases). - - to_python takes keys and gives values, from_python takes values and - gives keys. - - If you give hideDict=True, then the contents of the dictionary - will not show up in error messages. - - Examples:: - - >>> dc = DictConverter({1: 'one', 2: 'two'}) - >>> dc.to_python(1) - 'one' - >>> dc.from_python('one') - 1 - >>> dc.to_python(3) - Traceback (most recent call last): - .... - Invalid: Enter a value from: 1; 2 - >>> dc2 = dc(hideDict=True) - >>> dc2.hideDict - True - >>> dc2.dict - {1: 'one', 2: 'two'} - >>> dc2.to_python(3) - Traceback (most recent call last): - .... - Invalid: Choose something - >>> dc.from_python('three') - Traceback (most recent call last): - .... - Invalid: Nothing in my dictionary goes by the value 'three'. Choose one of: 'one'; 'two' - """ - - messages = dict( - keyNotFound=_('Choose something'), - chooseKey=_('Enter a value from: %(items)s'), - valueNotFound=_('That value is not known'), - chooseValue=_('Nothing in my dictionary goes by the value %(value)s.' - ' Choose one of: %(items)s')) - - dict = None - hideDict = False - - __unpackargs__ = ('dict',) - - def _convert_to_python(self, value, state): - try: - return self.dict[value] - except KeyError: - if self.hideDict: - raise Invalid(self.message('keyNotFound', state), value, state) - else: - items = sorted(self.dict) - items = '; '.join(map(repr, items)) - raise Invalid(self.message('chooseKey', - state, items=items), value, state) - - def _convert_from_python(self, value, state): - for k, v in self.dict.items(): - if value == v: - return k - if self.hideDict: - raise Invalid(self.message('valueNotFound', state), value, state) - else: - items = '; '.join(map(repr, iter(self.dict.values()))) - raise Invalid( - self.message('chooseValue', state, - value=repr(value), items=items), value, state) - - -class IndexListConverter(FancyValidator): - """ - Converts a index (which may be a string like '2') to the value in - the given list. - - Examples:: - - >>> index = IndexListConverter(['zero', 'one', 'two']) - >>> index.to_python(0) - 'zero' - >>> index.from_python('zero') - 0 - >>> index.to_python('1') - 'one' - >>> index.to_python(5) - Traceback (most recent call last): - Invalid: Index out of range - >>> index(not_empty=True).to_python(None) - Traceback (most recent call last): - Invalid: Please enter a value - >>> index.from_python('five') - Traceback (most recent call last): - Invalid: Item 'five' was not found in the list - """ - - list = None - - __unpackargs__ = ('list',) - - messages = dict( - integer=_('Must be an integer index'), - outOfRange=_('Index out of range'), - notFound=_('Item %(value)s was not found in the list')) - - def _convert_to_python(self, value, state): - try: - value = int(value) - except (ValueError, TypeError): - raise Invalid(self.message('integer', state), value, state) - try: - return self.list[value] - except IndexError: - raise Invalid(self.message('outOfRange', state), value, state) - - def _convert_from_python(self, value, state): - for i, v in enumerate(self.list): - if v == value: - return i - raise Invalid( - self.message('notFound', state, value=repr(value)), value, state) - - -class DateValidator(FancyValidator): - """ - Validates that a date is within the given range. Be sure to call - DateConverter first if you aren't expecting mxDateTime input. - - ``earliest_date`` and ``latest_date`` may be functions; if so, - they will be called each time before validating. - - ``after_now`` means a time after the current timestamp; note that - just a few milliseconds before now is invalid! ``today_or_after`` - is more permissive, and ignores hours and minutes. - - Examples:: - - >>> from datetime import datetime, timedelta - >>> d = DateValidator(earliest_date=datetime(2003, 1, 1)) - >>> d.to_python(datetime(2004, 1, 1)) - datetime.datetime(2004, 1, 1, 0, 0) - >>> d.to_python(datetime(2002, 1, 1)) - Traceback (most recent call last): - ... - Invalid: Date must be after Wednesday, 01 January 2003 - >>> d.to_python(datetime(2003, 1, 1)) - datetime.datetime(2003, 1, 1, 0, 0) - >>> d = DateValidator(after_now=True) - >>> now = datetime.now() - >>> d.to_python(now+timedelta(seconds=5)) == now+timedelta(seconds=5) - True - >>> d.to_python(now-timedelta(days=1)) - Traceback (most recent call last): - ... - Invalid: The date must be sometime in the future - >>> d.to_python(now+timedelta(days=1)) > now - True - >>> d = DateValidator(today_or_after=True) - >>> d.to_python(now) == now - True - - """ - - earliest_date = None - latest_date = None - after_now = False - # Like after_now, but just after this morning: - today_or_after = False - # Use None or 'datetime' for the datetime module in the standard lib, - # or 'mxDateTime' to force the mxDateTime module - datetime_module = None - - messages = dict( - after=_('Date must be after %(date)s'), - before=_('Date must be before %(date)s'), - # Double %'s, because this will be substituted twice: - date_format=_('%%A, %%d %%B %%Y'), - future=_('The date must be sometime in the future')) - - def _validate_python(self, value, state): - date_format = self.message('date_format', state) - if (str is not str # Python 2 - and isinstance(date_format, str)): - # strftime uses the locale encoding, not Unicode - encoding = locale.getlocale(locale.LC_TIME)[1] or 'utf-8' - date_format = date_format.encode(encoding) - else: - encoding = None - if self.earliest_date: - if callable(self.earliest_date): - earliest_date = self.earliest_date() - else: - earliest_date = self.earliest_date - if value < earliest_date: - date_formatted = earliest_date.strftime(date_format) - if encoding: - date_formatted = date_formatted.decode(encoding) - raise Invalid( - self.message('after', state, date=date_formatted), - value, state) - if self.latest_date: - if callable(self.latest_date): - latest_date = self.latest_date() - else: - latest_date = self.latest_date - if value > latest_date: - date_formatted = latest_date.strftime(date_format) - if encoding: - date_formatted = date_formatted.decode(encoding) - raise Invalid( - self.message('before', state, date=date_formatted), - value, state) - if self.after_now: - dt_mod = import_datetime(self.datetime_module) - now = datetime_now(dt_mod) - if value < now: - date_formatted = now.strftime(date_format) - if encoding: - date_formatted = date_formatted.decode(encoding) - raise Invalid( - self.message('future', state, date=date_formatted), - value, state) - if self.today_or_after: - dt_mod = import_datetime(self.datetime_module) - now = datetime_now(dt_mod) - today = datetime_makedate(dt_mod, - now.year, now.month, now.day) - value_as_date = datetime_makedate( - dt_mod, value.year, value.month, value.day) - if value_as_date < today: - date_formatted = now.strftime(date_format) - if encoding: - date_formatted = date_formatted.decode(encoding) - raise Invalid( - self.message('future', state, date=date_formatted), - value, state) - - -class Bool(FancyValidator): - """ - Always Valid, returns True or False based on the value and the - existance of the value. - - If you want to convert strings like ``'true'`` to booleans, then - use ``StringBool``. - - Examples:: - - >>> Bool.to_python(0) - False - >>> Bool.to_python(1) - True - >>> Bool.to_python('') - False - >>> Bool.to_python(None) - False - """ - - if_missing = False - - def _convert_to_python(self, value, state): - return bool(value) - - _convert_from_python = _convert_to_python - - def empty_value(self, value): - return False - - -class RangeValidator(FancyValidator): - """This is an abstract base class for Int and Number. - - It verifies that a value is within range. It accepts min and max - values in the constructor. - - (Since this is an abstract base class, the tests are in Int and Number.) - - """ - - messages = dict( - tooLow=_('Please enter a number that is %(min)s or greater'), - tooHigh=_('Please enter a number that is %(max)s or smaller')) - - min = None - max = None - - def _validate_python(self, value, state): - if self.min is not None: - if value < self.min: - msg = self.message('tooLow', state, min=self.min) - raise Invalid(msg, value, state) - if self.max is not None: - if value > self.max: - msg = self.message('tooHigh', state, max=self.max) - raise Invalid(msg, value, state) - - -class Int(RangeValidator): - """Convert a value to an integer. - - Example:: - - >>> Int.to_python('10') - 10 - >>> Int.to_python('ten') - Traceback (most recent call last): - ... - Invalid: Please enter an integer value - >>> Int(min=5).to_python('6') - 6 - >>> Int(max=10).to_python('11') - Traceback (most recent call last): - ... - Invalid: Please enter a number that is 10 or smaller - - """ - - messages = dict( - integer=_('Please enter an integer value')) - - def _convert_to_python(self, value, state): - try: - return int(value) - except (ValueError, TypeError): - raise Invalid(self.message('integer', state), value, state) - - _convert_from_python = _convert_to_python - - -class Number(RangeValidator): - """Convert a value to a float or integer. - - Tries to convert it to an integer if no information is lost. - - Example:: - - >>> Number.to_python('10') - 10 - >>> Number.to_python('10.5') - 10.5 - >>> Number.to_python('ten') - Traceback (most recent call last): - ... - Invalid: Please enter a number - >>> Number.to_python([1.2]) - Traceback (most recent call last): - ... - Invalid: Please enter a number - >>> Number(min=5).to_python('6.5') - 6.5 - >>> Number(max=10.5).to_python('11.5') - Traceback (most recent call last): - ... - Invalid: Please enter a number that is 10.5 or smaller - - """ - - messages = dict( - number=_('Please enter a number')) - - def _convert_to_python(self, value, state): - try: - value = float(value) - try: - int_value = int(value) - except OverflowError: - int_value = None - if value == int_value: - return int_value - return value - except (ValueError, TypeError): - raise Invalid(self.message('number', state), value, state) - - -class ByteString(FancyValidator): - """Convert to byte string, treating empty things as the empty string. - - Under Python 2.x you can also use the alias `String` for this validator. - - Also takes a `max` and `min` argument, and the string length must fall - in that range. - - Also you may give an `encoding` argument, which will encode any unicode - that is found. Lists and tuples are joined with `list_joiner` - (default ``', '``) in ``from_python``. - - :: - - >>> ByteString(min=2).to_python('a') - Traceback (most recent call last): - ... - Invalid: Enter a value 2 characters long or more - >>> ByteString(max=10).to_python('xxxxxxxxxxx') - Traceback (most recent call last): - ... - Invalid: Enter a value not more than 10 characters long - >>> ByteString().from_python(None) - '' - >>> ByteString().from_python([]) - '' - >>> ByteString().to_python(None) - '' - >>> ByteString(min=3).to_python(None) - Traceback (most recent call last): - ... - Invalid: Please enter a value - >>> ByteString(min=1).to_python('') - Traceback (most recent call last): - ... - Invalid: Please enter a value - - """ - - min = None - max = None - not_empty = None - encoding = None - list_joiner = ', ' - - messages = dict( - tooLong=_('Enter a value not more than %(max)i characters long'), - tooShort=_('Enter a value %(min)i characters long or more')) - - def __initargs__(self, new_attrs): - if self.not_empty is None and self.min: - self.not_empty = True - - def _convert_to_python(self, value, state): - if value is None: - value = '' - elif not isinstance(value, str): - try: - value = bytes(value) - except UnicodeEncodeError: - value = str(value) - if self.encoding is not None and isinstance(value, str): - value = value.encode(self.encoding) - return value - - def _convert_from_python(self, value, state): - if value is None: - value = '' - elif not isinstance(value, str): - if isinstance(value, (list, tuple)): - value = self.list_joiner.join( - self._convert_from_python(v, state) for v in value) - try: - value = str(value) - except UnicodeEncodeError: - value = str(value) - if self.encoding is not None and isinstance(value, str): - value = value.encode(self.encoding) - if self.strip: - value = value.strip() - return value - - def _validate_other(self, value, state): - if self.max is None and self.min is None: - return - if value is None: - value = '' - elif not isinstance(value, str): - try: - value = str(value) - except UnicodeEncodeError: - value = str(value) - if self.max is not None and len(value) > self.max: - raise Invalid( - self.message('tooLong', state, max=self.max), value, state) - if self.min is not None and len(value) < self.min: - raise Invalid( - self.message('tooShort', state, min=self.min), value, state) - - def empty_value(self, value): - return '' - - -class UnicodeString(ByteString): - """Convert things to unicode string. - - This is implemented as a specialization of the ByteString class. - - Under Python 3.x you can also use the alias `String` for this validator. - - In addition to the String arguments, an encoding argument is also - accepted. By default the encoding will be utf-8. You can overwrite - this using the encoding parameter. You can also set inputEncoding - and outputEncoding differently. An inputEncoding of None means - "do not decode", an outputEncoding of None means "do not encode". - - All converted strings are returned as Unicode strings. - - :: - - >>> UnicodeString().to_python(None) - u'' - >>> UnicodeString().to_python([]) - u'' - >>> UnicodeString(encoding='utf-7').to_python('Ni Ni Ni') - u'Ni Ni Ni' - - """ - encoding = 'utf-8' - inputEncoding = NoDefault - outputEncoding = NoDefault - messages = dict( - badEncoding=_('Invalid data or incorrect encoding')) - - def __init__(self, **kw): - ByteString.__init__(self, **kw) - if self.inputEncoding is NoDefault: - self.inputEncoding = self.encoding - if self.outputEncoding is NoDefault: - self.outputEncoding = self.encoding - - def _convert_to_python(self, value, state): - if not value: - return '' - if isinstance(value, str): - return value - if not isinstance(value, str): - if hasattr(value, '__unicode__'): - value = str(value) - return value - if not (str is str # Python 3 - and isinstance(value, bytes) and self.inputEncoding): - value = str(value) - if self.inputEncoding and not isinstance(value, str): - try: - value = str(value, self.inputEncoding) - except UnicodeDecodeError: - raise Invalid(self.message('badEncoding', state), value, state) - except TypeError: - raise Invalid( - self.message('badType', state, - type=type(value), value=value), value, state) - return value - - def _convert_from_python(self, value, state): - if not isinstance(value, str): - if hasattr(value, '__unicode__'): - value = str(value) - else: - value = str(value) - if self.outputEncoding and isinstance(value, str): - value = value.encode(self.outputEncoding) - return value - - def empty_value(self, value): - return '' - - -# Provide proper alias for native strings - -String = UnicodeString if str is str else ByteString - - -class Set(FancyValidator): - """ - This is for when you think you may return multiple values for a - certain field. - - This way the result will always be a list, even if there's only - one result. It's equivalent to ForEach(convert_to_list=True). - - If you give ``use_set=True``, then it will return an actual - ``set`` object. - - :: - - >>> Set.to_python(None) - [] - >>> Set.to_python('this') - ['this'] - >>> Set.to_python(('this', 'that')) - ['this', 'that'] - >>> s = Set(use_set=True) - >>> s.to_python(None) - set([]) - >>> s.to_python('this') - set(['this']) - >>> s.to_python(('this',)) - set(['this']) - """ - - use_set = False - - if_missing = () - accept_iterator = True - - def _convert_to_python(self, value, state): - if self.use_set: - if isinstance(value, set): - return value - elif isinstance(value, (list, tuple)): - return set(value) - elif value is None: - return set() - else: - return set([value]) - else: - if isinstance(value, list): - return value - elif isinstance(value, set): - return list(value) - elif isinstance(value, tuple): - return list(value) - elif value is None: - return [] - else: - return [value] - - def empty_value(self, value): - if self.use_set: - return set() - else: - return [] - - -class Email(FancyValidator): - r""" - Validate an email address. - - If you pass ``resolve_domain=True``, then it will try to resolve - the domain name to make sure it's valid. This takes longer, of - course. You must have the `dnspython `__ modules - installed to look up DNS (MX and A) records. - - :: - - >>> e = Email() - >>> e.to_python(' test@foo.com ') - 'test@foo.com' - >>> e.to_python('test') - Traceback (most recent call last): - ... - Invalid: An email address must contain a single @ - >>> e.to_python('test@foobar') - Traceback (most recent call last): - ... - Invalid: The domain portion of the email address is invalid (the portion after the @: foobar) - >>> e.to_python('test@foobar.com.5') - Traceback (most recent call last): - ... - Invalid: The domain portion of the email address is invalid (the portion after the @: foobar.com.5) - >>> e.to_python('test@foo..bar.com') - Traceback (most recent call last): - ... - Invalid: The domain portion of the email address is invalid (the portion after the @: foo..bar.com) - >>> e.to_python('test@.foo.bar.com') - Traceback (most recent call last): - ... - Invalid: The domain portion of the email address is invalid (the portion after the @: .foo.bar.com) - >>> e.to_python('nobody@xn--m7r7ml7t24h.com') - 'nobody@xn--m7r7ml7t24h.com' - >>> e.to_python('o*reilly@test.com') - 'o*reilly@test.com' - >>> e = Email(resolve_domain=True) - >>> e.resolve_domain - True - >>> e.to_python('doesnotexist@colorstudy.com') - 'doesnotexist@colorstudy.com' - >>> e.to_python('test@nyu.edu') - 'test@nyu.edu' - >>> # NOTE: If you do not have dnspython installed this example won't work: - >>> e.to_python('test@thisdomaindoesnotexistithinkforsure.com') - Traceback (most recent call last): - ... - Invalid: The domain of the email address does not exist (the portion after the @: thisdomaindoesnotexistithinkforsure.com) - >>> e.to_python('test@google.com') - u'test@google.com' - >>> e = Email(not_empty=False) - >>> e.to_python('') - - """ - - resolve_domain = False - resolve_timeout = 10 # timeout in seconds when resolving domains - - usernameRE = re.compile(r"^[\w!#$%&'*+\-/=?^`{|}~.]+$") - domainRE = re.compile(r''' - ^(?:[a-z0-9][a-z0-9\-]{,62}\.)+ # subdomain - (?:[a-z]{2,63}|xn--[a-z0-9\-]{2,59})$ # top level domain - ''', re.I | re.VERBOSE) - - messages = dict( - empty=_('Please enter an email address'), - noAt=_('An email address must contain a single @'), - badUsername=_('The username portion of the email address is invalid' - ' (the portion before the @: %(username)s)'), - socketError=_('An error occured when trying to connect to the server:' - ' %(error)s'), - badDomain=_('The domain portion of the email address is invalid' - ' (the portion after the @: %(domain)s)'), - domainDoesNotExist=_('The domain of the email address does not exist' - ' (the portion after the @: %(domain)s)')) - - def __init__(self, *args, **kw): - FancyValidator.__init__(self, *args, **kw) - if self.resolve_domain: - if not have_dns: - warnings.warn( - "dnspython is not installed on" - " your system (or the dns.resolver package cannot be found)." - " I cannot resolve domain names in addresses") - raise ImportError("no module named dns.resolver") - - def _validate_python(self, value, state): - if not value: - raise Invalid(self.message('empty', state), value, state) - value = value.strip() - splitted = value.split('@', 1) - try: - username, domain = splitted - except ValueError: - raise Invalid(self.message('noAt', state), value, state) - if not self.usernameRE.search(username): - raise Invalid( - self.message('badUsername', state, username=username), - value, state) - try: - idna_domain = [idna.ToASCII(p) for p in domain.split('.')] - if str is str: # Python 3 - idna_domain = [p.decode('ascii') for p in idna_domain] - idna_domain = '.'.join(idna_domain) - except UnicodeError: - # UnicodeError: label empty or too long - # This exception might happen if we have an invalid domain name part - # (for example test@.foo.bar.com) - raise Invalid( - self.message('badDomain', state, domain=domain), - value, state) - if not self.domainRE.search(idna_domain): - raise Invalid( - self.message('badDomain', state, domain=domain), - value, state) - if self.resolve_domain: - assert have_dns, "dnspython should be available" - global socket - if socket is None: - import socket - try: - try: - dns.resolver.query(domain, 'MX') - except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer) as e: - try: - dns.resolver.query(domain, 'A') - except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer) as e: - raise Invalid( - self.message('domainDoesNotExist', - state, domain=domain), value, state) - except (socket.error, dns.exception.DNSException) as e: - raise Invalid( - self.message('socketError', state, error=e), value, state) - - def _convert_to_python(self, value, state): - return value.strip() - - -class URL(FancyValidator): - """ - Validate a URL, either http://... or https://. If check_exists - is true, then we'll actually make a request for the page. - - If add_http is true, then if no scheme is present we'll add - http:// - - :: - - >>> u = URL(add_http=True) - >>> u.to_python('foo.com') - 'http://foo.com' - >>> u.to_python('http://hahaha.ha/bar.html') - 'http://hahaha.ha/bar.html' - >>> u.to_python('http://xn--m7r7ml7t24h.com') - 'http://xn--m7r7ml7t24h.com' - >>> u.to_python('http://xn--c1aay4a.xn--p1ai') - 'http://xn--c1aay4a.xn--p1ai' - >>> u.to_python('http://foo.com/test?bar=baz&fleem=morx') - 'http://foo.com/test?bar=baz&fleem=morx' - >>> u.to_python('http://foo.com/login?came_from=http%3A%2F%2Ffoo.com%2Ftest') - 'http://foo.com/login?came_from=http%3A%2F%2Ffoo.com%2Ftest' - >>> u.to_python('http://foo.com:8000/test.html') - 'http://foo.com:8000/test.html' - >>> u.to_python('http://foo.com/something\\nelse') - Traceback (most recent call last): - ... - Invalid: That is not a valid URL - >>> u.to_python('https://test.com') - 'https://test.com' - >>> u.to_python('http://test') - Traceback (most recent call last): - ... - Invalid: You must provide a full domain name (like test.com) - >>> u.to_python('http://test..com') - Traceback (most recent call last): - ... - Invalid: That is not a valid URL - >>> u = URL(add_http=False, check_exists=True) - >>> u.to_python('http://google.com') - 'http://google.com' - >>> u.to_python('google.com') - Traceback (most recent call last): - ... - Invalid: You must start your URL with http://, https://, etc - >>> u.to_python('http://www.formencode.org/does/not/exist/page.html') - Traceback (most recent call last): - ... - Invalid: The server responded that the page could not be found - >>> u.to_python('http://this.domain.does.not.exist.example.org/test.html') - ... # doctest: +ELLIPSIS - Traceback (most recent call last): - ... - Invalid: An error occured when trying to connect to the server: ... - - If you want to allow addresses without a TLD (e.g., ``localhost``) you can do:: - - >>> URL(require_tld=False).to_python('http://localhost') - 'http://localhost' - - By default, internationalized domain names (IDNA) in Unicode will be - accepted and encoded to ASCII using Punycode (as described in RFC 3490). - You may set allow_idna to False to change this behavior:: - - >>> URL(allow_idna=True).to_python( - ... 'http://\\u0433\\u0443\\u0433\\u043b.\\u0440\\u0444') - 'http://xn--c1aay4a.xn--p1ai' - >>> URL(allow_idna=True, add_http=True).to_python( - ... '\\u0433\\u0443\\u0433\\u043b.\\u0440\\u0444') - 'http://xn--c1aay4a.xn--p1ai' - >>> URL(allow_idna=False).to_python( - ... 'http://\\u0433\\u0443\\u0433\\u043b.\\u0440\\u0444') - Traceback (most recent call last): - ... - Invalid: That is not a valid URL - - """ - - add_http = True - allow_idna = True - check_exists = False - require_tld = True - - url_re = re.compile(r''' - ^(http|https):// - (?:[%:\w]*@)? # authenticator - (?: # ip or domain - (?P(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))| - (?P[a-z0-9][a-z0-9\-]{,62}\.)* # subdomain - (?P[a-z]{2,63}|xn--[a-z0-9\-]{2,59}) # top level domain - ) - (?::[0-9]{1,5})? # port - # files/delims/etc - (?P/[a-z0-9\-\._~:/\?#\[\]@!%\$&\'\(\)\*\+,;=]*)? - $ - ''', re.I | re.VERBOSE) - - scheme_re = re.compile(r'^[a-zA-Z]+:') - - messages = dict( - noScheme=_('You must start your URL with http://, https://, etc'), - badURL=_('That is not a valid URL'), - httpError=_('An error occurred when trying to access the URL:' - ' %(error)s'), - socketError=_('An error occured when trying to connect to the server:' - ' %(error)s'), - notFound=_('The server responded that the page could not be found'), - status=_('The server responded with a bad status code (%(status)s)'), - noTLD=_('You must provide a full domain name (like %(domain)s.com)')) - - def _convert_to_python(self, value, state): - value = value.strip() - if self.add_http: - if not self.scheme_re.search(value): - value = 'http://' + value - if self.allow_idna: - value = self._encode_idna(value) - match = self.scheme_re.search(value) - if not match: - raise Invalid(self.message('noScheme', state), value, state) - value = match.group(0).lower() + value[len(match.group(0)):] - match = self.url_re.search(value) - if not match: - raise Invalid(self.message('badURL', state), value, state) - if self.require_tld and not match.group('domain'): - raise Invalid( - self.message('noTLD', state, domain=match.group('tld')), - value, state) - if self.check_exists and value.startswith(('http://', 'https://')): - self._check_url_exists(value, state) - return value - - def _encode_idna(self, url): - global urlparse - if urlparse is None: - import urllib.parse - try: - scheme, netloc, path, params, query, fragment = urllib.parse.urlparse( - url) - except ValueError: - return url - try: - netloc = netloc.encode('idna') - if str is str: # Python 3 - netloc = netloc.decode('ascii') - return str(urllib.parse.urlunparse((scheme, netloc, - path, params, query, fragment))) - except UnicodeError: - return url - - def _check_url_exists(self, url, state): - global httplib, urlparse, socket - if httplib is None: - import http.client - if urlparse is None: - import urllib.parse - if socket is None: - import socket - scheme, netloc, path, params, query, fragment = urllib.parse.urlparse( - url, 'http') - if scheme == 'https': - ConnClass = http.client.HTTPSConnection - else: - ConnClass = http.client.HTTPConnection - try: - conn = ConnClass(netloc) - if params: - path += ';' + params - if query: - path += '?' + query - conn.request('HEAD', path) - res = conn.getresponse() - except http.client.HTTPException as e: - raise Invalid( - self.message('httpError', state, error=e), state, url) - except socket.error as e: - raise Invalid( - self.message('socketError', state, error=e), state, url) - else: - if res.status == 404: - raise Invalid( - self.message('notFound', state), state, url) - if not 200 <= res.status < 500: - raise Invalid( - self.message('status', state, status=res.status), - state, url) - - -class XRI(FancyValidator): - r""" - Validator for XRIs. - - It supports both i-names and i-numbers, of the first version of the XRI - standard. - - :: - - >>> inames = XRI(xri_type="i-name") - >>> inames.to_python(" =John.Smith ") - '=John.Smith' - >>> inames.to_python("@Free.Software.Foundation") - '@Free.Software.Foundation' - >>> inames.to_python("Python.Software.Foundation") - Traceback (most recent call last): - ... - Invalid: The type of i-name is not defined; it may be either individual or organizational - >>> inames.to_python("http://example.org") - Traceback (most recent call last): - ... - Invalid: The type of i-name is not defined; it may be either individual or organizational - >>> inames.to_python("=!2C43.1A9F.B6F6.E8E6") - Traceback (most recent call last): - ... - Invalid: "!2C43.1A9F.B6F6.E8E6" is an invalid i-name - >>> iname_with_schema = XRI(True, xri_type="i-name") - >>> iname_with_schema.to_python("=Richard.Stallman") - 'xri://=Richard.Stallman' - >>> inames.to_python("=John Smith") - Traceback (most recent call last): - ... - Invalid: "John Smith" is an invalid i-name - >>> inumbers = XRI(xri_type="i-number") - >>> inumbers.to_python("!!1000!de21.4536.2cb2.8074") - '!!1000!de21.4536.2cb2.8074' - >>> inumbers.to_python("@!1000.9554.fabd.129c!2847.df3c") - '@!1000.9554.fabd.129c!2847.df3c' - - """ - - iname_valid_pattern = re.compile(r""" - ^ - [\w]+ # A global alphanumeric i-name - (\.[\w]+)* # An i-name with dots - (\*[\w]+(\.[\w]+)*)* # A community i-name - $ - """, re.VERBOSE | re.UNICODE) - - iname_invalid_start = re.compile(r"^[\d\.-]", re.UNICODE) - """@cvar: These characters must not be at the beggining of the i-name""" - - inumber_pattern = re.compile(r""" - ^ - ( - [=@]! # It's a personal or organization i-number - | - !! # It's a network i-number - ) - [\dA-F]{1,4}(\.[\dA-F]{1,4}){0,3} # A global i-number - (![\dA-F]{1,4}(\.[\dA-F]{1,4}){0,3})* # Zero or more sub i-numbers - $ - """, re.VERBOSE | re.IGNORECASE) - - messages = dict( - noType=_('The type of i-name is not defined;' - ' it may be either individual or organizational'), - repeatedChar=_('Dots and dashes may not be repeated consecutively'), - badIname=_('"%(iname)s" is an invalid i-name'), - badInameStart=_('i-names may not start with numbers' - ' nor punctuation marks'), - badInumber=_('"%(inumber)s" is an invalid i-number'), - badType=_('The XRI must be a string (not a %(type)s: %(value)r)'), - badXri=_('"%(xri_type)s" is not a valid type of XRI')) - - def __init__(self, add_xri=False, xri_type="i-name", **kwargs): - """Create an XRI validator. - - @param add_xri: Should the schema be added if not present? - Officially it's optional. - @type add_xri: C{bool} - @param xri_type: What type of XRI should be validated? - Possible values: C{i-name} or C{i-number}. - @type xri_type: C{str} - - """ - self.add_xri = add_xri - assert xri_type in ('i-name', 'i-number'), ( - 'xri_type must be "i-name" or "i-number"') - self.xri_type = xri_type - super(XRI, self).__init__(**kwargs) - - def _convert_to_python(self, value, state): - """Prepend the 'xri://' schema if needed and remove trailing spaces""" - value = value.strip() - if self.add_xri and not value.startswith('xri://'): - value = 'xri://' + value - return value - - def _validate_python(self, value, state=None): - """Validate an XRI - - @raise Invalid: If at least one of the following conditions in met: - - C{value} is not a string. - - The XRI is not a personal, organizational or network one. - - The relevant validator (i-name or i-number) considers the XRI - is not valid. - - """ - if not isinstance(value, str): - raise Invalid( - self.message('badType', state, - type=str(type(value)), value=value), value, state) - - # Let's remove the schema, if any - if value.startswith('xri://'): - value = value[6:] - - if not value[0] in ('@', '=') and not ( - self.xri_type == 'i-number' and value[0] == '!'): - raise Invalid(self.message('noType', state), value, state) - - if self.xri_type == 'i-name': - self._validate_iname(value, state) - else: - self._validate_inumber(value, state) - - def _validate_iname(self, iname, state): - """Validate an i-name""" - # The type is not required here: - iname = iname[1:] - if '..' in iname or '--' in iname: - raise Invalid(self.message('repeatedChar', state), iname, state) - if self.iname_invalid_start.match(iname): - raise Invalid(self.message('badInameStart', state), iname, state) - if not self.iname_valid_pattern.match(iname) or '_' in iname: - raise Invalid( - self.message('badIname', state, iname=iname), iname, state) - - def _validate_inumber(self, inumber, state): - """Validate an i-number""" - if not self.__class__.inumber_pattern.match(inumber): - raise Invalid( - self.message('badInumber', state, - inumber=inumber, value=inumber), inumber, state) - - -class OpenId(FancyValidator): - r""" - OpenId validator. - - :: - >>> v = OpenId(add_schema=True) - >>> v.to_python(' example.net ') - 'http://example.net' - >>> v.to_python('@TurboGears') - 'xri://@TurboGears' - >>> w = OpenId(add_schema=False) - >>> w.to_python(' example.net ') - Traceback (most recent call last): - ... - Invalid: "example.net" is not a valid OpenId (it is neither an URL nor an XRI) - >>> w.to_python('!!1000') - '!!1000' - >>> w.to_python('look@me.com') - Traceback (most recent call last): - ... - Invalid: "look@me.com" is not a valid OpenId (it is neither an URL nor an XRI) - - """ - - messages = dict( - badId=_('"%(id)s" is not a valid OpenId' - ' (it is neither an URL nor an XRI)')) - - def __init__(self, add_schema=False, **kwargs): - """Create an OpenId validator. - - @param add_schema: Should the schema be added if not present? - @type add_schema: C{bool} - - """ - self.url_validator = URL(add_http=add_schema) - self.iname_validator = XRI(add_schema, xri_type="i-name") - self.inumber_validator = XRI(add_schema, xri_type="i-number") - - def _convert_to_python(self, value, state): - value = value.strip() - try: - return self.url_validator.to_python(value, state) - except Invalid: - try: - return self.iname_validator.to_python(value, state) - except Invalid: - try: - return self.inumber_validator.to_python(value, state) - except Invalid: - pass - # It's not an OpenId! - raise Invalid(self.message('badId', state, id=value), value, state) - - def _validate_python(self, value, state): - self._convert_to_python(value, state) - - -def StateProvince(*kw, **kwargs): - deprecation_warning("please use formencode.national.USStateProvince") - from formencode.national import USStateProvince - return USStateProvince(*kw, **kwargs) - - -def PhoneNumber(*kw, **kwargs): - deprecation_warning("please use formencode.national.USPhoneNumber") - from formencode.national import USPhoneNumber - return USPhoneNumber(*kw, **kwargs) - - -def IPhoneNumberValidator(*kw, **kwargs): - deprecation_warning( - "please use formencode.national.InternationalPhoneNumber") - from formencode.national import InternationalPhoneNumber - return InternationalPhoneNumber(*kw, **kwargs) - - -class FieldStorageUploadConverter(FancyValidator): - """ - Handles cgi.FieldStorage instances that are file uploads. - - This doesn't do any conversion, but it can detect empty upload - fields (which appear like normal fields, but have no filename when - no upload was given). - """ - def _convert_to_python(self, value, state=None): - if isinstance(value, cgi.FieldStorage): - if getattr(value, 'filename', None): - return value - raise Invalid('invalid', value, state) - else: - return value - - def is_empty(self, value): - if isinstance(value, cgi.FieldStorage): - return not bool(getattr(value, 'filename', None)) - return FancyValidator.is_empty(self, value) - - -class FileUploadKeeper(FancyValidator): - """ - Takes two inputs (a dictionary with keys ``static`` and - ``upload``) and converts them into one value on the Python side (a - dictionary with ``filename`` and ``content`` keys). The upload - takes priority over the static value. The filename may be None if - it can't be discovered. - - Handles uploads of both text and ``cgi.FieldStorage`` upload - values. - - This is basically for use when you have an upload field, and you - want to keep the upload around even if the rest of the form - submission fails. When converting *back* to the form submission, - there may be extra values ``'original_filename'`` and - ``'original_content'``, which may want to use in your form to show - the user you still have their content around. - - To use this, make sure you are using variabledecode, then use - something like:: - - - - - Then in your scheme:: - - class MyScheme(Scheme): - myfield = FileUploadKeeper() - - Note that big file uploads mean big hidden fields, and lots of - bytes passed back and forth in the case of an error. - """ - - upload_key = 'upload' - static_key = 'static' - - def _convert_to_python(self, value, state): - upload = value.get(self.upload_key) - static = value.get(self.static_key, '').strip() - filename = content = None - if isinstance(upload, cgi.FieldStorage): - filename = upload.filename - content = upload.value - elif isinstance(upload, str) and upload: - filename = None - # @@: Should this encode upload if it is unicode? - content = upload - if not content and static: - filename, content = static.split(None, 1) - filename = '' if filename == '-' else filename.decode('base64') - content = content.decode('base64') - return {'filename': filename, 'content': content} - - def _convert_from_python(self, value, state): - filename = value.get('filename', '') - content = value.get('content', '') - if filename or content: - result = self.pack_content(filename, content) - return {self.upload_key: '', - self.static_key: result, - 'original_filename': filename, - 'original_content': content} - else: - return {self.upload_key: '', - self.static_key: ''} - - def pack_content(self, filename, content): - enc_filename = self.base64encode(filename) or '-' - enc_content = (content or '').encode('base64') - result = '%s %s' % (enc_filename, enc_content) - return result - - -class DateConverter(FancyValidator): - """ - Validates and converts a string date, like mm/yy, dd/mm/yy, - dd-mm-yy, etc. Using ``month_style`` you can support - the three general styles ``mdy`` = ``us`` = ``mm/dd/yyyy``, - ``dmy`` = ``euro`` = ``dd/mm/yyyy`` and - ``ymd`` = ``iso`` = ``yyyy/mm/dd``. - - Accepts English month names, also abbreviated. Returns value as a - datetime object (you can get mx.DateTime objects if you use - ``datetime_module='mxDateTime'``). Two year dates are assumed to - be within 1950-2020, with dates from 21-49 being ambiguous and - signaling an error. - - Use accept_day=False if you just want a month/year (like for a - credit card expiration date). - - :: - - >>> d = DateConverter() - >>> d.to_python('12/3/09') - datetime.date(2009, 12, 3) - >>> d.to_python('12/3/2009') - datetime.date(2009, 12, 3) - >>> d.to_python('2/30/04') - Traceback (most recent call last): - ... - Invalid: That month only has 29 days - >>> d.to_python('13/2/05') - Traceback (most recent call last): - ... - Invalid: Please enter a month from 1 to 12 - >>> d.to_python('1/1/200') - Traceback (most recent call last): - ... - Invalid: Please enter a four-digit year after 1899 - - If you change ``month_style`` you can get European-style dates:: - - >>> d = DateConverter(month_style='dd/mm/yyyy') - >>> date = d.to_python('12/3/09') - >>> date - datetime.date(2009, 3, 12) - >>> d.from_python(date) - '12/03/2009' - """ - - # set to False if you want only month and year - accept_day = True - # allowed month styles: 'mdy' = 'us', 'dmy' = 'euro', 'ymd' = 'iso' - # also allowed: 'mm/dd/yyyy', 'dd/mm/yyyy', 'yyyy/mm/dd' - month_style = 'mdy' - # preferred separator for reverse conversion: '/', '.' or '-' - separator = '/' - - # Use 'datetime' to force the Python datetime module, or - # 'mxDateTime' to force the mxDateTime module (None means use - # datetime, or if not present mxDateTime) - datetime_module = None - - _month_names = { - 'jan': 1, 'january': 1, - 'feb': 2, 'febuary': 2, - 'mar': 3, 'march': 3, - 'apr': 4, 'april': 4, - 'may': 5, - 'jun': 6, 'june': 6, - 'jul': 7, 'july': 7, - 'aug': 8, 'august': 8, - 'sep': 9, 'sept': 9, 'september': 9, - 'oct': 10, 'october': 10, - 'nov': 11, 'november': 11, - 'dec': 12, 'december': 12, - } - - _date_re = dict( - dmy=re.compile( - r'^\s*(\d\d?)[\-\./\\](\d\d?|%s)[\-\./\\](\d\d\d?\d?)\s*$' - % '|'.join(_month_names), re.I), - mdy=re.compile( - r'^\s*(\d\d?|%s)[\-\./\\](\d\d?)[\-\./\\](\d\d\d?\d?)\s*$' - % '|'.join(_month_names), re.I), - ymd=re.compile( - r'^\s*(\d\d\d?\d?)[\-\./\\](\d\d?|%s)[\-\./\\](\d\d?)\s*$' - % '|'.join(_month_names), re.I), - my=re.compile( - r'^\s*(\d\d?|%s)[\-\./\\](\d\d\d?\d?)\s*$' - % '|'.join(_month_names), re.I), - ym=re.compile( - r'^\s*(\d\d\d?\d?)[\-\./\\](\d\d?|%s)\s*$' - % '|'.join(_month_names), re.I)) - - _formats = dict(d='%d', m='%m', y='%Y') - - _human_formats = dict(d=_('DD'), m=_('MM'), y=_('YYYY')) - - # Feb. should be leap-year aware (but mxDateTime does catch that) - _monthDays = { - 1: 31, 2: 29, 3: 31, 4: 30, 5: 31, 6: 30, 7: 31, 8: 31, - 9: 30, 10: 31, 11: 30, 12: 31} - - messages = dict( - badFormat=_('Please enter the date in the form %(format)s'), - monthRange=_('Please enter a month from 1 to 12'), - invalidDay=_('Please enter a valid day'), - dayRange=_('That month only has %(days)i days'), - invalidDate=_('That is not a valid day (%(exception)s)'), - unknownMonthName=_('Unknown month name: %(month)s'), - invalidYear=_('Please enter a number for the year'), - fourDigitYear=_('Please enter a four-digit year after 1899'), - wrongFormat=_('Please enter the date in the form %(format)s')) - - def __init__(self, *args, **kw): - super(DateConverter, self).__init__(*args, **kw) - month_style = (self.month_style or DateConverter.month_style).lower() - accept_day = bool(self.accept_day) - self.accept_day = self.accept_day - if month_style in ('mdy', - 'md', 'mm/dd/yyyy', 'mm/dd', 'us', 'american'): - month_style = 'mdy' - elif month_style in ('dmy', - 'dm', 'dd/mm/yyyy', 'dd/mm', 'euro', 'european'): - month_style = 'dmy' - elif month_style in ('ymd', - 'ym', 'yyyy/mm/dd', 'yyyy/mm', 'iso', 'china', 'chinese'): - month_style = 'ymd' - else: - raise TypeError('Bad month_style: %r' % month_style) - self.month_style = month_style - separator = self.separator - if not separator or separator == 'auto': - separator = dict(mdy='/', dmy='.', ymd='-')[month_style] - elif separator not in ('-', '.', '/', '\\'): - raise TypeError('Bad separator: %r' % separator) - self.separator = separator - self.format = separator.join(self._formats[part] - for part in month_style if part != 'd' or accept_day) - self.human_format = separator.join(self._human_formats[part] - for part in month_style if part != 'd' or accept_day) - - def _convert_to_python(self, value, state): - self.assert_string(value, state) - month_style = self.month_style - if not self.accept_day: - month_style = 'ym' if month_style == 'ymd' else 'my' - match = self._date_re[month_style].search(value) - if not match: - raise Invalid( - self.message('badFormat', state, - format=self.human_format), value, state) - groups = match.groups() - if self.accept_day: - if month_style == 'mdy': - month, day, year = groups - elif month_style == 'dmy': - day, month, year = groups - else: - year, month, day = groups - day = int(day) - if not 1 <= day <= 31: - raise Invalid(self.message('invalidDay', state), value, state) - else: - day = 1 - if month_style == 'my': - month, year = groups - else: - year, month = groups - month = self.make_month(month, state) - if not 1 <= month <= 12: - raise Invalid(self.message('monthRange', state), value, state) - if self._monthDays[month] < day: - raise Invalid( - self.message('dayRange', state, - days=self._monthDays[month]), value, state) - year = self.make_year(year, state) - dt_mod = import_datetime(self.datetime_module) - try: - return datetime_makedate(dt_mod, year, month, day) - except ValueError as v: - raise Invalid( - self.message('invalidDate', state, - exception=str(v)), value, state) - - def make_month(self, value, state): - try: - return int(value) - except ValueError: - try: - return self._month_names[value.lower().strip()] - except KeyError: - raise Invalid( - self.message('unknownMonthName', state, - month=value), value, state) - - def make_year(self, year, state): - try: - year = int(year) - except ValueError: - raise Invalid(self.message('invalidYear', state), year, state) - if year <= 20: - year += 2000 - elif 50 <= year < 100: - year += 1900 - if 20 < year < 50 or 99 < year < 1900: - raise Invalid(self.message('fourDigitYear', state), year, state) - return year - - def _convert_from_python(self, value, state): - if self.if_empty is not NoDefault and not value: - return '' - return value.strftime(self.format) - - -class TimeConverter(FancyValidator): - """ - Converts times in the format HH:MM:SSampm to (h, m, s). - Seconds are optional. - - For ampm, set use_ampm = True. For seconds, use_seconds = True. - Use 'optional' for either of these to make them optional. - - Examples:: - - >>> tim = TimeConverter() - >>> tim.to_python('8:30') - (8, 30) - >>> tim.to_python('20:30') - (20, 30) - >>> tim.to_python('30:00') - Traceback (most recent call last): - ... - Invalid: You must enter an hour in the range 0-23 - >>> tim.to_python('13:00pm') - Traceback (most recent call last): - ... - Invalid: You must enter an hour in the range 1-12 - >>> tim.to_python('12:-1') - Traceback (most recent call last): - ... - Invalid: You must enter a minute in the range 0-59 - >>> tim.to_python('12:02pm') - (12, 2) - >>> tim.to_python('12:02am') - (0, 2) - >>> tim.to_python('1:00PM') - (13, 0) - >>> tim.from_python((13, 0)) - '13:00:00' - >>> tim2 = tim(use_ampm=True, use_seconds=False) - >>> tim2.from_python((13, 0)) - '1:00pm' - >>> tim2.from_python((0, 0)) - '12:00am' - >>> tim2.from_python((12, 0)) - '12:00pm' - - Examples with ``datetime.time``:: - - >>> v = TimeConverter(use_datetime=True) - >>> a = v.to_python('18:00') - >>> a - datetime.time(18, 0) - >>> b = v.to_python('30:00') - Traceback (most recent call last): - ... - Invalid: You must enter an hour in the range 0-23 - >>> v2 = TimeConverter(prefer_ampm=True, use_datetime=True) - >>> v2.from_python(a) - '6:00:00pm' - >>> v3 = TimeConverter(prefer_ampm=True, - ... use_seconds=False, use_datetime=True) - >>> a = v3.to_python('18:00') - >>> a - datetime.time(18, 0) - >>> v3.from_python(a) - '6:00pm' - >>> a = v3.to_python('18:00:00') - Traceback (most recent call last): - ... - Invalid: You may not enter seconds - """ - - use_ampm = 'optional' - prefer_ampm = False - use_seconds = 'optional' - use_datetime = False - # This can be set to make it prefer mxDateTime: - datetime_module = None - - messages = dict( - noAMPM=_('You must indicate AM or PM'), - tooManyColon=_('There are too many :\'s'), - noSeconds=_('You may not enter seconds'), - secondsRequired=_('You must enter seconds'), - minutesRequired=_('You must enter minutes (after a :)'), - badNumber=_('The %(part)s value you gave is not a number: %(number)r'), - badHour=_('You must enter an hour in the range %(range)s'), - badMinute=_('You must enter a minute in the range 0-59'), - badSecond=_('You must enter a second in the range 0-59')) - - def _convert_to_python(self, value, state): - result = self._to_python_tuple(value, state) - if self.use_datetime: - dt_mod = import_datetime(self.datetime_module) - time_class = datetime_time(dt_mod) - return time_class(*result) - else: - return result - - def _to_python_tuple(self, value, state): - time = value.strip() - explicit_ampm = False - if self.use_ampm: - last_two = time[-2:].lower() - if last_two not in ('am', 'pm'): - if self.use_ampm != 'optional': - raise Invalid(self.message('noAMPM', state), value, state) - offset = 0 - else: - explicit_ampm = True - offset = 12 if last_two == 'pm' else 0 - time = time[:-2] - else: - offset = 0 - parts = time.split(':', 3) - if len(parts) > 3: - raise Invalid(self.message('tooManyColon', state), value, state) - if len(parts) == 3 and not self.use_seconds: - raise Invalid(self.message('noSeconds', state), value, state) - if (len(parts) == 2 - and self.use_seconds and self.use_seconds != 'optional'): - raise Invalid(self.message('secondsRequired', state), value, state) - if len(parts) == 1: - raise Invalid(self.message('minutesRequired', state), value, state) - try: - hour = int(parts[0]) - except ValueError: - raise Invalid( - self.message('badNumber', state, - number=parts[0], part='hour'), value, state) - if explicit_ampm: - if not 1 <= hour <= 12: - raise Invalid( - self.message('badHour', state, - number=hour, range='1-12'), value, state) - if hour == 12 and offset == 12: - # 12pm == 12 - pass - elif hour == 12 and offset == 0: - # 12am == 0 - hour = 0 - else: - hour += offset - else: - if not 0 <= hour < 24: - raise Invalid( - self.message('badHour', state, - number=hour, range='0-23'), value, state) - try: - minute = int(parts[1]) - except ValueError: - raise Invalid( - self.message('badNumber', state, - number=parts[1], part='minute'), value, state) - if not 0 <= minute < 60: - raise Invalid( - self.message('badMinute', state, number=minute), - value, state) - if len(parts) == 3: - try: - second = int(parts[2]) - except ValueError: - raise Invalid( - self.message('badNumber', state, - number=parts[2], part='second'), value, state) - if not 0 <= second < 60: - raise Invalid( - self.message('badSecond', state, number=second), - value, state) - else: - second = None - if second is None: - return (hour, minute) - else: - return (hour, minute, second) - - def _convert_from_python(self, value, state): - if isinstance(value, str): - return value - if hasattr(value, 'hour'): - hour, minute = value.hour, value.minute - second = value.second - elif len(value) == 3: - hour, minute, second = value - elif len(value) == 2: - hour, minute = value - second = 0 - ampm = '' - if (self.use_ampm == 'optional' and self.prefer_ampm) or ( - self.use_ampm and self.use_ampm != 'optional'): - ampm = 'am' - if hour > 12: - hour -= 12 - ampm = 'pm' - elif hour == 12: - ampm = 'pm' - elif hour == 0: - hour = 12 - if self.use_seconds: - return '%i:%02i:%02i%s' % (hour, minute, second, ampm) - else: - return '%i:%02i%s' % (hour, minute, ampm) - - -def PostalCode(*kw, **kwargs): - deprecation_warning("please use formencode.national.USPostalCode") - from formencode.national import USPostalCode - return USPostalCode(*kw, **kwargs) - - -class StripField(FancyValidator): - """ - Take a field from a dictionary, removing the key from the dictionary. - - ``name`` is the key. The field value and a new copy of the dictionary - with that field removed are returned. - - >>> StripField('test').to_python({'a': 1, 'test': 2}) - (2, {'a': 1}) - >>> StripField('test').to_python({}) - Traceback (most recent call last): - ... - Invalid: The name 'test' is missing - - """ - - __unpackargs__ = ('name',) - - messages = dict( - missing=_('The name %(name)s is missing')) - - def _convert_to_python(self, valueDict, state): - v = valueDict.copy() - try: - field = v.pop(self.name) - except KeyError: - raise Invalid( - self.message('missing', state, name=repr(self.name)), - valueDict, state) - return field, v - - def is_empty(self, value): - # empty dictionaries don't really apply here - return False - - -class StringBool(FancyValidator): # originally from TurboGears 1 - """ - Converts a string to a boolean. - - Values like 'true' and 'false' are considered True and False, - respectively; anything in ``true_values`` is true, anything in - ``false_values`` is false, case-insensitive). The first item of - those lists is considered the preferred form. - - :: - - >>> s = StringBool() - >>> s.to_python('yes'), s.to_python('no') - (True, False) - >>> s.to_python(1), s.to_python('N') - (True, False) - >>> s.to_python('ye') - Traceback (most recent call last): - ... - Invalid: Value should be 'true' or 'false' - """ - - true_values = ['true', 't', 'yes', 'y', 'on', '1'] - false_values = ['false', 'f', 'no', 'n', 'off', '0'] - - messages = dict( - string=_('Value should be %(true)r or %(false)r')) - - def _convert_to_python(self, value, state): - if isinstance(value, str): - value = value.strip().lower() - if value in self.true_values: - return True - if not value or value in self.false_values: - return False - raise Invalid( - self.message('string', state, - true=self.true_values[0], false=self.false_values[0]), - value, state) - return bool(value) - - def _convert_from_python(self, value, state): - return (self.true_values if value else self.false_values)[0] - -# Should deprecate: -StringBoolean = StringBool - - -class SignedString(FancyValidator): - """ - Encodes a string into a signed string, and base64 encodes both the - signature string and a random nonce. - - It is up to you to provide a secret, and to keep the secret handy - and consistent. - """ - - messages = dict( - malformed=_('Value does not contain a signature'), - badsig=_('Signature is not correct')) - - secret = None - nonce_length = 4 - - def _convert_to_python(self, value, state): - global sha1 - if not sha1: - from hashlib import sha1 - assert self.secret is not None, "You must give a secret" - parts = value.split(None, 1) - if not parts or len(parts) == 1: - raise Invalid(self.message('malformed', state), value, state) - sig, rest = parts - sig = sig.decode('base64') - rest = rest.decode('base64') - nonce = rest[:self.nonce_length] - rest = rest[self.nonce_length:] - expected = sha1(str(self.secret) + nonce + rest).digest() - if expected != sig: - raise Invalid(self.message('badsig', state), value, state) - return rest - - def _convert_from_python(self, value, state): - global sha1 - if not sha1: - from hashlib import sha1 - nonce = self.make_nonce() - value = str(value) - digest = sha1(self.secret + nonce + value).digest() - return self.encode(digest) + ' ' + self.encode(nonce + value) - - def encode(self, value): - return value.encode('base64').strip().replace('\n', '') - - def make_nonce(self): - global random - if not random: - import random - return ''.join(chr(random.randrange(256)) - for _i in range(self.nonce_length)) - - -class IPAddress(FancyValidator): - """ - Formencode validator to check whether a string is a correct IP address. - - Examples:: - - >>> ip = IPAddress() - >>> ip.to_python('127.0.0.1') - '127.0.0.1' - >>> ip.to_python('299.0.0.1') - Traceback (most recent call last): - ... - Invalid: The octets must be within the range of 0-255 (not '299') - >>> ip.to_python('192.168.0.1/1') - Traceback (most recent call last): - ... - Invalid: Please enter a valid IP address (a.b.c.d) - >>> ip.to_python('asdf') - Traceback (most recent call last): - ... - Invalid: Please enter a valid IP address (a.b.c.d) - """ - - messages = dict( - badFormat=_('Please enter a valid IP address (a.b.c.d)'), - leadingZeros=_('The octets must not have leading zeros'), - illegalOctets=_('The octets must be within the range of 0-255' - ' (not %(octet)r)')) - - leading_zeros = False - - def _validate_python(self, value, state=None): - try: - if not value: - raise ValueError - octets = value.split('.', 5) - # Only 4 octets? - if len(octets) != 4: - raise ValueError - # Correct octets? - for octet in octets: - if octet.startswith('0') and octet != '0': - if not self.leading_zeros: - raise Invalid( - self.message('leadingZeros', state), value, state) - # strip zeros so this won't be an octal number - octet = octet.lstrip('0') - if not 0 <= int(octet) < 256: - raise Invalid( - self.message('illegalOctets', state, octet=octet), - value, state) - # Splitting faild: wrong syntax - except ValueError: - raise Invalid(self.message('badFormat', state), value, state) - - -class CIDR(IPAddress): - """ - Formencode validator to check whether a string is in correct CIDR - notation (IP address, or IP address plus /mask). - - Examples:: - - >>> cidr = CIDR() - >>> cidr.to_python('127.0.0.1') - '127.0.0.1' - >>> cidr.to_python('299.0.0.1') - Traceback (most recent call last): - ... - Invalid: The octets must be within the range of 0-255 (not '299') - >>> cidr.to_python('192.168.0.1/1') - Traceback (most recent call last): - ... - Invalid: The network size (bits) must be within the range of 8-32 (not '1') - >>> cidr.to_python('asdf') - Traceback (most recent call last): - ... - Invalid: Please enter a valid IP address (a.b.c.d) or IP network (a.b.c.d/e) - """ - - messages = dict(IPAddress._messages, - badFormat=_('Please enter a valid IP address (a.b.c.d)' - ' or IP network (a.b.c.d/e)'), - illegalBits=_('The network size (bits) must be within the range' - ' of 8-32 (not %(bits)r)')) - - def _validate_python(self, value, state): - try: - # Split into octets and bits - if '/' in value: # a.b.c.d/e - addr, bits = value.split('/') - else: # a.b.c.d - addr, bits = value, 32 - # Use IPAddress validator to validate the IP part - IPAddress._validate_python(self, addr, state) - # Bits (netmask) correct? - if not 8 <= int(bits) <= 32: - raise Invalid( - self.message('illegalBits', state, bits=bits), - value, state) - # Splitting faild: wrong syntax - except ValueError: - raise Invalid(self.message('badFormat', state), value, state) - - -class MACAddress(FancyValidator): - """ - Formencode validator to check whether a string is a correct hardware - (MAC) address. - - Examples:: - - >>> mac = MACAddress() - >>> mac.to_python('aa:bb:cc:dd:ee:ff') - 'aabbccddeeff' - >>> mac.to_python('aa:bb:cc:dd:ee:ff:e') - Traceback (most recent call last): - ... - Invalid: A MAC address must contain 12 digits and A-F; the value you gave has 13 characters - >>> mac.to_python('aa:bb:cc:dd:ee:fx') - Traceback (most recent call last): - ... - Invalid: MAC addresses may only contain 0-9 and A-F (and optionally :), not 'x' - >>> MACAddress(add_colons=True).to_python('aabbccddeeff') - 'aa:bb:cc:dd:ee:ff' - """ - - strip = True - valid_characters = '0123456789abcdefABCDEF' - add_colons = False - - messages = dict( - badLength=_('A MAC address must contain 12 digits and A-F;' - ' the value you gave has %(length)s characters'), - badCharacter=_('MAC addresses may only contain 0-9 and A-F' - ' (and optionally :), not %(char)r')) - - def _convert_to_python(self, value, state): - address = value.replace(':', '').lower() # remove colons - if len(address) != 12: - raise Invalid( - self.message('badLength', state, - length=len(address)), address, state) - for char in address: - if char not in self.valid_characters: - raise Invalid( - self.message('badCharacter', state, - char=char), address, state) - if self.add_colons: - address = '%s:%s:%s:%s:%s:%s' % ( - address[0:2], address[2:4], address[4:6], - address[6:8], address[8:10], address[10:12]) - return address - - _convert_from_python = _convert_to_python - - -class FormValidator(FancyValidator): - """ - A FormValidator is something that can be chained with a Schema. - - Unlike normal chaining the FormValidator can validate forms that - aren't entirely valid. - - The important method is .validate(), of course. It gets passed a - dictionary of the (processed) values from the form. If you have - .validate_partial_form set to True, then it will get the incomplete - values as well -- check with the "in" operator if the form was able - to process any particular field. - - Anyway, .validate() should return a string or a dictionary. If a - string, it's an error message that applies to the whole form. If - not, then it should be a dictionary of fieldName: errorMessage. - The special key "form" is the error message for the form as a whole - (i.e., a string is equivalent to {"form": string}). - - Returns None on no errors. - """ - - validate_partial_form = False - - validate_partial_python = None - validate_partial_other = None - - def is_empty(self, value): - return False - - def field_is_empty(self, value): - return is_empty(value) - - -class RequireIfMissing(FormValidator): - """ - Require one field based on another field being present or missing. - - This validator is applied to a form, not an individual field (usually - using a Schema's ``pre_validators`` or ``chained_validators``) and is - available under both names ``RequireIfMissing`` and ``RequireIfPresent``. - - If you provide a ``missing`` value (a string key name) then - if that field is missing the field must be entered. - This gives you an either/or situation. - - If you provide a ``present`` value (another string key name) then - if that field is present, the required field must also be present. - - :: - - >>> from formencode import validators - >>> v = validators.RequireIfPresent('phone_type', present='phone') - >>> v.to_python(dict(phone_type='', phone='510 420 4577')) - Traceback (most recent call last): - ... - Invalid: You must give a value for phone_type - >>> v.to_python(dict(phone='')) - {'phone': ''} - - Note that if you have a validator on the optionally-required - field, you should probably use ``if_missing=None``. This way you - won't get an error from the Schema about a missing value. For example:: - - class PhoneInput(Schema): - phone = PhoneNumber() - phone_type = String(if_missing=None) - chained_validators = [RequireIfPresent('phone_type', present='phone')] - """ - - # Field that potentially is required: - required = None - # If this field is missing, then it is required: - missing = None - # If this field is present, then it is required: - present = None - - __unpackargs__ = ('required',) - - def _convert_to_python(self, value_dict, state): - is_empty = self.field_is_empty - if is_empty(value_dict.get(self.required)) and ( - (self.missing and is_empty(value_dict.get(self.missing))) or - (self.present and not is_empty(value_dict.get(self.present)))): - raise Invalid( - _('You must give a value for %s') % self.required, - value_dict, state, - error_dict={self.required: - Invalid(self.message('empty', state), - value_dict.get(self.required), state)}) - return value_dict - -RequireIfPresent = RequireIfMissing - -class RequireIfMatching(FormValidator): - """ - Require a list of fields based on the value of another field. - - This validator is applied to a form, not an individual field (usually - using a Schema's ``pre_validators`` or ``chained_validators``). - - You provide a field name, an expected value and a list of required fields - (a list of string key names). If the value of the field, if present, - matches the value of ``expected_value``, then the validator will raise an - ``Invalid`` exception for every field in ``required_fields`` that is - missing. - - :: - - >>> from formencode import validators - >>> v = validators.RequireIfMatching('phone_type', expected_value='mobile', required_fields=['mobile']) - >>> v.to_python(dict(phone_type='mobile')) - Traceback (most recent call last): - ... - formencode.api.Invalid: You must give a value for mobile - >>> v.to_python(dict(phone_type='someothervalue')) - {'phone_type': 'someothervalue'} - """ - - # Field that we will check for its value: - field = None - # Value that the field shall have - expected_value = None - # If this field is present, then these fields are required: - required_fields = [] - - __unpackargs__ = ('field', 'expected_value') - - def _convert_to_python(self, value_dict, state): - is_empty = self.field_is_empty - - if self.field in value_dict and value_dict.get(self.field) == self.expected_value: - for required_field in self.required_fields: - if required_field not in value_dict or is_empty(value_dict.get(required_field)): - raise Invalid( - _('You must give a value for %s') % required_field, - value_dict, state, - error_dict={required_field: - Invalid(self.message('empty', state), - value_dict.get(required_field), state)}) - return value_dict - -class FieldsMatch(FormValidator): - """ - Tests that the given fields match, i.e., are identical. Useful - for password+confirmation fields. Pass the list of field names in - as `field_names`. - - :: - - >>> f = FieldsMatch('pass', 'conf') - >>> sorted(f.to_python({'pass': 'xx', 'conf': 'xx'}).items()) - [('conf', 'xx'), ('pass', 'xx')] - >>> f.to_python({'pass': 'xx', 'conf': 'yy'}) - Traceback (most recent call last): - ... - Invalid: conf: Fields do not match - """ - - show_match = False - field_names = None - validate_partial_form = True - - __unpackargs__ = ('*', 'field_names') - - messages = dict( - invalid=_('Fields do not match (should be %(match)s)'), - invalidNoMatch=_('Fields do not match'), - notDict=_('Fields should be a dictionary')) - - def __init__(self, *args, **kw): - super(FieldsMatch, self).__init__(*args, **kw) - if len(self.field_names) < 2: - raise TypeError('FieldsMatch() requires at least two field names') - - def validate_partial(self, field_dict, state): - for name in self.field_names: - if name not in field_dict: - return - self._validate_python(field_dict, state) - - def _validate_python(self, field_dict, state): - try: - ref = field_dict[self.field_names[0]] - except TypeError: - # Generally because field_dict isn't a dict - raise Invalid(self.message('notDict', state), field_dict, state) - except KeyError: - ref = '' - errors = {} - for name in self.field_names[1:]: - if field_dict.get(name, '') != ref: - if self.show_match: - errors[name] = self.message('invalid', state, - match=ref) - else: - errors[name] = self.message('invalidNoMatch', state) - if errors: - error_list = sorted(errors.items()) - error_message = '
\n'.join( - '%s: %s' % (name, value) for name, value in error_list) - raise Invalid(error_message, field_dict, state, error_dict=errors) - - -class CreditCardValidator(FormValidator): - """ - Checks that credit card numbers are valid (if not real). - - You pass in the name of the field that has the credit card - type and the field with the credit card number. The credit - card type should be one of "visa", "mastercard", "amex", - "dinersclub", "discover", "jcb". - - You must check the expiration date yourself (there is no - relation between CC number/types and expiration dates). - - :: - - >>> cc = CreditCardValidator() - >>> sorted(cc.to_python({'ccType': 'visa', 'ccNumber': '4111111111111111'}).items()) - [('ccNumber', '4111111111111111'), ('ccType', 'visa')] - >>> cc.to_python({'ccType': 'visa', 'ccNumber': '411111111111111'}) - Traceback (most recent call last): - ... - Invalid: ccNumber: You did not enter a valid number of digits - >>> cc.to_python({'ccType': 'visa', 'ccNumber': '411111111111112'}) - Traceback (most recent call last): - ... - Invalid: ccNumber: You did not enter a valid number of digits - >>> cc().to_python({}) - Traceback (most recent call last): - ... - Invalid: The field ccType is missing - """ - - validate_partial_form = True - - cc_type_field = 'ccType' - cc_number_field = 'ccNumber' - - __unpackargs__ = ('cc_type_field', 'cc_number_field') - - messages = dict( - notANumber=_('Please enter only the number, no other characters'), - badLength=_('You did not enter a valid number of digits'), - invalidNumber=_('That number is not valid'), - missing_key=_('The field %(key)s is missing')) - - def validate_partial(self, field_dict, state): - if not field_dict.get(self.cc_type_field, None) \ - or not field_dict.get(self.cc_number_field, None): - return None - self._validate_python(field_dict, state) - - def _validate_python(self, field_dict, state): - errors = self._validateReturn(field_dict, state) - if errors: - error_list = sorted(errors.items()) - raise Invalid( - '
\n'.join('%s: %s' % (name, value) - for name, value in error_list), - field_dict, state, error_dict=errors) - - def _validateReturn(self, field_dict, state): - for field in self.cc_type_field, self.cc_number_field: - if field not in field_dict: - raise Invalid( - self.message('missing_key', state, key=field), - field_dict, state) - ccType = field_dict[self.cc_type_field].lower().strip() - number = field_dict[self.cc_number_field].strip() - number = number.replace(' ', '') - number = number.replace('-', '') - try: - int(number) - except ValueError: - return {self.cc_number_field: self.message('notANumber', state)} - assert ccType in self._cardInfo, ( - "I can't validate that type of credit card") - foundValid = False - validLength = False - for prefix, length in self._cardInfo[ccType]: - if len(number) == length: - validLength = True - if number.startswith(prefix): - foundValid = True - break - if not validLength: - return {self.cc_number_field: self.message('badLength', state)} - if not foundValid: - return {self.cc_number_field: self.message('invalidNumber', state)} - if not self._validateMod10(number): - return {self.cc_number_field: self.message('invalidNumber', state)} - return None - - def _validateMod10(self, s): - """Check string with the mod 10 algorithm (aka "Luhn formula").""" - checksum, factor = 0, 1 - for c in reversed(s): - for c in str(factor * int(c)): - checksum += int(c) - factor = 3 - factor - return checksum % 10 == 0 - - _cardInfo = { - "visa": [('4', 16), - ('4', 13)], - "mastercard": [('51', 16), - ('52', 16), - ('53', 16), - ('54', 16), - ('55', 16)], - "discover": [('6011', 16)], - "amex": [('34', 15), - ('37', 15)], - "dinersclub": [('300', 14), - ('301', 14), - ('302', 14), - ('303', 14), - ('304', 14), - ('305', 14), - ('36', 14), - ('38', 14)], - "jcb": [('3', 16), - ('2131', 15), - ('1800', 15)], - } - - -class CreditCardExpires(FormValidator): - """ - Checks that credit card expiration date is valid relative to - the current date. - - You pass in the name of the field that has the credit card - expiration month and the field with the credit card expiration - year. - - :: - - >>> ed = CreditCardExpires() - >>> sorted(ed.to_python({'ccExpiresMonth': '11', 'ccExpiresYear': '2250'}).items()) - [('ccExpiresMonth', '11'), ('ccExpiresYear', '2250')] - >>> ed.to_python({'ccExpiresMonth': '10', 'ccExpiresYear': '2005'}) - Traceback (most recent call last): - ... - Invalid: ccExpiresMonth: Invalid Expiration Date
- ccExpiresYear: Invalid Expiration Date - """ - - validate_partial_form = True - - cc_expires_month_field = 'ccExpiresMonth' - cc_expires_year_field = 'ccExpiresYear' - - __unpackargs__ = ('cc_expires_month_field', 'cc_expires_year_field') - - datetime_module = None - - messages = dict( - notANumber=_('Please enter numbers only for month and year'), - invalidNumber=_('Invalid Expiration Date')) - - def validate_partial(self, field_dict, state): - if not field_dict.get(self.cc_expires_month_field, None) \ - or not field_dict.get(self.cc_expires_year_field, None): - return None - self._validate_python(field_dict, state) - - def _validate_python(self, field_dict, state): - errors = self._validateReturn(field_dict, state) - if errors: - error_list = sorted(errors.items()) - raise Invalid( - '
\n'.join('%s: %s' % (name, value) - for name, value in error_list), - field_dict, state, error_dict=errors) - - def _validateReturn(self, field_dict, state): - ccExpiresMonth = str(field_dict[self.cc_expires_month_field]).strip() - ccExpiresYear = str(field_dict[self.cc_expires_year_field]).strip() - - try: - ccExpiresMonth = int(ccExpiresMonth) - ccExpiresYear = int(ccExpiresYear) - dt_mod = import_datetime(self.datetime_module) - now = datetime_now(dt_mod) - today = datetime_makedate(dt_mod, now.year, now.month, now.day) - next_month = ccExpiresMonth % 12 + 1 - next_month_year = ccExpiresYear - if next_month == 1: - next_month_year += 1 - expires_date = datetime_makedate( - dt_mod, next_month_year, next_month, 1) - assert expires_date > today - except ValueError: - return {self.cc_expires_month_field: - self.message('notANumber', state), - self.cc_expires_year_field: - self.message('notANumber', state)} - except AssertionError: - return {self.cc_expires_month_field: - self.message('invalidNumber', state), - self.cc_expires_year_field: - self.message('invalidNumber', state)} - - -class CreditCardSecurityCode(FormValidator): - """ - Checks that credit card security code has the correct number - of digits for the given credit card type. - - You pass in the name of the field that has the credit card - type and the field with the credit card security code. - - :: - - >>> code = CreditCardSecurityCode() - >>> sorted(code.to_python({'ccType': 'visa', 'ccCode': '111'}).items()) - [('ccCode', '111'), ('ccType', 'visa')] - >>> code.to_python({'ccType': 'visa', 'ccCode': '1111'}) - Traceback (most recent call last): - ... - Invalid: ccCode: Invalid credit card security code length - """ - - validate_partial_form = True - - cc_type_field = 'ccType' - cc_code_field = 'ccCode' - - __unpackargs__ = ('cc_type_field', 'cc_code_field') - - messages = dict( - notANumber=_('Please enter numbers only for credit card security code'), - badLength=_('Invalid credit card security code length')) - - def validate_partial(self, field_dict, state): - if (not field_dict.get(self.cc_type_field, None) - or not field_dict.get(self.cc_code_field, None)): - return None - self._validate_python(field_dict, state) - - def _validate_python(self, field_dict, state): - errors = self._validateReturn(field_dict, state) - if errors: - error_list = sorted(errors.items()) - raise Invalid( - '
\n'.join('%s: %s' % (name, value) - for name, value in error_list), - field_dict, state, error_dict=errors) - - def _validateReturn(self, field_dict, state): - ccType = str(field_dict[self.cc_type_field]).strip() - ccCode = str(field_dict[self.cc_code_field]).strip() - try: - int(ccCode) - except ValueError: - return {self.cc_code_field: self.message('notANumber', state)} - length = self._cardInfo[ccType] - if len(ccCode) != length: - return {self.cc_code_field: self.message('badLength', state)} - - # key = credit card type, value = length of security code - _cardInfo = dict(visa=3, mastercard=3, discover=3, amex=4) - - -def validators(): - """Return the names of all validators in this module.""" - return [name for name, value in globals().items() - if isinstance(value, type) and issubclass(value, Validator)] - -__all__ = ['Invalid'] + validators() - diff --git a/tox.ini b/tox.ini index 5fd8c596..57e8b8b3 100644 --- a/tox.ini +++ b/tox.ini @@ -732,9 +732,7 @@ commands = {[mssql-pyodbc-w32]commands} [testenv:py37-mssql-pyodbc-noauto-w32] platform = win32 -commands = - cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" - {[mssql-pyodbc-w32]commands} +commands = {[mssql-pyodbc-w32]commands} [testenv:py38-mssql-pyodbc-noauto-w32] platform = win32 @@ -773,9 +771,7 @@ commands = {[mysql-connector-w32]commands} [testenv:py37-mysql-connector-w32] platform = win32 -commands = - cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" - {[mysql-connector-w32]commands} +commands = {[mysql-connector-w32]commands} [testenv:py38-mysql-connector-w32] platform = win32 @@ -814,9 +810,7 @@ commands = {[pymysql-w32]commands} [testenv:py37-mysql-pymysql-w32] platform = win32 -commands = - cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" - {[pymysql-w32]commands} +commands = {[pymysql-w32]commands} [testenv:py38-mysql-pymysql-w32] platform = win32 @@ -856,9 +850,7 @@ commands = {[mariadb-w32]commands} [testenv:py37-mariadb-w32] platform = win32 -commands = - cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" - {[mariadb-w32]commands} +commands = {[mariadb-w32]commands} [testenv:py38-mariadb-w32] platform = win32 @@ -898,9 +890,7 @@ commands = {[mysql-pyodbc-w32]commands} [testenv:py37-mysql-pyodbc-noauto-w32] platform = win32 -commands = - cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" - {[mysql-pyodbc-w32]commands} +commands = {[mysql-pyodbc-w32]commands} [testenv:py38-mysql-pyodbc-noauto-w32] platform = win32 @@ -940,9 +930,7 @@ commands = {[mysql-pypyodbc-w32]commands} [testenv:py37-mysql-pypyodbc-noauto-w32] platform = win32 -commands = - cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" - {[mysql-pypyodbc-w32]commands} +commands = {[mysql-pypyodbc-w32]commands} [testenv:py38-mysql-pypyodbc-noauto-w32] platform = win32 @@ -981,9 +969,7 @@ commands = {[psycopg-w32]commands} [testenv:py37-postgres-psycopg-w32] platform = win32 -commands = - cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" - {[psycopg-w32]commands} +commands = {[psycopg-w32]commands} [testenv:py38-postgres-psycopg-w32] platform = win32 @@ -1022,9 +1008,7 @@ commands = {[pygresql-w32]commands} [testenv:py37-postgres-pygresql-w32] platform = win32 -commands = - cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" - {[pygresql-w32]commands} +commands = {[pygresql-w32]commands} [testenv:py38-postgres-pygresql-w32] platform = win32 @@ -1062,9 +1046,7 @@ commands = {[pypostgresql-w32]commands} [testenv:py37-postgres-pypostgresql-w32] platform = win32 -commands = - cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" - {[pypostgresql-w32]commands} +commands = {[pypostgresql-w32]commands} [testenv:py38-postgres-pypostgresql-w32] platform = win32 @@ -1103,9 +1085,7 @@ commands = {[pg8000-w32]commands} [testenv:py37-postgres-pg8000-w32] platform = win32 -commands = - cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" - {[pg8000-w32]commands} +commands = {[pg8000-w32]commands} [testenv:py38-postgres-pg8000-w32] platform = win32 @@ -1145,9 +1125,7 @@ commands = {[postgres-pyodbc-w32]commands} [testenv:py37-postgres-pyodbc-noauto-w32] platform = win32 -commands = - cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" - {[postgres-pyodbc-w32]commands} +commands = {[postgres-pyodbc-w32]commands} [testenv:py38-postgres-pyodbc-noauto-w32] platform = win32 @@ -1187,9 +1165,7 @@ commands = {[postgres-pypyodbc-w32]commands} [testenv:py37-postgres-pypyodbc-noauto-w32] platform = win32 -commands = - cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" - {[postgres-pypyodbc-w32]commands} +commands = {[postgres-pypyodbc-w32]commands} [testenv:py38-postgres-pypyodbc-noauto-w32] platform = win32 @@ -1226,9 +1202,7 @@ commands = {[sqlite-w32]commands} [testenv:py37-sqlite-w32] platform = win32 -commands = - cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" - {[sqlite-w32]commands} +commands = {[sqlite-w32]commands} [testenv:py38-sqlite-w32] platform = win32 @@ -1264,9 +1238,7 @@ commands = {[sqlite-memory-w32]commands} [testenv:py37-sqlite-memory-w32] platform = win32 -commands = - cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" - {[sqlite-memory-w32]commands} +commands = {[sqlite-memory-w32]commands} [testenv:py38-sqlite-memory-w32] platform = win32 From 73ffdca9970cde63e66636335e6161e73a48ad84 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 15 Dec 2020 16:56:18 +0300 Subject: [PATCH 286/509] Release 3.9.0 --- ANNOUNCE.rst | 48 ++++++++++++++++++++++++++------------- README.rst | 12 ++++++---- devscripts/build-all-docs | 2 +- docs/News.rst | 8 ++++--- sqlobject/__version__.py | 6 ++--- 5 files changed, 48 insertions(+), 28 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 9beb8c90..36371d0e 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,25 +1,40 @@ Hello! -I'm pleased to announce version 3.8.1a1, the first alpha of the upcoming -release of branch 3.8 of SQLObject. +I'm pleased to announce version 3.9.0, the first release +of branch 3.9 of SQLObject. -I'm pleased to announce version 3.8.1a2, the second alpha of the upcoming -release of branch 3.8 of SQLObject. -I'm pleased to announce version 3.8.1b1, the first beta of the upcoming -release of branch 3.8 of SQLObject. +What's new in SQLObject +======================= -I'm pleased to announce version 3.8.1rc1, the first release candidate -of the upcoming release of branch 3.8 of SQLObject. +Contributors for this release are: -I'm pleased to announce version 3.8.2, the first bugfix release of branch -3.8 of SQLObject. ++ Michael S. Root, Ameya Bapat - ``JSONCol``; ++ Jerry Nance - reported a bug with ``DateTime`` from ``Zope``. -What's new in SQLObject -======================= +Features +-------- + +* Add ``JSONCol``: a universal json column that converts simple Python objects + (None, bool, int, float, long, dict, list, str/unicode to/from JSON using + json.dumps/loads. A subclass of StringCol. Requires ``VARCHAR``/``TEXT`` + columns at backends, doesn't work with ``JSON`` columns. + +* Extend/fix support for ``DateTime`` from ``Zope``. + +* Drop support for very old version of ``mxDateTime`` + without ``mx.`` namespace. + +Drivers +------- + +* Support `mariadb `_. + +CI +-- -Contributors for this release are +* Run tests with Python 3.9 at Travis and AppVeyor. For a more complete list, please see the news: http://sqlobject.org/News.html @@ -32,8 +47,9 @@ SQLObject is an object-relational mapper. Your database tables are described as classes, and rows are instances of those classes. SQLObject is meant to be easy to use and quick to get started with. -SQLObject supports a number of backends: MySQL, PostgreSQL, SQLite, -Firebird, Sybase, MSSQL and MaxDB (also known as SAPDB). +It currently supports MySQL, PostgreSQL and SQLite; connections to other +backends - Firebird, Sybase, MSSQL and MaxDB (also known as SAPDB) - are +lesser debugged). Python 2.7 or 3.4+ is required. @@ -51,7 +67,7 @@ Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Download: -https://pypi.org/project/SQLObject/3.8.2a0.dev20201001/ +https://pypi.org/project/SQLObject/3.9.0 News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index a0f632de..cd66ddfa 100644 --- a/README.rst +++ b/README.rst @@ -1,13 +1,15 @@ -SQLObject 3.8.2a0 -================= +SQLObject 3.9.0 +=============== Thanks for looking at SQLObject. SQLObject is an object-relational mapper, i.e., a library that will wrap your database tables in Python classes, and your rows in Python instances. -It currently supports MySQL through the `MySQLdb` package, PostgreSQL -through the `psycopg` package, SQLite, Firebird, MaxDB (SAP DB), MS SQL, -and Sybase. Python 2.7 or 3.4+ is required. +It currently supports MySQL, PostgreSQL and SQLite; connections to other +backends - Firebird, Sybase, MSSQL and MaxDB (also known as SAPDB) - are +lesser debugged). + +Python 2.7 or 3.4+ is required. For more information please see the documentation in ``_, or online at http://sqlobject.org/ diff --git a/devscripts/build-all-docs b/devscripts/build-all-docs index 4eab6205..1f21c9a8 100755 --- a/devscripts/build-all-docs +++ b/devscripts/build-all-docs @@ -10,7 +10,7 @@ cd "`dirname \"$0\"`" && PROG_DIR="`pwd`" && cd .. && -build_docs 3.8.1 && +build_docs 3.9.0 && build_docs master devel && rm -rf docs/html && diff --git a/docs/News.rst b/docs/News.rst index 253ef84b..e1e59161 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,8 +5,10 @@ News .. contents:: Contents: :backlinks: none -SQLObject (master) -================== +SQLObject 3.9.0 +=============== + +Released 2020 Dec 15. Features -------- @@ -24,7 +26,7 @@ Features Drivers ------- -* Support ``mariadb``. +* Support `mariadb `_. CI -- diff --git a/sqlobject/__version__.py b/sqlobject/__version__.py index 579bdd6a..f133a875 100644 --- a/sqlobject/__version__.py +++ b/sqlobject/__version__.py @@ -1,8 +1,8 @@ -version = '3.8.1' +version = '3.9.0' major = 3 -minor = 8 -micro = 1 +minor = 9 +micro = 0 release_level = 'final' serial = 0 version_info = (major, minor, micro, release_level, serial) From 78cf7a8465a224ee11dac455c6b8affe92fa016f Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 15 Dec 2020 17:10:24 +0300 Subject: [PATCH 287/509] Prepare for the next release [skip ci] --- ANNOUNCE.rst | 49 +++++++++++++++++-------------------------------- README.rst | 4 ++-- docs/News.rst | 3 +++ 3 files changed, 22 insertions(+), 34 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 36371d0e..72872502 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,40 +1,25 @@ Hello! -I'm pleased to announce version 3.9.0, the first release -of branch 3.9 of SQLObject. +I'm pleased to announce version 3.9.1a1, the first alpha of the upcoming +release of branch 3.9 of SQLObject. +I'm pleased to announce version 3.9.1a2, the second alpha of the upcoming +release of branch 3.9 of SQLObject. -What's new in SQLObject -======================= - -Contributors for this release are: - -+ Michael S. Root, Ameya Bapat - ``JSONCol``; - -+ Jerry Nance - reported a bug with ``DateTime`` from ``Zope``. +I'm pleased to announce version 3.9.1b1, the first beta of the upcoming +release of branch 3.9 of SQLObject. -Features --------- +I'm pleased to announce version 3.9.1rc1, the first release candidate +of the upcoming release of branch 3.9 of SQLObject. -* Add ``JSONCol``: a universal json column that converts simple Python objects - (None, bool, int, float, long, dict, list, str/unicode to/from JSON using - json.dumps/loads. A subclass of StringCol. Requires ``VARCHAR``/``TEXT`` - columns at backends, doesn't work with ``JSON`` columns. +I'm pleased to announce version 3.9.1, the first bugfix release of branch +3.9 of SQLObject. -* Extend/fix support for ``DateTime`` from ``Zope``. -* Drop support for very old version of ``mxDateTime`` - without ``mx.`` namespace. - -Drivers -------- - -* Support `mariadb `_. - -CI --- +What's new in SQLObject +======================= -* Run tests with Python 3.9 at Travis and AppVeyor. +Contributors for this release are For a more complete list, please see the news: http://sqlobject.org/News.html @@ -47,9 +32,9 @@ SQLObject is an object-relational mapper. Your database tables are described as classes, and rows are instances of those classes. SQLObject is meant to be easy to use and quick to get started with. -It currently supports MySQL, PostgreSQL and SQLite; connections to other -backends - Firebird, Sybase, MSSQL and MaxDB (also known as SAPDB) - are -lesser debugged). +SQLObject supports a number of backends: MySQL, PostgreSQL, SQLite; +connections to other backends - Firebird, Sybase, MSSQL +and MaxDB (also known as SAPDB) - are lesser debugged). Python 2.7 or 3.4+ is required. @@ -67,7 +52,7 @@ Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Download: -https://pypi.org/project/SQLObject/3.9.0 +https://pypi.org/project/SQLObject/3.9.1a0.dev20201215/ News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index cd66ddfa..2442b674 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.9.0 -=============== +SQLObject 3.9.1a0 +================= Thanks for looking at SQLObject. SQLObject is an object-relational mapper, i.e., a library that will wrap your database tables in Python diff --git a/docs/News.rst b/docs/News.rst index e1e59161..5d5b0665 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,6 +5,9 @@ News .. contents:: Contents: :backlinks: none +SQLObject (master) +================== + SQLObject 3.9.0 =============== From a2b0c6297dafc14a37503fb8c089e0cbc4d9e925 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 18 Dec 2020 03:29:44 +0300 Subject: [PATCH 288/509] Build(setup.py): Change URLs for ``oursql`` in ``extras_require`` Provide separate URLs for Python 2.7 and 3.4+. [skip ci] --- docs/News.rst | 6 ++++++ setup.py | 5 ++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/docs/News.rst b/docs/News.rst index 5d5b0665..df973871 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,12 @@ News SQLObject (master) ================== +Build +----- + +* Change URLs for ``oursql`` in ``extras_require`` in ``setup.py``. + Provide separate URLs for Python 2.7 and 3.4+. + SQLObject 3.9.0 =============== diff --git a/setup.py b/setup.py index 58cd1d0f..674aaec9 100755 --- a/setup.py +++ b/setup.py @@ -115,7 +115,10 @@ 'mysql:python_version=="2.7"': ['MySQL-python'], 'mysql:python_version>="3.4"': ['mysqlclient'], 'mysql-connector': ['mysql-connector'], - 'oursql': ['oursql'], + 'oursql:python_version=="2.7"': [ + 'oursql @ git+https://github.com/sqlobject/oursql.git@master'], + 'oursql:python_version>="3.4"': [ + 'oursql3 @ git+https://github.com/sqlobject/oursql.git@py3k'], 'pymysql': ['pymysql'], # ODBC 'odbc': ['pyodbc'], From 6f6f974c00bf095cb8120ca2df3ca6ef18d52a94 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 18 Dec 2020 03:31:41 +0300 Subject: [PATCH 289/509] Build(setup.py): Add ``mariadb`` in ``extras_require`` [skip ci] --- docs/News.rst | 2 ++ docs/download.rst | 2 +- setup.py | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/News.rst b/docs/News.rst index df973871..59558ab6 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -14,6 +14,8 @@ Build * Change URLs for ``oursql`` in ``extras_require`` in ``setup.py``. Provide separate URLs for Python 2.7 and 3.4+. +* Add ``mariadb`` in ``extras_require`` in ``setup.py``. + SQLObject 3.9.0 =============== diff --git a/docs/download.rst b/docs/download.rst index 0126343b..69069dd9 100644 --- a/docs/download.rst +++ b/docs/download.rst @@ -63,7 +63,7 @@ MySQL ^^^^^ mysql (installs MySQL-python for Python 2.7 and mysqlclient for Python 3.4+) -mysql-connector oursql pymysql +mysql-connector oursql pymysql mariadb ODBC ^^^^ diff --git a/setup.py b/setup.py index 674aaec9..11a6cbaa 100755 --- a/setup.py +++ b/setup.py @@ -120,6 +120,7 @@ 'oursql:python_version>="3.4"': [ 'oursql3 @ git+https://github.com/sqlobject/oursql.git@py3k'], 'pymysql': ['pymysql'], + 'mariadb': ['mariadb'], # ODBC 'odbc': ['pyodbc'], 'pyodbc': ['pyodbc'], From a784248acfa8d1ba01b69553100fe20c4f0859ba Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 2 Jan 2021 01:03:40 +0300 Subject: [PATCH 290/509] CI(AppVeyor): Upgrade `tox` It seems we no longer need to limit version at AppVeyor. --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 84c56d4d..68dd3ce2 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -125,7 +125,7 @@ install: - "python --version" - "python -c \"import struct; print(struct.calcsize('P') * 8)\"" - "python -m pip install --upgrade \"pip<21\" \"setuptools<44\"" - - "pip install --upgrade \"tox<3.1\" ppu" + - "pip install --upgrade tox ppu" - "pip --version" # List ODBC drivers - ps: Get-OdbcDriver -Platform 32-bit | Select-Object -ExpandProperty Name From da5e27ffd5bd80acdba7459c276f5cd80c0e6162 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 2 Jan 2021 16:30:30 +0300 Subject: [PATCH 291/509] Test(tox): Fix `py-postgresql` package name --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 57e8b8b3..77d44c5e 100644 --- a/tox.ini +++ b/tox.ini @@ -28,7 +28,7 @@ deps = mariadb: mariadb postgres-psycopg: psycopg2-binary pygresql: -rdevscripts/requirements/requirements_pygresql.txt - pypostgresql: git+https://github.com/sqlobject/py-postgresql.git@fix_w32#egg=pypostgresql + pypostgresql: git+https://github.com/sqlobject/py-postgresql.git@fix_w32#egg=py-postgresql postgres-pg8000: git+https://github.com/sqlobject/pg8000.git@getuser#egg=pg8000 pyodbc: pyodbc pypyodbc: pypyodbc From d724e34b67a89e3dfddf2b2d7914673170312e71 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 20 Feb 2021 18:01:04 +0300 Subject: [PATCH 292/509] CI(.travis.yml): Use `- |` for multiline shell blocks --- .travis.yml | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9fddebe6..56623427 100644 --- a/.travis.yml +++ b/.travis.yml @@ -87,17 +87,20 @@ matrix: before_install: # Install version-specific dependencies - - if [[ $TESTS = py27-* ]]; then - sudo apt-get --quiet --yes install python-egenix-mxdatetime python-mysqldb python-psycopg2; + - | + if [[ $TESTS = py27-* ]]; then + sudo apt-get --quiet --yes install python-egenix-mxdatetime python-mysqldb python-psycopg2 fi - - if [[ $TESTS = py3*-* ]]; then - sudo apt-get --quiet --yes install python3-mysqldb python3-psycopg2; + - | + if [[ $TESTS = py3*-* ]]; then + sudo apt-get --quiet --yes install python3-mysqldb python3-psycopg2 fi # Install MariaDB mysql-compatible development files to compile mysql drivers - - if [[ $TESTS = py3[6789]-mysql ]]; then - sudo apt-get --quiet --yes install libmysqlclient-dev; + - | + if [[ $TESTS = py3[6789]-mysql ]]; then + sudo apt-get --quiet --yes install libmysqlclient-dev elif [[ $TESTS = py3[6789]-mariadb ]]; then - sudo apt-get --quiet --yes install libmariadb-dev-compat; + sudo apt-get --quiet --yes install libmariadb-dev-compat fi # Install and start the firebird database server. # We use firebird-super, so there's none of the inetd configuration @@ -107,14 +110,15 @@ before_install: # to create the test database. # Copied password initializtion from # https://github.com/xdenser/node-firebird-libfbclient/blob/master/.travis.yml - - if [[ $TESTS = *firebird* ]]; then - sudo apt-get --quiet --yes install firebird2.5-super && - sudo sed -i /etc/default/firebird2.5 -e 's/=no/=yes/' && - sudo /etc/init.d/firebird2.5-super start && sleep 5 && - sudo /bin/bash -c '(export FB_VER="2.5"; export FB_FLAVOUR="super";source /usr/share/firebird2.5-common/functions.sh; writeNewPassword masterkey)' && - sudo gsec -user sysdba -pass masterkey -add test -pw test && - sudo /bin/bash -c "echo \"CREATE DATABASE 'localhost:/tmp/test.fdb';\" > /var/lib/firebird/create_test_db" && - sudo chmod 644 /var/lib/firebird/create_test_db; + - | + if [[ $TESTS = *firebird* ]]; then + sudo apt-get --quiet --yes install firebird2.5-super + sudo sed -i /etc/default/firebird2.5 -e 's/=no/=yes/' + sudo /etc/init.d/firebird2.5-super start && sleep 5 + sudo /bin/bash -c '(export FB_VER="2.5"; export FB_FLAVOUR="super";source /usr/share/firebird2.5-common/functions.sh; writeNewPassword masterkey)' + sudo gsec -user sysdba -pass masterkey -add test -pw test + sudo /bin/bash -c "echo \"CREATE DATABASE 'localhost:/tmp/test.fdb';\" > /var/lib/firebird/create_test_db" + sudo chmod 644 /var/lib/firebird/create_test_db fi install: travis_retry pip install --upgrade "pip<21" "setuptools<44" tox coveralls codecov ppu From 52740edf09bb92b5d57d1364411db4c6bdc8d4fc Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 20 Feb 2021 18:47:48 +0300 Subject: [PATCH 293/509] Tests: Refactor `tox.ini` Requires `tox` >= 3.15. For tests with Python 3.4 run `tox` under Python 3.5. --- .travis.yml | 20 +- appveyor.yml | 2 +- devscripts/requirements/requirements_tox.txt | 2 +- tox.ini | 694 +------------------ 4 files changed, 52 insertions(+), 666 deletions(-) diff --git a/.travis.yml b/.travis.yml index 56623427..638d6484 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,8 +20,8 @@ matrix: include: - python: "2.7" env: TESTS=py27-mysql - - python: "3.4" - env: TESTS=py34-mysql + - python: "3.5" + env: TESTS=py34-mysql TOXPYTHON=/home/travis/virtualenv/python3.4.8/bin/python3.4 - python: "3.5" env: TESTS=py35-mysql - python: "3.6" @@ -46,8 +46,8 @@ matrix: dist: focal - python: "2.7" env: TESTS=py27-postgres - - python: "3.4" - env: TESTS=py34-postgres + - python: "3.5" + env: TESTS=py34-postgres TOXPYTHON=/home/travis/virtualenv/python3.4.8/bin/python3.4 - python: "3.5" env: TESTS=py35-postgres - python: "3.6" @@ -60,8 +60,8 @@ matrix: env: TESTS=py39-postgres - python: "2.7" env: TESTS=py27-sqlite - - python: "3.4" - env: TESTS=py34-sqlite + - python: "3.5" + env: TESTS=py34-sqlite TOXPYTHON=/home/travis/virtualenv/python3.4.8/bin/python3.4 - python: "3.5" env: TESTS=py35-sqlite - python: "3.6" @@ -95,6 +95,12 @@ before_install: if [[ $TESTS = py3*-* ]]; then sudo apt-get --quiet --yes install python3-mysqldb python3-psycopg2 fi + - | + if [[ $TESTS = py34-* ]]; then + # Manually install Python 3.4 to run tox under Python 3.5 and tests with Python 3.4 + curl -sSf --retry 5 -o python-3.4.tar.bz2 https://storage.googleapis.com/travis-ci-language-archives/python/binaries/ubuntu/16.04/x86_64/python-3.4.tar.bz2 + sudo tar xjf python-3.4.tar.bz2 --directory / + fi # Install MariaDB mysql-compatible development files to compile mysql drivers - | if [[ $TESTS = py3[6789]-mysql ]]; then @@ -121,7 +127,7 @@ before_install: sudo chmod 644 /var/lib/firebird/create_test_db fi -install: travis_retry pip install --upgrade "pip<21" "setuptools<44" tox coveralls codecov ppu +install: travis_retry pip install --upgrade "pip<21" "setuptools<44" "tox>=3.15" coveralls codecov ppu script: devscripts/tox-select-envs $TESTS diff --git a/appveyor.yml b/appveyor.yml index 68dd3ce2..38a7a1ec 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -125,7 +125,7 @@ install: - "python --version" - "python -c \"import struct; print(struct.calcsize('P') * 8)\"" - "python -m pip install --upgrade \"pip<21\" \"setuptools<44\"" - - "pip install --upgrade tox ppu" + - "pip install --upgrade \"tox>=3.15\" ppu" - "pip --version" # List ODBC drivers - ps: Get-OdbcDriver -Platform 32-bit | Select-Object -ExpandProperty Name diff --git a/devscripts/requirements/requirements_tox.txt b/devscripts/requirements/requirements_tox.txt index 8c9b6ed3..8b5960b9 100644 --- a/devscripts/requirements/requirements_tox.txt +++ b/devscripts/requirements/requirements_tox.txt @@ -1 +1 @@ -tox >= 2.0, < 3.1 +tox >= 3.15 diff --git a/tox.ini b/tox.ini index 77d44c5e..8eddc056 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -minversion = 2.0 +minversion = 3.15 envlist = py27,py3{4,5,6,7,8,9}-sqlite{,-memory},py{27,39}-flake8 # Base test environment settings @@ -62,27 +62,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysqldb]commands} -[testenv:py34-mysqldb] -commands = {envpython} -c "print('MySQL-python requires Python 2.7')" -deps = - -[testenv:py35-mysqldb] -commands = {envpython} -c "print('MySQL-python requires Python 2.7')" -deps = - -[testenv:py36-mysqldb] -commands = {envpython} -c "print('MySQL-python requires Python 2.7')" -deps = - -[testenv:py37-mysqldb] -commands = {envpython} -c "print('MySQL-python requires Python 2.7')" -deps = - -[testenv:py38-mysqldb] -commands = {envpython} -c "print('MySQL-python requires Python 2.7')" -deps = - -[testenv:py39-mysqldb] +[testenv:py3{4,5,6,7,8,9}-mysqldb] commands = {envpython} -c "print('MySQL-python requires Python 2.7')" deps = @@ -98,22 +78,7 @@ commands = commands = {envpython} -c "print('mysqlclient requires Python 3.4+')" deps = -[testenv:py34-mysqlclient] -commands = {[mysqlclient]commands} - -[testenv:py35-mysqlclient] -commands = {[mysqlclient]commands} - -[testenv:py36-mysqlclient] -commands = {[mysqlclient]commands} - -[testenv:py37-mysqlclient] -commands = {[mysqlclient]commands} - -[testenv:py38-mysqlclient] -commands = {[mysqlclient]commands} - -[testenv:py39-mysqlclient] +[testenv:py3{4,5,6,7,8,9}-mysqlclient] commands = {[mysqlclient]commands} [mysql-connector] @@ -129,22 +94,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-connector]commands} -[testenv:py34-mysql-connector-noauto] -commands = {[mysql-connector]commands} - -[testenv:py35-mysql-connector-noauto] -commands = {[mysql-connector]commands} - -[testenv:py36-mysql-connector-noauto] -commands = {[mysql-connector]commands} - -[testenv:py37-mysql-connector-noauto] -commands = {[mysql-connector]commands} - -[testenv:py38-mysql-connector-noauto] -commands = {[mysql-connector]commands} - -[testenv:py39-mysql-connector-noauto] +[testenv:py3{4,5,6,7,8,9}-mysql-connector-noauto] commands = {[mysql-connector]commands} [oursql] @@ -160,22 +110,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[oursql]commands} -[testenv:py34-mysql-oursql3-noauto] -commands = {[oursql]commands} - -[testenv:py35-mysql-oursql3-noauto] -commands = {[oursql]commands} - -[testenv:py36-mysql-oursql3-noauto] -commands = {[oursql]commands} - -[testenv:py37-mysql-oursql3-noauto] -commands = {[oursql]commands} - -[testenv:py38-mysql-oursql3-noauto] -commands = {[oursql]commands} - -[testenv:py39-mysql-oursql3-noauto] +[testenv:py3{4,5,6,7,8,9}-mysql-oursql3-noauto] commands = {[oursql]commands} [pymysql] @@ -191,22 +126,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pymysql]commands} -[testenv:py34-mysql-pymysql] -commands = {[pymysql]commands} - -[testenv:py35-mysql-pymysql] -commands = {[pymysql]commands} - -[testenv:py36-mysql-pymysql] -commands = {[pymysql]commands} - -[testenv:py37-mysql-pymysql] -commands = {[pymysql]commands} - -[testenv:py38-mysql-pymysql] -commands = {[pymysql]commands} - -[testenv:py39-mysql-pymysql] +[testenv:py3{4,5,6,7,8,9}-mysql-pymysql] commands = {[pymysql]commands} [mariadb] @@ -217,28 +137,11 @@ commands = pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=mariadb&charset=utf8&debug=1 mysql -uroot -e 'drop database sqlobject_test;' -[testenv:py27-mariadb] +[testenv:py{27,34,35}-mariadb] commands = {envpython} -c "print('mariadb requires Python 3.6+')" deps = -[testenv:py34-mariadb] -commands = {envpython} -c "print('mariadb requires Python 3.6+')" -deps = - -[testenv:py35-mariadb] -commands = {envpython} -c "print('mariadb requires Python 3.6+')" -deps = - -[testenv:py36-mariadb] -commands = {[mariadb]commands} - -[testenv:py37-mariadb] -commands = {[mariadb]commands} - -[testenv:py38-mariadb] -commands = {[mariadb]commands} - -[testenv:py39-mariadb] +[testenv:py3{6,7,8,9}-mariadb] commands = {[mariadb]commands} [mysql-pyodbc] @@ -255,22 +158,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pyodbc]commands} -[testenv:py34-mysql-pyodbc-noauto] -commands = {[mysql-pyodbc]commands} - -[testenv:py35-mysql-pyodbc-noauto] -commands = {[mysql-pyodbc]commands} - -[testenv:py36-mysql-pyodbc-noauto] -commands = {[mysql-pyodbc]commands} - -[testenv:py37-mysql-pyodbc-noauto] -commands = {[mysql-pyodbc]commands} - -[testenv:py38-mysql-pyodbc-noauto] -commands = {[mysql-pyodbc]commands} - -[testenv:py39-mysql-pyodbc-noauto] +[testenv:py3{4,5,6,7,8,9}-mysql-pyodbc-noauto] commands = {[mysql-pyodbc]commands} [mysql-pypyodbc] @@ -286,22 +174,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pypyodbc]commands} -[testenv:py34-mysql-pypyodbc-noauto] -commands = {[mysql-pypyodbc]commands} - -[testenv:py35-mysql-pypyodbc-noauto] -commands = {[mysql-pypyodbc]commands} - -[testenv:py36-mysql-pypyodbc-noauto] -commands = {[mysql-pypyodbc]commands} - -[testenv:py37-mysql-pypyodbc-noauto] -commands = {[mysql-pypyodbc]commands} - -[testenv:py38-mysql-pypyodbc-noauto] -commands = {[mysql-pypyodbc]commands} - -[testenv:py39-mysql-pypyodbc-noauto] +[testenv:py3{4,5,6,7,8,9}-mysql-pypyodbc-noauto] commands = {[mysql-pypyodbc]commands} # PostgreSQL test environments @@ -318,22 +191,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[psycopg]commands} -[testenv:py34-postgres-psycopg] -commands = {[psycopg]commands} - -[testenv:py35-postgres-psycopg] -commands = {[psycopg]commands} - -[testenv:py36-postgres-psycopg] -commands = {[psycopg]commands} - -[testenv:py37-postgres-psycopg] -commands = {[psycopg]commands} - -[testenv:py38-postgres-psycopg] -commands = {[psycopg]commands} - -[testenv:py39-postgres-psycopg] +[testenv:py3{4,5,6,7,8,9}-postgres-psycopg] commands = {[psycopg]commands} [pygresql] @@ -349,22 +207,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pygresql]commands} -[testenv:py34-postgres-pygresql] -commands = {[pygresql]commands} - -[testenv:py35-postgres-pygresql] -commands = {[pygresql]commands} - -[testenv:py36-postgres-pygresql] -commands = {[pygresql]commands} - -[testenv:py37-postgres-pygresql] -commands = {[pygresql]commands} - -[testenv:py38-postgres-pygresql] -commands = {[pygresql]commands} - -[testenv:py39-postgres-pygresql] +[testenv:py3{4,5,6,7,8,9}-postgres-pygresql] commands = {[pygresql]commands} [pypostgresql] @@ -379,22 +222,7 @@ commands = commands = {envpython} -c "print('pypostgresql requires Python 3.4+')" deps = -[testenv:py34-postgres-pypostgresql] -commands = {[pypostgresql]commands} - -[testenv:py35-postgres-pypostgresql] -commands = {[pypostgresql]commands} - -[testenv:py36-postgres-pypostgresql] -commands = {[pypostgresql]commands} - -[testenv:py37-postgres-pypostgresql] -commands = {[pypostgresql]commands} - -[testenv:py38-postgres-pypostgresql] -commands = {[pypostgresql]commands} - -[testenv:py39-postgres-pypostgresql] +[testenv:py3{4,5,6,7,8,9}-postgres-pypostgresql] commands = {[pypostgresql]commands} [pg8000] @@ -410,22 +238,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pg8000]commands} -[testenv:py34-postgres-pg8000] -commands = {[pg8000]commands} - -[testenv:py35-postgres-pg8000] -commands = {[pg8000]commands} - -[testenv:py36-postgres-pg8000] -commands = {[pg8000]commands} - -[testenv:py37-postgres-pg8000] -commands = {[pg8000]commands} - -[testenv:py38-postgres-pg8000] -commands = {[pg8000]commands} - -[testenv:py39-postgres-pg8000] +[testenv:py3{4,5,6,7,8,9}-postgres-pg8000] commands = {[pg8000]commands} [postgres-pyodbc] @@ -442,22 +255,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pyodbc]commands} -[testenv:py34-postgres-pyodbc-noauto] -commands = {[postgres-pyodbc]commands} - -[testenv:py35-postgres-pyodbc-noauto] -commands = {[postgres-pyodbc]commands} - -[testenv:py36-postgres-pyodbc-noauto] -commands = {[postgres-pyodbc]commands} - -[testenv:py37-postgres-pyodbc-noauto] -commands = {[postgres-pyodbc]commands} - -[testenv:py38-postgres-pyodbc-noauto] -commands = {[postgres-pyodbc]commands} - -[testenv:py39-postgres-pyodbc-noauto] +[testenv:py3{4,5,6,7,8,9}-postgres-pyodbc-noauto] commands = {[postgres-pyodbc]commands} [postgres-pypyodbc] @@ -473,22 +271,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pypyodbc]commands} -[testenv:py34-postgres-pypyodbc-noauto] -commands = {[postgres-pypyodbc]commands} - -[testenv:py35-postgres-pypyodbc-noauto] -commands = {[postgres-pypyodbc]commands} - -[testenv:py36-postgres-pypyodbc-noauto] -commands = {[postgres-pypyodbc]commands} - -[testenv:py37-postgres-pypyodbc-noauto] -commands = {[postgres-pypyodbc]commands} - -[testenv:py38-postgres-pypyodbc-noauto] -commands = {[postgres-pypyodbc]commands} - -[testenv:py39-postgres-pypyodbc-noauto] +[testenv:py3{4,5,6,7,8,9}-postgres-pypyodbc-noauto] commands = {[postgres-pypyodbc]commands} @@ -505,22 +288,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite]commands} -[testenv:py34-sqlite] -commands = {[sqlite]commands} - -[testenv:py35-sqlite] -commands = {[sqlite]commands} - -[testenv:py36-sqlite] -commands = {[sqlite]commands} - -[testenv:py37-sqlite] -commands = {[sqlite]commands} - -[testenv:py38-sqlite] -commands = {[sqlite]commands} - -[testenv:py39-sqlite] +[testenv:py3{4,5,6,7,8,9}-sqlite] commands = {[sqlite]commands} [sqlite-memory] @@ -533,22 +301,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite-memory]commands} -[testenv:py34-sqlite-memory] -commands = {[sqlite-memory]commands} - -[testenv:py35-sqlite-memory] -commands = {[sqlite-memory]commands} - -[testenv:py36-sqlite-memory] -commands = {[sqlite-memory]commands} - -[testenv:py37-sqlite-memory] -commands = {[sqlite-memory]commands} - -[testenv:py38-sqlite-memory] -commands = {[sqlite-memory]commands} - -[testenv:py39-sqlite-memory] +[testenv:py3{4,5,6,7,8,9}-sqlite-memory] commands = {[sqlite-memory]commands} [sqlite-supersqlite] @@ -563,22 +316,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite-supersqlite]commands} -[testenv:py34-sqlite-supersqlite] -commands = {[sqlite-supersqlite]commands} - -[testenv:py35-sqlite-supersqlite] -commands = {[sqlite-supersqlite]commands} - -[testenv:py36-sqlite-supersqlite] -commands = {[sqlite-supersqlite]commands} - -[testenv:py37-sqlite-supersqlite] -commands = {[sqlite-supersqlite]commands} - -[testenv:py38-sqlite-supersqlite] -commands = {[sqlite-supersqlite]commands} - -[testenv:py39-sqlite-supersqlite] +[testenv:py3{4,5,6,7,8,9}-sqlite-supersqlite] commands = {[sqlite-supersqlite]commands} @@ -596,22 +334,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[fdb]commands} -[testenv:py34-firebird-fdb] -commands = {[fdb]commands} - -[testenv:py35-firebird-fdb] -commands = {[fdb]commands} - -[testenv:py36-firebird-fdb] -commands = {[fdb]commands} - -[testenv:py37-firebird-fdb] -commands = {[fdb]commands} - -[testenv:py38-firebird-fdb] -commands = {[fdb]commands} - -[testenv:py39-firebird-fdb] +[testenv:py3{4,5,6,7,8,9}-firebird-fdb] commands = {[fdb]commands} [firebirdsql] @@ -627,50 +350,12 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[firebirdsql]commands} -[testenv:py34-firebirdsql] -commands = {[firebirdsql]commands} - -[testenv:py35-firebirdsql] -commands = {[firebirdsql]commands} - -[testenv:py36-firebirdsql] -commands = {[firebirdsql]commands} - -[testenv:py37-firebirdsql] +[testenv:py3{4,5,6,7,8,9}-firebirdsql] commands = {[firebirdsql]commands} -[testenv:py38-firebirdsql] -commands = {[firebirdsql]commands} - -[testenv:py39-firebirdsql] -commands = {[firebirdsql]commands} # Special test environments -[testenv:py27-flake8] -changedir = ./ -deps = - flake8 -commands = - {[testenv]commands} - flake8 . - -[testenv:py34-flake8] -changedir = ./ -deps = - flake8 -commands = - {[testenv]commands} - flake8 . - -[testenv:py35-flake8] -changedir = ./ -deps = - flake8 -commands = - {[testenv]commands} - flake8 . - -[testenv:py36-flake8] +[testenv:py{27,34,35,36,37,38,39}-flake8] changedir = ./ deps = flake8 @@ -678,29 +363,6 @@ commands = {[testenv]commands} flake8 . -[testenv:py37-flake8] -changedir = ./ -deps = - flake8 -commands = - {[testenv]commands} - flake8 . - -[testenv:py38-flake8] -changedir = ./ -deps = - flake8 -commands = - {[testenv]commands} - flake8 . - -[testenv:py39-flake8] -changedir = ./ -deps = - flake8 -commands = - {[testenv]commands} - flake8 . # Windows testing [mssql-pyodbc-w32] @@ -718,27 +380,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mssql-pyodbc-w32]commands} -[testenv:py34-mssql-pyodbc-noauto-w32] -platform = win32 -commands = {[mssql-pyodbc-w32]commands} - -[testenv:py35-mssql-pyodbc-noauto-w32] -platform = win32 -commands = {[mssql-pyodbc-w32]commands} - -[testenv:py36-mssql-pyodbc-noauto-w32] -platform = win32 -commands = {[mssql-pyodbc-w32]commands} - -[testenv:py37-mssql-pyodbc-noauto-w32] -platform = win32 -commands = {[mssql-pyodbc-w32]commands} - -[testenv:py38-mssql-pyodbc-noauto-w32] -platform = win32 -commands = {[mssql-pyodbc-w32]commands} - -[testenv:py39-mssql-pyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9}-mssql-pyodbc-noauto-w32] platform = win32 commands = {[mssql-pyodbc-w32]commands} @@ -757,27 +399,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-connector-w32]commands} -[testenv:py34-mysql-connector-w32] -platform = win32 -commands = {[mysql-connector-w32]commands} - -[testenv:py35-mysql-connector-w32] -platform = win32 -commands = {[mysql-connector-w32]commands} - -[testenv:py36-mysql-connector-w32] -platform = win32 -commands = {[mysql-connector-w32]commands} - -[testenv:py37-mysql-connector-w32] -platform = win32 -commands = {[mysql-connector-w32]commands} - -[testenv:py38-mysql-connector-w32] -platform = win32 -commands = {[mysql-connector-w32]commands} - -[testenv:py39-mysql-connector-w32] +[testenv:py3{4,5,6,7,8,9}-mysql-connector-w32] platform = win32 commands = {[mysql-connector-w32]commands} @@ -796,27 +418,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pymysql-w32]commands} -[testenv:py34-mysql-pymysql-w32] -platform = win32 -commands = {[pymysql-w32]commands} - -[testenv:py35-mysql-pymysql-w32] -platform = win32 -commands = {[pymysql-w32]commands} - -[testenv:py36-mysql-pymysql-w32] -platform = win32 -commands = {[pymysql-w32]commands} - -[testenv:py37-mysql-pymysql-w32] -platform = win32 -commands = {[pymysql-w32]commands} - -[testenv:py38-mysql-pymysql-w32] -platform = win32 -commands = {[pymysql-w32]commands} - -[testenv:py39-mysql-pymysql-w32] +[testenv:py3{4,5,6,7,8,9}-mysql-pymysql-w32] platform = win32 commands = {[pymysql-w32]commands} @@ -829,34 +431,12 @@ commands = pytest --cov=sqlobject -D "mysql://root:Password12!@localhost/sqlobject_test?driver=mariadb&charset=utf8&debug=1" mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' -[testenv:py27-mariadb-w32] -platform = win32 -commands = {envpython} -c "print('mariadb requires Python 3.6+')" -deps = - -[testenv:py34-mariadb-w32] -platform = win32 -commands = {envpython} -c "print('mariadb requires Python 3.6+')" -deps = - -[testenv:py35-mariadb-w32] +[testenv:py{27,34,35}-mariadb-w32] platform = win32 commands = {envpython} -c "print('mariadb requires Python 3.6+')" deps = -[testenv:py36-mariadb-w32] -platform = win32 -commands = {[mariadb-w32]commands} - -[testenv:py37-mariadb-w32] -platform = win32 -commands = {[mariadb-w32]commands} - -[testenv:py38-mariadb-w32] -platform = win32 -commands = {[mariadb-w32]commands} - -[testenv:py39-mariadb-w32] +[testenv:py3{6,7,8,9}-mariadb-w32] platform = win32 commands = {[mariadb-w32]commands} @@ -876,27 +456,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pyodbc-w32]commands} -[testenv:py34-mysql-pyodbc-noauto-w32] -platform = win32 -commands = {[mysql-pyodbc-w32]commands} - -[testenv:py35-mysql-pyodbc-noauto-w32] -platform = win32 -commands = {[mysql-pyodbc-w32]commands} - -[testenv:py36-mysql-pyodbc-noauto-w32] -platform = win32 -commands = {[mysql-pyodbc-w32]commands} - -[testenv:py37-mysql-pyodbc-noauto-w32] -platform = win32 -commands = {[mysql-pyodbc-w32]commands} - -[testenv:py38-mysql-pyodbc-noauto-w32] -platform = win32 -commands = {[mysql-pyodbc-w32]commands} - -[testenv:py39-mysql-pyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9}-mysql-pyodbc-noauto-w32] platform = win32 commands = {[mysql-pyodbc-w32]commands} @@ -916,27 +476,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pypyodbc-w32]commands} -[testenv:py34-mysql-pypyodbc-noauto-w32] -platform = win32 -commands = {[mysql-pypyodbc-w32]commands} - -[testenv:py35-mysql-pypyodbc-noauto-w32] -platform = win32 -commands = {[mysql-pypyodbc-w32]commands} - -[testenv:py36-mysql-pypyodbc-noauto-w32] -platform = win32 -commands = {[mysql-pypyodbc-w32]commands} - -[testenv:py37-mysql-pypyodbc-noauto-w32] -platform = win32 -commands = {[mysql-pypyodbc-w32]commands} - -[testenv:py38-mysql-pypyodbc-noauto-w32] -platform = win32 -commands = {[mysql-pypyodbc-w32]commands} - -[testenv:py39-mysql-pypyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9}-mysql-pypyodbc-noauto-w32] platform = win32 commands = {[mysql-pypyodbc-w32]commands} @@ -955,27 +495,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[psycopg-w32]commands} -[testenv:py34-postgres-psycopg-w32] -platform = win32 -commands = {[psycopg-w32]commands} - -[testenv:py35-postgres-psycopg-w32] -platform = win32 -commands = {[psycopg-w32]commands} - -[testenv:py36-postgres-psycopg-w32] -platform = win32 -commands = {[psycopg-w32]commands} - -[testenv:py37-postgres-psycopg-w32] -platform = win32 -commands = {[psycopg-w32]commands} - -[testenv:py38-postgres-psycopg-w32] -platform = win32 -commands = {[psycopg-w32]commands} - -[testenv:py39-postgres-psycopg-w32] +[testenv:py3{4,5,6,7,8,9}-postgres-psycopg-w32] platform = win32 commands = {[psycopg-w32]commands} @@ -994,27 +514,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pygresql-w32]commands} -[testenv:py34-postgres-pygresql-w32] -platform = win32 -commands = {[pygresql-w32]commands} - -[testenv:py35-postgres-pygresql-w32] -platform = win32 -commands = {[pygresql-w32]commands} - -[testenv:py36-postgres-pygresql-w32] -platform = win32 -commands = {[pygresql-w32]commands} - -[testenv:py37-postgres-pygresql-w32] -platform = win32 -commands = {[pygresql-w32]commands} - -[testenv:py38-postgres-pygresql-w32] -platform = win32 -commands = {[pygresql-w32]commands} - -[testenv:py39-postgres-pygresql-w32] +[testenv:py3{4,5,6,7,8,9}-postgres-pygresql-w32] platform = win32 commands = {[pygresql-w32]commands} @@ -1032,27 +532,7 @@ platform = win32 commands = {envpython} -c "print('pypostgresql requires Python 3.4+')" deps = -[testenv:py34-postgres-pypostgresql-w32] -platform = win32 -commands = {[pypostgresql-w32]commands} - -[testenv:py35-postgres-pypostgresql-w32] -platform = win32 -commands = {[pypostgresql-w32]commands} - -[testenv:py36-postgres-pypostgresql-w32] -platform = win32 -commands = {[pypostgresql-w32]commands} - -[testenv:py37-postgres-pypostgresql-w32] -platform = win32 -commands = {[pypostgresql-w32]commands} - -[testenv:py38-postgres-pypostgresql-w32] -platform = win32 -commands = {[pypostgresql-w32]commands} - -[testenv:py39-postgres-pypostgresql-w32] +[testenv:py3{4,5,6,7,8,9}-postgres-pypostgresql-w32] platform = win32 commands = {[pypostgresql-w32]commands} @@ -1071,27 +551,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pg8000-w32]commands} -[testenv:py34-postgres-pg8000-w32] -platform = win32 -commands = {[pg8000-w32]commands} - -[testenv:py35-postgres-pg8000-w32] -platform = win32 -commands = {[pg8000-w32]commands} - -[testenv:py36-postgres-pg8000-w32] -platform = win32 -commands = {[pg8000-w32]commands} - -[testenv:py37-postgres-pg8000-w32] -platform = win32 -commands = {[pg8000-w32]commands} - -[testenv:py38-postgres-pg8000-w32] -platform = win32 -commands = {[pg8000-w32]commands} - -[testenv:py39-postgres-pg8000-w32] +[testenv:py3{4,5,6,7,8,9}-postgres-pg8000-w32] platform = win32 commands = {[pg8000-w32]commands} @@ -1111,27 +571,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pyodbc-w32]commands} -[testenv:py34-postgres-pyodbc-noauto-w32] -platform = win32 -commands = {[postgres-pyodbc-w32]commands} - -[testenv:py35-postgres-pyodbc-noauto-w32] -platform = win32 -commands = {[postgres-pyodbc-w32]commands} - -[testenv:py36-postgres-pyodbc-noauto-w32] -platform = win32 -commands = {[postgres-pyodbc-w32]commands} - -[testenv:py37-postgres-pyodbc-noauto-w32] -platform = win32 -commands = {[postgres-pyodbc-w32]commands} - -[testenv:py38-postgres-pyodbc-noauto-w32] -platform = win32 -commands = {[postgres-pyodbc-w32]commands} - -[testenv:py39-postgres-pyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9}-postgres-pyodbc-noauto-w32] platform = win32 commands = {[postgres-pyodbc-w32]commands} @@ -1151,27 +591,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pypyodbc-w32]commands} -[testenv:py34-postgres-pypyodbc-noauto-w32] -platform = win32 -commands = {[postgres-pypyodbc-w32]commands} - -[testenv:py35-postgres-pypyodbc-noauto-w32] -platform = win32 -commands = {[postgres-pypyodbc-w32]commands} - -[testenv:py36-postgres-pypyodbc-noauto-w32] -platform = win32 -commands = {[postgres-pypyodbc-w32]commands} - -[testenv:py37-postgres-pypyodbc-noauto-w32] -platform = win32 -commands = {[postgres-pypyodbc-w32]commands} - -[testenv:py38-postgres-pypyodbc-noauto-w32] -platform = win32 -commands = {[postgres-pypyodbc-w32]commands} - -[testenv:py39-postgres-pypyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9}-postgres-pypyodbc-noauto-w32] platform = win32 commands = {[postgres-pypyodbc-w32]commands} @@ -1188,27 +608,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite-w32]commands} -[testenv:py34-sqlite-w32] -platform = win32 -commands = {[sqlite-w32]commands} - -[testenv:py35-sqlite-w32] -platform = win32 -commands = {[sqlite-w32]commands} - -[testenv:py36-sqlite-w32] -platform = win32 -commands = {[sqlite-w32]commands} - -[testenv:py37-sqlite-w32] -platform = win32 -commands = {[sqlite-w32]commands} - -[testenv:py38-sqlite-w32] -platform = win32 -commands = {[sqlite-w32]commands} - -[testenv:py39-sqlite-w32] +[testenv:py3{4,5,6,7,8,9}-sqlite-w32] platform = win32 commands = {[sqlite-w32]commands} @@ -1224,26 +624,6 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite-memory-w32]commands} -[testenv:py34-sqlite-memory-w32] -platform = win32 -commands = {[sqlite-memory-w32]commands} - -[testenv:py35-sqlite-memory-w32] -platform = win32 -commands = {[sqlite-memory-w32]commands} - -[testenv:py36-sqlite-memory-w32] -platform = win32 -commands = {[sqlite-memory-w32]commands} - -[testenv:py37-sqlite-memory-w32] -platform = win32 -commands = {[sqlite-memory-w32]commands} - -[testenv:py38-sqlite-memory-w32] -platform = win32 -commands = {[sqlite-memory-w32]commands} - -[testenv:py39-sqlite-memory-w32] +[testenv:py3{4,5,6,7,8,9}-sqlite-memory-w32] platform = win32 commands = {[sqlite-memory-w32]commands} From 70355ffdaab154c93494c5ed2e32395a5bbd4737 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 21 Feb 2021 02:24:46 +0300 Subject: [PATCH 294/509] Tests(tox.ini): Limit `PyMySQL` version for Python 2.7 and 3.4 --- devscripts/requirements/requirements_pymysql.txt | 3 +++ tox.ini | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 devscripts/requirements/requirements_pymysql.txt diff --git a/devscripts/requirements/requirements_pymysql.txt b/devscripts/requirements/requirements_pymysql.txt new file mode 100644 index 00000000..47ca8d09 --- /dev/null +++ b/devscripts/requirements/requirements_pymysql.txt @@ -0,0 +1,3 @@ +pymysql < 1.0; python_version == '2.7' +pymysql < 0.10.0; python_version == '3.4' +pymysql; python_version >= '3.5' diff --git a/tox.ini b/tox.ini index 8eddc056..95bfdbd7 100644 --- a/tox.ini +++ b/tox.ini @@ -24,7 +24,7 @@ deps = mysql-connector: mysql-connector <= 2.2.2 mysql-oursql: git+https://github.com/sqlobject/oursql.git@master#egg=oursql mysql-oursql3: git+https://github.com/sqlobject/oursql.git@py3k#egg=oursql - pymysql: pymysql + pymysql: -rdevscripts/requirements/requirements_pymysql.txt mariadb: mariadb postgres-psycopg: psycopg2-binary pygresql: -rdevscripts/requirements/requirements_pygresql.txt From 9e9724b152a4bbc359708906cf327af2d7fe2e51 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 22 Feb 2021 12:50:18 +0300 Subject: [PATCH 295/509] Docs(News): Update News [skip ci] --- docs/News.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/News.rst b/docs/News.rst index 59558ab6..43d381cb 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -16,6 +16,16 @@ Build * Add ``mariadb`` in ``extras_require`` in ``setup.py``. +CI +-- + +* For tests with Python 3.4 run ``tox`` under Python 3.5. + +Tests +----- + +* Refactor ``tox.ini``. + SQLObject 3.9.0 =============== From 28974d303f13f085113018651ad7f074d510937c Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 22 Feb 2021 12:51:50 +0300 Subject: [PATCH 296/509] Build(devscripts): Rename `split.sh` -> `split_tag.sh` [skip ci] --- devscripts/branch | 2 +- devscripts/prerelease | 2 +- devscripts/prerelease-tag | 2 +- devscripts/release | 2 +- devscripts/{split.sh => split_tag.sh} | 0 devscripts/{test-split.sh => test-split_tag.sh} | 2 +- 6 files changed, 5 insertions(+), 5 deletions(-) rename devscripts/{split.sh => split_tag.sh} (100%) rename devscripts/{test-split.sh => test-split_tag.sh} (93%) diff --git a/devscripts/branch b/devscripts/branch index 908e5fb3..7c7ef731 100755 --- a/devscripts/branch +++ b/devscripts/branch @@ -8,7 +8,7 @@ fi branch="$1" treeish="$2" -. `dirname $0`/split.sh && +. `dirname $0`/split_tag.sh && branch="$1" if [ -z "$treeish" ]; then diff --git a/devscripts/prerelease b/devscripts/prerelease index edd7358e..dd788c6f 100755 --- a/devscripts/prerelease +++ b/devscripts/prerelease @@ -10,7 +10,7 @@ else branch="$2" fi -. `dirname $0`/split.sh && +. `dirname $0`/split_tag.sh && split_tag $tag $branch git checkout "$branch" && diff --git a/devscripts/prerelease-tag b/devscripts/prerelease-tag index b7f10175..46ac39e7 100755 --- a/devscripts/prerelease-tag +++ b/devscripts/prerelease-tag @@ -10,7 +10,7 @@ else branch="$2" fi -. `dirname $0`/split.sh && +. `dirname $0`/split_tag.sh && split_tag $tag $branch git checkout "$branch" && diff --git a/devscripts/release b/devscripts/release index 35154c95..33bb23ff 100755 --- a/devscripts/release +++ b/devscripts/release @@ -15,7 +15,7 @@ find build -name '*.py[co]' -delete && python setup.py bdist_wheel --universal && version=`python setup.py --version` -. `dirname $0`/split.sh && +. `dirname $0`/split_tag.sh && split_tag $version if [ "$state" = final ]; then diff --git a/devscripts/split.sh b/devscripts/split_tag.sh similarity index 100% rename from devscripts/split.sh rename to devscripts/split_tag.sh diff --git a/devscripts/test-split.sh b/devscripts/test-split_tag.sh similarity index 93% rename from devscripts/test-split.sh rename to devscripts/test-split_tag.sh index a5f17495..0dc48c30 100755 --- a/devscripts/test-split.sh +++ b/devscripts/test-split_tag.sh @@ -1,6 +1,6 @@ #! /bin/sh -. `dirname $0`/split.sh && +. `dirname $0`/split_tag.sh && test_eq() { if [ "$1" != "$2" ]; then From 00c4a089d8185576f4ebcf5eba94d96044f3b092 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 22 Feb 2021 13:02:18 +0300 Subject: [PATCH 297/509] Build(devscripts): Split post-release tag and counter [skip ci] --- devscripts/split_tag.sh | 2 +- devscripts/test-split_tag.sh | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/devscripts/split_tag.sh b/devscripts/split_tag.sh index ce5c3c5e..d0024f04 100644 --- a/devscripts/split_tag.sh +++ b/devscripts/split_tag.sh @@ -1,6 +1,6 @@ split_tag() { branch=$2 - set -- `echo $1 | sed -e 's/\./ /g' -e 's/a/ alpha /' -e 's/b/ beta /' -e 's/rc/ rc /' -e 's/\([0-9]\)c/\1 rc /'` + set -- `echo $1 | sed -e 's/\./ /g' -e 's/a/ alpha /' -e 's/b/ beta /' -e 's/rc/ rc /' -e 's/\([0-9]\)c/\1 rc /' -e 's/post\([0-9]\+\)/ post \1/'` major=$1 minor=$2 micro=$3 diff --git a/devscripts/test-split_tag.sh b/devscripts/test-split_tag.sh index 0dc48c30..40b9d3d4 100755 --- a/devscripts/test-split_tag.sh +++ b/devscripts/test-split_tag.sh @@ -23,3 +23,11 @@ test_eq "$minor" 12 test_eq "$micro" 42 test_eq "$state" "release candidate" test_eq "$serial" 4 + +split_tag 21.12.42.post1 +test_eq "$branch" 21.12 +test_eq "$major" 21 +test_eq "$minor" 12 +test_eq "$micro" 42 +test_eq "$state" "post" +test_eq "$serial" 1 From 99861557ab30dd842c4b0d22f0c995d7f29d1778 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 22 Feb 2021 15:00:46 +0300 Subject: [PATCH 298/509] Build(devscripts/postrelease): Improve commit message [skip ci] --- devscripts/postrelease | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devscripts/postrelease b/devscripts/postrelease index 55dfe674..0a9c73a5 100755 --- a/devscripts/postrelease +++ b/devscripts/postrelease @@ -3,4 +3,4 @@ git checkout HEAD~ ANNOUNCE.rst setup.cfg && `git var GIT_EDITOR` ANNOUNCE.rst setup.cfg README.rst docs/News.rst && -exec git commit --message="Prepare for the next release" ANNOUNCE.rst setup.cfg README.rst docs/News.rst +exec git commit --message="Build: Prepare for the next release" --message="[skip ci]" ANNOUNCE.rst setup.cfg README.rst docs/News.rst From 47307e617424d8a4bdcad350ca235a72396fd23f Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 23 Feb 2021 21:12:58 +0300 Subject: [PATCH 299/509] Feat(PostgreSQL): Adapt to the latest `pg8000` --- docs/News.rst | 5 +++++ sqlobject/postgres/pgconnection.py | 28 +++++++++++++++++++++------- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index 43d381cb..234fca55 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,11 @@ News SQLObject (master) ================== +Drivers +------- + +* Adapt to the latest ``pg8000``. + Build ----- diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index 85a50945..749ca575 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -10,13 +10,26 @@ class ErrorMessage(str): def __new__(cls, e, append_msg=''): - obj = str.__new__(cls, e.args[0] + append_msg) - if hasattr(e, 'pgcode'): # psycopg2 or psycopg2.errors - obj.code = getattr(e, 'pgcode', None) - obj.error = getattr(e, 'pgerror', None) + eargs0 = emessage = e.args[0] + if e.__module__.startswith('pg8000') \ + and isinstance(e.args, tuple) and len(e.args) > 1: + # pg8000 =~ 1.12 for Python 3.4 + ecode = e.args[2] + eerror = emessage = e.args[3] + elif e.__module__.startswith('pg8000') and isinstance(eargs0, dict): + # pg8000 =~ 1.13 for Python 2.7 + # pg8000 for Python 3.5+ + ecode = eargs0['C'] + eerror = emessage = eargs0['M'] + elif hasattr(e, 'pgcode'): # psycopg2 or psycopg2.errors + ecode = getattr(e, 'pgcode', None) + eerror = getattr(e, 'pgerror', None) else: - obj.code = getattr(e, 'code', None) - obj.error = getattr(e, 'error', None) + ecode = getattr(e, 'code', None) + eerror = getattr(e, 'error', None) + obj = str.__new__(cls, emessage + append_msg) + obj.code = ecode + obj.error = eerror obj.module = e.__module__ obj.exception = e.__class__.__name__ return obj @@ -237,7 +250,8 @@ def _executeRetry(self, conn, cursor, query): raise dberrors.OperationalError(ErrorMessage(e)) except self.module.IntegrityError as e: msg = ErrorMessage(e) - if getattr(e, 'code', -1) == '23505' or \ + if getattr(msg, 'code', -1) == '23505' or \ + getattr(e, 'code', -1) == '23505' or \ getattr(e, 'pgcode', -1) == '23505' or \ getattr(e, 'sqlstate', -1) == '23505' or \ e.args[0] == '23505': From aa8815be7576ca097233993d6387a34196570c1d Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 23 Feb 2021 21:20:21 +0300 Subject: [PATCH 300/509] Tests(tox.ini): Limit `pg8000` version for Python 2.7 and 3.4 Revert back to stock `pg8000`. --- devscripts/requirements/requirements_pg8000.txt | 3 +++ devscripts/requirements/requirements_pygresql.txt | 2 +- setup.py | 4 +++- tox.ini | 2 +- 4 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 devscripts/requirements/requirements_pg8000.txt diff --git a/devscripts/requirements/requirements_pg8000.txt b/devscripts/requirements/requirements_pg8000.txt new file mode 100644 index 00000000..06cd178f --- /dev/null +++ b/devscripts/requirements/requirements_pg8000.txt @@ -0,0 +1,3 @@ +pg8000 < 1.13; python_version == '2.7' +pg8000 < 1.12.4; python_version == '3.4' +pg8000; python_version >= '3.5' diff --git a/devscripts/requirements/requirements_pygresql.txt b/devscripts/requirements/requirements_pygresql.txt index ea4052ca..5fbb3514 100644 --- a/devscripts/requirements/requirements_pygresql.txt +++ b/devscripts/requirements/requirements_pygresql.txt @@ -1,2 +1,2 @@ -pygresql<5.2; python_version == '3.4' +pygresql < 5.2; python_version == '3.4' pygresql; python_version != '3.4' diff --git a/setup.py b/setup.py index 11a6cbaa..3dfd2caa 100755 --- a/setup.py +++ b/setup.py @@ -133,7 +133,9 @@ 'pygresql': ['pygresql'], 'pypostgresql': ['py-postgresql'], 'py-postgresql': ['py-postgresql'], - 'pg8000': ['pg8000'], + 'pg8000:python_version=="2.7"': ['pg8000<1.13'], + 'pg8000:python_version=="3.4"': ['pg8000<1.12.4'], + 'pg8000:python_version>="3.5"': ['pg8000'], # 'sapdb': ['sapdb'], 'sqlite': ['pysqlite'], diff --git a/tox.ini b/tox.ini index 95bfdbd7..67765a34 100644 --- a/tox.ini +++ b/tox.ini @@ -29,7 +29,7 @@ deps = postgres-psycopg: psycopg2-binary pygresql: -rdevscripts/requirements/requirements_pygresql.txt pypostgresql: git+https://github.com/sqlobject/py-postgresql.git@fix_w32#egg=py-postgresql - postgres-pg8000: git+https://github.com/sqlobject/pg8000.git@getuser#egg=pg8000 + pg8000: -rdevscripts/requirements/requirements_pg8000.txt pyodbc: pyodbc pypyodbc: pypyodbc supersqlite: supersqlite From 3173e08bcd55284c5b914d7d59088c94ad83f7c7 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 23 Feb 2021 22:00:41 +0300 Subject: [PATCH 301/509] Feat(PostgreSQL): Protect `getuser()` It can raise `ImportError` on w32 due to absent of `pwd` module. --- docs/News.rst | 3 +++ sqlobject/postgres/pgconnection.py | 11 ++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/docs/News.rst b/docs/News.rst index 234fca55..f190d966 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -13,6 +13,9 @@ Drivers * Adapt to the latest ``pg8000``. +* Protect ``getuser()`` - it can raise ``ImportError`` on w32 + due to absent of ``pwd`` module. + Build ----- diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index 749ca575..722f3d4e 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -35,6 +35,15 @@ def __new__(cls, e, append_msg=''): return obj +def _getuser(): + # ``getuser()`` on w32 can raise ``ImportError`` + # due to absent of ``pwd`` module. + try: + return getuser() + except ImportError: + return None + + class PostgresConnection(DBAPI): supportTransactions = True @@ -174,7 +183,7 @@ def __init__(self, dsn=None, host=None, port=None, db=None, dsn_dict["host"] = None dsn_dict["unix_sock"] = host if user is None: - dsn_dict["user"] = getuser() + dsn_dict["user"] = _getuser() self.dsn = dsn self.driver = driver self.unicodeCols = kw.pop('unicodeCols', False) From 8bcaa3cc57c96d915549b8666548b4e0d5fabaa9 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 27 Feb 2021 16:40:16 +0300 Subject: [PATCH 302/509] Release 3.9.1 --- ANNOUNCE.rst | 40 ++++++++++++++++++++++++++-------------- README.rst | 4 ++-- docs/News.rst | 6 ++++-- sqlobject/__version__.py | 4 ++-- 4 files changed, 34 insertions(+), 20 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 72872502..fdee54bc 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,25 +1,37 @@ Hello! -I'm pleased to announce version 3.9.1a1, the first alpha of the upcoming -release of branch 3.9 of SQLObject. +I'm pleased to announce version 3.9.1, the first minor feature release +of branch 3.9 of SQLObject. -I'm pleased to announce version 3.9.1a2, the second alpha of the upcoming -release of branch 3.9 of SQLObject. -I'm pleased to announce version 3.9.1b1, the first beta of the upcoming -release of branch 3.9 of SQLObject. +What's new in SQLObject +======================= -I'm pleased to announce version 3.9.1rc1, the first release candidate -of the upcoming release of branch 3.9 of SQLObject. +Drivers +------- -I'm pleased to announce version 3.9.1, the first bugfix release of branch -3.9 of SQLObject. +* Adapt to the latest ``pg8000``. +* Protect ``getuser()`` - it can raise ``ImportError`` on w32 + due to absent of ``pwd`` module. -What's new in SQLObject -======================= +Build +----- + +* Change URLs for ``oursql`` in ``extras_require`` in ``setup.py``. + Provide separate URLs for Python 2.7 and 3.4+. + +* Add ``mariadb`` in ``extras_require`` in ``setup.py``. + +CI +-- + +* For tests with Python 3.4 run ``tox`` under Python 3.5. + +Tests +----- -Contributors for this release are +* Refactor ``tox.ini``. For a more complete list, please see the news: http://sqlobject.org/News.html @@ -52,7 +64,7 @@ Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Download: -https://pypi.org/project/SQLObject/3.9.1a0.dev20201215/ +https://pypi.org/project/SQLObject/3.9.1 News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 2442b674..80d69665 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.9.1a0 -================= +SQLObject 3.9.1 +=============== Thanks for looking at SQLObject. SQLObject is an object-relational mapper, i.e., a library that will wrap your database tables in Python diff --git a/docs/News.rst b/docs/News.rst index f190d966..06c9c8fd 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,8 +5,10 @@ News .. contents:: Contents: :backlinks: none -SQLObject (master) -================== +SQLObject 3.9.1 +=============== + +Released 2021 Feb 27. Drivers ------- diff --git a/sqlobject/__version__.py b/sqlobject/__version__.py index f133a875..cb43f08a 100644 --- a/sqlobject/__version__.py +++ b/sqlobject/__version__.py @@ -1,8 +1,8 @@ -version = '3.9.0' +version = '3.9.1' major = 3 minor = 9 -micro = 0 +micro = 1 release_level = 'final' serial = 0 version_info = (major, minor, micro, release_level, serial) From 1551a039c36ae52b03076a7826b3fded29950245 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 27 Feb 2021 16:49:36 +0300 Subject: [PATCH 303/509] Build: Prepare for the next release [skip ci] --- ANNOUNCE.rst | 40 ++++++++++++++-------------------------- README.rst | 4 ++-- docs/News.rst | 3 +++ 3 files changed, 19 insertions(+), 28 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index fdee54bc..5f6c2aa6 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,37 +1,25 @@ Hello! -I'm pleased to announce version 3.9.1, the first minor feature release -of branch 3.9 of SQLObject. +I'm pleased to announce version 3.9.2a1, the first alpha of the upcoming +release of branch 3.9 of SQLObject. +I'm pleased to announce version 3.9.2a2, the second alpha of the upcoming +release of branch 3.9 of SQLObject. -What's new in SQLObject -======================= - -Drivers -------- - -* Adapt to the latest ``pg8000``. - -* Protect ``getuser()`` - it can raise ``ImportError`` on w32 - due to absent of ``pwd`` module. +I'm pleased to announce version 3.9.2b1, the first beta of the upcoming +release of branch 3.9 of SQLObject. -Build ------ +I'm pleased to announce version 3.9.2rc1, the first release candidate +of the upcoming release of branch 3.9 of SQLObject. -* Change URLs for ``oursql`` in ``extras_require`` in ``setup.py``. - Provide separate URLs for Python 2.7 and 3.4+. +I'm pleased to announce version 3.9.2, the first bugfix release of branch +3.9 of SQLObject. -* Add ``mariadb`` in ``extras_require`` in ``setup.py``. -CI --- - -* For tests with Python 3.4 run ``tox`` under Python 3.5. - -Tests ------ +What's new in SQLObject +======================= -* Refactor ``tox.ini``. +Contributors for this release are For a more complete list, please see the news: http://sqlobject.org/News.html @@ -64,7 +52,7 @@ Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Download: -https://pypi.org/project/SQLObject/3.9.1 +https://pypi.org/project/SQLObject/3.9.2a0.dev20210227/ News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 80d69665..2152854e 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.9.1 -=============== +SQLObject 3.9.2a0 +================= Thanks for looking at SQLObject. SQLObject is an object-relational mapper, i.e., a library that will wrap your database tables in Python diff --git a/docs/News.rst b/docs/News.rst index 06c9c8fd..37935f3a 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,6 +5,9 @@ News .. contents:: Contents: :backlinks: none +SQLObject (master) +================== + SQLObject 3.9.1 =============== From cf99cde3cb2a828ee165e2b32dc886a0b881f17e Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 27 Feb 2021 16:58:29 +0300 Subject: [PATCH 304/509] Build(devscripts): Update `RELEASE-CHECKLIST` Remove duplicate "commit and merge" instructions. [skip ci] --- devscripts/RELEASE-CHECKLIST | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/devscripts/RELEASE-CHECKLIST b/devscripts/RELEASE-CHECKLIST index e85de5e2..42f6b10b 100644 --- a/devscripts/RELEASE-CHECKLIST +++ b/devscripts/RELEASE-CHECKLIST @@ -17,8 +17,7 @@ 'dev' and date stamp). If it's the first stable release of the branch - edit build-all-docs, - advance stable branch. Commit. If it's not master - merge to all higher - branches and master. + advance stable branch. Commit. Verify. From a95ac237f6c8289afa872c879622cb14cb7af995 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 27 Feb 2021 17:00:20 +0300 Subject: [PATCH 305/509] Build(devscripts): Update `RELEASE-CHECKLIST` Reorder instructions: run `push-all` after `postrelease`. [skip ci] --- devscripts/RELEASE-CHECKLIST | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/devscripts/RELEASE-CHECKLIST b/devscripts/RELEASE-CHECKLIST index 42f6b10b..f47ec418 100644 --- a/devscripts/RELEASE-CHECKLIST +++ b/devscripts/RELEASE-CHECKLIST @@ -34,15 +34,15 @@ 6. Move old releases at SourceForge to subdirectory OldFiles. -7. Run devscripts/push-all in the development repository to push all - branches and tags to the public repositories. - -8. Run devscripts/postrelease. The script restores ANNOUNCE.rst and +7. Run devscripts/postrelease. The script restores ANNOUNCE.rst and setup.cfg from the previous commit (HEAD~). It calls editor; update next version, remove the list of contributors and the list of changes, edit download URL in ANNOUNCE.rst. Edit README.rst and docs/News.rst - add new version. +8. Run devscripts/push-all in the development repository to push all + branches and tags to the public repositories. + 9. Generate new docs using devscripts/build-all-docs. Upload docs using devscripts/publish-docs. From df7ad69dca4d25021b0f07f90aac075b38d20227 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 27 Feb 2021 17:04:44 +0300 Subject: [PATCH 306/509] Build(devscripts): Fix `build-all-docs`: Set the current version [skip ci] --- devscripts/build-all-docs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devscripts/build-all-docs b/devscripts/build-all-docs index 1f21c9a8..34aacd3c 100755 --- a/devscripts/build-all-docs +++ b/devscripts/build-all-docs @@ -10,7 +10,7 @@ cd "`dirname \"$0\"`" && PROG_DIR="`pwd`" && cd .. && -build_docs 3.9.0 && +build_docs 3.9.1 && build_docs master devel && rm -rf docs/html && From 1f50e64d9fa6cd96843cdbf3901c0517a075cfe6 Mon Sep 17 00:00:00 2001 From: James Hudson Date: Thu, 3 Jun 2021 16:23:41 +0100 Subject: [PATCH 307/509] Add new converter for pendulum.DateTime --- sqlobject/converters.py | 14 ++++++++++++++ sqlobject/tests/test_datetime.py | 22 +++++++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/sqlobject/converters.py b/sqlobject/converters.py index fa6ea1c0..667fdded 100644 --- a/sqlobject/converters.py +++ b/sqlobject/converters.py @@ -22,6 +22,13 @@ mxDateTimeType = None mxDateTimeDeltaType = None +try: + import pendulum +except ImportError: + pendulumDateTimeType = None +else: + pendulumDateTimeType = pendulum.DateTime + try: from DateTime import DateTime as zopeDateTime except ImportError: @@ -215,6 +222,13 @@ def mxTimeConverter(value, db): registerConverter(mxDateTimeDeltaType, mxTimeConverter) +if pendulumDateTimeType: + def pendulumConverter(value, db): + return "'%s'" % value.to_datetime_string() + + registerConverter(pendulum.DateTime, pendulumConverter) + + if zopeDateTimeType: def zopeDateTimeConverter(value, db): return "'%s'" % value.strftime("%Y-%m-%d %H:%M:%S") diff --git a/sqlobject/tests/test_datetime.py b/sqlobject/tests/test_datetime.py index 06ce1ae6..21ed5a62 100644 --- a/sqlobject/tests/test_datetime.py +++ b/sqlobject/tests/test_datetime.py @@ -7,7 +7,7 @@ DATETIME_IMPLEMENTATION, MXDATETIME_IMPLEMENTATION, mxdatetime_available, \ ZOPE_DATETIME_IMPLEMENTATION, zope_datetime_available from sqlobject.tests.dbtest import getConnection, setupClass - +from sqlobject.converters import pendulumDateTimeType ######################################## # Date/time columns @@ -130,6 +130,26 @@ def test_mxDateTime(): assert dt2.col3.minute == _now.minute assert dt2.col3.second == int(_now.second) +if pendulumDateTimeType: + import pendulum + + class DateTimePendulum(SQLObject): + col1 = DateTimeCol() + + def test_PendulumDateTime(): + setupClass(DateTimePendulum) + _now = pendulum.now() + dtp = DateTimePendulum(col1=_now) + + assert isinstance(dtp.col1, datetime) + assert dtp.col1.year == _now.year + assert dtp.col1.month == _now.month + assert dtp.col1.day == _now.day + assert dtp.col1.hour == _now.hour + assert dtp.col1.minute == _now.minute + assert int(dtp.col1.second) == int(_now.second) + + if zope_datetime_available: col.default_datetime_implementation = ZOPE_DATETIME_IMPLEMENTATION from DateTime import DateTime as zopeDateTime From 48e7eac934099caec2d7f3a0b86ff2badb000ec4 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 4 Jun 2021 19:13:02 +0300 Subject: [PATCH 308/509] CI: Downgrade `pip` to `<19.2` for Python 3.4 compatibility --- .travis.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 638d6484..adcd77ac 100644 --- a/.travis.yml +++ b/.travis.yml @@ -127,7 +127,7 @@ before_install: sudo chmod 644 /var/lib/firebird/create_test_db fi -install: travis_retry pip install --upgrade "pip<21" "setuptools<44" "tox>=3.15" coveralls codecov ppu +install: travis_retry pip install --upgrade "pip<19.2" "setuptools<44" "tox>=3.15" coveralls codecov ppu script: devscripts/tox-select-envs $TESTS diff --git a/appveyor.yml b/appveyor.yml index 38a7a1ec..808f4404 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -124,7 +124,7 @@ install: - "SET TOXPYTHON=%PYTHON_HOME%\\python.exe" - "python --version" - "python -c \"import struct; print(struct.calcsize('P') * 8)\"" - - "python -m pip install --upgrade \"pip<21\" \"setuptools<44\"" + - "python -m pip install --upgrade \"pip<19.2\" \"setuptools<44\"" - "pip install --upgrade \"tox>=3.15\" ppu" - "pip --version" # List ODBC drivers From 51387761fa25f7d41916a3876753ef86ad4f4d7f Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 4 Jun 2021 19:16:26 +0300 Subject: [PATCH 309/509] Tests(tox): Install `zope.datetime` --- tox.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tox.ini b/tox.ini index 67765a34..28717e6d 100644 --- a/tox.ini +++ b/tox.ini @@ -19,6 +19,8 @@ commands = {envpython} -c "import struct; print(struct.calcsize('P') * 8)" deps = -rdevscripts/requirements/requirements_tests.txt + py34: zope.datetime < 4.3 + !py34: zope.datetime mysqldb: mysql-python mysqlclient: mysqlclient mysql-connector: mysql-connector <= 2.2.2 From 84a4595b6a3f881979fb2d1a8ee39196fca08243 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 4 Jun 2021 19:25:48 +0300 Subject: [PATCH 310/509] Docs: Add compatibility with `Pendulum` Authors: Add James Hudson. [skip ci] --- docs/Authors.rst | 1 + docs/News.rst | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/docs/Authors.rst b/docs/Authors.rst index 9f1c6fe5..5ac91443 100644 --- a/docs/Authors.rst +++ b/docs/Authors.rst @@ -37,6 +37,7 @@ Contributions have been made by: * Michael S. Root * Scott Stahl * Markus Elfring +* James Hudson * Oleg Broytman .. image:: https://sourceforge.net/sflogo.php?group_id=74338&type=10 diff --git a/docs/News.rst b/docs/News.rst index 37935f3a..96cc7f7c 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,11 @@ News SQLObject (master) ================== +Features +-------- + +* Add compatibility with ``Pendulum``. + SQLObject 3.9.1 =============== From 6624e0a319fb81e11a586cb5ac2f8fd5c4b95b27 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 4 Jun 2021 19:27:58 +0300 Subject: [PATCH 311/509] Tests(tox): Install `pendulum` for new test in `test_datetime` --- tox.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tox.ini b/tox.ini index 67765a34..158c18cf 100644 --- a/tox.ini +++ b/tox.ini @@ -19,6 +19,8 @@ commands = {envpython} -c "import struct; print(struct.calcsize('P') * 8)" deps = -rdevscripts/requirements/requirements_tests.txt + py34: pendulum < 2.1 + !py34: pendulum mysqldb: mysql-python mysqlclient: mysqlclient mysql-connector: mysql-connector <= 2.2.2 From 661f41c795e020ffea9d16df0e340d54c73974c1 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 4 Jun 2021 19:32:04 +0300 Subject: [PATCH 312/509] Tests(test_datetime): Fix `test_PendulumDateTime` Reset `default_datetime_implementation` back to `datetime`. --- sqlobject/tests/test_datetime.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sqlobject/tests/test_datetime.py b/sqlobject/tests/test_datetime.py index 21ed5a62..b40e4dd4 100644 --- a/sqlobject/tests/test_datetime.py +++ b/sqlobject/tests/test_datetime.py @@ -131,6 +131,7 @@ def test_mxDateTime(): assert dt2.col3.second == int(_now.second) if pendulumDateTimeType: + col.default_datetime_implementation = DATETIME_IMPLEMENTATION import pendulum class DateTimePendulum(SQLObject): From 924c868a16fde2c2d31609c3c26d4d49052ef0a0 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 19 Jul 2021 00:32:56 +0300 Subject: [PATCH 313/509] Docs: Change Travis CI URLs CI relocated from travis-ci.org to travis-ci.com. [skip ci] --- docs/DeveloperGuide.rst | 4 ++-- docs/News.rst | 6 ++++++ setup.py | 4 ++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/docs/DeveloperGuide.rst b/docs/DeveloperGuide.rst index 966c379d..4ac95566 100644 --- a/docs/DeveloperGuide.rst +++ b/docs/DeveloperGuide.rst @@ -272,8 +272,8 @@ exercised, even if the tests are absolutely complete. We now use Travis CI and AppVeyor to run tests. See the statuses: -.. image:: https://travis-ci.org/sqlobject/sqlobject.svg?branch=master - :target: https://travis-ci.org/sqlobject/sqlobject +.. image:: https://api.travis-ci.com/sqlobject/sqlobject.svg?branch=master + :target: https://travis-ci.com/github/sqlobject/sqlobject .. image:: https://ci.appveyor.com/api/projects/status/github/sqlobject/sqlobject?branch=master :target: https://ci.appveyor.com/project/phdru/sqlobject diff --git a/docs/News.rst b/docs/News.rst index 96cc7f7c..af6b8a7d 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -13,6 +13,12 @@ Features * Add compatibility with ``Pendulum``. +Documentation +------------- + +* Change Travis CI URLs: + CI relocated from travis-ci.org to travis-ci.com. + SQLObject 3.9.1 =============== diff --git a/setup.py b/setup.py index 3dfd2caa..c7f59f24 100755 --- a/setup.py +++ b/setup.py @@ -42,8 +42,8 @@ `SourceForge `_ and `GitHub `_. -.. image:: https://travis-ci.org/sqlobject/sqlobject.svg?branch=master - :target: https://travis-ci.org/sqlobject/sqlobject +.. image:: https://api.travis-ci.com/sqlobject/sqlobject.svg?branch=master + :target: https://travis-ci.com/github/sqlobject/sqlobject """, long_description_content_type="text/x-rst", classifiers=[ From 87757d537df98bb7fb9b40e6f402266ef39b2c7e Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 25 Jul 2021 14:49:55 +0300 Subject: [PATCH 314/509] Tests(tox): Limit `VIRTUALENV_PIP` version for Python 3.4 --- tox.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tox.ini b/tox.ini index c03d56cd..64e08bd6 100644 --- a/tox.ini +++ b/tox.ini @@ -40,6 +40,8 @@ deps = firebird-fdb: fdb firebirdsql: firebirdsql passenv = CI TRAVIS TRAVIS_* APPVEYOR DISTUTILS_USE_SDK MSSdk INCLUDE LIB PGPASSWORD WINDIR +setenv = + VIRTUALENV_PIP = 19.1.1 # Don't fail or warn on uninstalled commands platform = linux whitelist_externals = From f4741f8e03171883554319c6d7d59a26dedd1762 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 25 Jul 2021 19:54:28 +0300 Subject: [PATCH 315/509] Tests(tox): Limit `pip` and `setuptools` versions for Python 3.4 --- tox.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tox.ini b/tox.ini index 64e08bd6..88febe67 100644 --- a/tox.ini +++ b/tox.ini @@ -18,6 +18,8 @@ commands = {envpython} --version {envpython} -c "import struct; print(struct.calcsize('P') * 8)" deps = + pip < 19.2 + setuptools < 44 -rdevscripts/requirements/requirements_tests.txt py34: pendulum < 2.1 py34: zope.datetime < 4.3 From 6a4df62a61757f64c452359a57ff956bac6f452d Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 3 Oct 2021 17:52:17 +0300 Subject: [PATCH 316/509] Build(devscripts): `rsync -a` -> `rsync -ahPv` Especially remove option `-4`. [skip ci] --- devscripts/build-all-docs | 2 +- devscripts/release | 4 ++-- docs/rebuild | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/devscripts/build-all-docs b/devscripts/build-all-docs index 34aacd3c..8cb4ba16 100755 --- a/devscripts/build-all-docs +++ b/devscripts/build-all-docs @@ -3,7 +3,7 @@ build_docs() { git checkout "$1" && devscripts/build-docs && - rsync -ahP --del --exclude=/robots.txt docs/html/ ../SQLObject-docs/"$2"/ + rsync -ahPv --del --exclude=/robots.txt docs/html/ ../SQLObject-docs/"$2"/ } cd "`dirname \"$0\"`" && diff --git a/devscripts/release b/devscripts/release index 33bb23ff..3873ec25 100755 --- a/devscripts/release +++ b/devscripts/release @@ -19,8 +19,8 @@ version=`python setup.py --version` split_tag $version if [ "$state" = final ]; then - rsync -ahP4 dist/* frs.sourceforge.net:/home/frs/project/sqlobject/sqlobject/"$version"/ && - rsync -ahP4 ANNOUNCE.rst frs.sourceforge.net:/home/frs/project/sqlobject/sqlobject/"$version"/README.rst || exit 1 + rsync -ahPv dist/* frs.sourceforge.net:/home/frs/project/sqlobject/sqlobject/"$version"/ && + rsync -ahPv ANNOUNCE.rst frs.sourceforge.net:/home/frs/project/sqlobject/sqlobject/"$version"/README.rst || exit 1 devscripts/sftp-frs fi && diff --git a/docs/rebuild b/docs/rebuild index 12703849..4798a23d 100755 --- a/docs/rebuild +++ b/docs/rebuild @@ -2,4 +2,4 @@ PYTHONPATH=.. make html && find . -name \*.tmp -type f -delete && -exec rsync -ahP --del --exclude=.buildinfo --exclude=objects.inv _build/html . +exec rsync -ahPv --del --exclude=.buildinfo --exclude=objects.inv _build/html . From 0d612ecb5e3f367a7734636d31cd2e80d1edd27e Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 5 Oct 2021 10:47:59 +0300 Subject: [PATCH 317/509] Build: Remove personal script `setup` [skip ci] --- devscripts/setup | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100755 devscripts/setup diff --git a/devscripts/setup b/devscripts/setup deleted file mode 100755 index e28d6765..00000000 --- a/devscripts/setup +++ /dev/null @@ -1,10 +0,0 @@ -#! /bin/sh - -umask 022 # -rwxr-xr-x -cd "`dirname \"$0\"`"/.. && - -for py_ver in 2.7 3.4 3.5 3.6 3.7 3.8 3.9; do - python$py_ver -m pip install --install-option=-O2 --upgrade . -done && - -exec rm -rf build dist SQLObject.egg-info MANIFEST *.egg From d7c7996ed212ee18b416f527a7dfc4e746434465 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Gmach?= Date: Mon, 18 Oct 2021 15:42:10 +0200 Subject: [PATCH 318/509] fix typo --- docs/SQLObject.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index ddbe2c5d..a4adc741 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -584,7 +584,7 @@ in-place:: the class definition is equivalent to calling certain class methods (like ``addColumn()``). -Now we can get the backreference with ``aPerson.addresses``, which +Now we can get the backreference with ``Person.addresses``, which returns a list. An example:: >>> p.addresses From caa8261b0b21bca42dc10825359ab7114470dc22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Gmach?= Date: Mon, 18 Oct 2021 17:38:14 +0200 Subject: [PATCH 319/509] fix typo --- docs/SQLObject.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index ddbe2c5d..079da8d4 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -264,7 +264,7 @@ To create a new object (and row), use class instantiation, like:: .. note:: In SQLObject NULL/None does *not* mean default. NULL is a funny - thing; it mean very different things in different contexts and to + thing; it means very different things in different contexts and to different people. Sometimes it means "default", sometimes "not applicable", sometimes "unknown". If you want a default, NULL or otherwise, you always have to be explicit in your class From 8878c12bb3e1508ea34b277e30b5e542be3139cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Gmach?= Date: Mon, 18 Oct 2021 17:40:15 +0200 Subject: [PATCH 320/509] remove redundant dot --- docs/SQLObject.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index ddbe2c5d..4e1962f4 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -304,7 +304,7 @@ Here's a longer example of using the class:: >>> p is p2 True -Columns are accessed like attributes. (This uses the ``property`` +Columns are accessed like attributes (This uses the ``property`` feature of Python, so that retrieving and setting these attributes executes code). Also note that objects are unique -- there is generally only one ``Person`` instance of a particular id in memory at From bc88b43dc6b34c42c25e3fd751df214bf83b2e37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Gmach?= Date: Mon, 18 Oct 2021 17:48:57 +0200 Subject: [PATCH 321/509] fix hint about indexes Using an index properly improves performance, not importance. --- docs/SQLObject.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index ddbe2c5d..96780597 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -461,7 +461,7 @@ slicing, this makes batched queries easy to write: the entire result set to sort the items (so it knows which the first ten are), and depending on your query may need to scan through the entire table (depending on your use of indexes). - Indexes are probably the most important way to improve importance + Indexes are probably the most important way to improve performance in a case like this, and you may find caching to be more effective than slicing. From f73d5f8df8d3fac02e110d2138976cba750924d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Gmach?= Date: Mon, 18 Oct 2021 17:55:24 +0200 Subject: [PATCH 322/509] fix address example --- docs/SQLObject.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index ddbe2c5d..3fe858a8 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -546,8 +546,8 @@ addresses, of course:: Note the column ``person = ForeignKey("Person")``. This is a reference to a `Person` object. We refer to other classes by name -(with a string). In the database there will be a ``person_id`` -column, type ``INT``, which points to the ``person`` column. +(with a string). In the address table there will be a ``person_id`` +column, type ``INT``, which points to the ``person`` table. .. note:: From fa13293d11eb11c1fb1400234fdc7c7c27c31b8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Gmach?= Date: Tue, 19 Oct 2021 15:56:45 +0200 Subject: [PATCH 323/509] fix description for `joinColumn` --- docs/SQLObject.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index ddbe2c5d..33beaf34 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -1357,7 +1357,7 @@ Several keyword arguments are allowed to the `MultipleJoin` constructor: have a table ``Product``, and another table has a column ``ProductNo`` that points to this table, then you'd use ``joinColumn="ProductNo"``. WARNING: the argument you pass must - conform to the column name in the database, not to the column in the + conform to the column name in the database, not to the attribute in the class. So, if you have a SQLObject containing the ``ProductNo`` column, this will probably be translated into ``product_no_id`` in the DB (``product_no`` is the normal uppercase- to-lowercase + From 6b1514aa4d881b947e799595d6d92cffdb342922 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 31 Oct 2021 12:51:59 +0300 Subject: [PATCH 324/509] Docs(Authors): Add Juergen Gmach [skip ci] --- docs/Authors.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Authors.rst b/docs/Authors.rst index 5ac91443..70115048 100644 --- a/docs/Authors.rst +++ b/docs/Authors.rst @@ -38,6 +38,7 @@ Contributions have been made by: * Scott Stahl * Markus Elfring * James Hudson +* Juergen Gmach * Oleg Broytman .. image:: https://sourceforge.net/sflogo.php?group_id=74338&type=10 From b74820a65dbbaa48064bc0f3d98091b1a3820a41 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 7 Nov 2021 00:33:20 +0300 Subject: [PATCH 325/509] Tests: Python 3.10 --- docs/News.rst | 5 ++++ setup.py | 1 + tox.ini | 73 ++++++++++++++++++++++++++------------------------- 3 files changed, 43 insertions(+), 36 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index af6b8a7d..4c45d135 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -13,6 +13,11 @@ Features * Add compatibility with ``Pendulum``. +Tests +----- + +* Run tests with Python 3.10. + Documentation ------------- diff --git a/setup.py b/setup.py index c7f59f24..d98fb37d 100755 --- a/setup.py +++ b/setup.py @@ -61,6 +61,7 @@ "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", "Topic :: Database", "Topic :: Database :: Front-Ends", "Topic :: Software Development :: Libraries :: Python Modules", diff --git a/tox.ini b/tox.ini index 88febe67..5f65b49d 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 3.15 -envlist = py27,py3{4,5,6,7,8,9}-sqlite{,-memory},py{27,39}-flake8 +envlist = py27,py3{4,5,6,7,8,9,10}-sqlite{,-memory},py{27,310}-flake8 # Base test environment settings [testenv] @@ -14,12 +14,13 @@ basepython = py37: {env:TOXPYTHON:python3.7} py38: {env:TOXPYTHON:python3.8} py39: {env:TOXPYTHON:python3.9} + py310: {env:TOXPYTHON:python3.10} commands = {envpython} --version {envpython} -c "import struct; print(struct.calcsize('P') * 8)" deps = - pip < 19.2 - setuptools < 44 + py27,py34: pip < 19.2 + py27,py34: setuptools < 44 -rdevscripts/requirements/requirements_tests.txt py34: pendulum < 2.1 py34: zope.datetime < 4.3 @@ -70,7 +71,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysqldb]commands} -[testenv:py3{4,5,6,7,8,9}-mysqldb] +[testenv:py3{4,5,6,7,8,9,10}-mysqldb] commands = {envpython} -c "print('MySQL-python requires Python 2.7')" deps = @@ -86,7 +87,7 @@ commands = commands = {envpython} -c "print('mysqlclient requires Python 3.4+')" deps = -[testenv:py3{4,5,6,7,8,9}-mysqlclient] +[testenv:py3{4,5,6,7,8,9,10}-mysqlclient] commands = {[mysqlclient]commands} [mysql-connector] @@ -102,7 +103,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-connector]commands} -[testenv:py3{4,5,6,7,8,9}-mysql-connector-noauto] +[testenv:py3{4,5,6,7,8,9,10}-mysql-connector-noauto] commands = {[mysql-connector]commands} [oursql] @@ -118,7 +119,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[oursql]commands} -[testenv:py3{4,5,6,7,8,9}-mysql-oursql3-noauto] +[testenv:py3{4,5,6,7,8,9,10}-mysql-oursql3-noauto] commands = {[oursql]commands} [pymysql] @@ -134,7 +135,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pymysql]commands} -[testenv:py3{4,5,6,7,8,9}-mysql-pymysql] +[testenv:py3{4,5,6,7,8,9,10}-mysql-pymysql] commands = {[pymysql]commands} [mariadb] @@ -149,7 +150,7 @@ commands = commands = {envpython} -c "print('mariadb requires Python 3.6+')" deps = -[testenv:py3{6,7,8,9}-mariadb] +[testenv:py3{6,7,8,9,10}-mariadb] commands = {[mariadb]commands} [mysql-pyodbc] @@ -166,7 +167,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pyodbc]commands} -[testenv:py3{4,5,6,7,8,9}-mysql-pyodbc-noauto] +[testenv:py3{4,5,6,7,8,9,10}-mysql-pyodbc-noauto] commands = {[mysql-pyodbc]commands} [mysql-pypyodbc] @@ -182,7 +183,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pypyodbc]commands} -[testenv:py3{4,5,6,7,8,9}-mysql-pypyodbc-noauto] +[testenv:py3{4,5,6,7,8,9,10}-mysql-pypyodbc-noauto] commands = {[mysql-pypyodbc]commands} # PostgreSQL test environments @@ -199,7 +200,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[psycopg]commands} -[testenv:py3{4,5,6,7,8,9}-postgres-psycopg] +[testenv:py3{4,5,6,7,8,9,10}-postgres-psycopg] commands = {[psycopg]commands} [pygresql] @@ -215,7 +216,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pygresql]commands} -[testenv:py3{4,5,6,7,8,9}-postgres-pygresql] +[testenv:py3{4,5,6,7,8,9,10}-postgres-pygresql] commands = {[pygresql]commands} [pypostgresql] @@ -230,7 +231,7 @@ commands = commands = {envpython} -c "print('pypostgresql requires Python 3.4+')" deps = -[testenv:py3{4,5,6,7,8,9}-postgres-pypostgresql] +[testenv:py3{4,5,6,7,8,9,10}-postgres-pypostgresql] commands = {[pypostgresql]commands} [pg8000] @@ -246,7 +247,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pg8000]commands} -[testenv:py3{4,5,6,7,8,9}-postgres-pg8000] +[testenv:py3{4,5,6,7,8,9,10}-postgres-pg8000] commands = {[pg8000]commands} [postgres-pyodbc] @@ -263,7 +264,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pyodbc]commands} -[testenv:py3{4,5,6,7,8,9}-postgres-pyodbc-noauto] +[testenv:py3{4,5,6,7,8,9,10}-postgres-pyodbc-noauto] commands = {[postgres-pyodbc]commands} [postgres-pypyodbc] @@ -279,7 +280,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pypyodbc]commands} -[testenv:py3{4,5,6,7,8,9}-postgres-pypyodbc-noauto] +[testenv:py3{4,5,6,7,8,9,10}-postgres-pypyodbc-noauto] commands = {[postgres-pypyodbc]commands} @@ -296,7 +297,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite]commands} -[testenv:py3{4,5,6,7,8,9}-sqlite] +[testenv:py3{4,5,6,7,8,9,10}-sqlite] commands = {[sqlite]commands} [sqlite-memory] @@ -309,7 +310,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite-memory]commands} -[testenv:py3{4,5,6,7,8,9}-sqlite-memory] +[testenv:py3{4,5,6,7,8,9,10}-sqlite-memory] commands = {[sqlite-memory]commands} [sqlite-supersqlite] @@ -324,7 +325,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite-supersqlite]commands} -[testenv:py3{4,5,6,7,8,9}-sqlite-supersqlite] +[testenv:py3{4,5,6,7,8,9,10}-sqlite-supersqlite] commands = {[sqlite-supersqlite]commands} @@ -342,7 +343,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[fdb]commands} -[testenv:py3{4,5,6,7,8,9}-firebird-fdb] +[testenv:py3{4,5,6,7,8,9,10}-firebird-fdb] commands = {[fdb]commands} [firebirdsql] @@ -358,7 +359,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[firebirdsql]commands} -[testenv:py3{4,5,6,7,8,9}-firebirdsql] +[testenv:py3{4,5,6,7,8,9,10}-firebirdsql] commands = {[firebirdsql]commands} @@ -388,7 +389,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mssql-pyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9}-mssql-pyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10}-mssql-pyodbc-noauto-w32] platform = win32 commands = {[mssql-pyodbc-w32]commands} @@ -407,7 +408,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-connector-w32]commands} -[testenv:py3{4,5,6,7,8,9}-mysql-connector-w32] +[testenv:py3{4,5,6,7,8,9,10}-mysql-connector-w32] platform = win32 commands = {[mysql-connector-w32]commands} @@ -426,7 +427,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pymysql-w32]commands} -[testenv:py3{4,5,6,7,8,9}-mysql-pymysql-w32] +[testenv:py3{4,5,6,7,8,9,10}-mysql-pymysql-w32] platform = win32 commands = {[pymysql-w32]commands} @@ -444,7 +445,7 @@ platform = win32 commands = {envpython} -c "print('mariadb requires Python 3.6+')" deps = -[testenv:py3{6,7,8,9}-mariadb-w32] +[testenv:py3{6,7,8,9,10}-mariadb-w32] platform = win32 commands = {[mariadb-w32]commands} @@ -464,7 +465,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9}-mysql-pyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10}-mysql-pyodbc-noauto-w32] platform = win32 commands = {[mysql-pyodbc-w32]commands} @@ -484,7 +485,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pypyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9}-mysql-pypyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10}-mysql-pypyodbc-noauto-w32] platform = win32 commands = {[mysql-pypyodbc-w32]commands} @@ -503,7 +504,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[psycopg-w32]commands} -[testenv:py3{4,5,6,7,8,9}-postgres-psycopg-w32] +[testenv:py3{4,5,6,7,8,9,10}-postgres-psycopg-w32] platform = win32 commands = {[psycopg-w32]commands} @@ -522,7 +523,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pygresql-w32]commands} -[testenv:py3{4,5,6,7,8,9}-postgres-pygresql-w32] +[testenv:py3{4,5,6,7,8,9,10}-postgres-pygresql-w32] platform = win32 commands = {[pygresql-w32]commands} @@ -540,7 +541,7 @@ platform = win32 commands = {envpython} -c "print('pypostgresql requires Python 3.4+')" deps = -[testenv:py3{4,5,6,7,8,9}-postgres-pypostgresql-w32] +[testenv:py3{4,5,6,7,8,9,10}-postgres-pypostgresql-w32] platform = win32 commands = {[pypostgresql-w32]commands} @@ -559,7 +560,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pg8000-w32]commands} -[testenv:py3{4,5,6,7,8,9}-postgres-pg8000-w32] +[testenv:py3{4,5,6,7,8,9,10}-postgres-pg8000-w32] platform = win32 commands = {[pg8000-w32]commands} @@ -579,7 +580,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9}-postgres-pyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10}-postgres-pyodbc-noauto-w32] platform = win32 commands = {[postgres-pyodbc-w32]commands} @@ -599,7 +600,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pypyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9}-postgres-pypyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10}-postgres-pypyodbc-noauto-w32] platform = win32 commands = {[postgres-pypyodbc-w32]commands} @@ -616,7 +617,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite-w32]commands} -[testenv:py3{4,5,6,7,8,9}-sqlite-w32] +[testenv:py3{4,5,6,7,8,9,10}-sqlite-w32] platform = win32 commands = {[sqlite-w32]commands} @@ -632,6 +633,6 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite-memory-w32]commands} -[testenv:py3{4,5,6,7,8,9}-sqlite-memory-w32] +[testenv:py3{4,5,6,7,8,9,10}-sqlite-memory-w32] platform = win32 commands = {[sqlite-memory-w32]commands} From c3933b813383cc1b269b6c2564e89e3c7aa523e9 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 8 Nov 2021 00:34:15 +0300 Subject: [PATCH 326/509] Docs(DevGuide): Document more requirements Document more requirements and recommendations for the source code and commit messages. [skip ci] --- docs/DeveloperGuide.rst | 23 ++++++++++++++++++++++- docs/News.rst | 14 ++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/docs/DeveloperGuide.rst b/docs/DeveloperGuide.rst index 4ac95566..955dc03d 100644 --- a/docs/DeveloperGuide.rst +++ b/docs/DeveloperGuide.rst @@ -125,6 +125,9 @@ Python Style Guide. Some things to take particular note of: .. _PEP 8: http://www.python.org/dev/peps/pep-0008/ +* With some exceptions sources must be pure ASCII. Including string + literals and comments. + * With a few exceptions sources must be `flake8`_-clean (and hence pep8-clean). Please consider using pre-commit hook installed by running ``flake8 --install-hook``. @@ -196,6 +199,9 @@ Python Style Guide. Some things to take particular note of: Don't use single quotes ('''). Don't bother trying make the string less vertically compact. + Not strictly required but ``reStructuredText`` format for docstrings is + very much recommended. + * Comments go right before the thing they are commenting on. * Methods never, ever, ever start with capital letters. Generally @@ -298,9 +304,24 @@ Documentation ============= Please write documentation. Documentation should live in the docs/ -directory in reStructuredText format. We use Sphinx to convert docs to +directory in ``reStructuredText`` format. We use Sphinx to convert docs to HTML. +Contributing +============ + +* Now de-facto `stadard for good commit messages + `_ is required. + +* `Conventional commit subject liness + `_ are recommended. + +* ``Markdown`` format for commit message bodies is recommended. + `Github-flavored Markdown `_ is allowed. + +* Commit messages must be pure ASCII. No fancy Unicode emojies, + quotes, etc. + .. image:: https://sourceforge.net/sflogo.php?group_id=74338&type=10 :target: https://sourceforge.net/projects/sqlobject :class: noborder diff --git a/docs/News.rst b/docs/News.rst index 4c45d135..c1a52547 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -21,6 +21,20 @@ Tests Documentation ------------- +* DevGuide: source code must be pure ASCII. + +* DevGuide: ``reStructuredText`` format for docstrings is recommended. + +* DevGuide: de-facto good commit message format is required: + subject/body/trailers. + +* DevGuide: ``conventional commit`` format for commit message subject lines + is recommended. + +* DevGuide: ``Markdown`` format for commit message bodies is recommended. + +* DevGuide: commit messages must be pure ASCII. + * Change Travis CI URLs: CI relocated from travis-ci.org to travis-ci.com. From 2a7d26086f73028fdb651f9e22e99c812b81b883 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Tue, 11 Jan 2022 16:56:41 +0200 Subject: [PATCH 327/509] Remove "U" option in open for Python 3.11 compatibility --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index d98fb37d..cdfcb9aa 100755 --- a/setup.py +++ b/setup.py @@ -11,7 +11,7 @@ execfile(versionpath, sqlobject_version) # noqa: F821 'execfile' Py3 elif sys.version_info >= (3, 4): - exec(open(versionpath, 'rU').read(), sqlobject_version) + exec(open(versionpath, 'r').read(), sqlobject_version) else: raise ImportError("SQLObject requires Python 2.7 or 3.4+") From 18f55ff5894eeb33dc77d6318cf32f0d4341f661 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 11 Jan 2022 21:41:33 +0300 Subject: [PATCH 328/509] Docs(Authors): Add Hugo van Kemenade [skip ci] --- docs/Authors.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Authors.rst b/docs/Authors.rst index 70115048..6c5b23c9 100644 --- a/docs/Authors.rst +++ b/docs/Authors.rst @@ -39,6 +39,7 @@ Contributions have been made by: * Markus Elfring * James Hudson * Juergen Gmach +* Hugo van Kemenade * Oleg Broytman .. image:: https://sourceforge.net/sflogo.php?group_id=74338&type=10 From 9f3ca7e00da3d820b7181a9988f82424b2439254 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 21 Feb 2022 18:29:29 +0300 Subject: [PATCH 329/509] Feat(dbconnection): Allow connections in `ConnectionHub` to be strings This allows to open a new connection in every thread. --- docs/News.rst | 3 +++ sqlobject/dbconnection.py | 13 +++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index c1a52547..afce29f1 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -11,6 +11,9 @@ SQLObject (master) Features -------- +* Allow connections in ``ConnectionHub`` to be strings. + This allows to open a new connection in every thread. + * Add compatibility with ``Pendulum``. Tests diff --git a/sqlobject/dbconnection.py b/sqlobject/dbconnection.py index e3de62e8..6a383e79 100644 --- a/sqlobject/dbconnection.py +++ b/sqlobject/dbconnection.py @@ -989,14 +989,21 @@ def __set__(self, obj, value): def getConnection(self): try: - return self.threadingLocal.connection + connection = self.threadingLocal.connection + if isinstance(connection, string_type): + connection = connectionForURI(connection) + self.threadingLocal.connection = connection except AttributeError: try: - return self.processConnection + connection = self.processConnection + if isinstance(connection, string_type): + connection = connectionForURI(connection) + self.processConnection = connection except AttributeError: raise AttributeError( "No connection has been defined for this thread " "or process") + return connection def doInTransaction(self, func, *args, **kw): """ @@ -1019,6 +1026,8 @@ def doInTransaction(self, func, *args, **kw): except AttributeError: old_conn = self.processConnection old_conn_is_threading = False + if isinstance(old_conn, string_type): + old_conn = connectionForURI(old_conn) conn = old_conn.transaction() if old_conn_is_threading: self.threadConnection = conn From 91057747751df3793898898903fb371709ccc1f8 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 21 Feb 2022 23:17:59 +0300 Subject: [PATCH 330/509] Build(devscripts): Run Python 3.10 in `test-sqlobject.cmd` --- devscripts/test-sqlobject.cmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devscripts/test-sqlobject.cmd b/devscripts/test-sqlobject.cmd index 97846d80..8c7e38d0 100644 --- a/devscripts/test-sqlobject.cmd +++ b/devscripts/test-sqlobject.cmd @@ -3,7 +3,7 @@ SetLocal EnableDelayedExpansion set SavePATH=%PATH% -for %%V in (27 34 35 36 37 38 39) do ( +for %%V in (27 34 35 36 37 38 39 310) do ( for %%s in (32 64) do ( set PATH=C:\Python%%V-%%s;C:\Python%%V-%%s\Scripts;!SavePATH! set TOXPYTHON=C:\Python%%V-%%s\python.exe From 71da8511dd6ab1b45c2d2057849602b7d66a8435 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 22 Feb 2022 00:12:02 +0300 Subject: [PATCH 331/509] Test(tox): `postgres-psycopg` -> `psycopg` --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 5f65b49d..e29e1d77 100644 --- a/tox.ini +++ b/tox.ini @@ -33,7 +33,7 @@ deps = mysql-oursql3: git+https://github.com/sqlobject/oursql.git@py3k#egg=oursql pymysql: -rdevscripts/requirements/requirements_pymysql.txt mariadb: mariadb - postgres-psycopg: psycopg2-binary + psycopg: psycopg2-binary pygresql: -rdevscripts/requirements/requirements_pygresql.txt pypostgresql: git+https://github.com/sqlobject/py-postgresql.git@fix_w32#egg=py-postgresql pg8000: -rdevscripts/requirements/requirements_pg8000.txt From 576f82f00163ef041ff994f9ed9cca168300c835 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 22 Feb 2022 00:13:04 +0300 Subject: [PATCH 332/509] Test(tox): Use our branch `combined-fixes` for `py-postgresql` The branch combines fixes from `fix_w32` and `pr/114` (parse PostgreSQL version screwed by Debian). --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index e29e1d77..8fadaffc 100644 --- a/tox.ini +++ b/tox.ini @@ -35,7 +35,7 @@ deps = mariadb: mariadb psycopg: psycopg2-binary pygresql: -rdevscripts/requirements/requirements_pygresql.txt - pypostgresql: git+https://github.com/sqlobject/py-postgresql.git@fix_w32#egg=py-postgresql + pypostgresql: git+https://github.com/sqlobject/py-postgresql.git@combined-fixes#egg=py-postgresql pg8000: -rdevscripts/requirements/requirements_pg8000.txt pyodbc: pyodbc pypyodbc: pypyodbc From 42a1f53a2368e4a53d0bef0227295d3fec9f4731 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 23 Feb 2022 05:28:19 +0300 Subject: [PATCH 333/509] Tests(tox): Limit version of `psycopg2-binary` for Python 3.4 --- tox.ini | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 8fadaffc..73adcfee 100644 --- a/tox.ini +++ b/tox.ini @@ -33,7 +33,8 @@ deps = mysql-oursql3: git+https://github.com/sqlobject/oursql.git@py3k#egg=oursql pymysql: -rdevscripts/requirements/requirements_pymysql.txt mariadb: mariadb - psycopg: psycopg2-binary + py34-psycopg: psycopg2-binary==2.8.4 + !py34-psycopg: psycopg2-binary pygresql: -rdevscripts/requirements/requirements_pygresql.txt pypostgresql: git+https://github.com/sqlobject/py-postgresql.git@combined-fixes#egg=py-postgresql pg8000: -rdevscripts/requirements/requirements_pg8000.txt From 836763622ef5b93f933cbd712ef7b65cdb742183 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 23 Feb 2022 19:02:45 +0300 Subject: [PATCH 334/509] Tests(tox): Use long options for MySQL/PostgreSQL tools --- tox.ini | 120 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 60 insertions(+), 60 deletions(-) diff --git a/tox.ini b/tox.ini index 73adcfee..9c2ae387 100644 --- a/tox.ini +++ b/tox.ini @@ -62,10 +62,10 @@ whitelist_externals = [mysqldb] commands = {[testenv]commands} - -mysql -uroot -e 'drop database sqlobject_test;' - mysql -uroot -e 'create database sqlobject_test;' + -mysql --user=root --execute='drop database sqlobject_test;' + mysql --user=root --execute='create database sqlobject_test;' pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=mysqldb&debug=1 - mysql -uroot -e 'drop database sqlobject_test;' + mysql --user=root --execute='drop database sqlobject_test;' [testenv:py27-mysqldb] commands = @@ -79,10 +79,10 @@ deps = [mysqlclient] commands = {[testenv]commands} - -mysql -uroot -e 'drop database sqlobject_test;' - mysql -uroot -e 'create database sqlobject_test;' + -mysql --user=root --execute='drop database sqlobject_test;' + mysql --user=root --execute='create database sqlobject_test;' pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=mysqldb&charset=utf8&debug=1 - mysql -uroot -e 'drop database sqlobject_test;' + mysql --user=root --execute='drop database sqlobject_test;' [testenv:py27-mysqlclient] commands = {envpython} -c "print('mysqlclient requires Python 3.4+')" @@ -94,10 +94,10 @@ commands = {[mysqlclient]commands} [mysql-connector] commands = {[testenv]commands} - -mysql -uroot -e 'drop database sqlobject_test;' - mysql -uroot -e 'create database sqlobject_test;' + -mysql --user=root --execute='drop database sqlobject_test;' + mysql --user=root --execute='create database sqlobject_test;' pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=connector&charset=utf8&debug=1 - mysql -uroot -e 'drop database sqlobject_test;' + mysql --user=root --execute='drop database sqlobject_test;' [testenv:py27-mysql-connector-noauto] commands = @@ -110,10 +110,10 @@ commands = {[mysql-connector]commands} [oursql] commands = {[testenv]commands} - -mysql -uroot -e 'drop database sqlobject_test;' - mysql -uroot -e 'create database sqlobject_test;' + -mysql --user=root --execute='drop database sqlobject_test;' + mysql --user=root --execute='create database sqlobject_test;' pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=oursql&charset=utf8&debug=1 - mysql -uroot -e 'drop database sqlobject_test;' + mysql --user=root --execute='drop database sqlobject_test;' [testenv:py27-mysql-oursql-noauto] commands = @@ -126,10 +126,10 @@ commands = {[oursql]commands} [pymysql] commands = {[testenv]commands} - -mysql -uroot -e 'drop database sqlobject_test;' - mysql -uroot -e 'create database sqlobject_test;' + -mysql --user=root --execute='drop database sqlobject_test;' + mysql --user=root --execute='create database sqlobject_test;' pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=pymysql&charset=utf8&debug=1 - mysql -uroot -e 'drop database sqlobject_test;' + mysql --user=root --execute='drop database sqlobject_test;' [testenv:py27-mysql-pymysql] commands = @@ -142,10 +142,10 @@ commands = {[pymysql]commands} [mariadb] commands = {[testenv]commands} - -mysql -uroot -e 'drop database sqlobject_test;' - mysql -uroot -e 'create database sqlobject_test;' + -mysql --user=root --execute='drop database sqlobject_test;' + mysql --user=root --execute='create database sqlobject_test;' pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=mariadb&charset=utf8&debug=1 - mysql -uroot -e 'drop database sqlobject_test;' + mysql --user=root --execute='drop database sqlobject_test;' [testenv:py{27,34,35}-mariadb] commands = {envpython} -c "print('mariadb requires Python 3.6+')" @@ -158,10 +158,10 @@ commands = {[mariadb]commands} commands = {[testenv]commands} {envpython} -c "import pyodbc; print(pyodbc.drivers())" - -mysql -uroot -e 'drop database sqlobject_test;' - mysql -uroot -e 'create database sqlobject_test;' + -mysql --user=root --execute='drop database sqlobject_test;' + mysql --user=root --execute='create database sqlobject_test;' pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=pyodbc&odbcdrv=MySQL&charset=utf8&debug=1 - mysql -uroot -e 'drop database sqlobject_test;' + mysql --user=root --execute='drop database sqlobject_test;' [testenv:py27-mysql-pyodbc-noauto] commands = @@ -174,10 +174,10 @@ commands = {[mysql-pyodbc]commands} [mysql-pypyodbc] commands = {[testenv]commands} - -mysql -uroot -e 'drop database sqlobject_test;' - mysql -uroot -e 'create database sqlobject_test;' + -mysql --user=root --execute='drop database sqlobject_test;' + mysql --user=root --execute='create database sqlobject_test;' pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=MySQL&charset=utf8&debug=1 - mysql -uroot -e 'drop database sqlobject_test;' + mysql --user=root --execute='drop database sqlobject_test;' [testenv:py27-mysql-pypyodbc-noauto] commands = @@ -191,10 +191,10 @@ commands = {[mysql-pypyodbc]commands} [psycopg] commands = {[testenv]commands} - -dropdb -U postgres -w sqlobject_test - createdb -U postgres -w sqlobject_test + -dropdb --username=postgres --no-password sqlobject_test + createdb --username=postgres --no-password sqlobject_test pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test - dropdb -U postgres -w sqlobject_test + dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-psycopg] commands = @@ -207,10 +207,10 @@ commands = {[psycopg]commands} [pygresql] commands = {[testenv]commands} - -dropdb -U postgres -w sqlobject_test - createdb -U postgres -w sqlobject_test + -dropdb --username=postgres --no-password sqlobject_test + createdb --username=postgres --no-password sqlobject_test pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test - dropdb -U postgres -w sqlobject_test + dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pygresql] commands = @@ -223,10 +223,10 @@ commands = {[pygresql]commands} [pypostgresql] commands = {[testenv]commands} - -dropdb -U postgres -w sqlobject_test - createdb -U postgres -w sqlobject_test + -dropdb --username=postgres --no-password sqlobject_test + createdb --username=postgres --no-password sqlobject_test pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test - dropdb -U postgres -w sqlobject_test + dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pypostgresql] commands = {envpython} -c "print('pypostgresql requires Python 3.4+')" @@ -238,10 +238,10 @@ commands = {[pypostgresql]commands} [pg8000] commands = {[testenv]commands} - -dropdb -U postgres -w sqlobject_test - createdb -U postgres -w sqlobject_test + -dropdb --username=postgres --no-password sqlobject_test + createdb --username=postgres --no-password sqlobject_test pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=pg8000&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test - dropdb -U postgres -w sqlobject_test + dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pg8000] commands = @@ -255,10 +255,10 @@ commands = {[pg8000]commands} commands = {[testenv]commands} {envpython} -c "import pyodbc; print(pyodbc.drivers())" - -dropdb -U postgres -w sqlobject_test - createdb -U postgres -w sqlobject_test + -dropdb --username=postgres --no-password sqlobject_test + createdb --username=postgres --no-password sqlobject_test pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=pyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test - dropdb -U postgres -w sqlobject_test + dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pyodbc-noauto] commands = @@ -271,10 +271,10 @@ commands = {[postgres-pyodbc]commands} [postgres-pypyodbc] commands = {[testenv]commands} - -dropdb -U postgres -w sqlobject_test - createdb -U postgres -w sqlobject_test + -dropdb --username=postgres --no-password sqlobject_test + createdb --username=postgres --no-password sqlobject_test pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test - dropdb -U postgres -w sqlobject_test + dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pypyodbc-noauto] commands = @@ -494,10 +494,10 @@ commands = {[mysql-pypyodbc-w32]commands} platform = win32 commands = {[testenv]commands} - -dropdb -U postgres -w sqlobject_test - createdb -U postgres -w sqlobject_test + -dropdb --username=postgres --no-password sqlobject_test + createdb --username=postgres --no-password sqlobject_test pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=psycopg2&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test - dropdb -U postgres -w sqlobject_test + dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-psycopg-w32] platform = win32 @@ -513,10 +513,10 @@ commands = {[psycopg-w32]commands} platform = win32 commands = {[testenv]commands} - -dropdb -U postgres -w sqlobject_test - createdb -U postgres -w sqlobject_test + -dropdb --username=postgres --no-password sqlobject_test + createdb --username=postgres --no-password sqlobject_test -pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test - dropdb -U postgres -w sqlobject_test + dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pygresql-noauto-w32] platform = win32 @@ -532,10 +532,10 @@ commands = {[pygresql-w32]commands} platform = win32 commands = {[testenv]commands} - -dropdb -U postgres -w sqlobject_test - createdb -U postgres -w sqlobject_test + -dropdb --username=postgres --no-password sqlobject_test + createdb --username=postgres --no-password sqlobject_test pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test - dropdb -U postgres -w sqlobject_test + dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pypostgresql-w32] platform = win32 @@ -550,10 +550,10 @@ commands = {[pypostgresql-w32]commands} platform = win32 commands = {[testenv]commands} - -dropdb -U postgres -w sqlobject_test - createdb -U postgres -w sqlobject_test + -dropdb --username=postgres --no-password sqlobject_test + createdb --username=postgres --no-password sqlobject_test pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pg8000&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test - dropdb -U postgres -w sqlobject_test + dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pg8000-w32] platform = win32 @@ -570,10 +570,10 @@ platform = win32 commands = {[testenv]commands} {envpython} -c "import pyodbc; print(pyodbc.drivers())" - -dropdb -U postgres -w sqlobject_test - createdb -U postgres -w sqlobject_test + -dropdb --username=postgres --no-password sqlobject_test + createdb --username=postgres --no-password sqlobject_test pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pyodbc&odbcdrv=PostgreSQL%20ANSI%28x64%29&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test - dropdb -U postgres -w sqlobject_test + dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pyodbc-noauto-w32] platform = win32 @@ -590,10 +590,10 @@ platform = win32 commands = {[testenv]commands} {envpython} -c "import pypyodbc; print(pypyodbc.drivers())" - -dropdb -U postgres -w sqlobject_test - createdb -U postgres -w sqlobject_test + -dropdb --username=postgres --no-password sqlobject_test + createdb --username=postgres --no-password sqlobject_test pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=PostgreSQL%20ANSI%28x64%29&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test - dropdb -U postgres -w sqlobject_test + dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pypyodbc-noauto-w32] platform = win32 From 1aed26838d1616b3686b74697e01bb4da5e47b79 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 16 Sep 2022 23:37:31 +0300 Subject: [PATCH 335/509] Style: Fix `flake8` E275 missing whitespace after keyword --- sqlobject/tests/test_identity.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sqlobject/tests/test_identity.py b/sqlobject/tests/test_identity.py index b3111f25..2c862efe 100644 --- a/sqlobject/tests/test_identity.py +++ b/sqlobject/tests/test_identity.py @@ -20,10 +20,10 @@ def test_identity(): SOTestIdentity(n=100) # i1 # verify result i1get = SOTestIdentity.get(1) - assert(i1get.n == 100) + assert (i1get.n == 100) # insert while giving identity SOTestIdentity(id=2, n=200) # i2 # verify result i2get = SOTestIdentity.get(2) - assert(i2get.n == 200) + assert (i2get.n == 200) From 71ba79e666a738d37cf1d57eb82e2be1b61a2c90 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 16 Sep 2022 23:40:49 +0300 Subject: [PATCH 336/509] Style: Fix `flake8` E501 line too long --- sqlobject/include/hashcol.py | 12 ++++++++---- sqlobject/sqlbuilder.py | 5 +++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/sqlobject/include/hashcol.py b/sqlobject/include/hashcol.py index e36b980e..83f8fec4 100644 --- a/sqlobject/include/hashcol.py +++ b/sqlobject/include/hashcol.py @@ -6,8 +6,10 @@ class DbHash: - """ Presents a comparison object for hashes, allowing plain text to be - automagically compared with the base content. """ + """ + Presents a comparison object for hashes, allowing plain text to be + automagically compared with the base content + """ def __init__(self, hash, hashMethod): self.hash = hash @@ -99,7 +101,9 @@ def createValidators(self): class HashCol(sqlobject.col.StringCol): - """ End-user HashCol class. May be instantiated with 'hashMethod', a function - which returns the string hash of any other string (i.e. basestring). """ + """ + End-user HashCol class. May be instantiated with 'hashMethod', a function + which returns the string hash of any other string (i.e. basestring) + """ baseClass = SOHashCol diff --git a/sqlobject/sqlbuilder.py b/sqlobject/sqlbuilder.py index 844ab9ea..9eabcf52 100644 --- a/sqlobject/sqlbuilder.py +++ b/sqlobject/sqlbuilder.py @@ -1509,8 +1509,9 @@ def tablesUsedImmediate(self): class ImportProxy(SQLExpression): - '''Class to be used in column definitions that rely on other tables that might - not yet be in a classregistry. + ''' + Class to be used in column definitions that rely on other tables that might + not yet be in a classregistry ''' FieldClass = ImportProxyField From 50e50dc0c972ab80c6dc8f3ca64fe7c762cb73ed Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 16 Sep 2022 23:42:13 +0300 Subject: [PATCH 337/509] Style(hashcol): Improve docstring formatting --- sqlobject/include/hashcol.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sqlobject/include/hashcol.py b/sqlobject/include/hashcol.py index 83f8fec4..7a8bbf4d 100644 --- a/sqlobject/include/hashcol.py +++ b/sqlobject/include/hashcol.py @@ -63,7 +63,7 @@ def __repr__(self): class HashValidator(sqlobject.col.StringValidator): - """ Provides formal SQLObject validation services for the HashCol. """ + """Provides formal SQLObject validation services for the HashCol""" def to_python(self, value, state): """ Passes out a hash object. """ @@ -72,14 +72,14 @@ def to_python(self, value, state): return DbHash(hash=value, hashMethod=self.hashMethod) def from_python(self, value, state): - """ Store the given value as a MD5 hash, or None if specified. """ + """Store the given value as a MD5 hash, or None if specified""" if value is None: return None return self.hashMethod(value) class SOHashCol(sqlobject.col.SOStringCol): - """ The internal HashCol definition. By default, enforces a md5 digest. """ + """The internal HashCol definition. By default, enforces a md5 digest""" def __init__(self, **kw): if 'hashMethod' not in kw: From 8cde480dfa2940ae1ea4626873627d7ed2d4f325 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 17 Sep 2022 14:54:18 +0300 Subject: [PATCH 338/509] Fix(test): Use `"`-quotes for command line w32 doesn't like apostrophes. Use apostrophes for inner strings. --- tox.ini | 118 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 59 insertions(+), 59 deletions(-) diff --git a/tox.ini b/tox.ini index 9c2ae387..6a93ed98 100644 --- a/tox.ini +++ b/tox.ini @@ -62,10 +62,10 @@ whitelist_externals = [mysqldb] commands = {[testenv]commands} - -mysql --user=root --execute='drop database sqlobject_test;' - mysql --user=root --execute='create database sqlobject_test;' - pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=mysqldb&debug=1 - mysql --user=root --execute='drop database sqlobject_test;' + -mysql --user=root --execute="drop database sqlobject_test;" + mysql --user=root --execute="create database sqlobject_test;" + pytest --cov=sqlobject -D "mysql://root:@localhost/sqlobject_test?driver=mysqldb&debug=1" + mysql --user=root --execute="drop database sqlobject_test;" [testenv:py27-mysqldb] commands = @@ -79,10 +79,10 @@ deps = [mysqlclient] commands = {[testenv]commands} - -mysql --user=root --execute='drop database sqlobject_test;' - mysql --user=root --execute='create database sqlobject_test;' - pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=mysqldb&charset=utf8&debug=1 - mysql --user=root --execute='drop database sqlobject_test;' + -mysql --user=root --execute="drop database sqlobject_test;" + mysql --user=root --execute="create database sqlobject_test;" + pytest --cov=sqlobject -D "mysql://root:@localhost/sqlobject_test?driver=mysqldb&charset=utf8&debug=1" + mysql --user=root --execute="drop database sqlobject_test;" [testenv:py27-mysqlclient] commands = {envpython} -c "print('mysqlclient requires Python 3.4+')" @@ -94,10 +94,10 @@ commands = {[mysqlclient]commands} [mysql-connector] commands = {[testenv]commands} - -mysql --user=root --execute='drop database sqlobject_test;' - mysql --user=root --execute='create database sqlobject_test;' - pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=connector&charset=utf8&debug=1 - mysql --user=root --execute='drop database sqlobject_test;' + -mysql --user=root --execute="drop database sqlobject_test;" + mysql --user=root --execute="create database sqlobject_test;" + pytest --cov=sqlobject -D "mysql://root:@localhost/sqlobject_test?driver=connector&charset=utf8&debug=1" + mysql --user=root --execute="drop database sqlobject_test;" [testenv:py27-mysql-connector-noauto] commands = @@ -110,10 +110,10 @@ commands = {[mysql-connector]commands} [oursql] commands = {[testenv]commands} - -mysql --user=root --execute='drop database sqlobject_test;' - mysql --user=root --execute='create database sqlobject_test;' - pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=oursql&charset=utf8&debug=1 - mysql --user=root --execute='drop database sqlobject_test;' + -mysql --user=root --execute="drop database sqlobject_test;" + mysql --user=root --execute="create database sqlobject_test;" + pytest --cov=sqlobject -D "mysql://root:@localhost/sqlobject_test?driver=oursql&charset=utf8&debug=1" + mysql --user=root --execute="drop database sqlobject_test;" [testenv:py27-mysql-oursql-noauto] commands = @@ -126,10 +126,10 @@ commands = {[oursql]commands} [pymysql] commands = {[testenv]commands} - -mysql --user=root --execute='drop database sqlobject_test;' - mysql --user=root --execute='create database sqlobject_test;' - pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=pymysql&charset=utf8&debug=1 - mysql --user=root --execute='drop database sqlobject_test;' + -mysql --user=root --execute="drop database sqlobject_test;" + mysql --user=root --execute="create database sqlobject_test;" + pytest --cov=sqlobject -D "mysql://root:@localhost/sqlobject_test?driver=pymysql&charset=utf8&debug=1" + mysql --user=root --execute="drop database sqlobject_test;" [testenv:py27-mysql-pymysql] commands = @@ -142,10 +142,10 @@ commands = {[pymysql]commands} [mariadb] commands = {[testenv]commands} - -mysql --user=root --execute='drop database sqlobject_test;' - mysql --user=root --execute='create database sqlobject_test;' - pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=mariadb&charset=utf8&debug=1 - mysql --user=root --execute='drop database sqlobject_test;' + -mysql --user=root --execute="drop database sqlobject_test;" + mysql --user=root --execute="create database sqlobject_test;" + pytest --cov=sqlobject -D "mysql://root:@localhost/sqlobject_test?driver=mariadb&charset=utf8&debug=1" + mysql --user=root --execute="drop database sqlobject_test;" [testenv:py{27,34,35}-mariadb] commands = {envpython} -c "print('mariadb requires Python 3.6+')" @@ -158,10 +158,10 @@ commands = {[mariadb]commands} commands = {[testenv]commands} {envpython} -c "import pyodbc; print(pyodbc.drivers())" - -mysql --user=root --execute='drop database sqlobject_test;' - mysql --user=root --execute='create database sqlobject_test;' - pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=pyodbc&odbcdrv=MySQL&charset=utf8&debug=1 - mysql --user=root --execute='drop database sqlobject_test;' + -mysql --user=root --execute="drop database sqlobject_test;" + mysql --user=root --execute="create database sqlobject_test;" + pytest --cov=sqlobject -D "mysql://root:@localhost/sqlobject_test?driver=pyodbc&odbcdrv=MySQL&charset=utf8&debug=1" + mysql --user=root --execute="drop database sqlobject_test;" [testenv:py27-mysql-pyodbc-noauto] commands = @@ -174,10 +174,10 @@ commands = {[mysql-pyodbc]commands} [mysql-pypyodbc] commands = {[testenv]commands} - -mysql --user=root --execute='drop database sqlobject_test;' - mysql --user=root --execute='create database sqlobject_test;' - pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=MySQL&charset=utf8&debug=1 - mysql --user=root --execute='drop database sqlobject_test;' + -mysql --user=root --execute="drop database sqlobject_test;" + mysql --user=root --execute="create database sqlobject_test;" + pytest --cov=sqlobject -D "mysql://root:@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=MySQL&charset=utf8&debug=1" + mysql --user=root --execute="drop database sqlobject_test;" [testenv:py27-mysql-pypyodbc-noauto] commands = @@ -193,7 +193,7 @@ commands = {[testenv]commands} -dropdb --username=postgres --no-password sqlobject_test createdb --username=postgres --no-password sqlobject_test - pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test + pytest --cov=sqlobject -D "postgres://postgres:@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-psycopg] @@ -209,7 +209,7 @@ commands = {[testenv]commands} -dropdb --username=postgres --no-password sqlobject_test createdb --username=postgres --no-password sqlobject_test - pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test + pytest --cov=sqlobject -D "postgres://postgres:@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pygresql] @@ -225,7 +225,7 @@ commands = {[testenv]commands} -dropdb --username=postgres --no-password sqlobject_test createdb --username=postgres --no-password sqlobject_test - pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test + pytest --cov=sqlobject -D "postgres://postgres:@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pypostgresql] @@ -240,7 +240,7 @@ commands = {[testenv]commands} -dropdb --username=postgres --no-password sqlobject_test createdb --username=postgres --no-password sqlobject_test - pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=pg8000&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test + pytest --cov=sqlobject -D "postgres://postgres:@localhost/sqlobject_test?driver=pg8000&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pg8000] @@ -257,7 +257,7 @@ commands = {envpython} -c "import pyodbc; print(pyodbc.drivers())" -dropdb --username=postgres --no-password sqlobject_test createdb --username=postgres --no-password sqlobject_test - pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=pyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test + pytest --cov=sqlobject -D "postgres://postgres:@localhost/sqlobject_test?driver=pyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pyodbc-noauto] @@ -273,7 +273,7 @@ commands = {[testenv]commands} -dropdb --username=postgres --no-password sqlobject_test createdb --username=postgres --no-password sqlobject_test - pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test + pytest --cov=sqlobject -D "postgres://postgres:@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pypyodbc-noauto] @@ -290,7 +290,7 @@ commands = {[postgres-pypyodbc]commands} commands = {[testenv]commands} -rm -f /tmp/sqlobject_test.sqdb - pytest --cov=sqlobject -D sqlite:///tmp/sqlobject_test.sqdb?debug=1 + pytest --cov=sqlobject -D "sqlite:///tmp/sqlobject_test.sqdb?debug=1" rm -f /tmp/sqlobject_test.sqdb [testenv:py27-sqlite] @@ -318,7 +318,7 @@ commands = {[sqlite-memory]commands} commands = {[testenv]commands} -rm -f /tmp/sqlobject_test.sqdb - -pytest --cov=sqlobject -D sqlite:///tmp/sqlobject_test.sqdb?driver=supersqlite&debug=1 + -pytest --cov=sqlobject -D "sqlite:///tmp/sqlobject_test.sqdb?driver=supersqlite&debug=1" rm -f /tmp/sqlobject_test.sqdb [testenv:py27-sqlite-supersqlite] @@ -336,7 +336,7 @@ commands = {[testenv]commands} sudo rm -f /tmp/test.fdb isql-fb -u test -p test -i /var/lib/firebird/create_test_db - pytest --cov=sqlobject -D 'firebird://test:test@localhost/tmp/test.fdb?debug=1' + pytest --cov=sqlobject -D "firebird://test:test@localhost/tmp/test.fdb?debug=1" sudo rm -f /tmp/test.fdb [testenv:py27-firebird-fdb] @@ -352,7 +352,7 @@ commands = {[testenv]commands} sudo rm -f /tmp/test.fdb isql-fb -u test -p test -i /var/lib/firebird/create_test_db - pytest --cov=sqlobject -D 'firebird://test:test@localhost:3050/tmp/test.fdb?driver=firebirdsql&charset=utf8&debug=1' + pytest --cov=sqlobject -D "firebird://test:test@localhost:3050/tmp/test.fdb?driver=firebirdsql&charset=utf8&debug=1" sudo rm -f /tmp/test.fdb [testenv:py27-firebirdsql] @@ -398,10 +398,10 @@ commands = {[mssql-pyodbc-w32]commands} platform = win32 commands = {[testenv]commands} - -mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' - mysql -u root "-pPassword12!" -e 'create database sqlobject_test;' + -mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" + mysql -u root "-pPassword12!" -e "create database sqlobject_test;" pytest --cov=sqlobject -D "mysql://root:Password12!@localhost/sqlobject_test?driver=connector&charset=utf8&debug=1" - mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' + mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" [testenv:py27-mysql-connector-w32] platform = win32 @@ -417,10 +417,10 @@ commands = {[mysql-connector-w32]commands} platform = win32 commands = {[testenv]commands} - -mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' - mysql -u root "-pPassword12!" -e 'create database sqlobject_test;' + -mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" + mysql -u root "-pPassword12!" -e "create database sqlobject_test;" pytest --cov=sqlobject -D "mysql://root:Password12!@localhost/sqlobject_test?driver=pymysql&charset=utf8&debug=1" - mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' + mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" [testenv:py27-mysql-pymysql-w32] platform = win32 @@ -436,10 +436,10 @@ commands = {[pymysql-w32]commands} platform = win32 commands = {[testenv]commands} - -mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' - mysql -u root "-pPassword12!" -e 'create database sqlobject_test;' + -mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" + mysql -u root "-pPassword12!" -e "create database sqlobject_test;" pytest --cov=sqlobject -D "mysql://root:Password12!@localhost/sqlobject_test?driver=mariadb&charset=utf8&debug=1" - mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' + mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" [testenv:py{27,34,35}-mariadb-w32] platform = win32 @@ -455,10 +455,10 @@ platform = win32 commands = {[testenv]commands} {envpython} -c "import pyodbc; print(pyodbc.drivers())" - -mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' - mysql -u root "-pPassword12!" -e 'create database sqlobject_test;' - pytest --cov=sqlobject -D mysql://root:Password12!@localhost/sqlobject_test?driver=pyodbc&odbcdrv=MySQL%20ODBC%205.3%20ANSI%20Driver&charset=utf8&debug=1 - mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' + -mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" + mysql -u root "-pPassword12!" -e "create database sqlobject_test;" + pytest --cov=sqlobject -D "mysql://root:Password12!@localhost/sqlobject_test?driver=pyodbc&odbcdrv=MySQL%20ODBC%205.3%20ANSI%20Driver&charset=utf8&debug=1" + mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" [testenv:py27-mysql-pyodbc-noauto-w32] platform = win32 @@ -475,10 +475,10 @@ platform = win32 commands = {[testenv]commands} {envpython} -c "import pypyodbc; print(pypyodbc.drivers())" - -mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' - mysql -u root "-pPassword12!" -e 'create database sqlobject_test;' - pytest --cov=sqlobject -D mysql://root:Password12!@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=MySQL%20ODBC%205.3%20ANSI%20Driver&charset=utf8&debug=1 - mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' + -mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" + mysql -u root "-pPassword12!" -e "create database sqlobject_test;" + pytest --cov=sqlobject -D "mysql://root:Password12!@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=MySQL%20ODBC%205.3%20ANSI%20Driver&charset=utf8&debug=1" + mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" [testenv:py27-mysql-pypyodbc-noauto-w32] platform = win32 From ec1b75d8e4dde24154ee972ce117c01cc247b372 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 27 Sep 2021 19:21:54 +0300 Subject: [PATCH 339/509] CI: Stop testing at Travis CI and AppVeyor --- .travis.yml | 140 ----------------------------------- MANIFEST.in | 2 +- appveyor.yml | 141 ------------------------------------ devscripts/BRANCH-CHECKLIST | 2 +- devscripts/branch | 2 +- docs/DeveloperGuide.rst | 13 ---- docs/News.rst | 7 ++ docs/TODO.rst | 2 +- run_with_env.cmd | 88 ---------------------- setup.py | 3 - tox.ini | 2 +- 11 files changed, 12 insertions(+), 390 deletions(-) delete mode 100644 .travis.yml delete mode 100644 appveyor.yml delete mode 100644 run_with_env.cmd diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index adcd77ac..00000000 --- a/.travis.yml +++ /dev/null @@ -1,140 +0,0 @@ -os: linux - -dist: xenial - -language: python - -python: - - "2.7" - -cache: pip - -services: - - mysql - - postgres - -addons: - postgresql: "9.4" - -matrix: - include: - - python: "2.7" - env: TESTS=py27-mysql - - python: "3.5" - env: TESTS=py34-mysql TOXPYTHON=/home/travis/virtualenv/python3.4.8/bin/python3.4 - - python: "3.5" - env: TESTS=py35-mysql - - python: "3.6" - env: TESTS=py36-mysql - - python: "3.7" - env: TESTS=py37-mysql - - python: "3.8" - env: TESTS=py38-mysql - - python: "3.9" - env: TESTS=py39-mysql - - python: "3.6" - env: TESTS=py36-mariadb - dist: focal - - python: "3.7" - env: TESTS=py37-mariadb - dist: focal - - python: "3.8" - env: TESTS=py38-mariadb - dist: focal - - python: "3.9" - env: TESTS=py39-mariadb - dist: focal - - python: "2.7" - env: TESTS=py27-postgres - - python: "3.5" - env: TESTS=py34-postgres TOXPYTHON=/home/travis/virtualenv/python3.4.8/bin/python3.4 - - python: "3.5" - env: TESTS=py35-postgres - - python: "3.6" - env: TESTS=py36-postgres - - python: "3.7" - env: TESTS=py37-postgres - - python: "3.8" - env: TESTS=py38-postgres - - python: "3.9" - env: TESTS=py39-postgres - - python: "2.7" - env: TESTS=py27-sqlite - - python: "3.5" - env: TESTS=py34-sqlite TOXPYTHON=/home/travis/virtualenv/python3.4.8/bin/python3.4 - - python: "3.5" - env: TESTS=py35-sqlite - - python: "3.6" - env: TESTS=py36-sqlite - - python: "3.7" - env: TESTS=py37-sqlite - - python: "3.8" - env: TESTS=py38-sqlite - - python: "3.9" - env: TESTS=py39-sqlite - - python: "2.7" - env: TESTS=py27-flake8 - - python: "3.8" - env: TESTS=py38-flake8 - - python: "2.7" - env: TESTS=py27-firebird - - python: "3.6" - env: TESTS=py36-firebird - - allow_failures: - - env: TESTS=py27-firebird - - env: TESTS=py36-firebird - -before_install: - # Install version-specific dependencies - - | - if [[ $TESTS = py27-* ]]; then - sudo apt-get --quiet --yes install python-egenix-mxdatetime python-mysqldb python-psycopg2 - fi - - | - if [[ $TESTS = py3*-* ]]; then - sudo apt-get --quiet --yes install python3-mysqldb python3-psycopg2 - fi - - | - if [[ $TESTS = py34-* ]]; then - # Manually install Python 3.4 to run tox under Python 3.5 and tests with Python 3.4 - curl -sSf --retry 5 -o python-3.4.tar.bz2 https://storage.googleapis.com/travis-ci-language-archives/python/binaries/ubuntu/16.04/x86_64/python-3.4.tar.bz2 - sudo tar xjf python-3.4.tar.bz2 --directory / - fi - # Install MariaDB mysql-compatible development files to compile mysql drivers - - | - if [[ $TESTS = py3[6789]-mysql ]]; then - sudo apt-get --quiet --yes install libmysqlclient-dev - elif [[ $TESTS = py3[6789]-mariadb ]]; then - sudo apt-get --quiet --yes install libmariadb-dev-compat - fi - # Install and start the firebird database server. - # We use firebird-super, so there's none of the inetd configuration - # required by firebird-classic. - # We also create a test user for the firebird test and - # create a script that can be fed into isql-fb - # to create the test database. - # Copied password initializtion from - # https://github.com/xdenser/node-firebird-libfbclient/blob/master/.travis.yml - - | - if [[ $TESTS = *firebird* ]]; then - sudo apt-get --quiet --yes install firebird2.5-super - sudo sed -i /etc/default/firebird2.5 -e 's/=no/=yes/' - sudo /etc/init.d/firebird2.5-super start && sleep 5 - sudo /bin/bash -c '(export FB_VER="2.5"; export FB_FLAVOUR="super";source /usr/share/firebird2.5-common/functions.sh; writeNewPassword masterkey)' - sudo gsec -user sysdba -pass masterkey -add test -pw test - sudo /bin/bash -c "echo \"CREATE DATABASE 'localhost:/tmp/test.fdb';\" > /var/lib/firebird/create_test_db" - sudo chmod 644 /var/lib/firebird/create_test_db - fi - -install: travis_retry pip install --upgrade "pip<19.2" "setuptools<44" "tox>=3.15" coveralls codecov ppu - -script: devscripts/tox-select-envs $TESTS - -after_success: - - cd sqlobject - - coveralls - - codecov - -before_cache: - - remove-old-files.py -o 180 ~/.cache/pip diff --git a/MANIFEST.in b/MANIFEST.in index cb6c6a70..adf1c2bd 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,6 +1,6 @@ global-include *.py *.rst *.txt recursive-include docs *.css *.html *.js *.gif *.png -include LICENSE MANIFEST.in .travis.yml tox.ini +include LICENSE MANIFEST.in .tox.ini include debian/* sqlobject/.coveragerc include docs/Makefile docs/genapidocs docs/rebuild recursive-exclude devscripts * diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index 808f4404..00000000 --- a/appveyor.yml +++ /dev/null @@ -1,141 +0,0 @@ -# Install SQLObject on windows and test against MS SQL server and postgres -# Heavily inspired by Oliver Grisel's appveyor-demo (https://github.com/ogrisel/python-appveyor-demo) -# and Michael Sverdlik's appveyor-utils (https://github.com/cloudify-cosmo/appveyor-utils) -version: '{branch}-{build}' - -image: Visual Studio 2019 - -cache: - - '%LOCALAPPDATA%\pip\Cache' - -# Match travis -clone_depth: 50 - -services: - - mysql - - postgresql - -environment: - MYSQL_PWD: "Password12!" - PGUSER: "postgres" - PGPASSWORD: "Password12!" - - global: - # SDK v7.0 MSVC Express 2008's SetEnv.cmd script will fail if the - # /E:ON and /V:ON options are not enabled in the batch script intepreter - # See: http://stackoverflow.com/a/13751649/163740 - CMD_IN_ENV: "cmd /E:ON /V:ON /C .\\run_with_env.cmd" - - matrix: - - TESTS: "py27-mysql" - PYTHON_ARCH: "32" - PYTHON_VERSION: "2.7" - PYTHON_HOME: "C:\\Python27" - db: mysql - - TESTS: "py36-mysql" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.6" - PYTHON_HOME: "C:\\Python36-x64" - db: mysql - - TESTS: "py37-mysql" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.7" - PYTHON_HOME: "C:\\Python37-x64" - db: mysql - - TESTS: "py38-mysql" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.8" - PYTHON_HOME: "C:\\Python38-x64" - db: mysql - - TESTS: "py39-mysql" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.9" - PYTHON_HOME: "C:\\Python39-x64" - db: mysql - - TESTS: "py36-mariadb" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.6" - PYTHON_HOME: "C:\\Python36-x64" - db: mysql - - TESTS: "py37-mariadb" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.7" - PYTHON_HOME: "C:\\Python37-x64" - db: mysql - - TESTS: "py38-mariadb" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.8" - PYTHON_HOME: "C:\\Python38-x64" - db: mysql - - TESTS: "py39-mariadb" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.9" - PYTHON_HOME: "C:\\Python39-x64" - db: mysql - - TESTS: "py27-postgres" - PYTHON_ARCH: "32" - PYTHON_VERSION: "2.7" - PYTHON_HOME: "C:\\Python27" - db: postgresql - - TESTS: "py36-postgres" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.6" - PYTHON_HOME: "C:\\Python36-x64" - db: postgresql - - TESTS: "py37-postgres" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.7" - PYTHON_HOME: "C:\\Python37-x64" - db: postgresql - - TESTS: "py38-postgres" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.8" - PYTHON_HOME: "C:\\Python38-x64" - db: postgresql - - TESTS: "py39-postgres" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.9" - PYTHON_HOME: "C:\\Python39-x64" - db: postgresql - - TESTS: "py27-sqlite" - PYTHON_ARCH: "32" - PYTHON_VERSION: "2.7" - PYTHON_HOME: "C:\\Python27" - - TESTS: "py36-sqlite" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.6" - PYTHON_HOME: "C:\\Python36-x64" - - TESTS: "py37-sqlite" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.7" - PYTHON_HOME: "C:\\Python37-x64" - - TESTS: "py38-sqlite" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.8" - PYTHON_HOME: "C:\\Python38-x64" - - TESTS: "py39-sqlite" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.9" - PYTHON_HOME: "C:\\Python39-x64" - -install: - # Ensure we use the right python version - - "SET PATH=%PYTHON_HOME%;%PYTHON_HOME%\\Scripts;C:\\Program Files\\MySQL\\MySQL Server 5.7\\bin;C:\\Program Files\\PostgreSQL\\9.6\\bin;%PATH%" - - "SET TOXPYTHON=%PYTHON_HOME%\\python.exe" - - "python --version" - - "python -c \"import struct; print(struct.calcsize('P') * 8)\"" - - "python -m pip install --upgrade \"pip<19.2\" \"setuptools<44\"" - - "pip install --upgrade \"tox>=3.15\" ppu" - - "pip --version" - # List ODBC drivers - - ps: Get-OdbcDriver -Platform 32-bit | Select-Object -ExpandProperty Name - - ps: Get-OdbcDriver -Platform 64-bit | Select-Object -ExpandProperty Name - -# Not a C project, so no build step -build: false - -test_script: - - "%CMD_IN_ENV% devscripts\\tox-select-envs %TESTS%" - -after_test: - - "remove-old-files.py -o 180 %LOCALAPPDATA%\\pip\\Cache" diff --git a/devscripts/BRANCH-CHECKLIST b/devscripts/BRANCH-CHECKLIST index da9c16ac..29899043 100644 --- a/devscripts/BRANCH-CHECKLIST +++ b/devscripts/BRANCH-CHECKLIST @@ -9,7 +9,7 @@ setup.cfg in the branch edit section [publish] - uncomment doc-dest for stable branch. In setup.py in the branch edit URL (remove '/devel') and download URLs. In setup.py and DeveloperGuide.rst edit - Travis CI build status image URL (change branch). Commit. + CI build status image URL (change branch). Commit. 1b. If the branching point was master the script checks out master and calls editor again; edit README.rst, __version__.py and News.rst in diff --git a/devscripts/branch b/devscripts/branch index 7c7ef731..dfcd6df1 100755 --- a/devscripts/branch +++ b/devscripts/branch @@ -42,7 +42,7 @@ micro = 0 release_level = 'trunk' serial = 0 version_info = (major, minor, micro, release_level, serial)" > sqlobject/__version__.py && - `git var GIT_EDITOR` README.rst sqlobject/__version__.py docs/News.rst appveyor.yml setup.py && + `git var GIT_EDITOR` README.rst sqlobject/__version__.py docs/News.rst setup.py && git commit --message="Next branch will be $major.$next_minor" README.rst sqlobject/__version__.py docs/News.rst setup.py && exec sed -i /"$major\.$minor"/"$major.$next_minor"/ ANNOUNCE.rst diff --git a/docs/DeveloperGuide.rst b/docs/DeveloperGuide.rst index 955dc03d..262ffa2a 100644 --- a/docs/DeveloperGuide.rst +++ b/docs/DeveloperGuide.rst @@ -276,19 +276,6 @@ forced to write the test. That's no fun for us, to just be writing tests. So please, write tests; everything at least needs to be exercised, even if the tests are absolutely complete. -We now use Travis CI and AppVeyor to run tests. See the statuses: - -.. image:: https://api.travis-ci.com/sqlobject/sqlobject.svg?branch=master - :target: https://travis-ci.com/github/sqlobject/sqlobject - -.. image:: https://ci.appveyor.com/api/projects/status/github/sqlobject/sqlobject?branch=master - :target: https://ci.appveyor.com/project/phdru/sqlobject - -To avoid triggering unnecessary test run at CI services add text `[skip ci] -`_ or -``[ci skip]`` anywhere in your commit messages for commits that don't change -code (documentation updates and such). - We use `coverage.py `_ to measures code coverage by tests and upload the result for analyzis to `Coveralls `_ and diff --git a/docs/News.rst b/docs/News.rst index afce29f1..1f5d666b 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -21,6 +21,13 @@ Tests * Run tests with Python 3.10. +CI +-- + +* Stop testing at Travis CI. + +* Stop testing at AppVeyor. + Documentation ------------- diff --git a/docs/TODO.rst b/docs/TODO.rst index 106a5996..39dff951 100644 --- a/docs/TODO.rst +++ b/docs/TODO.rst @@ -3,7 +3,7 @@ TODO * Fix test ordering problem with Postgres. -* Fix unicode problems with pyodbc at AppVeyor. +* Fix unicode problems with pyodbc. * Resolve timeout problems with MSSQL. diff --git a/run_with_env.cmd b/run_with_env.cmd deleted file mode 100644 index 5da547c4..00000000 --- a/run_with_env.cmd +++ /dev/null @@ -1,88 +0,0 @@ -:: To build extensions for 64 bit Python 3, we need to configure environment -:: variables to use the MSVC 2010 C++ compilers from GRMSDKX_EN_DVD.iso of: -:: MS Windows SDK for Windows 7 and .NET Framework 4 (SDK v7.1) -:: -:: To build extensions for 64 bit Python 2, we need to configure environment -:: variables to use the MSVC 2008 C++ compilers from GRMSDKX_EN_DVD.iso of: -:: MS Windows SDK for Windows 7 and .NET Framework 3.5 (SDK v7.0) -:: -:: 32 bit builds, and 64-bit builds for 3.5 and beyond, do not require specific -:: environment configurations. -:: -:: Note: this script needs to be run with the /E:ON and /V:ON flags for the -:: cmd interpreter, at least for (SDK v7.0) -:: -:: More details at: -:: https://github.com/cython/cython/wiki/64BitCythonExtensionsOnWindows -:: http://stackoverflow.com/a/13751649/163740 -:: -:: Author: Olivier Grisel -:: License: CC0 1.0 Universal: http://creativecommons.org/publicdomain/zero/1.0/ -:: -:: Notes about batch files for Python people: -:: -:: Quotes in values are literally part of the values: -:: SET FOO="bar" -:: FOO is now five characters long: " b a r " -:: If you don't want quotes, don't include them on the right-hand side. -:: -:: The CALL lines at the end of this file look redundant, but if you move them -:: outside of the IF clauses, they do not run properly in the SET_SDK_64==Y -:: case, I don't know why. -@ECHO OFF - -SET COMMAND_TO_RUN=%* -SET WIN_SDK_ROOT=C:\Program Files\Microsoft SDKs\Windows -SET WIN_WDK=c:\Program Files (x86)\Windows Kits\10\Include\wdf - -:: Extract the major and minor versions, and allow for the minor version to be -:: more than 9. This requires the version number to have two dots in it. -SET MAJOR_PYTHON_VERSION=%PYTHON_VERSION:~0,1% -IF "%PYTHON_VERSION:~3,1%" == "." ( - SET MINOR_PYTHON_VERSION=%PYTHON_VERSION:~2,1% -) ELSE ( - SET MINOR_PYTHON_VERSION=%PYTHON_VERSION:~2,2% -) - -:: Based on the Python version, determine what SDK version to use, and whether -:: to set the SDK for 64-bit. -IF %MAJOR_PYTHON_VERSION% == 2 ( - SET WINDOWS_SDK_VERSION="v7.0" - SET SET_SDK_64=Y -) ELSE ( - IF %MAJOR_PYTHON_VERSION% == 3 ( - SET WINDOWS_SDK_VERSION="v7.1" - IF %MINOR_PYTHON_VERSION% LEQ 4 ( - SET SET_SDK_64=Y - ) ELSE ( - SET SET_SDK_64=N - IF EXIST "%WIN_WDK%" ( - :: See: https://connect.microsoft.com/VisualStudio/feedback/details/1610302/ - REN "%WIN_WDK%" 0wdf - ) - ) - ) ELSE ( - ECHO Unsupported Python version: "%MAJOR_PYTHON_VERSION%" - EXIT 1 - ) -) - -IF %PYTHON_ARCH% == 64 ( - IF %SET_SDK_64% == Y ( - ECHO Configuring Windows SDK %WINDOWS_SDK_VERSION% for Python %MAJOR_PYTHON_VERSION% on a 64 bit architecture - SET DISTUTILS_USE_SDK=1 - SET MSSdk=1 - "%WIN_SDK_ROOT%\%WINDOWS_SDK_VERSION%\Setup\WindowsSdkVer.exe" -q -version:%WINDOWS_SDK_VERSION% - "%WIN_SDK_ROOT%\%WINDOWS_SDK_VERSION%\Bin\SetEnv.cmd" /x64 /release - ECHO Executing: %COMMAND_TO_RUN% - call %COMMAND_TO_RUN% || EXIT 1 - ) ELSE ( - ECHO Using default MSVC build environment for 64 bit architecture - ECHO Executing: %COMMAND_TO_RUN% - call %COMMAND_TO_RUN% || EXIT 1 - ) -) ELSE ( - ECHO Using default MSVC build environment for 32 bit architecture - ECHO Executing: %COMMAND_TO_RUN% - call %COMMAND_TO_RUN% || EXIT 1 -) diff --git a/setup.py b/setup.py index cdfcb9aa..c65eb313 100755 --- a/setup.py +++ b/setup.py @@ -41,9 +41,6 @@ For development see the projects at `SourceForge `_ and `GitHub `_. - -.. image:: https://api.travis-ci.com/sqlobject/sqlobject.svg?branch=master - :target: https://travis-ci.com/github/sqlobject/sqlobject """, long_description_content_type="text/x-rst", classifiers=[ diff --git a/tox.ini b/tox.ini index 6a93ed98..250b03c6 100644 --- a/tox.ini +++ b/tox.ini @@ -43,7 +43,7 @@ deps = supersqlite: supersqlite firebird-fdb: fdb firebirdsql: firebirdsql -passenv = CI TRAVIS TRAVIS_* APPVEYOR DISTUTILS_USE_SDK MSSdk INCLUDE LIB PGPASSWORD WINDIR +passenv = CI setenv = VIRTUALENV_PIP = 19.1.1 # Don't fail or warn on uninstalled commands From d2921ea11e634169b3cbeba3707fc6bd5f048d07 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 27 Sep 2021 20:33:36 +0300 Subject: [PATCH 340/509] Tests(tox): Stop collecting test coverage --- MANIFEST.in | 2 +- .../requirements/requirements_tests.txt | 1 - docs/DeveloperGuide.rst | 11 ---- sqlobject/.coveragerc | 10 --- sqlobject/.gitignore | 2 - tox.ini | 66 +++++++++---------- 6 files changed, 34 insertions(+), 58 deletions(-) delete mode 100644 sqlobject/.coveragerc delete mode 100644 sqlobject/.gitignore diff --git a/MANIFEST.in b/MANIFEST.in index adf1c2bd..c3330428 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,7 +1,7 @@ global-include *.py *.rst *.txt recursive-include docs *.css *.html *.js *.gif *.png include LICENSE MANIFEST.in .tox.ini -include debian/* sqlobject/.coveragerc +include debian/* include docs/Makefile docs/genapidocs docs/rebuild recursive-exclude devscripts * recursive-exclude docs/_build * diff --git a/devscripts/requirements/requirements_tests.txt b/devscripts/requirements/requirements_tests.txt index 9d647535..73674957 100644 --- a/devscripts/requirements/requirements_tests.txt +++ b/devscripts/requirements/requirements_tests.txt @@ -2,4 +2,3 @@ pytest < 5.0; python_version == '2.7' or python_version == '3.4' pytest; python_version >= '3.5' -pytest-cov diff --git a/docs/DeveloperGuide.rst b/docs/DeveloperGuide.rst index 262ffa2a..3b9a0bb2 100644 --- a/docs/DeveloperGuide.rst +++ b/docs/DeveloperGuide.rst @@ -276,17 +276,6 @@ forced to write the test. That's no fun for us, to just be writing tests. So please, write tests; everything at least needs to be exercised, even if the tests are absolutely complete. -We use `coverage.py `_ -to measures code coverage by tests and upload the result for analyzis to -`Coveralls `_ and -`Codecov `_: - -.. image:: https://coveralls.io/repos/github/sqlobject/sqlobject/badge.svg?branch=master - :target: https://coveralls.io/github/sqlobject/sqlobject?branch=master - -.. image:: https://codecov.io/gh/sqlobject/sqlobject/branch/master/graph/badge.svg - :target: https://codecov.io/gh/sqlobject/sqlobject - Documentation ============= diff --git a/sqlobject/.coveragerc b/sqlobject/.coveragerc deleted file mode 100644 index b4c9dee6..00000000 --- a/sqlobject/.coveragerc +++ /dev/null @@ -1,10 +0,0 @@ -[run] -omit = - firebird/*.py - maxdb/*.py - mssql/*.py - sybase/*.py - tests/test_boundattributes.py - tests/test_paste.py - util/threadinglocal.py - wsgi_middleware.py diff --git a/sqlobject/.gitignore b/sqlobject/.gitignore deleted file mode 100644 index b53725ca..00000000 --- a/sqlobject/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/.coverage -/coverage.xml diff --git a/tox.ini b/tox.ini index 250b03c6..5acb951c 100644 --- a/tox.ini +++ b/tox.ini @@ -64,7 +64,7 @@ commands = {[testenv]commands} -mysql --user=root --execute="drop database sqlobject_test;" mysql --user=root --execute="create database sqlobject_test;" - pytest --cov=sqlobject -D "mysql://root:@localhost/sqlobject_test?driver=mysqldb&debug=1" + pytest -D "mysql://root:@localhost/sqlobject_test?driver=mysqldb&debug=1" mysql --user=root --execute="drop database sqlobject_test;" [testenv:py27-mysqldb] @@ -81,7 +81,7 @@ commands = {[testenv]commands} -mysql --user=root --execute="drop database sqlobject_test;" mysql --user=root --execute="create database sqlobject_test;" - pytest --cov=sqlobject -D "mysql://root:@localhost/sqlobject_test?driver=mysqldb&charset=utf8&debug=1" + pytest -D "mysql://root:@localhost/sqlobject_test?driver=mysqldb&charset=utf8&debug=1" mysql --user=root --execute="drop database sqlobject_test;" [testenv:py27-mysqlclient] @@ -96,7 +96,7 @@ commands = {[testenv]commands} -mysql --user=root --execute="drop database sqlobject_test;" mysql --user=root --execute="create database sqlobject_test;" - pytest --cov=sqlobject -D "mysql://root:@localhost/sqlobject_test?driver=connector&charset=utf8&debug=1" + pytest -D "mysql://root:@localhost/sqlobject_test?driver=connector&charset=utf8&debug=1" mysql --user=root --execute="drop database sqlobject_test;" [testenv:py27-mysql-connector-noauto] @@ -112,7 +112,7 @@ commands = {[testenv]commands} -mysql --user=root --execute="drop database sqlobject_test;" mysql --user=root --execute="create database sqlobject_test;" - pytest --cov=sqlobject -D "mysql://root:@localhost/sqlobject_test?driver=oursql&charset=utf8&debug=1" + pytest -D "mysql://root:@localhost/sqlobject_test?driver=oursql&charset=utf8&debug=1" mysql --user=root --execute="drop database sqlobject_test;" [testenv:py27-mysql-oursql-noauto] @@ -128,7 +128,7 @@ commands = {[testenv]commands} -mysql --user=root --execute="drop database sqlobject_test;" mysql --user=root --execute="create database sqlobject_test;" - pytest --cov=sqlobject -D "mysql://root:@localhost/sqlobject_test?driver=pymysql&charset=utf8&debug=1" + pytest -D "mysql://root:@localhost/sqlobject_test?driver=pymysql&charset=utf8&debug=1" mysql --user=root --execute="drop database sqlobject_test;" [testenv:py27-mysql-pymysql] @@ -144,7 +144,7 @@ commands = {[testenv]commands} -mysql --user=root --execute="drop database sqlobject_test;" mysql --user=root --execute="create database sqlobject_test;" - pytest --cov=sqlobject -D "mysql://root:@localhost/sqlobject_test?driver=mariadb&charset=utf8&debug=1" + pytest -D "mysql://root:@localhost/sqlobject_test?driver=mariadb&charset=utf8&debug=1" mysql --user=root --execute="drop database sqlobject_test;" [testenv:py{27,34,35}-mariadb] @@ -160,7 +160,7 @@ commands = {envpython} -c "import pyodbc; print(pyodbc.drivers())" -mysql --user=root --execute="drop database sqlobject_test;" mysql --user=root --execute="create database sqlobject_test;" - pytest --cov=sqlobject -D "mysql://root:@localhost/sqlobject_test?driver=pyodbc&odbcdrv=MySQL&charset=utf8&debug=1" + pytest -D "mysql://root:@localhost/sqlobject_test?driver=pyodbc&odbcdrv=MySQL&charset=utf8&debug=1" mysql --user=root --execute="drop database sqlobject_test;" [testenv:py27-mysql-pyodbc-noauto] @@ -176,7 +176,7 @@ commands = {[testenv]commands} -mysql --user=root --execute="drop database sqlobject_test;" mysql --user=root --execute="create database sqlobject_test;" - pytest --cov=sqlobject -D "mysql://root:@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=MySQL&charset=utf8&debug=1" + pytest -D "mysql://root:@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=MySQL&charset=utf8&debug=1" mysql --user=root --execute="drop database sqlobject_test;" [testenv:py27-mysql-pypyodbc-noauto] @@ -193,7 +193,7 @@ commands = {[testenv]commands} -dropdb --username=postgres --no-password sqlobject_test createdb --username=postgres --no-password sqlobject_test - pytest --cov=sqlobject -D "postgres://postgres:@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest -D "postgres://postgres:@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-psycopg] @@ -209,7 +209,7 @@ commands = {[testenv]commands} -dropdb --username=postgres --no-password sqlobject_test createdb --username=postgres --no-password sqlobject_test - pytest --cov=sqlobject -D "postgres://postgres:@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest -D "postgres://postgres:@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pygresql] @@ -225,7 +225,7 @@ commands = {[testenv]commands} -dropdb --username=postgres --no-password sqlobject_test createdb --username=postgres --no-password sqlobject_test - pytest --cov=sqlobject -D "postgres://postgres:@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest -D "postgres://postgres:@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pypostgresql] @@ -240,7 +240,7 @@ commands = {[testenv]commands} -dropdb --username=postgres --no-password sqlobject_test createdb --username=postgres --no-password sqlobject_test - pytest --cov=sqlobject -D "postgres://postgres:@localhost/sqlobject_test?driver=pg8000&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest -D "postgres://postgres:@localhost/sqlobject_test?driver=pg8000&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pg8000] @@ -257,7 +257,7 @@ commands = {envpython} -c "import pyodbc; print(pyodbc.drivers())" -dropdb --username=postgres --no-password sqlobject_test createdb --username=postgres --no-password sqlobject_test - pytest --cov=sqlobject -D "postgres://postgres:@localhost/sqlobject_test?driver=pyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest -D "postgres://postgres:@localhost/sqlobject_test?driver=pyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pyodbc-noauto] @@ -273,7 +273,7 @@ commands = {[testenv]commands} -dropdb --username=postgres --no-password sqlobject_test createdb --username=postgres --no-password sqlobject_test - pytest --cov=sqlobject -D "postgres://postgres:@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest -D "postgres://postgres:@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pypyodbc-noauto] @@ -290,7 +290,7 @@ commands = {[postgres-pypyodbc]commands} commands = {[testenv]commands} -rm -f /tmp/sqlobject_test.sqdb - pytest --cov=sqlobject -D "sqlite:///tmp/sqlobject_test.sqdb?debug=1" + pytest -D "sqlite:///tmp/sqlobject_test.sqdb?debug=1" rm -f /tmp/sqlobject_test.sqdb [testenv:py27-sqlite] @@ -304,7 +304,7 @@ commands = {[sqlite]commands} [sqlite-memory] commands = {[testenv]commands} - pytest --cov=sqlobject -D sqlite:/:memory:?debug=1 + pytest -D sqlite:/:memory:?debug=1 [testenv:py27-sqlite-memory] commands = @@ -318,7 +318,7 @@ commands = {[sqlite-memory]commands} commands = {[testenv]commands} -rm -f /tmp/sqlobject_test.sqdb - -pytest --cov=sqlobject -D "sqlite:///tmp/sqlobject_test.sqdb?driver=supersqlite&debug=1" + -pytest -D "sqlite:///tmp/sqlobject_test.sqdb?driver=supersqlite&debug=1" rm -f /tmp/sqlobject_test.sqdb [testenv:py27-sqlite-supersqlite] @@ -336,7 +336,7 @@ commands = {[testenv]commands} sudo rm -f /tmp/test.fdb isql-fb -u test -p test -i /var/lib/firebird/create_test_db - pytest --cov=sqlobject -D "firebird://test:test@localhost/tmp/test.fdb?debug=1" + pytest -D "firebird://test:test@localhost/tmp/test.fdb?debug=1" sudo rm -f /tmp/test.fdb [testenv:py27-firebird-fdb] @@ -352,7 +352,7 @@ commands = {[testenv]commands} sudo rm -f /tmp/test.fdb isql-fb -u test -p test -i /var/lib/firebird/create_test_db - pytest --cov=sqlobject -D "firebird://test:test@localhost:3050/tmp/test.fdb?driver=firebirdsql&charset=utf8&debug=1" + pytest -D "firebird://test:test@localhost:3050/tmp/test.fdb?driver=firebirdsql&charset=utf8&debug=1" sudo rm -f /tmp/test.fdb [testenv:py27-firebirdsql] @@ -381,7 +381,7 @@ commands = {envpython} -c "import pyodbc; print(pyodbc.drivers())" -sqlcmd -U sa -P "Password12!" -S .\SQL2014 -Q "DROP DATABASE sqlobject_test" sqlcmd -U sa -P "Password12!" -S .\SQL2014 -Q "CREATE DATABASE sqlobject_test" - pytest --cov=sqlobject -D "mssql://sa:Password12!@localhost\SQL2014/sqlobject_test?driver=pyodbc&odbcdrv=SQL%20Server&timeout=30&debug=1" + pytest -D "mssql://sa:Password12!@localhost\SQL2014/sqlobject_test?driver=pyodbc&odbcdrv=SQL%20Server&timeout=30&debug=1" sqlcmd -U sa -P "Password12!" -S .\SQL2014 -Q "DROP DATABASE sqlobject_test" [testenv:py27-mssql-pyodbc-noauto-w32] @@ -400,7 +400,7 @@ commands = {[testenv]commands} -mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" mysql -u root "-pPassword12!" -e "create database sqlobject_test;" - pytest --cov=sqlobject -D "mysql://root:Password12!@localhost/sqlobject_test?driver=connector&charset=utf8&debug=1" + pytest -D "mysql://root:Password12!@localhost/sqlobject_test?driver=connector&charset=utf8&debug=1" mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" [testenv:py27-mysql-connector-w32] @@ -419,7 +419,7 @@ commands = {[testenv]commands} -mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" mysql -u root "-pPassword12!" -e "create database sqlobject_test;" - pytest --cov=sqlobject -D "mysql://root:Password12!@localhost/sqlobject_test?driver=pymysql&charset=utf8&debug=1" + pytest -D "mysql://root:Password12!@localhost/sqlobject_test?driver=pymysql&charset=utf8&debug=1" mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" [testenv:py27-mysql-pymysql-w32] @@ -438,7 +438,7 @@ commands = {[testenv]commands} -mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" mysql -u root "-pPassword12!" -e "create database sqlobject_test;" - pytest --cov=sqlobject -D "mysql://root:Password12!@localhost/sqlobject_test?driver=mariadb&charset=utf8&debug=1" + pytest -D "mysql://root:Password12!@localhost/sqlobject_test?driver=mariadb&charset=utf8&debug=1" mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" [testenv:py{27,34,35}-mariadb-w32] @@ -457,7 +457,7 @@ commands = {envpython} -c "import pyodbc; print(pyodbc.drivers())" -mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" mysql -u root "-pPassword12!" -e "create database sqlobject_test;" - pytest --cov=sqlobject -D "mysql://root:Password12!@localhost/sqlobject_test?driver=pyodbc&odbcdrv=MySQL%20ODBC%205.3%20ANSI%20Driver&charset=utf8&debug=1" + pytest -D "mysql://root:Password12!@localhost/sqlobject_test?driver=pyodbc&odbcdrv=MySQL%20ODBC%205.3%20ANSI%20Driver&charset=utf8&debug=1" mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" [testenv:py27-mysql-pyodbc-noauto-w32] @@ -477,7 +477,7 @@ commands = {envpython} -c "import pypyodbc; print(pypyodbc.drivers())" -mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" mysql -u root "-pPassword12!" -e "create database sqlobject_test;" - pytest --cov=sqlobject -D "mysql://root:Password12!@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=MySQL%20ODBC%205.3%20ANSI%20Driver&charset=utf8&debug=1" + pytest -D "mysql://root:Password12!@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=MySQL%20ODBC%205.3%20ANSI%20Driver&charset=utf8&debug=1" mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" [testenv:py27-mysql-pypyodbc-noauto-w32] @@ -496,7 +496,7 @@ commands = {[testenv]commands} -dropdb --username=postgres --no-password sqlobject_test createdb --username=postgres --no-password sqlobject_test - pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=psycopg2&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=psycopg2&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-psycopg-w32] @@ -515,7 +515,7 @@ commands = {[testenv]commands} -dropdb --username=postgres --no-password sqlobject_test createdb --username=postgres --no-password sqlobject_test - -pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + -pytest -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pygresql-noauto-w32] @@ -534,7 +534,7 @@ commands = {[testenv]commands} -dropdb --username=postgres --no-password sqlobject_test createdb --username=postgres --no-password sqlobject_test - pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pypostgresql-w32] @@ -552,7 +552,7 @@ commands = {[testenv]commands} -dropdb --username=postgres --no-password sqlobject_test createdb --username=postgres --no-password sqlobject_test - pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pg8000&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pg8000&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pg8000-w32] @@ -572,7 +572,7 @@ commands = {envpython} -c "import pyodbc; print(pyodbc.drivers())" -dropdb --username=postgres --no-password sqlobject_test createdb --username=postgres --no-password sqlobject_test - pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pyodbc&odbcdrv=PostgreSQL%20ANSI%28x64%29&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pyodbc&odbcdrv=PostgreSQL%20ANSI%28x64%29&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pyodbc-noauto-w32] @@ -592,7 +592,7 @@ commands = {envpython} -c "import pypyodbc; print(pypyodbc.drivers())" -dropdb --username=postgres --no-password sqlobject_test createdb --username=postgres --no-password sqlobject_test - pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=PostgreSQL%20ANSI%28x64%29&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=PostgreSQL%20ANSI%28x64%29&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pypyodbc-noauto-w32] @@ -609,7 +609,7 @@ commands = {[postgres-pypyodbc-w32]commands} platform = win32 commands = {[testenv]commands} - pytest --cov=sqlobject -D sqlite:/C:/projects/sqlobject/sqlobject_test.sqdb?debug=1 + pytest -D sqlite:/C:/projects/sqlobject/sqlobject_test.sqdb?debug=1 cmd /c "del C:\projects\sqlobject\sqlobject_test.sqdb" [testenv:py27-sqlite-w32] @@ -626,7 +626,7 @@ commands = {[sqlite-w32]commands} platform = win32 commands = {[testenv]commands} - pytest --cov=sqlobject -D sqlite:/:memory:?debug=1 + pytest -D sqlite:/:memory:?debug=1 [testenv:py27-sqlite-memory-w32] platform = win32 From 4cb3e4e694dff3d582bce785a2e62489055479fa Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 27 Sep 2021 19:29:02 +0300 Subject: [PATCH 341/509] CI: GitHub Actions --- .github/workflows/run-tests.yaml | 55 ++++++++++++++++++++++++++++++++ docs/DeveloperGuide.rst | 6 ++++ docs/News.rst | 2 ++ setup.py | 5 ++- 4 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/run-tests.yaml diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml new file mode 100644 index 00000000..d55cb334 --- /dev/null +++ b/.github/workflows/run-tests.yaml @@ -0,0 +1,55 @@ +name: Run tests + +on: [push, pull_request] + +jobs: + run-tests: + + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest] + python-version: ["2.7"] + include: + - os: ubuntu-latest + os-name: Linux + pip-cache-path: ~/.cache/pip + + name: Python ${{ matrix.python-version }} @ ${{ matrix.os-name }} + runs-on: ${{ matrix.os }} + + steps: + + # Setup Python/pip + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Cache pip + uses: actions/cache@v2 + with: + path: ${{ matrix.pip-cache-path }} + key: ${{ runner.os }}-pip + + # Setup tox + - name: Install dependencies + run: | + python --version + python -m pip install --upgrade "pip<21.0" "setuptools<45" wheel + pip --version + pip install --upgrade virtualenv tox + - name: Set TOXENV + run: | + import os, sys + pyver = '%d%d' % tuple(sys.version_info[:2]) + toxenv = 'py%s-sqlite' % pyver + if os.name == 'posix': + toxenv += ',py%s-flake8' % pyver + with open(os.environ['GITHUB_ENV'], 'a') as f: + f.write('TOXENV=' + toxenv + '\n') + shell: python + + - name: Run tox + run: | + python -c "import os; print(os.environ['TOXENV'])" + tox diff --git a/docs/DeveloperGuide.rst b/docs/DeveloperGuide.rst index 3b9a0bb2..2cd0f8f6 100644 --- a/docs/DeveloperGuide.rst +++ b/docs/DeveloperGuide.rst @@ -276,6 +276,12 @@ forced to write the test. That's no fun for us, to just be writing tests. So please, write tests; everything at least needs to be exercised, even if the tests are absolutely complete. +We now use `Github Actions `_ +to run tests. + +.. image:: https://github.com/sqlobject/sqlobject/actions/workflows/run-tests.yaml/badge.svg?branch=github-actions + :target: https://github.com/sqlobject/sqlobject/actions/workflows/run-tests.yaml + Documentation ============= diff --git a/docs/News.rst b/docs/News.rst index 1f5d666b..67090893 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -24,6 +24,8 @@ Tests CI -- +* GitHub Actions. + * Stop testing at Travis CI. * Stop testing at AppVeyor. diff --git a/setup.py b/setup.py index c65eb313..57ea5394 100755 --- a/setup.py +++ b/setup.py @@ -41,7 +41,10 @@ For development see the projects at `SourceForge `_ and `GitHub `_. -""", + +.. image:: https://github.com/sqlobject/sqlobject/actions/workflows/run-tests.yaml/badge.svg?branch=github-actions + :target: https://github.com/sqlobject/sqlobject/actions/workflows/run-tests.yaml +""", # noqa: E501 line too long long_description_content_type="text/x-rst", classifiers=[ "Development Status :: 5 - Production/Stable", From 1c5ed87d699191c13a5754637f138c9db5656981 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 27 Sep 2021 20:23:26 +0300 Subject: [PATCH 342/509] CI(GHActions): Use `devscripts/tox-select-envs` --- .github/workflows/run-tests.yaml | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index d55cb334..df7de5ca 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -38,18 +38,15 @@ jobs: python -m pip install --upgrade "pip<21.0" "setuptools<45" wheel pip --version pip install --upgrade virtualenv tox - - name: Set TOXENV + - name: Set PYVER run: | import os, sys pyver = '%d%d' % tuple(sys.version_info[:2]) - toxenv = 'py%s-sqlite' % pyver - if os.name == 'posix': - toxenv += ',py%s-flake8' % pyver with open(os.environ['GITHUB_ENV'], 'a') as f: - f.write('TOXENV=' + toxenv + '\n') + f.write('PYVER=' + pyver + '\n') shell: python - name: Run tox run: | - python -c "import os; print(os.environ['TOXENV'])" - tox + python -c "import os; print(os.environ['PYVER'])" + devscripts/tox-select-envs $PYVER-sqlite From 6843aa173302384aebd69f7187b0b23551762927 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 27 Sep 2021 20:40:12 +0300 Subject: [PATCH 343/509] CI(GHActions): Run tests on w64 --- .github/workflows/run-tests.yaml | 13 ++++++++++--- tox.ini | 4 ++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index df7de5ca..ff384fd5 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -8,12 +8,15 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest] + os: [ubuntu-latest, windows-latest] python-version: ["2.7"] include: - os: ubuntu-latest os-name: Linux pip-cache-path: ~/.cache/pip + - os: windows-latest + os-name: w32 + pip-cache-path: ~\AppData\Local\pip\Cache name: Python ${{ matrix.python-version }} @ ${{ matrix.os-name }} runs-on: ${{ matrix.os }} @@ -46,7 +49,11 @@ jobs: f.write('PYVER=' + pyver + '\n') shell: python - - name: Run tox + - name: Run tox @ Linux run: | - python -c "import os; print(os.environ['PYVER'])" devscripts/tox-select-envs $PYVER-sqlite + if: ${{ runner.os == 'Linux' }} + - name: Run tox @ w64 + run: | + devscripts\tox-select-envs.cmd %PYVER%-sqlite + if: ${{ runner.os == 'Windows' }} diff --git a/tox.ini b/tox.ini index 5acb951c..37ddb217 100644 --- a/tox.ini +++ b/tox.ini @@ -609,8 +609,8 @@ commands = {[postgres-pypyodbc-w32]commands} platform = win32 commands = {[testenv]commands} - pytest -D sqlite:/C:/projects/sqlobject/sqlobject_test.sqdb?debug=1 - cmd /c "del C:\projects\sqlobject\sqlobject_test.sqdb" + pytest -D sqlite:/{env:TEMP}/sqlobject_test.sqdb?debug=1 + cmd /c "del {env:TEMP}\sqlobject_test.sqdb" [testenv:py27-sqlite-w32] platform = win32 From 804dcee1a00dd168ff7fe7bb559b1c8b6f68e915 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 28 Sep 2021 20:00:52 +0300 Subject: [PATCH 344/509] CI(GHActions): Run `flake8` tests --- .github/workflows/run-tests.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index ff384fd5..307794b6 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -52,6 +52,7 @@ jobs: - name: Run tox @ Linux run: | devscripts/tox-select-envs $PYVER-sqlite + devscripts/tox-select-envs $PYVER-flake8 if: ${{ runner.os == 'Linux' }} - name: Run tox @ w64 run: | From 0d8ba319dd141f617b3663ca353d77f83d834da5 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 28 Sep 2021 20:10:44 +0300 Subject: [PATCH 345/509] CI(GHActions): Run tests with PostgreSQL --- .github/workflows/run-tests.yaml | 14 +++++ tox.ini | 97 ++++++++++++++++---------------- 2 files changed, 63 insertions(+), 48 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 307794b6..0e5d7651 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -23,6 +23,17 @@ jobs: steps: + # Setup PostgreSQL + - uses: ankane/setup-postgres@v1 + - name: Setup Postgres user + run: | + sudo -u postgres psql --command="ALTER USER runner CREATEDB ENCRYPTED PASSWORD 'test'" + if: ${{ runner.os == 'Linux' }} + - name: Setup Postgres user + run: | + psql --command="CREATE USER runner CREATEDB ENCRYPTED PASSWORD 'test'" + if: ${{ runner.os == 'Windows' }} + # Setup Python/pip - uses: actions/checkout@v2 - uses: actions/setup-python@v2 @@ -47,14 +58,17 @@ jobs: pyver = '%d%d' % tuple(sys.version_info[:2]) with open(os.environ['GITHUB_ENV'], 'a') as f: f.write('PYVER=' + pyver + '\n') + f.write('PGPASSWORD=test\n') shell: python - name: Run tox @ Linux run: | + devscripts/tox-select-envs $PYVER-postgres devscripts/tox-select-envs $PYVER-sqlite devscripts/tox-select-envs $PYVER-flake8 if: ${{ runner.os == 'Linux' }} - name: Run tox @ w64 run: | + devscripts\tox-select-envs.cmd %PYVER%-postgres devscripts\tox-select-envs.cmd %PYVER%-sqlite if: ${{ runner.os == 'Windows' }} diff --git a/tox.ini b/tox.ini index 37ddb217..a5a8ca28 100644 --- a/tox.ini +++ b/tox.ini @@ -46,6 +46,7 @@ deps = passenv = CI setenv = VIRTUALENV_PIP = 19.1.1 + PGPASSWORD = test # Don't fail or warn on uninstalled commands platform = linux whitelist_externals = @@ -191,10 +192,10 @@ commands = {[mysql-pypyodbc]commands} [psycopg] commands = {[testenv]commands} - -dropdb --username=postgres --no-password sqlobject_test - createdb --username=postgres --no-password sqlobject_test - pytest -D "postgres://postgres:@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test - dropdb --username=postgres --no-password sqlobject_test + -dropdb --username=runner --no-password sqlobject_test + createdb --username=runner --no-password sqlobject_test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-psycopg] commands = @@ -207,10 +208,10 @@ commands = {[psycopg]commands} [pygresql] commands = {[testenv]commands} - -dropdb --username=postgres --no-password sqlobject_test - createdb --username=postgres --no-password sqlobject_test - pytest -D "postgres://postgres:@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test - dropdb --username=postgres --no-password sqlobject_test + -dropdb --username=runner --no-password sqlobject_test + createdb --username=runner --no-password sqlobject_test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-pygresql] commands = @@ -223,10 +224,10 @@ commands = {[pygresql]commands} [pypostgresql] commands = {[testenv]commands} - -dropdb --username=postgres --no-password sqlobject_test - createdb --username=postgres --no-password sqlobject_test - pytest -D "postgres://postgres:@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test - dropdb --username=postgres --no-password sqlobject_test + -dropdb --username=runner --no-password sqlobject_test + createdb --username=runner --no-password sqlobject_test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-pypostgresql] commands = {envpython} -c "print('pypostgresql requires Python 3.4+')" @@ -238,10 +239,10 @@ commands = {[pypostgresql]commands} [pg8000] commands = {[testenv]commands} - -dropdb --username=postgres --no-password sqlobject_test - createdb --username=postgres --no-password sqlobject_test - pytest -D "postgres://postgres:@localhost/sqlobject_test?driver=pg8000&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test - dropdb --username=postgres --no-password sqlobject_test + -dropdb --username=runner --no-password sqlobject_test + createdb --username=runner --no-password sqlobject_test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pg8000&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-pg8000] commands = @@ -255,10 +256,10 @@ commands = {[pg8000]commands} commands = {[testenv]commands} {envpython} -c "import pyodbc; print(pyodbc.drivers())" - -dropdb --username=postgres --no-password sqlobject_test - createdb --username=postgres --no-password sqlobject_test - pytest -D "postgres://postgres:@localhost/sqlobject_test?driver=pyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test - dropdb --username=postgres --no-password sqlobject_test + -dropdb --username=runner --no-password sqlobject_test + createdb --username=runner --no-password sqlobject_test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-pyodbc-noauto] commands = @@ -271,10 +272,10 @@ commands = {[postgres-pyodbc]commands} [postgres-pypyodbc] commands = {[testenv]commands} - -dropdb --username=postgres --no-password sqlobject_test - createdb --username=postgres --no-password sqlobject_test - pytest -D "postgres://postgres:@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test - dropdb --username=postgres --no-password sqlobject_test + -dropdb --username=runner --no-password sqlobject_test + createdb --username=runner --no-password sqlobject_test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-pypyodbc-noauto] commands = @@ -494,10 +495,10 @@ commands = {[mysql-pypyodbc-w32]commands} platform = win32 commands = {[testenv]commands} - -dropdb --username=postgres --no-password sqlobject_test - createdb --username=postgres --no-password sqlobject_test - pytest -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=psycopg2&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test - dropdb --username=postgres --no-password sqlobject_test + -dropdb --username=runner --no-password sqlobject_test + createdb --username=runner --no-password sqlobject_test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg2&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-psycopg-w32] platform = win32 @@ -513,10 +514,10 @@ commands = {[psycopg-w32]commands} platform = win32 commands = {[testenv]commands} - -dropdb --username=postgres --no-password sqlobject_test - createdb --username=postgres --no-password sqlobject_test - -pytest -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test - dropdb --username=postgres --no-password sqlobject_test + -dropdb --username=runner --no-password sqlobject_test + createdb --username=runner --no-password sqlobject_test + -pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-pygresql-noauto-w32] platform = win32 @@ -532,10 +533,10 @@ commands = {[pygresql-w32]commands} platform = win32 commands = {[testenv]commands} - -dropdb --username=postgres --no-password sqlobject_test - createdb --username=postgres --no-password sqlobject_test - pytest -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test - dropdb --username=postgres --no-password sqlobject_test + -dropdb --username=runner --no-password sqlobject_test + createdb --username=runner --no-password sqlobject_test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-pypostgresql-w32] platform = win32 @@ -550,10 +551,10 @@ commands = {[pypostgresql-w32]commands} platform = win32 commands = {[testenv]commands} - -dropdb --username=postgres --no-password sqlobject_test - createdb --username=postgres --no-password sqlobject_test - pytest -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pg8000&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test - dropdb --username=postgres --no-password sqlobject_test + -dropdb --username=runner --no-password sqlobject_test + createdb --username=runner --no-password sqlobject_test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pg8000&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-pg8000-w32] platform = win32 @@ -570,10 +571,10 @@ platform = win32 commands = {[testenv]commands} {envpython} -c "import pyodbc; print(pyodbc.drivers())" - -dropdb --username=postgres --no-password sqlobject_test - createdb --username=postgres --no-password sqlobject_test - pytest -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pyodbc&odbcdrv=PostgreSQL%20ANSI%28x64%29&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test - dropdb --username=postgres --no-password sqlobject_test + -dropdb --username=runner --no-password sqlobject_test + createdb --username=runner --no-password sqlobject_test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pyodbc&odbcdrv=PostgreSQL%20ANSI%28x64%29&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-pyodbc-noauto-w32] platform = win32 @@ -590,10 +591,10 @@ platform = win32 commands = {[testenv]commands} {envpython} -c "import pypyodbc; print(pypyodbc.drivers())" - -dropdb --username=postgres --no-password sqlobject_test - createdb --username=postgres --no-password sqlobject_test - pytest -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=PostgreSQL%20ANSI%28x64%29&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test - dropdb --username=postgres --no-password sqlobject_test + -dropdb --username=runner --no-password sqlobject_test + createdb --username=runner --no-password sqlobject_test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=PostgreSQL%20ANSI%28x64%29&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-pypyodbc-noauto-w32] platform = win32 From 17bf01d0e15fb6bbb95a5777cac7c2f6236b4031 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 28 Sep 2021 20:24:26 +0300 Subject: [PATCH 346/509] Tests(tox): Run Postgres tests in default order --- docs/TODO.rst | 2 -- tox.ini | 24 ++++++++++++------------ 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/docs/TODO.rst b/docs/TODO.rst index 39dff951..0d2c9423 100644 --- a/docs/TODO.rst +++ b/docs/TODO.rst @@ -1,8 +1,6 @@ TODO ---- -* Fix test ordering problem with Postgres. - * Fix unicode problems with pyodbc. * Resolve timeout problems with MSSQL. diff --git a/tox.ini b/tox.ini index a5a8ca28..89b67537 100644 --- a/tox.ini +++ b/tox.ini @@ -194,7 +194,7 @@ commands = {[testenv]commands} -dropdb --username=runner --no-password sqlobject_test createdb --username=runner --no-password sqlobject_test - pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-psycopg] @@ -210,7 +210,7 @@ commands = {[testenv]commands} -dropdb --username=runner --no-password sqlobject_test createdb --username=runner --no-password sqlobject_test - pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-pygresql] @@ -226,7 +226,7 @@ commands = {[testenv]commands} -dropdb --username=runner --no-password sqlobject_test createdb --username=runner --no-password sqlobject_test - pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-pypostgresql] @@ -241,7 +241,7 @@ commands = {[testenv]commands} -dropdb --username=runner --no-password sqlobject_test createdb --username=runner --no-password sqlobject_test - pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pg8000&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pg8000&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-pg8000] @@ -258,7 +258,7 @@ commands = {envpython} -c "import pyodbc; print(pyodbc.drivers())" -dropdb --username=runner --no-password sqlobject_test createdb --username=runner --no-password sqlobject_test - pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-pyodbc-noauto] @@ -274,7 +274,7 @@ commands = {[testenv]commands} -dropdb --username=runner --no-password sqlobject_test createdb --username=runner --no-password sqlobject_test - pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-pypyodbc-noauto] @@ -497,7 +497,7 @@ commands = {[testenv]commands} -dropdb --username=runner --no-password sqlobject_test createdb --username=runner --no-password sqlobject_test - pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg2&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg2&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-psycopg-w32] @@ -516,7 +516,7 @@ commands = {[testenv]commands} -dropdb --username=runner --no-password sqlobject_test createdb --username=runner --no-password sqlobject_test - -pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + -pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-pygresql-noauto-w32] @@ -535,7 +535,7 @@ commands = {[testenv]commands} -dropdb --username=runner --no-password sqlobject_test createdb --username=runner --no-password sqlobject_test - pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-pypostgresql-w32] @@ -553,7 +553,7 @@ commands = {[testenv]commands} -dropdb --username=runner --no-password sqlobject_test createdb --username=runner --no-password sqlobject_test - pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pg8000&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pg8000&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-pg8000-w32] @@ -573,7 +573,7 @@ commands = {envpython} -c "import pyodbc; print(pyodbc.drivers())" -dropdb --username=runner --no-password sqlobject_test createdb --username=runner --no-password sqlobject_test - pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pyodbc&odbcdrv=PostgreSQL%20ANSI%28x64%29&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pyodbc&odbcdrv=PostgreSQL%20ANSI%28x64%29&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-pyodbc-noauto-w32] @@ -593,7 +593,7 @@ commands = {envpython} -c "import pypyodbc; print(pypyodbc.drivers())" -dropdb --username=runner --no-password sqlobject_test createdb --username=runner --no-password sqlobject_test - pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=PostgreSQL%20ANSI%28x64%29&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=PostgreSQL%20ANSI%28x64%29&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-pypyodbc-noauto-w32] From f1a3d33bba66bb888e9138df23b49264ea1f1268 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 28 Sep 2021 20:26:21 +0300 Subject: [PATCH 347/509] Tests(tox): Skip some tests py27-pg8000-w32 reports authentication error `InterfaceError: Authentication method 10 not recognized by pg8000.` pg8000 py37+ under Linux reports errors with closed sockets. pypostgresql fails on some tests. --- tox.ini | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/tox.ini b/tox.ini index 89b67537..f9992e6b 100644 --- a/tox.ini +++ b/tox.ini @@ -229,11 +229,11 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py27-postgres-pypostgresql] +[testenv:py27-postgres-pypostgresql-noauto] commands = {envpython} -c "print('pypostgresql requires Python 3.4+')" deps = -[testenv:py3{4,5,6,7,8,9,10}-postgres-pypostgresql] +[testenv:py3{4,5,6,7,8,9,10}-postgres-pypostgresql-noauto] commands = {[pypostgresql]commands} [pg8000] @@ -249,7 +249,10 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pg8000]commands} -[testenv:py3{4,5,6,7,8,9,10}-postgres-pg8000] +[testenv:py3{4,5,6}-postgres-pg8000] +commands = {[pg8000]commands} + +[testenv:py3{7,8,9,10}-postgres-pg8000-noauto] commands = {[pg8000]commands} [postgres-pyodbc] @@ -538,12 +541,12 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py27-postgres-pypostgresql-w32] +[testenv:py27-postgres-pypostgresql-noauto-w32] platform = win32 commands = {envpython} -c "print('pypostgresql requires Python 3.4+')" deps = -[testenv:py3{4,5,6,7,8,9,10}-postgres-pypostgresql-w32] +[testenv:py3{4,5,6,7,8,9,10}-postgres-pypostgresql-noauto-w32] platform = win32 commands = {[pypostgresql-w32]commands} @@ -556,7 +559,7 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pg8000&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py27-postgres-pg8000-w32] +[testenv:py27-postgres-pg8000-noauto-w32] platform = win32 commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base From 988e73e6aa311920dda0bb583b4778ba49991540 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 26 Feb 2022 03:54:38 +0300 Subject: [PATCH 348/509] CI(GHActions): Run tests under Python 3.5 --- .github/workflows/run-tests.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 0e5d7651..a2eacd03 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -9,7 +9,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, windows-latest] - python-version: ["2.7"] + python-version: ["2.7", "3.5"] include: - os: ubuntu-latest os-name: Linux From 1e4019e1c117b359d6d39823468c48da14df096d Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 17 Apr 2022 17:09:56 +0300 Subject: [PATCH 349/509] Tests(tox): Fix `pymysql` versions Python 3.5 requires `pymysql` < 1.0. --- devscripts/requirements/requirements_pymysql.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/devscripts/requirements/requirements_pymysql.txt b/devscripts/requirements/requirements_pymysql.txt index 47ca8d09..b8c7bc6a 100644 --- a/devscripts/requirements/requirements_pymysql.txt +++ b/devscripts/requirements/requirements_pymysql.txt @@ -1,3 +1,3 @@ -pymysql < 1.0; python_version == '2.7' +pymysql < 1.0; python_version == '2.7' or python_version == '3.5' pymysql < 0.10.0; python_version == '3.4' -pymysql; python_version >= '3.5' +pymysql; python_version >= '3.6' From b0299a54f5cd611e1f8a9d1ddc214508f79504e9 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 17 Apr 2022 18:07:25 +0300 Subject: [PATCH 350/509] Fix(MySQL): Fix encoding --- sqlobject/mysql/mysqlconnection.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index 95d6b58e..ebc5686f 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -397,6 +397,9 @@ def columnsFromSchema(self, tableName, soClass): # (SQLObject expected '') kw['notNone'] = (nullAllowed.upper() != 'YES' and True or False) + if not PY2 and isinstance(t, bytes): + t = t.decode('ascii') + if default and t.startswith('int'): kw['default'] = int(default) elif default and t.startswith('float'): @@ -413,6 +416,8 @@ def columnsFromSchema(self, tableName, soClass): return results def guessClass(self, t): + if not PY2 and isinstance(t, bytes): + t = t.decode('ascii') if t.startswith('int'): return col.IntCol, {} elif t.startswith('enum'): From 6259596b1095a24daf5ba6eaeb36253e17661597 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 17 Apr 2022 21:21:21 +0300 Subject: [PATCH 351/509] Tests(tox): Enable tests for `mysql-connector` --- tox.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tox.ini b/tox.ini index f9992e6b..2dca2f16 100644 --- a/tox.ini +++ b/tox.ini @@ -100,12 +100,12 @@ commands = pytest -D "mysql://root:@localhost/sqlobject_test?driver=connector&charset=utf8&debug=1" mysql --user=root --execute="drop database sqlobject_test;" -[testenv:py27-mysql-connector-noauto] +[testenv:py27-mysql-connector] commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-connector]commands} -[testenv:py3{4,5,6,7,8,9,10}-mysql-connector-noauto] +[testenv:py3{4,5,6,7,8,9,10}-mysql-connector] commands = {[mysql-connector]commands} [oursql] From c38bed3e3ef61b7d30a250146db6515a51fc7f01 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 19 Apr 2022 17:42:40 +0300 Subject: [PATCH 352/509] Fix(MySQL): Convert bytes to unicode Convert bytes to unicode for `mysql.connector` under Python 3. --- sqlobject/mysql/mysqlconnection.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index ebc5686f..e1d74c84 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -1,5 +1,6 @@ from sqlobject import col, dberrors from sqlobject.compat import PY2 +from sqlobject.converters import registerConverter, StringLikeConverter from sqlobject.dbconnection import DBAPI @@ -101,12 +102,14 @@ def __init__(self, db, user, password='', host='localhost', port=0, **kw): else: raise ImportError( 'Cannot find a MySQL driver, tried %s' % drivers) + self.host = host self.port = port or 3306 self.db = db self.user = user self.password = password self.kw = {} + for key in ("unix_socket", "init_command", "read_default_file", "read_default_group", "conv"): if key in kw: @@ -151,6 +154,9 @@ def __init__(self, db, user, password='', host='localhost', port=0, **kw): elif driver == 'mariadb': self.kw.pop("charset", None) + elif driver == 'connector': + registerConverter(bytes, ConnectorBytesConverter) + global mysql_Bin if not PY2 and mysql_Bin is None: mysql_Bin = self.module.Binary @@ -533,3 +539,10 @@ def can_use_json_funcs(self): can_use_json_funcs = (server_version >= (5, 7, 0)) self._can_use_json_funcs = can_use_json_funcs return can_use_json_funcs + + +def ConnectorBytesConverter(value, db): + assert db == 'mysql' + if not PY2: + value = value.decode('latin1') + return StringLikeConverter(value, db) From b815441e42211f13586088c502831cabb2fd44b7 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 19 Apr 2022 18:12:59 +0300 Subject: [PATCH 353/509] CI(GHActions): MySQL --- .github/workflows/run-tests.yaml | 5 ++ tox.ini | 104 +++++++++++++++---------------- 2 files changed, 57 insertions(+), 52 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index a2eacd03..a00242e3 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -23,6 +23,9 @@ jobs: steps: + # Setup MySQL + - uses: ankane/setup-mysql@v1 + # Setup PostgreSQL - uses: ankane/setup-postgres@v1 - name: Setup Postgres user @@ -63,12 +66,14 @@ jobs: - name: Run tox @ Linux run: | + devscripts/tox-select-envs $PYVER-mysql devscripts/tox-select-envs $PYVER-postgres devscripts/tox-select-envs $PYVER-sqlite devscripts/tox-select-envs $PYVER-flake8 if: ${{ runner.os == 'Linux' }} - name: Run tox @ w64 run: | + devscripts\tox-select-envs.cmd %PYVER%-mysql devscripts\tox-select-envs.cmd %PYVER%-postgres devscripts\tox-select-envs.cmd %PYVER%-sqlite if: ${{ runner.os == 'Windows' }} diff --git a/tox.ini b/tox.ini index 2dca2f16..eecaa8fb 100644 --- a/tox.ini +++ b/tox.ini @@ -63,10 +63,10 @@ whitelist_externals = [mysqldb] commands = {[testenv]commands} - -mysql --user=root --execute="drop database sqlobject_test;" - mysql --user=root --execute="create database sqlobject_test;" - pytest -D "mysql://root:@localhost/sqlobject_test?driver=mysqldb&debug=1" - mysql --user=root --execute="drop database sqlobject_test;" + -mysql --execute="drop database sqlobject_test;" + mysql --execute="create database sqlobject_test;" + pytest -D "mysql://localhost/sqlobject_test?driver=mysqldb&debug=1" + mysql --execute="drop database sqlobject_test;" [testenv:py27-mysqldb] commands = @@ -80,10 +80,10 @@ deps = [mysqlclient] commands = {[testenv]commands} - -mysql --user=root --execute="drop database sqlobject_test;" - mysql --user=root --execute="create database sqlobject_test;" - pytest -D "mysql://root:@localhost/sqlobject_test?driver=mysqldb&charset=utf8&debug=1" - mysql --user=root --execute="drop database sqlobject_test;" + -mysql --execute="drop database sqlobject_test;" + mysql --execute="create database sqlobject_test;" + pytest -D "mysql://localhost/sqlobject_test?driver=mysqldb&charset=utf8&debug=1" + mysql --execute="drop database sqlobject_test;" [testenv:py27-mysqlclient] commands = {envpython} -c "print('mysqlclient requires Python 3.4+')" @@ -95,10 +95,10 @@ commands = {[mysqlclient]commands} [mysql-connector] commands = {[testenv]commands} - -mysql --user=root --execute="drop database sqlobject_test;" - mysql --user=root --execute="create database sqlobject_test;" - pytest -D "mysql://root:@localhost/sqlobject_test?driver=connector&charset=utf8&debug=1" - mysql --user=root --execute="drop database sqlobject_test;" + -mysql --execute="drop database sqlobject_test;" + mysql --execute="create database sqlobject_test;" + pytest -D "mysql://localhost/sqlobject_test?driver=connector&charset=utf8&debug=1" + mysql --execute="drop database sqlobject_test;" [testenv:py27-mysql-connector] commands = @@ -111,10 +111,10 @@ commands = {[mysql-connector]commands} [oursql] commands = {[testenv]commands} - -mysql --user=root --execute="drop database sqlobject_test;" - mysql --user=root --execute="create database sqlobject_test;" - pytest -D "mysql://root:@localhost/sqlobject_test?driver=oursql&charset=utf8&debug=1" - mysql --user=root --execute="drop database sqlobject_test;" + -mysql --execute="drop database sqlobject_test;" + mysql --execute="create database sqlobject_test;" + pytest -D "mysql://localhost/sqlobject_test?driver=oursql&charset=utf8&debug=1" + mysql --execute="drop database sqlobject_test;" [testenv:py27-mysql-oursql-noauto] commands = @@ -127,10 +127,10 @@ commands = {[oursql]commands} [pymysql] commands = {[testenv]commands} - -mysql --user=root --execute="drop database sqlobject_test;" - mysql --user=root --execute="create database sqlobject_test;" - pytest -D "mysql://root:@localhost/sqlobject_test?driver=pymysql&charset=utf8&debug=1" - mysql --user=root --execute="drop database sqlobject_test;" + -mysql --execute="drop database sqlobject_test;" + mysql --execute="create database sqlobject_test;" + pytest -D "mysql://localhost/sqlobject_test?driver=pymysql&charset=utf8&debug=1" + mysql --execute="drop database sqlobject_test;" [testenv:py27-mysql-pymysql] commands = @@ -143,10 +143,10 @@ commands = {[pymysql]commands} [mariadb] commands = {[testenv]commands} - -mysql --user=root --execute="drop database sqlobject_test;" - mysql --user=root --execute="create database sqlobject_test;" - pytest -D "mysql://root:@localhost/sqlobject_test?driver=mariadb&charset=utf8&debug=1" - mysql --user=root --execute="drop database sqlobject_test;" + -mysql --execute="drop database sqlobject_test;" + mysql --execute="create database sqlobject_test;" + pytest -D "mysql://localhost/sqlobject_test?driver=mariadb&charset=utf8&debug=1" + mysql --execute="drop database sqlobject_test;" [testenv:py{27,34,35}-mariadb] commands = {envpython} -c "print('mariadb requires Python 3.6+')" @@ -159,10 +159,10 @@ commands = {[mariadb]commands} commands = {[testenv]commands} {envpython} -c "import pyodbc; print(pyodbc.drivers())" - -mysql --user=root --execute="drop database sqlobject_test;" - mysql --user=root --execute="create database sqlobject_test;" - pytest -D "mysql://root:@localhost/sqlobject_test?driver=pyodbc&odbcdrv=MySQL&charset=utf8&debug=1" - mysql --user=root --execute="drop database sqlobject_test;" + -mysql --execute="drop database sqlobject_test;" + mysql --execute="create database sqlobject_test;" + pytest -D "mysql://localhost/sqlobject_test?driver=pyodbc&odbcdrv=MySQL&charset=utf8&debug=1" + mysql --execute="drop database sqlobject_test;" [testenv:py27-mysql-pyodbc-noauto] commands = @@ -175,10 +175,10 @@ commands = {[mysql-pyodbc]commands} [mysql-pypyodbc] commands = {[testenv]commands} - -mysql --user=root --execute="drop database sqlobject_test;" - mysql --user=root --execute="create database sqlobject_test;" - pytest -D "mysql://root:@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=MySQL&charset=utf8&debug=1" - mysql --user=root --execute="drop database sqlobject_test;" + -mysql --execute="drop database sqlobject_test;" + mysql --execute="create database sqlobject_test;" + pytest -D "mysql://localhost/sqlobject_test?driver=pypyodbc&odbcdrv=MySQL&charset=utf8&debug=1" + mysql --execute="drop database sqlobject_test;" [testenv:py27-mysql-pypyodbc-noauto] commands = @@ -402,10 +402,10 @@ commands = {[mssql-pyodbc-w32]commands} platform = win32 commands = {[testenv]commands} - -mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" - mysql -u root "-pPassword12!" -e "create database sqlobject_test;" - pytest -D "mysql://root:Password12!@localhost/sqlobject_test?driver=connector&charset=utf8&debug=1" - mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" + -mysql --user=ODBC -e "drop database sqlobject_test;" + mysql --user=ODBC -e "create database sqlobject_test;" + pytest -D "mysql://ODBC@localhost/sqlobject_test?driver=connector&charset=utf8&debug=1" + mysql --user=ODBC -e "drop database sqlobject_test;" [testenv:py27-mysql-connector-w32] platform = win32 @@ -421,10 +421,10 @@ commands = {[mysql-connector-w32]commands} platform = win32 commands = {[testenv]commands} - -mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" - mysql -u root "-pPassword12!" -e "create database sqlobject_test;" - pytest -D "mysql://root:Password12!@localhost/sqlobject_test?driver=pymysql&charset=utf8&debug=1" - mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" + -mysql --user=ODBC -e "drop database sqlobject_test;" + mysql --user=ODBC -e "create database sqlobject_test;" + pytest -D "mysql://ODBC@localhost/sqlobject_test?driver=pymysql&charset=utf8&debug=1" + mysql --user=ODBC -e "drop database sqlobject_test;" [testenv:py27-mysql-pymysql-w32] platform = win32 @@ -440,10 +440,10 @@ commands = {[pymysql-w32]commands} platform = win32 commands = {[testenv]commands} - -mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" - mysql -u root "-pPassword12!" -e "create database sqlobject_test;" - pytest -D "mysql://root:Password12!@localhost/sqlobject_test?driver=mariadb&charset=utf8&debug=1" - mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" + -mysql --user=ODBC -e "drop database sqlobject_test;" + mysql --user=ODBC -e "create database sqlobject_test;" + pytest -D "mysql://ODBC@localhost/sqlobject_test?driver=mariadb&charset=utf8&debug=1" + mysql --user=ODBC -e "drop database sqlobject_test;" [testenv:py{27,34,35}-mariadb-w32] platform = win32 @@ -459,10 +459,10 @@ platform = win32 commands = {[testenv]commands} {envpython} -c "import pyodbc; print(pyodbc.drivers())" - -mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" - mysql -u root "-pPassword12!" -e "create database sqlobject_test;" - pytest -D "mysql://root:Password12!@localhost/sqlobject_test?driver=pyodbc&odbcdrv=MySQL%20ODBC%205.3%20ANSI%20Driver&charset=utf8&debug=1" - mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" + -mysql --user=ODBC -e "drop database sqlobject_test;" + mysql --user=ODBC -e "create database sqlobject_test;" + pytest -D "mysql://ODBC@localhost/sqlobject_test?driver=pyodbc&odbcdrv=MySQL%20ODBC%205.3%20ANSI%20Driver&charset=utf8&debug=1" + mysql --user=ODBC -e "drop database sqlobject_test;" [testenv:py27-mysql-pyodbc-noauto-w32] platform = win32 @@ -479,10 +479,10 @@ platform = win32 commands = {[testenv]commands} {envpython} -c "import pypyodbc; print(pypyodbc.drivers())" - -mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" - mysql -u root "-pPassword12!" -e "create database sqlobject_test;" - pytest -D "mysql://root:Password12!@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=MySQL%20ODBC%205.3%20ANSI%20Driver&charset=utf8&debug=1" - mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" + -mysql --user=ODBC -e "drop database sqlobject_test;" + mysql --user=ODBC -e "create database sqlobject_test;" + pytest -D "mysql://ODBC@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=MySQL%20ODBC%205.3%20ANSI%20Driver&charset=utf8&debug=1" + mysql --user=ODBC -e "drop database sqlobject_test;" [testenv:py27-mysql-pypyodbc-noauto-w32] platform = win32 From 18dbbc65877e2adb451db69aec207d542f90733f Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 15 Sep 2022 20:08:23 +0300 Subject: [PATCH 354/509] Fix(mysql-connector): Fix dbName under Python 2 --- sqlobject/mysql/mysqlconnection.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index e1d74c84..0a670f78 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -542,7 +542,8 @@ def can_use_json_funcs(self): def ConnectorBytesConverter(value, db): - assert db == 'mysql' if not PY2: + # For PY2 this converter is called also for SQLite + assert db == 'mysql' value = value.decode('latin1') return StringLikeConverter(value, db) From 04da46e0d3773b80fa2db2021956b53c95574da8 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 15 Sep 2022 20:29:20 +0300 Subject: [PATCH 355/509] Fix(tox): Skip `py27-mysqldb` Old `MySQLdb` for Python 2.7 requires old MySQL, it cannot be compiled with MySQL 8+. --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index eecaa8fb..37c39a6a 100644 --- a/tox.ini +++ b/tox.ini @@ -68,7 +68,7 @@ commands = pytest -D "mysql://localhost/sqlobject_test?driver=mysqldb&debug=1" mysql --execute="drop database sqlobject_test;" -[testenv:py27-mysqldb] +[testenv:py27-mysqldb-noauto] commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysqldb]commands} From 4261d5a101b91697e5fea93c88223bc48f24ad40 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 15 Sep 2022 22:29:50 +0300 Subject: [PATCH 356/509] Fix(tox): Make `mysql-connector` connect as the local user --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 37c39a6a..7b3ee574 100644 --- a/tox.ini +++ b/tox.ini @@ -97,7 +97,7 @@ commands = {[testenv]commands} -mysql --execute="drop database sqlobject_test;" mysql --execute="create database sqlobject_test;" - pytest -D "mysql://localhost/sqlobject_test?driver=connector&charset=utf8&debug=1" + pytest -D "mysql://runner:@localhost/sqlobject_test?driver=connector&charset=utf8&debug=1" mysql --execute="drop database sqlobject_test;" [testenv:py27-mysql-connector] From 30ba31d4d49c212124d4994abc4b237cc2e57100 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 16 Sep 2022 16:33:04 +0300 Subject: [PATCH 357/509] Fix(mysql-connector): Convert bytearrays --- sqlobject/mysql/mysqlconnection.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index 0a670f78..c4a72a6e 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -480,10 +480,10 @@ def guessClass(self, t): return col.Col, {} def listTables(self): - return [v[0] for v in self.queryAll("SHOW TABLES")] + return _decodeBytearrays(self.queryAll("SHOW TABLES")) def listDatabases(self): - return [v[0] for v in self.queryAll("SHOW DATABASES")] + return _decodeBytearrays(self.queryAll("SHOW DATABASES")) def _createOrDropDatabase(self, op="CREATE"): self.query('%s DATABASE %s' % (op, self.db)) @@ -547,3 +547,11 @@ def ConnectorBytesConverter(value, db): assert db == 'mysql' value = value.decode('latin1') return StringLikeConverter(value, db) + + +def _decodeBytearrays(v_list): + if not v_list: + return [] + if not PY2 and isinstance(v_list[0][0], bytearray): + return [v[0].decode('ascii') for v in v_list] + return [v[0] for v in v_list] From b79929b1abfa4ccb96be0838adb5c6b7f7b5c88b Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 16 Sep 2022 23:27:28 +0300 Subject: [PATCH 358/509] Feat(GHActions): Python 3.6-3.10 --- .github/workflows/run-tests.yaml | 2 +- devscripts/requirements/requirements_tests.txt | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index a00242e3..fe4b24d9 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -9,7 +9,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, windows-latest] - python-version: ["2.7", "3.5"] + python-version: ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10"] include: - os: ubuntu-latest os-name: Linux diff --git a/devscripts/requirements/requirements_tests.txt b/devscripts/requirements/requirements_tests.txt index 73674957..d6a51173 100644 --- a/devscripts/requirements/requirements_tests.txt +++ b/devscripts/requirements/requirements_tests.txt @@ -1,4 +1,8 @@ -r requirements.txt pytest < 5.0; python_version == '2.7' or python_version == '3.4' -pytest; python_version >= '3.5' + +# Pytest 7.0 introduced a major bug; see +# https://github.com/pytest-dev/pytest/issues/9620 + +pytest < 7.0; python_version >= '3.5' From 012da8ffa26f4b8419f19be8d00fdf544297725e Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 17 Sep 2022 22:55:44 +0300 Subject: [PATCH 359/509] CI(GHActions): Fix versions for newer Pythons --- .github/workflows/run-tests.yaml | 2 +- tox.ini | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index fe4b24d9..6bc5a27b 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -52,7 +52,7 @@ jobs: - name: Install dependencies run: | python --version - python -m pip install --upgrade "pip<21.0" "setuptools<45" wheel + python -m pip install --upgrade pip setuptools wheel pip --version pip install --upgrade virtualenv tox - name: Set PYVER diff --git a/tox.ini b/tox.ini index 7b3ee574..60e6814c 100644 --- a/tox.ini +++ b/tox.ini @@ -19,8 +19,6 @@ commands = {envpython} --version {envpython} -c "import struct; print(struct.calcsize('P') * 8)" deps = - py27,py34: pip < 19.2 - py27,py34: setuptools < 44 -rdevscripts/requirements/requirements_tests.txt py34: pendulum < 2.1 py34: zope.datetime < 4.3 @@ -45,7 +43,6 @@ deps = firebirdsql: firebirdsql passenv = CI setenv = - VIRTUALENV_PIP = 19.1.1 PGPASSWORD = test # Don't fail or warn on uninstalled commands platform = linux From abd02481adbab503e0787c0d32f5c86248cce543 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 18 Sep 2022 20:28:28 +0300 Subject: [PATCH 360/509] CI(GHActions): Show `tox`/`pytest` version --- .github/workflows/run-tests.yaml | 3 +++ tox.ini | 2 ++ 2 files changed, 5 insertions(+) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 6bc5a27b..edf0a592 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -64,6 +64,9 @@ jobs: f.write('PGPASSWORD=test\n') shell: python + - name: tox version + run: | + tox --version - name: Run tox @ Linux run: | devscripts/tox-select-envs $PYVER-mysql diff --git a/tox.ini b/tox.ini index 60e6814c..828cc915 100644 --- a/tox.ini +++ b/tox.ini @@ -18,6 +18,7 @@ basepython = commands = {envpython} --version {envpython} -c "import struct; print(struct.calcsize('P') * 8)" + {envpython} -m pytest --version deps = -rdevscripts/requirements/requirements_tests.txt py34: pendulum < 2.1 @@ -370,6 +371,7 @@ commands = {[firebirdsql]commands} changedir = ./ deps = flake8 + pytest < 7.0 commands = {[testenv]commands} flake8 . From 1a0168e0b4c891c51b6255e1295111409bf98fc5 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 20 Sep 2022 19:40:58 +0300 Subject: [PATCH 361/509] Release 3.10.0 --- ANNOUNCE.rst | 57 +++++++++++++++++++++++++++++---------- README.rst | 4 +-- devscripts/build-all-docs | 2 +- docs/News.rst | 9 +++---- sqlobject/__version__.py | 6 ++--- 5 files changed, 53 insertions(+), 25 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 5f6c2aa6..cfec8c15 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,25 +1,54 @@ Hello! -I'm pleased to announce version 3.9.2a1, the first alpha of the upcoming -release of branch 3.9 of SQLObject. +I'm pleased to announce version 3.10.0, the first release of branch +3.10 of SQLObject. -I'm pleased to announce version 3.9.2a2, the second alpha of the upcoming -release of branch 3.9 of SQLObject. -I'm pleased to announce version 3.9.2b1, the first beta of the upcoming -release of branch 3.9 of SQLObject. +What's new in SQLObject +======================= -I'm pleased to announce version 3.9.2rc1, the first release candidate -of the upcoming release of branch 3.9 of SQLObject. +Contributors for this release are +James Hudson, Juergen Gmach, Hugo van Kemenade. +Many thanks! -I'm pleased to announce version 3.9.2, the first bugfix release of branch -3.9 of SQLObject. +Features +-------- +* Allow connections in ``ConnectionHub`` to be strings. + This allows to open a new connection in every thread. -What's new in SQLObject -======================= +* Add compatibility with ``Pendulum``. + +Tests +----- + +* Run tests with Python 3.10. + +CI +-- + +* GitHub Actions. + +* Stop testing at Travis CI. + +* Stop testing at AppVeyor. + +Documentation +------------- + +* DevGuide: source code must be pure ASCII. + +* DevGuide: ``reStructuredText`` format for docstrings is recommended. + +* DevGuide: de-facto good commit message format is required: + subject/body/trailers. + +* DevGuide: ``conventional commit`` format for commit message subject lines + is recommended. + +* DevGuide: ``Markdown`` format for commit message bodies is recommended. -Contributors for this release are +* DevGuide: commit messages must be pure ASCII. For a more complete list, please see the news: http://sqlobject.org/News.html @@ -52,7 +81,7 @@ Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Download: -https://pypi.org/project/SQLObject/3.9.2a0.dev20210227/ +https://pypi.org/project/SQLObject/3.10.0 News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 2152854e..92b1dd71 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.9.2a0 -================= +SQLObject 3.10.0 +================ Thanks for looking at SQLObject. SQLObject is an object-relational mapper, i.e., a library that will wrap your database tables in Python diff --git a/devscripts/build-all-docs b/devscripts/build-all-docs index 8cb4ba16..8942edb7 100755 --- a/devscripts/build-all-docs +++ b/devscripts/build-all-docs @@ -10,7 +10,7 @@ cd "`dirname \"$0\"`" && PROG_DIR="`pwd`" && cd .. && -build_docs 3.9.1 && +build_docs 3.10.0 && build_docs master devel && rm -rf docs/html && diff --git a/docs/News.rst b/docs/News.rst index 67090893..12c0a786 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,8 +5,10 @@ News .. contents:: Contents: :backlinks: none -SQLObject (master) -================== +SQLObject 3.10.0 +================ + +Released 2022 Sep 20. Features -------- @@ -47,9 +49,6 @@ Documentation * DevGuide: commit messages must be pure ASCII. -* Change Travis CI URLs: - CI relocated from travis-ci.org to travis-ci.com. - SQLObject 3.9.1 =============== diff --git a/sqlobject/__version__.py b/sqlobject/__version__.py index cb43f08a..e01c255e 100644 --- a/sqlobject/__version__.py +++ b/sqlobject/__version__.py @@ -1,8 +1,8 @@ -version = '3.9.1' +version = '3.10.0' major = 3 -minor = 9 -micro = 1 +minor = 10 +micro = 0 release_level = 'final' serial = 0 version_info = (major, minor, micro, release_level, serial) From 66fe5d47cd4277a1aee2e1876c4fe535c3bf11ff Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 20 Sep 2022 20:19:26 +0300 Subject: [PATCH 362/509] Build: Prepare for the next release [skip ci] --- ANNOUNCE.rst | 57 +++++++++++++-------------------------------------- README.rst | 4 ++-- docs/News.rst | 3 +++ 3 files changed, 19 insertions(+), 45 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index cfec8c15..c9b634bd 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,54 +1,25 @@ Hello! -I'm pleased to announce version 3.10.0, the first release of branch -3.10 of SQLObject. - - -What's new in SQLObject -======================= - -Contributors for this release are -James Hudson, Juergen Gmach, Hugo van Kemenade. -Many thanks! - -Features --------- - -* Allow connections in ``ConnectionHub`` to be strings. - This allows to open a new connection in every thread. - -* Add compatibility with ``Pendulum``. +I'm pleased to announce version 3.10.1a1, the first alpha of the upcoming +release of branch 3.10 of SQLObject. -Tests ------ +I'm pleased to announce version 3.10.1a2, the second alpha of the upcoming +release of branch 3.10 of SQLObject. -* Run tests with Python 3.10. +I'm pleased to announce version 3.10.1b1, the first beta of the upcoming +release of branch 3.10 of SQLObject. -CI --- +I'm pleased to announce version 3.10.1rc1, the first release candidate +of the upcoming release of branch 3.10 of SQLObject. -* GitHub Actions. - -* Stop testing at Travis CI. - -* Stop testing at AppVeyor. - -Documentation -------------- - -* DevGuide: source code must be pure ASCII. - -* DevGuide: ``reStructuredText`` format for docstrings is recommended. - -* DevGuide: de-facto good commit message format is required: - subject/body/trailers. +I'm pleased to announce version 3.10.1, the first bugfix release of branch +3.10 of SQLObject. -* DevGuide: ``conventional commit`` format for commit message subject lines - is recommended. -* DevGuide: ``Markdown`` format for commit message bodies is recommended. +What's new in SQLObject +======================= -* DevGuide: commit messages must be pure ASCII. +Contributors for this release are For a more complete list, please see the news: http://sqlobject.org/News.html @@ -81,7 +52,7 @@ Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Download: -https://pypi.org/project/SQLObject/3.10.0 +https://pypi.org/project/SQLObject/3.10.1a0.dev20221020/ News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 92b1dd71..c9102052 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.10.0 -================ +SQLObject 3.10.1a0 +================== Thanks for looking at SQLObject. SQLObject is an object-relational mapper, i.e., a library that will wrap your database tables in Python diff --git a/docs/News.rst b/docs/News.rst index 12c0a786..42f56160 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,6 +5,9 @@ News .. contents:: Contents: :backlinks: none +SQLObject (master) +================== + SQLObject 3.10.0 ================ From fb5a71609a3ace1441555cb687539bc1c0f147eb Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 21 Sep 2022 02:39:07 +0300 Subject: [PATCH 363/509] CI(GHActions): fail fast, use `setup-python@v4`, `cache@v3` --- .github/workflows/run-tests.yaml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index edf0a592..2c0330d7 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -6,7 +6,6 @@ jobs: run-tests: strategy: - fail-fast: false matrix: os: [ubuntu-latest, windows-latest] python-version: ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10"] @@ -39,11 +38,11 @@ jobs: # Setup Python/pip - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 + - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Cache pip - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ${{ matrix.pip-cache-path }} key: ${{ runner.os }}-pip From 8d80a738de4e210cdf679a13ad328cae3902bc61 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 21 Sep 2022 11:00:07 +0300 Subject: [PATCH 364/509] Build(devscripts/release): Disable progress bar for `twine` [skip ci] --- devscripts/release | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devscripts/release b/devscripts/release index 3873ec25..8893a52f 100755 --- a/devscripts/release +++ b/devscripts/release @@ -24,5 +24,5 @@ if [ "$state" = final ]; then devscripts/sftp-frs fi && -twine upload --skip-existing dist/* && +twine upload --disable-progress-bar --skip-existing dist/* && exec rm -rf build dist docs/html SQLObject.egg-info From 3fa162e89cbb1611e03ccbf140cecb7fbddd4f1c Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 23 Sep 2022 15:54:40 +0300 Subject: [PATCH 365/509] Docs(ANNOUNCE): Add Developer Guide and brief installation instruction [skip ci] --- ANNOUNCE.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index c9b634bd..7d270b01 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -48,6 +48,9 @@ http://sqlobject.org Development: http://sqlobject.org/devel/ +Developer Guide: +http://sqlobject.org/DeveloperGuide.html + Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss @@ -64,6 +67,10 @@ https://stackoverflow.com/questions/tagged/sqlobject Example ======= +Install:: + + $ pip install sqlobject + Create a simple class that wraps a table:: >>> from sqlobject import * From e3f4e1a00f36a197cc9318ea4fc5911da02ea7ef Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 23 Sep 2022 16:22:22 +0300 Subject: [PATCH 366/509] Docs(ANNOUNCE): Reorder URLs: first users then developers Change the URL for mailing lists. [skip ci] --- ANNOUNCE.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 7d270b01..ae694356 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -45,15 +45,6 @@ Where is SQLObject Site: http://sqlobject.org -Development: -http://sqlobject.org/devel/ - -Developer Guide: -http://sqlobject.org/DeveloperGuide.html - -Mailing list: -https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss - Download: https://pypi.org/project/SQLObject/3.10.1a0.dev20221020/ @@ -63,6 +54,15 @@ http://sqlobject.org/News.html StackOverflow: https://stackoverflow.com/questions/tagged/sqlobject +Mailing lists: +https://sourceforge.net/p/sqlobject/mailman/ + +Development: +http://sqlobject.org/devel/ + +Developer Guide: +http://sqlobject.org/DeveloperGuide.html + Example ======= From 8417bda4771e6281f3851bc18c4c2fed5d48a2c0 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 25 Sep 2022 14:48:53 +0300 Subject: [PATCH 367/509] Add lists of supported DB API drivers [skip ci] --- ANNOUNCE.rst | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index ae694356..db59849f 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -32,9 +32,13 @@ SQLObject is an object-relational mapper. Your database tables are described as classes, and rows are instances of those classes. SQLObject is meant to be easy to use and quick to get started with. -SQLObject supports a number of backends: MySQL, PostgreSQL, SQLite; -connections to other backends - Firebird, Sybase, MSSQL -and MaxDB (also known as SAPDB) - are lesser debugged). +SQLObject supports a number of backends: MySQL/MariaDB (with a number of +DB API drivers: ``MySQLdb``, ``mysqlclient``, ``mysql-connector``, +``PyMySQL``, ``mariadb``), PostgreSQL (``psycopg2``, ``PyGreSQL``, +partially ``pg8000`` and ``py-postgresql``), SQLite (builtin ``sqlite``, +``pysqlite``, partially ``supersqlite``); connections to other backends +- Firebird, Sybase, MSSQL and MaxDB (also known as SAPDB) - are less +debugged). Python 2.7 or 3.4+ is required. From 780cc55642eddbdc1b41557f79fe1d406415f334 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 25 Sep 2022 14:52:49 +0300 Subject: [PATCH 368/509] It's free, open-source (MIT), Python [skip ci] --- ANNOUNCE.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index db59849f..40828217 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -28,9 +28,10 @@ http://sqlobject.org/News.html What is SQLObject ================= -SQLObject is an object-relational mapper. Your database tables are described -as classes, and rows are instances of those classes. SQLObject is meant to be -easy to use and quick to get started with. +SQLObject is a free and open-source (LGPL) Python object-relational +mapper. Your database tables are described as classes, and rows are +instances of those classes. SQLObject is meant to be easy to use and +quick to get started with. SQLObject supports a number of backends: MySQL/MariaDB (with a number of DB API drivers: ``MySQLdb``, ``mysqlclient``, ``mysql-connector``, From e2e7df6412ea84348729eb9450e7107bd5170c74 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 26 Oct 2022 00:05:08 +0300 Subject: [PATCH 369/509] Tests(tox): Remove `basepython` We no longer use `TOXPYTHON`. --- tox.ini | 9 --------- 1 file changed, 9 deletions(-) diff --git a/tox.ini b/tox.ini index 828cc915..cc53f368 100644 --- a/tox.ini +++ b/tox.ini @@ -6,15 +6,6 @@ envlist = py27,py3{4,5,6,7,8,9,10}-sqlite{,-memory},py{27,310}-flake8 [testenv] # Ensure we cd into sqlobject before running the tests changedir = ./sqlobject/ -basepython = - py27: {env:TOXPYTHON:python2.7} - py34: {env:TOXPYTHON:python3.4} - py35: {env:TOXPYTHON:python3.5} - py36: {env:TOXPYTHON:python3.6} - py37: {env:TOXPYTHON:python3.7} - py38: {env:TOXPYTHON:python3.8} - py39: {env:TOXPYTHON:python3.9} - py310: {env:TOXPYTHON:python3.10} commands = {envpython} --version {envpython} -c "import struct; print(struct.calcsize('P') * 8)" From 25ab36002ae4affa9d9337b5b11fdee94aecfa1c Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 25 Oct 2022 01:26:30 +0300 Subject: [PATCH 370/509] Tests, CI: Add Python 3.11 --- .github/workflows/run-tests.yaml | 2 +- devscripts/test-sqlobject.cmd | 2 +- docs/News.rst | 5 +++ setup.py | 1 + tox.ini | 68 ++++++++++++++++---------------- 5 files changed, 42 insertions(+), 36 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 2c0330d7..80335a8c 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -8,7 +8,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest] - python-version: ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10"] + python-version: ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11"] include: - os: ubuntu-latest os-name: Linux diff --git a/devscripts/test-sqlobject.cmd b/devscripts/test-sqlobject.cmd index 8c7e38d0..f227bf09 100644 --- a/devscripts/test-sqlobject.cmd +++ b/devscripts/test-sqlobject.cmd @@ -3,7 +3,7 @@ SetLocal EnableDelayedExpansion set SavePATH=%PATH% -for %%V in (27 34 35 36 37 38 39 310) do ( +for %%V in (27 34 35 36 37 38 39 310 311) do ( for %%s in (32 64) do ( set PATH=C:\Python%%V-%%s;C:\Python%%V-%%s\Scripts;!SavePATH! set TOXPYTHON=C:\Python%%V-%%s\python.exe diff --git a/docs/News.rst b/docs/News.rst index 42f56160..e2d0b97a 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,11 @@ News SQLObject (master) ================== +Tests, CI +--------- + +* Run tests with Python 3.11. + SQLObject 3.10.0 ================ diff --git a/setup.py b/setup.py index 57ea5394..b67aa317 100755 --- a/setup.py +++ b/setup.py @@ -62,6 +62,7 @@ "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", "Topic :: Database", "Topic :: Database :: Front-Ends", "Topic :: Software Development :: Libraries :: Python Modules", diff --git a/tox.ini b/tox.ini index cc53f368..1f8bbbf6 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 3.15 -envlist = py27,py3{4,5,6,7,8,9,10}-sqlite{,-memory},py{27,310}-flake8 +envlist = py27,py3{4,5,6,7,8,9,10,11}-sqlite{,-memory},py{27,36,311}-flake8 # Base test environment settings [testenv] @@ -62,7 +62,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysqldb]commands} -[testenv:py3{4,5,6,7,8,9,10}-mysqldb] +[testenv:py3{4,5,6,7,8,9,10,11}-mysqldb] commands = {envpython} -c "print('MySQL-python requires Python 2.7')" deps = @@ -78,7 +78,7 @@ commands = commands = {envpython} -c "print('mysqlclient requires Python 3.4+')" deps = -[testenv:py3{4,5,6,7,8,9,10}-mysqlclient] +[testenv:py3{4,5,6,7,8,9,10,11}-mysqlclient] commands = {[mysqlclient]commands} [mysql-connector] @@ -94,7 +94,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-connector]commands} -[testenv:py3{4,5,6,7,8,9,10}-mysql-connector] +[testenv:py3{4,5,6,7,8,9,10,11}-mysql-connector] commands = {[mysql-connector]commands} [oursql] @@ -110,7 +110,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[oursql]commands} -[testenv:py3{4,5,6,7,8,9,10}-mysql-oursql3-noauto] +[testenv:py3{4,5,6,7,8,9,10,11}-mysql-oursql3-noauto] commands = {[oursql]commands} [pymysql] @@ -126,7 +126,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pymysql]commands} -[testenv:py3{4,5,6,7,8,9,10}-mysql-pymysql] +[testenv:py3{4,5,6,7,8,9,10,11}-mysql-pymysql] commands = {[pymysql]commands} [mariadb] @@ -141,7 +141,7 @@ commands = commands = {envpython} -c "print('mariadb requires Python 3.6+')" deps = -[testenv:py3{6,7,8,9,10}-mariadb] +[testenv:py3{6,7,8,9,10,11}-mariadb] commands = {[mariadb]commands} [mysql-pyodbc] @@ -158,7 +158,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pyodbc]commands} -[testenv:py3{4,5,6,7,8,9,10}-mysql-pyodbc-noauto] +[testenv:py3{4,5,6,7,8,9,10,11}-mysql-pyodbc-noauto] commands = {[mysql-pyodbc]commands} [mysql-pypyodbc] @@ -174,7 +174,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pypyodbc]commands} -[testenv:py3{4,5,6,7,8,9,10}-mysql-pypyodbc-noauto] +[testenv:py3{4,5,6,7,8,9,10,11}-mysql-pypyodbc-noauto] commands = {[mysql-pypyodbc]commands} # PostgreSQL test environments @@ -191,7 +191,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[psycopg]commands} -[testenv:py3{4,5,6,7,8,9,10}-postgres-psycopg] +[testenv:py3{4,5,6,7,8,9,10,11}-postgres-psycopg] commands = {[psycopg]commands} [pygresql] @@ -207,7 +207,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pygresql]commands} -[testenv:py3{4,5,6,7,8,9,10}-postgres-pygresql] +[testenv:py3{4,5,6,7,8,9,10,11}-postgres-pygresql] commands = {[pygresql]commands} [pypostgresql] @@ -222,7 +222,7 @@ commands = commands = {envpython} -c "print('pypostgresql requires Python 3.4+')" deps = -[testenv:py3{4,5,6,7,8,9,10}-postgres-pypostgresql-noauto] +[testenv:py3{4,5,6,7,8,9,10,11}-postgres-pypostgresql-noauto] commands = {[pypostgresql]commands} [pg8000] @@ -241,7 +241,7 @@ commands = [testenv:py3{4,5,6}-postgres-pg8000] commands = {[pg8000]commands} -[testenv:py3{7,8,9,10}-postgres-pg8000-noauto] +[testenv:py3{7,8,9,10,11}-postgres-pg8000-noauto] commands = {[pg8000]commands} [postgres-pyodbc] @@ -258,7 +258,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pyodbc]commands} -[testenv:py3{4,5,6,7,8,9,10}-postgres-pyodbc-noauto] +[testenv:py3{4,5,6,7,8,9,10,11}-postgres-pyodbc-noauto] commands = {[postgres-pyodbc]commands} [postgres-pypyodbc] @@ -274,7 +274,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pypyodbc]commands} -[testenv:py3{4,5,6,7,8,9,10}-postgres-pypyodbc-noauto] +[testenv:py3{4,5,6,7,8,9,10,11}-postgres-pypyodbc-noauto] commands = {[postgres-pypyodbc]commands} @@ -291,7 +291,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite]commands} -[testenv:py3{4,5,6,7,8,9,10}-sqlite] +[testenv:py3{4,5,6,7,8,9,10,11}-sqlite] commands = {[sqlite]commands} [sqlite-memory] @@ -304,7 +304,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite-memory]commands} -[testenv:py3{4,5,6,7,8,9,10}-sqlite-memory] +[testenv:py3{4,5,6,7,8,9,10,11}-sqlite-memory] commands = {[sqlite-memory]commands} [sqlite-supersqlite] @@ -319,7 +319,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite-supersqlite]commands} -[testenv:py3{4,5,6,7,8,9,10}-sqlite-supersqlite] +[testenv:py3{4,5,6,7,8,9,10,11}-sqlite-supersqlite] commands = {[sqlite-supersqlite]commands} @@ -337,7 +337,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[fdb]commands} -[testenv:py3{4,5,6,7,8,9,10}-firebird-fdb] +[testenv:py3{4,5,6,7,8,9,10,11}-firebird-fdb] commands = {[fdb]commands} [firebirdsql] @@ -353,7 +353,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[firebirdsql]commands} -[testenv:py3{4,5,6,7,8,9,10}-firebirdsql] +[testenv:py3{4,5,6,7,8,9,10,11}-firebirdsql] commands = {[firebirdsql]commands} @@ -384,7 +384,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mssql-pyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9,10}-mssql-pyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11}-mssql-pyodbc-noauto-w32] platform = win32 commands = {[mssql-pyodbc-w32]commands} @@ -403,7 +403,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-connector-w32]commands} -[testenv:py3{4,5,6,7,8,9,10}-mysql-connector-w32] +[testenv:py3{4,5,6,7,8,9,10,11}-mysql-connector-w32] platform = win32 commands = {[mysql-connector-w32]commands} @@ -422,7 +422,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pymysql-w32]commands} -[testenv:py3{4,5,6,7,8,9,10}-mysql-pymysql-w32] +[testenv:py3{4,5,6,7,8,9,10,11}-mysql-pymysql-w32] platform = win32 commands = {[pymysql-w32]commands} @@ -440,7 +440,7 @@ platform = win32 commands = {envpython} -c "print('mariadb requires Python 3.6+')" deps = -[testenv:py3{6,7,8,9,10}-mariadb-w32] +[testenv:py3{6,7,8,9,10,11}-mariadb-w32] platform = win32 commands = {[mariadb-w32]commands} @@ -460,7 +460,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9,10}-mysql-pyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11}-mysql-pyodbc-noauto-w32] platform = win32 commands = {[mysql-pyodbc-w32]commands} @@ -480,7 +480,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pypyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9,10}-mysql-pypyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11}-mysql-pypyodbc-noauto-w32] platform = win32 commands = {[mysql-pypyodbc-w32]commands} @@ -499,7 +499,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[psycopg-w32]commands} -[testenv:py3{4,5,6,7,8,9,10}-postgres-psycopg-w32] +[testenv:py3{4,5,6,7,8,9,10,11}-postgres-psycopg-w32] platform = win32 commands = {[psycopg-w32]commands} @@ -518,7 +518,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pygresql-w32]commands} -[testenv:py3{4,5,6,7,8,9,10}-postgres-pygresql-w32] +[testenv:py3{4,5,6,7,8,9,10,11}-postgres-pygresql-w32] platform = win32 commands = {[pygresql-w32]commands} @@ -536,7 +536,7 @@ platform = win32 commands = {envpython} -c "print('pypostgresql requires Python 3.4+')" deps = -[testenv:py3{4,5,6,7,8,9,10}-postgres-pypostgresql-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11}-postgres-pypostgresql-noauto-w32] platform = win32 commands = {[pypostgresql-w32]commands} @@ -555,7 +555,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pg8000-w32]commands} -[testenv:py3{4,5,6,7,8,9,10}-postgres-pg8000-w32] +[testenv:py3{4,5,6,7,8,9,10,11}-postgres-pg8000-w32] platform = win32 commands = {[pg8000-w32]commands} @@ -575,7 +575,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9,10}-postgres-pyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11}-postgres-pyodbc-noauto-w32] platform = win32 commands = {[postgres-pyodbc-w32]commands} @@ -595,7 +595,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pypyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9,10}-postgres-pypyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11}-postgres-pypyodbc-noauto-w32] platform = win32 commands = {[postgres-pypyodbc-w32]commands} @@ -612,7 +612,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite-w32]commands} -[testenv:py3{4,5,6,7,8,9,10}-sqlite-w32] +[testenv:py3{4,5,6,7,8,9,10,11}-sqlite-w32] platform = win32 commands = {[sqlite-w32]commands} @@ -628,6 +628,6 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite-memory-w32]commands} -[testenv:py3{4,5,6,7,8,9,10}-sqlite-memory-w32] +[testenv:py3{4,5,6,7,8,9,10,11}-sqlite-memory-w32] platform = win32 commands = {[sqlite-memory-w32]commands} From 302bfb6818745c31b5c863eacfdc315b5784d396 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 27 Oct 2022 19:05:04 +0300 Subject: [PATCH 371/509] Tests(tox): Fix the list of `flake8` environments --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 1f8bbbf6..81df7f69 100644 --- a/tox.ini +++ b/tox.ini @@ -358,7 +358,7 @@ commands = {[firebirdsql]commands} # Special test environments -[testenv:py{27,34,35,36,37,38,39}-flake8] +[testenv:py{27,34,35,36,37,38,39,310,311}-flake8] changedir = ./ deps = flake8 From 6509ac8c44f0ef98e6d64007a7cc9efd2abf083b Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 17 Nov 2022 21:54:35 +0300 Subject: [PATCH 372/509] Fix(compat): Use `.exec_module(.create_module())` instead of `.load_module()` Use `module_loader.exec_module(module_loader.create_module())` instead of `module_loader.load_module()` when available. --- docs/News.rst | 6 ++++++ sqlobject/compat.py | 11 ++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/docs/News.rst b/docs/News.rst index e2d0b97a..0eaaa97d 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,12 @@ News SQLObject (master) ================== +Minor features +-------------- + +* Use ``module_loader.exec_module(module_loader.create_module())`` + instead of ``module_loader.load_module()`` when available. + Tests, CI --------- diff --git a/sqlobject/compat.py b/sqlobject/compat.py index 72d696f4..fc8edf25 100644 --- a/sqlobject/compat.py +++ b/sqlobject/compat.py @@ -47,4 +47,13 @@ def load_module_from_file(base_name, module_name, filename): def load_module_from_file(base_name, module_name, filename): specs = importlib.util.spec_from_file_location(module_name, filename) - return specs.loader.load_module() + loader = specs.loader + if hasattr(loader, 'create_module'): + module = loader.create_module(specs) + else: + module = None + if module is None: + return specs.loader.load_module() + else: + loader.exec_module(module) + return module From 44c441439545d48f9eccf172ff0b0b76bb18ac8d Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 18 Nov 2022 18:29:44 +0300 Subject: [PATCH 373/509] Docs(README): Update Copied from https://github.com/sqlobject/.github/tree/master/profile [skip ci] --- README.rst | 87 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 79 insertions(+), 8 deletions(-) diff --git a/README.rst b/README.rst index c9102052..8c310399 100644 --- a/README.rst +++ b/README.rst @@ -1,15 +1,86 @@ SQLObject 3.10.1a0 ================== -Thanks for looking at SQLObject. SQLObject is an object-relational -mapper, i.e., a library that will wrap your database tables in Python -classes, and your rows in Python instances. +SQLObject is a free and open-source (LGPL) Python object-relational +mapper. Your database tables are described as classes, and rows are +instances of those classes. SQLObject is meant to be easy to use and +quick to get started with. -It currently supports MySQL, PostgreSQL and SQLite; connections to other -backends - Firebird, Sybase, MSSQL and MaxDB (also known as SAPDB) - are -lesser debugged). +SQLObject supports a number of backends: MySQL/MariaDB (with a number of +DB API drivers: ``MySQLdb``, ``mysqlclient``, ``mysql-connector``, +``PyMySQL``, ``mariadb``), PostgreSQL (``psycopg2``, ``PyGreSQL``, +partially ``pg8000`` and ``py-postgresql``), SQLite (builtin ``sqlite``, +``pysqlite``, partially ``supersqlite``); connections to other backends +- Firebird, Sybase, MSSQL and MaxDB (also known as SAPDB) - are less +debugged). Python 2.7 or 3.4+ is required. -For more information please see the documentation in -``_, or online at http://sqlobject.org/ + +Where is SQLObject +================== + +Site: +http://sqlobject.org + +Download: +https://pypi.org/project/SQLObject/ + +News and changes: +http://sqlobject.org/News.html + +StackOverflow: +https://stackoverflow.com/questions/tagged/sqlobject + +Mailing lists: +https://sourceforge.net/p/sqlobject/mailman/ + +Development: +http://sqlobject.org/devel/ + +Developer Guide: +http://sqlobject.org/DeveloperGuide.html + + +Example +======= + +Install:: + + $ pip install sqlobject + +Create a simple class that wraps a table:: + + >>> from sqlobject import * + >>> + >>> sqlhub.processConnection = connectionForURI('sqlite:/:memory:') + >>> + >>> class Person(SQLObject): + ... fname = StringCol() + ... mi = StringCol(length=1, default=None) + ... lname = StringCol() + ... + >>> Person.createTable() + +Use the object:: + + >>> p = Person(fname="John", lname="Doe") + >>> p + + >>> p.fname + 'John' + >>> p.mi = 'Q' + >>> p2 = Person.get(1) + >>> p2 + + >>> p is p2 + True + +Queries:: + + >>> p3 = Person.selectBy(lname="Doe")[0] + >>> p3 + + >>> pc = Person.select(Person.q.lname=="Doe").count() + >>> pc + 1 From 295eb1aee711bcbc7c01612a5e4657415fef7f25 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 3 Dec 2022 01:15:34 +0300 Subject: [PATCH 374/509] CI: Unify names I always call it "w32" even if it's really 64-bit. [skip ci] --- .github/workflows/run-tests.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 80335a8c..7b5c8b45 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -73,7 +73,7 @@ jobs: devscripts/tox-select-envs $PYVER-sqlite devscripts/tox-select-envs $PYVER-flake8 if: ${{ runner.os == 'Linux' }} - - name: Run tox @ w64 + - name: Run tox @ w32 run: | devscripts\tox-select-envs.cmd %PYVER%-mysql devscripts\tox-select-envs.cmd %PYVER%-postgres From 0745abd1c5a2c0123c18879ed9f1baa08f7bc5ef Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 6 Dec 2022 19:44:17 +0300 Subject: [PATCH 375/509] CI(GHActions): Use `conda` to install older Pythons Ubuntu >= 22 and `setup-python` dropped Pythons < 3.7. Use `s-weigand/setup-conda` instead of `setup-python`. --- .github/workflows/run-tests.yaml | 5 +++++ docs/News.rst | 11 +++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 7b5c8b45..a0fc3141 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -38,9 +38,14 @@ jobs: # Setup Python/pip - uses: actions/checkout@v2 + - uses: s-weigand/setup-conda@v1 + with: + python-version: ${{ matrix.python-version }} + if: ${{ runner.os == 'Linux' && matrix.python-version != '3.11' }} - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} + if: ${{ runner.os != 'Linux' || matrix.python-version == '3.11' }} - name: Cache pip uses: actions/cache@v3 with: diff --git a/docs/News.rst b/docs/News.rst index 0eaaa97d..02bcdb4a 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -14,11 +14,18 @@ Minor features * Use ``module_loader.exec_module(module_loader.create_module())`` instead of ``module_loader.load_module()`` when available. -Tests, CI ---------- +Tests +----- * Run tests with Python 3.11. +CI +-- + +* Ubuntu >= 22 and ``setup-python`` dropped Pythons < 3.7. + Use ``conda`` via ``s-weigand/setup-conda`` instead of ``setup-python`` + to install older Pythons on Linux. + SQLObject 3.10.0 ================ From b46a80e04bb2c5f3a873549edd5947527f0088d1 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 9 Dec 2022 15:17:15 +0300 Subject: [PATCH 376/509] CI(GHActions): Set `$LD_LIBRARY_PATH` Python 2.7 on Linux requires `$LD_LIBRARY_PATH`. --- .github/workflows/run-tests.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index a0fc3141..5eb73dc9 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -62,8 +62,15 @@ jobs: - name: Set PYVER run: | import os, sys + ld_library_path = None pyver = '%d%d' % tuple(sys.version_info[:2]) + if os.name == 'posix': + if pyver == '27': # Python 2.7 on Linux requires `$LD_LIBRARY_PATH` + ld_library_path = os.path.join( + os.path.dirname(os.path.dirname(sys.executable)), 'lib') with open(os.environ['GITHUB_ENV'], 'a') as f: + if ld_library_path: + f.write('LD_LIBRARY_PATH=' + ld_library_path + '\n') f.write('PYVER=' + pyver + '\n') f.write('PGPASSWORD=test\n') shell: python From 089c9885aebbce49bae7f0388ee57df5b182ffd0 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 15 Dec 2022 19:55:37 +0300 Subject: [PATCH 377/509] Tests(tox): Limit "tox < 4" `tox` 4+ has incompatible `tox.ini` syntax. It's impossible to use one `tox.ini` for Pythons < 3.7 and 3.7+. --- .github/workflows/run-tests.yaml | 2 +- devscripts/requirements/requirements_tox.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 5eb73dc9..bc676984 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -58,7 +58,7 @@ jobs: python --version python -m pip install --upgrade pip setuptools wheel pip --version - pip install --upgrade virtualenv tox + pip install --upgrade virtualenv "tox < 4" - name: Set PYVER run: | import os, sys diff --git a/devscripts/requirements/requirements_tox.txt b/devscripts/requirements/requirements_tox.txt index 8b5960b9..b72a322f 100644 --- a/devscripts/requirements/requirements_tox.txt +++ b/devscripts/requirements/requirements_tox.txt @@ -1 +1 @@ -tox >= 3.15 +tox >= 3.15, < 4 From 89a7e24d7de75c745c60481d0da68aa204427f59 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 4 Dec 2022 20:54:55 +0300 Subject: [PATCH 378/509] Feat(MySQL): Add `mysql-connector-python` --- .../requirements_connector_python.txt | 10 ++++++++++ docs/News.rst | 8 +++++++- setup.py | 1 + sqlobject/mysql/mysqlconnection.py | 15 ++++++++------- tox.ini | 17 +++++++++++++++++ 5 files changed, 43 insertions(+), 8 deletions(-) create mode 100644 devscripts/requirements/requirements_connector_python.txt diff --git a/devscripts/requirements/requirements_connector_python.txt b/devscripts/requirements/requirements_connector_python.txt new file mode 100644 index 00000000..d06b1911 --- /dev/null +++ b/devscripts/requirements/requirements_connector_python.txt @@ -0,0 +1,10 @@ +mysql-connector-python <= 8.0.23; python_version == '2.7' +protobuf < 3.19; python_version == '3.4' +mysql-connector-python <= 8.0.22, > 2.0; python_version == '3.4' +mysql-connector-python <= 8.0.23, >= 8.0.5; python_version == '3.5' +mysql-connector-python <= 8.0.28, >= 8.0.6; python_version == '3.6' +mysql-connector-python >= 8.0.13; python_version == '3.7' +mysql-connector-python >= 8.0.19; python_version == '3.8' +mysql-connector-python >= 8.0.24; python_version == '3.9' +mysql-connector-python >= 8.0.28; python_version == '3.10' +mysql-connector-python >= 8.0.31; python_version >= '3.11' diff --git a/docs/News.rst b/docs/News.rst index 02bcdb4a..c9d65c90 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -14,6 +14,11 @@ Minor features * Use ``module_loader.exec_module(module_loader.create_module())`` instead of ``module_loader.load_module()`` when available. +Drivers +------- + +* Added ``mysql-connector-python``. + Tests ----- @@ -468,7 +473,8 @@ Minor features 'kinterbasdb' in that order. pyfirebirdsql is supported but has problems. * Add ``driver`` keyword for MySQLConnection. Allowed values are 'mysqldb', - 'connector', 'oursql' and 'pymysql'. Default is to test for mysqldb only. + 'connector', 'connector-python', 'oursql' and 'pymysql'. Default is to + test for mysqldb only. * Add support for `MySQL Connector `_ (pure python; `binary diff --git a/setup.py b/setup.py index b67aa317..db824658 100755 --- a/setup.py +++ b/setup.py @@ -117,6 +117,7 @@ 'mysql:python_version=="2.7"': ['MySQL-python'], 'mysql:python_version>="3.4"': ['mysqlclient'], 'mysql-connector': ['mysql-connector'], + 'mysql-connector-python': ['mysql-connector-python'], 'oursql:python_version=="2.7"': [ 'oursql @ git+https://github.com/sqlobject/oursql.git@master'], 'oursql:python_version>="3.4"': [ diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index c4a72a6e..ac3e0629 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -59,7 +59,7 @@ def __init__(self, db, user, password='', host='localhost', port=0, **kw): self.CR_SERVER_LOST = \ MySQLdb.constants.CR.CR_SERVER_LOST self.ER_DUP_ENTRY = MySQLdb.constants.ER.DUP_ENTRY - elif driver == 'connector': + elif driver in ('connector', 'connector-python'): import mysql.connector self.module = mysql.connector self.CR_SERVER_GONE_ERROR = \ @@ -92,7 +92,7 @@ def __init__(self, db, user, password='', host='localhost', port=0, **kw): else: raise ValueError( 'Unknown MySQL driver "%s", ' - 'expected mysqldb, connector, ' + 'expected mysqldb, connector, connector-python, ' 'oursql, pymysql, mariadb, ' 'odbc, pyodbc or pypyodbc' % driver) except ImportError: @@ -118,7 +118,7 @@ def __init__(self, db, user, password='', host='localhost', port=0, **kw): "client_flag", "local_infile"): if key in kw: self.kw[key] = int(kw.pop(key)) - if driver == 'connector': + if driver in ('connector', 'connector-python'): for key in ("ssl_key", "ssl_cert", "ssl_ca", "ssl_capath"): if key in kw: self.kw[key] = kw.pop(key) @@ -154,7 +154,7 @@ def __init__(self, db, user, password='', host='localhost', port=0, **kw): elif driver == 'mariadb': self.kw.pop("charset", None) - elif driver == 'connector': + elif driver in ('connector', 'connector-python'): registerConverter(bytes, ConnectorBytesConverter) global mysql_Bin @@ -185,7 +185,7 @@ def makeConnection(self): def character_set_name(self): return dbEncoding + '_' + dbEncoding Connection.character_set_name = character_set_name - if self.driver == 'connector': + if self.driver in ('connector', 'connector-python'): self.kw['consume_results'] = True try: if self.driver in ('odbc', 'pyodbc', 'pypyodbc'): @@ -237,7 +237,7 @@ def _setAutoCommit(self, conn, auto): try: conn.autocommit(auto) except TypeError: - # mysql-connector has autocommit as a property + # mysql-connector{-python} has autocommit as a property conn.autocommit = auto def _force_reconnect(self, conn): @@ -252,7 +252,8 @@ def _executeRetry(self, conn, cursor, query): self.printDebug(conn, query, 'QueryR') dbEncoding = self.dbEncoding if dbEncoding and not isinstance(query, bytes) and ( - self.driver in ('mysqldb', 'connector', 'oursql', 'mariadb')): + self.driver in ('mysqldb', 'connector', 'connector-python', + 'oursql', 'mariadb')): query = query.encode(dbEncoding, 'surrogateescape') # When a server connection is lost and a query is attempted, most of # the time the query will raise a SERVER_LOST exception, then at the diff --git a/tox.ini b/tox.ini index 81df7f69..9d1bd95f 100644 --- a/tox.ini +++ b/tox.ini @@ -19,6 +19,7 @@ deps = mysqldb: mysql-python mysqlclient: mysqlclient mysql-connector: mysql-connector <= 2.2.2 + mysql-connector-python: -rdevscripts/requirements/requirements_connector_python.txt mysql-oursql: git+https://github.com/sqlobject/oursql.git@master#egg=oursql mysql-oursql3: git+https://github.com/sqlobject/oursql.git@py3k#egg=oursql pymysql: -rdevscripts/requirements/requirements_pymysql.txt @@ -97,6 +98,22 @@ commands = [testenv:py3{4,5,6,7,8,9,10,11}-mysql-connector] commands = {[mysql-connector]commands} +[mysql-connector-python] +commands = + {[testenv]commands} + -mysql --execute="drop database sqlobject_test;" + mysql --execute="create database sqlobject_test;" + pytest -D "mysql://runner:@localhost/sqlobject_test?driver=connector-python&charset=utf8&debug=1" + mysql --execute="drop database sqlobject_test;" + +[testenv:py27-mysql-connector-python{,-w32}] +commands = + easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base + {[mysql-connector-python]commands} + +[testenv:py3{4,5,6,7,8,9,10,11}-mysql-connector-python{,-w32}] +commands = {[mysql-connector-python]commands} + [oursql] commands = {[testenv]commands} From 4927a0677762005a794862e940209b7046ea695d Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 4 Dec 2022 20:55:57 +0300 Subject: [PATCH 379/509] Fix(dbconnection): autocommit value must be bool --- sqlobject/dbconnection.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sqlobject/dbconnection.py b/sqlobject/dbconnection.py index 6a383e79..e691f2d4 100644 --- a/sqlobject/dbconnection.py +++ b/sqlobject/dbconnection.py @@ -799,7 +799,7 @@ def __init__(self, dbConnection): self._obsolete = True self._dbConnection = dbConnection self._connection = dbConnection.getConnection() - self._dbConnection._setAutoCommit(self._connection, 0) + self._dbConnection._setAutoCommit(self._connection, False) self.cache = CacheSet(cache=dbConnection.doCache) self._deletedCache = {} self._obsolete = False @@ -924,7 +924,7 @@ def __getattr__(self, attr): def _makeObsolete(self): self._obsolete = True if self._dbConnection.autoCommit: - self._dbConnection._setAutoCommit(self._connection, 1) + self._dbConnection._setAutoCommit(self._connection, True) self._dbConnection.releaseConnection(self._connection, explicit=True) self._connection = None @@ -938,7 +938,7 @@ def begin(self): "without rolling back this one" self._obsolete = False self._connection = self._dbConnection.getConnection() - self._dbConnection._setAutoCommit(self._connection, 0) + self._dbConnection._setAutoCommit(self._connection, False) def __del__(self): if self._obsolete: From 8b1204c5983ded07f95a20db96553de7d9d9f431 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 4 Dec 2022 20:56:57 +0300 Subject: [PATCH 380/509] Tests: Allow transactions with MySQL MySQL (mostly MariaDB these days) enabled transactions by default long ago. --- sqlobject/tests/dbtest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlobject/tests/dbtest.py b/sqlobject/tests/dbtest.py index c7c8b0ea..e934ac51 100644 --- a/sqlobject/tests/dbtest.py +++ b/sqlobject/tests/dbtest.py @@ -43,7 +43,7 @@ def test_featureX(): '+memorydb': 'sqlite', '+rlike': 'mysql postgres sqlite', '+schema': 'postgres', - '-transactions': 'mysql', + '-transactions': ' ', } From 613839ed6f4948b1504f762d1622a987cdce0407 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 4 Dec 2022 20:58:15 +0300 Subject: [PATCH 381/509] Tests: Skip some inheritance tests under `mysql-connector-python` M-C-P falls into an infinite loop. --- .../inheritance/tests/test_deep_inheritance.py | 6 +++++- sqlobject/inheritance/tests/test_inheritance.py | 16 +++++++++++++++- .../inheritance/tests/test_inheritance_tree.py | 8 +++++++- sqlobject/mysql/mysqlconnection.py | 4 ++++ 4 files changed, 31 insertions(+), 3 deletions(-) diff --git a/sqlobject/inheritance/tests/test_deep_inheritance.py b/sqlobject/inheritance/tests/test_deep_inheritance.py index 1ef4d36f..4bdc8e34 100644 --- a/sqlobject/inheritance/tests/test_deep_inheritance.py +++ b/sqlobject/inheritance/tests/test_deep_inheritance.py @@ -72,6 +72,11 @@ def test_creation_fail2(): def test_deep_inheritance(): + conn = getConnection() + if conn.module.__name__ == 'mysql.connector' \ + and conn.connector_type == 'mysql.connector-python': + skip("connector-python falls into an infinite loop here") + setupClass([DIManager, DIEmployee, DIPerson]) manager = DIManager(firstName='Project', lastName='Manager', @@ -81,7 +86,6 @@ def test_deep_inheritance(): so_position='Project leader', manager=manager).id DIPerson(firstName='Oneof', lastName='Authors', manager=manager) - conn = getConnection() cache = conn.cache cache.clear() diff --git a/sqlobject/inheritance/tests/test_inheritance.py b/sqlobject/inheritance/tests/test_inheritance.py index cc26c8f5..2dfd0e3a 100644 --- a/sqlobject/inheritance/tests/test_inheritance.py +++ b/sqlobject/inheritance/tests/test_inheritance.py @@ -1,7 +1,21 @@ +import pytest from pytest import raises from sqlobject import IntCol, StringCol from sqlobject.inheritance import InheritableSQLObject -from sqlobject.tests.dbtest import setupClass +from sqlobject.tests.dbtest import getConnection, setupClass + + +try: + connection = getConnection() +except (AttributeError, NameError): + # The module was imported during documentation building + pass +else: + if connection.module.__name__ == 'mysql.connector' \ + and connection.connector_type == 'mysql.connector-python': + pytestmark = pytest.mark.skip( + "connector-python falls into an infinite loop here") + ######################################## # Inheritance diff --git a/sqlobject/inheritance/tests/test_inheritance_tree.py b/sqlobject/inheritance/tests/test_inheritance_tree.py index 58cdb7ea..34666c38 100644 --- a/sqlobject/inheritance/tests/test_inheritance_tree.py +++ b/sqlobject/inheritance/tests/test_inheritance_tree.py @@ -1,6 +1,7 @@ +from pytest import skip from sqlobject import StringCol from sqlobject.inheritance import InheritableSQLObject -from sqlobject.tests.dbtest import setupClass +from sqlobject.tests.dbtest import getConnection, setupClass ######################################## # Inheritance Tree @@ -28,6 +29,11 @@ class Tree5(Tree2): def test_tree(): + conn = getConnection() + if conn.module.__name__ == 'mysql.connector' \ + and conn.connector_type == 'mysql.connector-python': + skip("connector-python falls into an infinite loop here") + setupClass([Tree1, Tree2, Tree3, Tree4, Tree5]) Tree1(aprop='t1') # t1 diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index ac3e0629..76b11724 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -67,6 +67,10 @@ def __init__(self, db, user, password='', host='localhost', port=0, **kw): self.CR_SERVER_LOST = \ mysql.connector.errorcode.CR_SERVER_LOST self.ER_DUP_ENTRY = mysql.connector.errorcode.ER_DUP_ENTRY + if driver == 'connector-python': + self.connector_type = 'mysql.connector-python' + else: + self.connector_type = 'mysql.connector' elif driver == 'oursql': import oursql self.module = oursql From eeb61ea9059372d005cd5fe3398f0d73b827bd0f Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 4 Dec 2022 21:01:09 +0300 Subject: [PATCH 382/509] Tests(mysql-connector-python): Limit versions Versions 8.0.30+ require charset `utf8mb4` on the server which is not available on old MySQL and MariaDB servers. --- .../requirements/requirements_connector_python.txt | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/devscripts/requirements/requirements_connector_python.txt b/devscripts/requirements/requirements_connector_python.txt index d06b1911..e4bffe7a 100644 --- a/devscripts/requirements/requirements_connector_python.txt +++ b/devscripts/requirements/requirements_connector_python.txt @@ -3,8 +3,9 @@ protobuf < 3.19; python_version == '3.4' mysql-connector-python <= 8.0.22, > 2.0; python_version == '3.4' mysql-connector-python <= 8.0.23, >= 8.0.5; python_version == '3.5' mysql-connector-python <= 8.0.28, >= 8.0.6; python_version == '3.6' -mysql-connector-python >= 8.0.13; python_version == '3.7' -mysql-connector-python >= 8.0.19; python_version == '3.8' -mysql-connector-python >= 8.0.24; python_version == '3.9' -mysql-connector-python >= 8.0.28; python_version == '3.10' -mysql-connector-python >= 8.0.31; python_version >= '3.11' +mysql-connector-python <= 8.0.29, >= 8.0.13; python_version == '3.7' +mysql-connector-python <= 8.0.29, >= 8.0.19; python_version == '3.8' +mysql-connector-python <= 8.0.29, >= 8.0.24; python_version == '3.9' +mysql-connector-python <= 8.0.29, >= 8.0.28; python_version == '3.10' +#mysql-connector-python >= 8.0.31; python_version >= '3.11' +mysql-connector-python == 8.0.29; python_version >= '3.11' From d85fd1c45bc700cd1233afb34d124c75be538847 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 16 Dec 2022 00:30:41 +0300 Subject: [PATCH 383/509] CI(GHActions): More descriptive step names Add OS name. --- .github/workflows/run-tests.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index bc676984..31b170bc 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -27,11 +27,11 @@ jobs: # Setup PostgreSQL - uses: ankane/setup-postgres@v1 - - name: Setup Postgres user + - name: Setup Postgres user @ Linux run: | sudo -u postgres psql --command="ALTER USER runner CREATEDB ENCRYPTED PASSWORD 'test'" if: ${{ runner.os == 'Linux' }} - - name: Setup Postgres user + - name: Setup Postgres user @ w32 run: | psql --command="CREATE USER runner CREATEDB ENCRYPTED PASSWORD 'test'" if: ${{ runner.os == 'Windows' }} From bd1459096795e5ce5f4c31c2ce10955aba44fac1 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 22 Dec 2022 19:18:57 +0300 Subject: [PATCH 384/509] Build(RELEASE-CHECKLIST): Minor update [skip ci] --- devscripts/RELEASE-CHECKLIST | 48 ++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/devscripts/RELEASE-CHECKLIST b/devscripts/RELEASE-CHECKLIST index f47ec418..91d47036 100644 --- a/devscripts/RELEASE-CHECKLIST +++ b/devscripts/RELEASE-CHECKLIST @@ -1,54 +1,48 @@ 0. Run full test suite in all branches and in master. Continue if all tests passed. -1. Check out the release branch. If it is a stable release - edit - docs/News.rst to set release date. Commit. - -2. If release branch is not master - run devscripts/prerelease $NEW_TAG; if +1. If release branch is not master - run devscripts/prerelease $NEW_TAG; if it's master - run devscripts/prerelease $NEW_TAG master. - The script checks out the release branch and calls editor; update - version, the list of contributors, the list of changes and download - URL in ANNOUNCE.rst; edit __version__.py and README.rst in the release - branch - fix versions. Edit section [egg_info] in setup.cfg - set if - it is a stable or development release. In setup.py edit "Development - Status" in trove classifiers; edit download URLs: if a non-stable - version - append 'dev' and date stamp, for a stable version remove - 'dev' and date stamp). - - If it's the first stable release of the branch - edit build-all-docs, - advance stable branch. - - Commit. Verify. + The script checks out the release branch and calls editor; if it's the + first stable release of the branch - edit build-all-docs, advance stable + branch; if it is a stable release - edit docs/News.rst to set release + date; update version, the list of contributors, the list of changes and + download URL in ANNOUNCE.rst; edit __version__.py and README.rst in the + release branch - fix versions. Edit section [egg_info] in setup.cfg - + set if it is a stable or development release. In setup.py edit + "Development Status" in trove classifiers; edit download URLs: if a + non-stable version - append 'dev' and date stamp, for a stable version + remove 'dev' and date stamp). Commit. Verify. -3. If it's not master - null-merge to the next higher branch. +2. If it's not master - null-merge to the next higher branch. -4. If release branch is not master - run devscripts/prerelease-tag +3. If release branch is not master - run devscripts/prerelease-tag $NEW_TAG; if it's master - run devscripts/prerelease-tag $NEW_TAG master. This checks out the release branch and creates the new tag at the head of the release branch. -5. Run devscripts/release. This generates and uploads new archives to PyPI +4. Run devscripts/release. This generates and uploads new archives to PyPI and if it is a stable release - uploads archives and release announcement (ANNOUNCE.rst) to SourceForge. -6. Move old releases at SourceForge to subdirectory OldFiles. +5. Move old releases at SourceForge to subdirectory OldFiles. -7. Run devscripts/postrelease. The script restores ANNOUNCE.rst and +6. Run devscripts/postrelease. The script restores ANNOUNCE.rst and setup.cfg from the previous commit (HEAD~). It calls editor; update next version, remove the list of contributors and the list of changes, edit download URL in ANNOUNCE.rst. Edit README.rst and docs/News.rst - add new version. -8. Run devscripts/push-all in the development repository to push all +7. Run devscripts/push-all in the development repository to push all branches and tags to the public repositories. -9. Generate new docs using devscripts/build-all-docs. Upload docs using +8. Generate new docs using devscripts/build-all-docs. Upload docs using devscripts/publish-docs. -10. Send announcement to the SQLObject mailing list. For a stable - release send announcements to python, python-announce and python-db - mailing lists. +9. Send announcement to the SQLObject mailing list. For a stable + release send announcements to python, python-announce and python-db + mailing lists. 10. Announce new release(s) at Twitter (https://twitter.com/SQLObject) and Wikipedia (https://en.wikipedia.org/wiki/SQLObject). If it is a stable From 5347ce559a2dc11f4ca190e5291b22e0b5beecbb Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 22 Dec 2022 19:22:18 +0300 Subject: [PATCH 385/509] Release 3.10.1 --- ANNOUNCE.rst | 37 +++++++++++++++++++++++-------------- README.rst | 4 ++-- devscripts/build-all-docs | 2 +- docs/News.rst | 4 ++-- sqlobject/__version__.py | 4 ++-- 5 files changed, 30 insertions(+), 21 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 40828217..8f84a2dc 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,25 +1,34 @@ Hello! -I'm pleased to announce version 3.10.1a1, the first alpha of the upcoming -release of branch 3.10 of SQLObject. +I'm pleased to announce version 3.10.1, the first minor feature release of +branch 3.10 of SQLObject. -I'm pleased to announce version 3.10.1a2, the second alpha of the upcoming -release of branch 3.10 of SQLObject. -I'm pleased to announce version 3.10.1b1, the first beta of the upcoming -release of branch 3.10 of SQLObject. +What's new in SQLObject +======================= -I'm pleased to announce version 3.10.1rc1, the first release candidate -of the upcoming release of branch 3.10 of SQLObject. +Minor features +-------------- -I'm pleased to announce version 3.10.1, the first bugfix release of branch -3.10 of SQLObject. +* Use ``module_loader.exec_module(module_loader.create_module())`` + instead of ``module_loader.load_module()`` when available. +Drivers +------- -What's new in SQLObject -======================= +* Added ``mysql-connector-python``. + +Tests +----- + +* Run tests with Python 3.11. + +CI +-- -Contributors for this release are +* Ubuntu >= 22 and ``setup-python`` dropped Pythons < 3.7. + Use ``conda`` via ``s-weigand/setup-conda`` instead of ``setup-python`` + to install older Pythons on Linux. For a more complete list, please see the news: http://sqlobject.org/News.html @@ -51,7 +60,7 @@ Site: http://sqlobject.org Download: -https://pypi.org/project/SQLObject/3.10.1a0.dev20221020/ +https://pypi.org/project/SQLObject/3.10.1 News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 8c310399..8fb170f0 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.10.1a0 -================== +SQLObject 3.10.1 +================ SQLObject is a free and open-source (LGPL) Python object-relational mapper. Your database tables are described as classes, and rows are diff --git a/devscripts/build-all-docs b/devscripts/build-all-docs index 8942edb7..8da2c52b 100755 --- a/devscripts/build-all-docs +++ b/devscripts/build-all-docs @@ -10,7 +10,7 @@ cd "`dirname \"$0\"`" && PROG_DIR="`pwd`" && cd .. && -build_docs 3.10.0 && +build_docs 3.10.1 && build_docs master devel && rm -rf docs/html && diff --git a/docs/News.rst b/docs/News.rst index c9d65c90..68b43687 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,8 +5,8 @@ News .. contents:: Contents: :backlinks: none -SQLObject (master) -================== +SQLObject 3.10.1 +================ Minor features -------------- diff --git a/sqlobject/__version__.py b/sqlobject/__version__.py index e01c255e..7753d960 100644 --- a/sqlobject/__version__.py +++ b/sqlobject/__version__.py @@ -1,8 +1,8 @@ -version = '3.10.0' +version = '3.10.1' major = 3 minor = 10 -micro = 0 +micro = 1 release_level = 'final' serial = 0 version_info = (major, minor, micro, release_level, serial) From 1d0f1bc72a475ce82fac0b1c701b77bcd1e51d3e Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 22 Dec 2022 19:29:48 +0300 Subject: [PATCH 386/509] Build: Prepare for the next release [skip ci] --- ANNOUNCE.rst | 37 ++++++++++++++----------------------- README.rst | 4 ++-- docs/News.rst | 3 +++ 3 files changed, 19 insertions(+), 25 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 8f84a2dc..0040aed7 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,34 +1,25 @@ Hello! -I'm pleased to announce version 3.10.1, the first minor feature release of -branch 3.10 of SQLObject. +I'm pleased to announce version 3.10.2a1, the first alpha of the upcoming +release of branch 3.10 of SQLObject. +I'm pleased to announce version 3.10.2a2, the second alpha of the upcoming +release of branch 3.10 of SQLObject. -What's new in SQLObject -======================= - -Minor features --------------- - -* Use ``module_loader.exec_module(module_loader.create_module())`` - instead of ``module_loader.load_module()`` when available. +I'm pleased to announce version 3.10.2b1, the first beta of the upcoming +release of branch 3.10 of SQLObject. -Drivers -------- +I'm pleased to announce version 3.10.2rc1, the first release candidate +of the upcoming release of branch 3.10 of SQLObject. -* Added ``mysql-connector-python``. +I'm pleased to announce version 3.10.2, the first bugfix release of branch +3.10 of SQLObject. -Tests ------ -* Run tests with Python 3.11. - -CI --- +What's new in SQLObject +======================= -* Ubuntu >= 22 and ``setup-python`` dropped Pythons < 3.7. - Use ``conda`` via ``s-weigand/setup-conda`` instead of ``setup-python`` - to install older Pythons on Linux. +Contributors for this release are For a more complete list, please see the news: http://sqlobject.org/News.html @@ -60,7 +51,7 @@ Site: http://sqlobject.org Download: -https://pypi.org/project/SQLObject/3.10.1 +https://pypi.org/project/SQLObject/3.10.2a0.dev20221222/ News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 8fb170f0..3896cef6 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.10.1 -================ +SQLObject 3.10.2a0 +================== SQLObject is a free and open-source (LGPL) Python object-relational mapper. Your database tables are described as classes, and rows are diff --git a/docs/News.rst b/docs/News.rst index 68b43687..36c0229d 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,6 +5,9 @@ News .. contents:: Contents: :backlinks: none +SQLObject (master) +================== + SQLObject 3.10.1 ================ From 8872b7924b98f15456edf9750a64e02b54da67dc Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 22 Dec 2022 19:18:57 +0300 Subject: [PATCH 387/509] Build(RELEASE-CHECKLIST): Minor update [skip ci] --- devscripts/RELEASE-CHECKLIST | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/devscripts/RELEASE-CHECKLIST b/devscripts/RELEASE-CHECKLIST index 91d47036..a7909b4f 100644 --- a/devscripts/RELEASE-CHECKLIST +++ b/devscripts/RELEASE-CHECKLIST @@ -24,27 +24,26 @@ 4. Run devscripts/release. This generates and uploads new archives to PyPI and if it is a stable release - uploads archives and release - announcement (ANNOUNCE.rst) to SourceForge. + announcement (ANNOUNCE.rst) to SourceForge. Move old releases at + SourceForge to subdirectory OldFiles. -5. Move old releases at SourceForge to subdirectory OldFiles. - -6. Run devscripts/postrelease. The script restores ANNOUNCE.rst and +5. Run devscripts/postrelease. The script restores ANNOUNCE.rst and setup.cfg from the previous commit (HEAD~). It calls editor; update next version, remove the list of contributors and the list of changes, edit download URL in ANNOUNCE.rst. Edit README.rst and docs/News.rst - add new version. -7. Run devscripts/push-all in the development repository to push all +6. Run devscripts/push-all in the development repository to push all branches and tags to the public repositories. -8. Generate new docs using devscripts/build-all-docs. Upload docs using +7. Generate new docs using devscripts/build-all-docs. Upload docs using devscripts/publish-docs. -9. Send announcement to the SQLObject mailing list. For a stable +8. Send announcement to the SQLObject mailing list. For a stable release send announcements to python, python-announce and python-db mailing lists. -10. Announce new release(s) at Twitter (https://twitter.com/SQLObject) and - Wikipedia (https://en.wikipedia.org/wiki/SQLObject). If it is a stable - release - announce it at - https://en.wikipedia.org/wiki/Comparison_of_object-relational_mapping_software. +9. Announce new release(s) at Twitter (https://twitter.com/SQLObject) and + Wikipedia (https://en.wikipedia.org/wiki/SQLObject). If it is a stable + release - announce it at + https://en.wikipedia.org/wiki/Comparison_of_object-relational_mapping_software. From f089c78127c7631fe8f4258487d377f4b4bcde68 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 26 Dec 2022 20:02:09 +0300 Subject: [PATCH 388/509] Docs(News): Split `News.rst` [skip ci] --- docs/News.rst | 549 +---------------------------------------------- docs/News6.rst | 566 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 567 insertions(+), 548 deletions(-) create mode 100644 docs/News6.rst diff --git a/docs/News.rst b/docs/News.rst index 36c0229d..a0ebdf7f 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -78,557 +78,10 @@ Documentation * DevGuide: commit messages must be pure ASCII. -SQLObject 3.9.1 -=============== - -Released 2021 Feb 27. - -Drivers -------- - -* Adapt to the latest ``pg8000``. - -* Protect ``getuser()`` - it can raise ``ImportError`` on w32 - due to absent of ``pwd`` module. - -Build ------ - -* Change URLs for ``oursql`` in ``extras_require`` in ``setup.py``. - Provide separate URLs for Python 2.7 and 3.4+. - -* Add ``mariadb`` in ``extras_require`` in ``setup.py``. - -CI --- - -* For tests with Python 3.4 run ``tox`` under Python 3.5. - -Tests ------ - -* Refactor ``tox.ini``. - -SQLObject 3.9.0 -=============== - -Released 2020 Dec 15. - -Features --------- - -* Add ``JSONCol``: a universal json column that converts simple Python objects - (None, bool, int, float, long, dict, list, str/unicode to/from JSON using - json.dumps/loads. A subclass of StringCol. Requires ``VARCHAR``/``TEXT`` - columns at backends, doesn't work with ``JSON`` columns. - -* Extend/fix support for ``DateTime`` from ``Zope``. - -* Drop support for very old version of ``mxDateTime`` - without ``mx.`` namespace. - -Drivers -------- - -* Support `mariadb `_. - -CI --- - -* Run tests with Python 3.9 at Travis and AppVeyor. - -SQLObject 3.8.1 -=============== - -Released 2020 Oct 01. - -Documentation -------------- - -* Use conf.py options to exclude sqlmeta options. - -Tests ------ - -* Fix ``PyGreSQL`` version for Python 3.4. - -CI --- - -* Run tests with Python 3.8 at AppVeyor. - -SQLObject 3.8.0 -=============== - -Released 7 Dec 2019. - -Features --------- - -* Add driver ``supersqlite``. Not all tests are passing - so the driver isn't added to the list of default drivers. - -Minor features --------------- - -* Improve sqlrepr'ing ``ALL/ANY/SOME()``: always put the expression - at the right side of the comparison operation. - -Bug fixes ---------- - -* Fixed a bug in cascade deletion/nullification. - -* Fixed a bug in ``PostgresConnection.columnsFromSchema``: - PostgreSQL 12 removed outdated catalog attribute - ``pg_catalog.pg_attrdef.adsrc``. - -* Fixed a bug working with microseconds in Time columns. - -CI --- - -* Run tests with Python 3.8 at Travis CI. - -SQLObject 3.7.3 -=============== - -Released 22 Sep 2019. - -Bug fixes ---------- - -* Avoid excessive parentheses around ``ALL/ANY/SOME()``. - -Tests ------ - -* Add tests for cascade deletion. - -* Add tests for ``sqlbuilder.ALL/ANY/SOME()``. - -* Fix calls to ``pytest.mark.skipif`` - make conditions bool instead of str. - -* Fix module-level calls to ``pytest.mark.skip`` - add reasons. - -* Fix escape sequences ``'\%'`` -> ``'\\%'``. - -CI --- - -* Reduce the number of virtual machines/containers: - one OS, one DB, one python version, many drivers per VM. - -* Fix sqlite test under Python 3.7+ at AppVeyor. - -SQLObject 3.7.2 -=============== - -Released 1 May 2019. - -Minor features --------------- - -* Adapt Postgres exception handling to ``psycopg2`` version ``2.8``: - in the recent ``psycopg2`` errors are in ``psycopg2.errors`` module. - -* Removed RdbhostConnection: David Keeney and rdbhost seem to be unavailable - since 2017. - -SQLObject 3.7.1 -=============== - -Released 2 Feb 2019. - -Bug fixes ---------- - -* Fixed a unicode problem in the latest mysqlclient. - -Documentation -------------- - -* Exclude sqlmeta members from some of the api docs. - The inclusion of of these sqlmeta members in these files breaks - reproducible builds. - -Development ------------ - -* Source code was made flake8-clean using the latest flake8. - -CI --- - -* Run tests with Python 3.7. - -SQLObject 3.7.0 -=============== - -Released 6 June 2018. - -Features --------- - -* Add signals on commit and rollback; pull request by Scott Stahl. - -Bug fixes ---------- - -* Fix SSL-related parameters for MySQL-connector (connector uses - a different param style). Bug reported by Christophe Popov. - -Drivers -------- - -* Remove psycopg1. Driver ``psycopg`` is now just an alias for ``psycopg2``. - -Tests ------ - -* Install psycopg2 from `psycopg2-binary`_ package. - -.. _`psycopg2-binary`: https://pypi.org/project/psycopg2-binary/ - -SQLObject 3.6.0 -=============== - -Released 24 Feb 2018. - -Minor features --------------- - -* Close cursors after using to free resources immediately - instead of waiting for gc. - -Bug fixes ---------- - -* Fix for TypeError using selectBy on a BLOBCol. PR by Michael S. Root. - -Drivers -------- - -* Extend support for oursql and Python 3 (requires our fork of the driver). - -* Fix cursor.arraysize - pymssql doesn't have arraysize. - -* Set timeout for ODBC with MSSQL. - -* Fix _setAutoCommit for MSSQL. - -Documentation -------------- - -* Document extras that are available for installation. - -Build ------ - -* Use ``python_version`` environment marker in ``setup.py`` to make - ``install_requires`` and ``extras_require`` declarative. This makes - the universal wheel truly universal. - -* Use ``python_requires`` keyword in ``setup.py``. - -SQLObject 3.5.0 -=============== - -Released 15 Nov 2017. - -Minor features --------------- - -* Add Python3 special methods for division to SQLExpression. - Pull request by Michael S. Root. - -Drivers -------- - -* Add support for `pg8000 `_ - PostgreSQL driver. - -* Fix autoreconnect with pymysql driver. Contributed by Shailesh Mungikar. - -Documentation -------------- - -* Remove generated HTML from eggs/wheels (docs are installed into wrong - place). Generated docs are still included in the source distribution. - -Tests ------ - -* Add tests for PyGreSQL, py-postgresql and pg8000 at AppVeyor. - -* Fixed bugs in py-postgresql at AppVeyor. SQLObject requires - the latest version of the driver from our fork. - -SQLObject 3.4.0 -=============== - -Released 5 Aug 2017. - -Features --------- - -* Python 2.6 is no longer supported. The minimal supported version is - Python 2.7. - -Drivers (work in progress) --------------------------- - -* Encode binary values for py-postgresql driver. This fixes the - last remaining problems with the driver. - -* Encode binary values for PyGreSQL driver using the same encoding as for - py-postgresql driver. This fixes the last remaining problems with the driver. - - Our own encoding is needed because unescape_bytea(escape_bytea()) is not - idempotent. See the comment for PQunescapeBytea at - https://www.postgresql.org/docs/9.6/static/libpq-exec.html: - - This conversion is not exactly the inverse of PQescapeBytea, because the - string is not expected to be "escaped" when received from PQgetvalue. In - particular this means there is no need for string quoting considerations. - -* List all drivers in extras_require in setup.py. - -Minor features --------------- - -* Use base64.b64encode/b64decode instead of deprecated - encodestring/decodestring. - -Tests ------ - -* Fix a bug with sqlite-memory: rollback transaction and close connection. - The solution was found by Dr. Neil Muller. - -* Use remove-old-files.py from ppu to cleanup pip cache - at Travis and AppVeyor. - -* Add test_csvimport.py more as an example how to use load_csv - from sqlobject.util.csvimport. - -SQLObject 3.3.0 -=============== - -Released 7 May 2017. - -Features --------- - -* Support for Python 2.6 is declared obsolete and will be removed - in the next release. - -Minor features --------------- - -* Convert scripts repository to devscripts subdirectory. - Some of thses scripts are version-dependent so it's better to have them - in the main repo. - -* Test for __nonzero__ under Python 2, __bool__ under Python 3 in BoolCol. - -Drivers (work in progress) --------------------------- - -* Add support for PyODBC and PyPyODBC (pure-python ODBC DB API driver) for - MySQL, PostgreSQL and MS SQL. Driver names are ``pyodbc``, ``pypyodbc`` - or ``odbc`` (try ``pyodbc`` and ``pypyodbc``). There are some problems - with pyodbc and many problems with pypyodbc. - -Documentation -------------- - -* Stop updating http://sqlobject.readthedocs.org/ - it's enough to have - http://sqlobject.org/ - -Tests ------ - -* Run tests at Travis CI and AppVeyor with Python 3.6, x86 and x64. - -* Stop running tests at Travis with Python 2.6. - -* Stop running tests at AppVeyor with pymssql - too many timeouts and - problems. - -SQLObject 3.2.0 -=============== - -Released 11 Mar 2017. - -Minor features --------------- - -* Drop table name from ``VACUUM`` command in SQLiteConnection: SQLite - doesn't vacuum a single table and SQLite 3.15 uses the supplied name as - the name of the attached database to vacuum. - -* Remove ``driver`` keyword from RdbhostConnection as it allows one driver - ``rdbhdb``. - -* Add ``driver`` keyword for FirebirdConnection. Allowed values are 'fdb', - 'kinterbasdb' and 'pyfirebirdsql'. Default is to test 'fdb' and - 'kinterbasdb' in that order. pyfirebirdsql is supported but has problems. - -* Add ``driver`` keyword for MySQLConnection. Allowed values are 'mysqldb', - 'connector', 'connector-python', 'oursql' and 'pymysql'. Default is to - test for mysqldb only. - -* Add support for `MySQL Connector - `_ (pure python; `binary - packages `_ are not at - PyPI and hence are hard to install and test). - -* Add support for `oursql `_ MySQL - driver (only Python 2.6 and 2.7 until oursql author fixes Python 3 - compatibility). - -* Add support for `PyMySQL `_ - pure - python mysql interface). - -* Add parameter ``timeout`` for MSSQLConnection (usable only with pymssql - driver); timeouts are in seconds. - -* Remove deprecated ez_setup.py. - -Drivers (work in progress) --------------------------- - -* Extend support for PyGreSQL driver. There are still some problems. - -* Add support for `py-postgresql - `_ PostgreSQL driver. There - are still problems with the driver. - -* Add support for `pyfirebirdsql - `_.There are still problems with - the driver. - -Bug fixes ---------- - -* Fix MSSQLConnection.columnsFromSchema: remove `(` and `)` from default - value. - -* Fix MSSQLConnection and SybaseConnection: insert default values into a table - with just one IDENTITY column. - -* Remove excessive NULLs from ``CREATE TABLE`` for MSSQL/Sybase. - -* Fix concatenation operator for MSSQL/Sybase (it's ``+``, not ``||``). - -* Fix MSSQLConnection.server_version() under Py3 (decode version to str). - -Documentation -------------- - -* The docs are now generated with Sphinx. - -* Move ``docs/LICENSE`` to the top-level directory so that Github - recognizes it. - -Tests ------ - -* Rename ``py.test`` -> ``pytest`` in tests and docs. - -* Great Renaming: fix ``pytest`` warnings by renaming ``TestXXX`` classes - to ``SOTestXXX`` to prevent ``pytest`` to recognize them as test classes. - -* Fix ``pytest`` warnings by converting yield tests to plain calls: yield - tests were deprecated in ``pytest``. - -* Tests are now run at CIs with Python 3.5. - -* Drop ``Circle CI``. - -* Run at Travis CI tests with Firebird backend (server version 2.5; - drivers fdb and firebirdsql). There are problems with tests. - -* Run tests at AppVeyor for windows testing. Run tests with MS SQL, - MySQL, Postgres and SQLite backends; use Python 2.7, 3.4 and 3.5, - x86 and x64. There are problems with MS SQL and MySQL. - -SQLObject 3.1.0 -=============== - -Released 16 Aug 2016. - -Features --------- - -* Add UuidCol. - -* Add JsonbCol. Only for PostgreSQL. - Requires psycopg2 >= 2.5.4 and PostgreSQL >= 9.2. - -* Add JSONCol, a universal json column. - -* For Python >= 3.4 minimal FormEncode version is now 1.3.1. - -* If mxDateTime is in use, convert timedelta (returned by MySQL) to - mxDateTime.Time. - -Documentation -------------- - -* Developer's Guide is extended to explain SQLObject architecture - and how to create a new column type. - -* Fix URLs that can be found; remove missing links. - -* Rename reStructuredText files from \*.txt to \*.rst. - -Source code ------------ - -* Fix all `import *` using https://github.com/zestyping/star-destroyer. - -Tests ------ - -* Tests are now run at Circle CI. - -* Use pytest-cov for test coverage. Report test coverage - via coveralls.io and codecov.io. - -* Install mxDateTime to run date/time tests with it. - -SQLObject 3.0.0 -=============== - -Released 1 Jun 2016. - -Features --------- - -* Support for Python 2 and Python 3 with one codebase! - (Python version >= 3.4 currently required.) - -Minor features --------------- - -* PyDispatcher (>=2.0.4) was made an external dependency. - -Development ------------ - -* Source code was made flake8-clean. - -Documentation -------------- - -* Documentation is published at http://sqlobject.readthedocs.org/ in - Sphinx format. `Older news`__ -.. __: News5.html +.. __: News6.html .. image:: https://sourceforge.net/sflogo.php?group_id=74338&type=10 :target: https://sourceforge.net/projects/sqlobject diff --git a/docs/News6.rst b/docs/News6.rst new file mode 100644 index 00000000..313c62b3 --- /dev/null +++ b/docs/News6.rst @@ -0,0 +1,566 @@ +++++ +News +++++ + +.. contents:: Contents: + :backlinks: none + +SQLObject 3.9.1 +=============== + +Released 2021 Feb 27. + +Drivers +------- + +* Adapt to the latest ``pg8000``. + +* Protect ``getuser()`` - it can raise ``ImportError`` on w32 + due to absent of ``pwd`` module. + +Build +----- + +* Change URLs for ``oursql`` in ``extras_require`` in ``setup.py``. + Provide separate URLs for Python 2.7 and 3.4+. + +* Add ``mariadb`` in ``extras_require`` in ``setup.py``. + +CI +-- + +* For tests with Python 3.4 run ``tox`` under Python 3.5. + +Tests +----- + +* Refactor ``tox.ini``. + +SQLObject 3.9.0 +=============== + +Released 2020 Dec 15. + +Features +-------- + +* Add ``JSONCol``: a universal json column that converts simple Python objects + (None, bool, int, float, long, dict, list, str/unicode to/from JSON using + json.dumps/loads. A subclass of StringCol. Requires ``VARCHAR``/``TEXT`` + columns at backends, doesn't work with ``JSON`` columns. + +* Extend/fix support for ``DateTime`` from ``Zope``. + +* Drop support for very old version of ``mxDateTime`` + without ``mx.`` namespace. + +Drivers +------- + +* Support `mariadb `_. + +CI +-- + +* Run tests with Python 3.9 at Travis and AppVeyor. + +SQLObject 3.8.1 +=============== + +Released 2020 Oct 01. + +Documentation +------------- + +* Use conf.py options to exclude sqlmeta options. + +Tests +----- + +* Fix ``PyGreSQL`` version for Python 3.4. + +CI +-- + +* Run tests with Python 3.8 at AppVeyor. + +SQLObject 3.8.0 +=============== + +Released 7 Dec 2019. + +Features +-------- + +* Add driver ``supersqlite``. Not all tests are passing + so the driver isn't added to the list of default drivers. + +Minor features +-------------- + +* Improve sqlrepr'ing ``ALL/ANY/SOME()``: always put the expression + at the right side of the comparison operation. + +Bug fixes +--------- + +* Fixed a bug in cascade deletion/nullification. + +* Fixed a bug in ``PostgresConnection.columnsFromSchema``: + PostgreSQL 12 removed outdated catalog attribute + ``pg_catalog.pg_attrdef.adsrc``. + +* Fixed a bug working with microseconds in Time columns. + +CI +-- + +* Run tests with Python 3.8 at Travis CI. + +SQLObject 3.7.3 +=============== + +Released 22 Sep 2019. + +Bug fixes +--------- + +* Avoid excessive parentheses around ``ALL/ANY/SOME()``. + +Tests +----- + +* Add tests for cascade deletion. + +* Add tests for ``sqlbuilder.ALL/ANY/SOME()``. + +* Fix calls to ``pytest.mark.skipif`` - make conditions bool instead of str. + +* Fix module-level calls to ``pytest.mark.skip`` - add reasons. + +* Fix escape sequences ``'\%'`` -> ``'\\%'``. + +CI +-- + +* Reduce the number of virtual machines/containers: + one OS, one DB, one python version, many drivers per VM. + +* Fix sqlite test under Python 3.7+ at AppVeyor. + +SQLObject 3.7.2 +=============== + +Released 1 May 2019. + +Minor features +-------------- + +* Adapt Postgres exception handling to ``psycopg2`` version ``2.8``: + in the recent ``psycopg2`` errors are in ``psycopg2.errors`` module. + +* Removed RdbhostConnection: David Keeney and rdbhost seem to be unavailable + since 2017. + +SQLObject 3.7.1 +=============== + +Released 2 Feb 2019. + +Bug fixes +--------- + +* Fixed a unicode problem in the latest mysqlclient. + +Documentation +------------- + +* Exclude sqlmeta members from some of the api docs. + The inclusion of of these sqlmeta members in these files breaks + reproducible builds. + +Development +----------- + +* Source code was made flake8-clean using the latest flake8. + +CI +-- + +* Run tests with Python 3.7. + +SQLObject 3.7.0 +=============== + +Released 6 June 2018. + +Features +-------- + +* Add signals on commit and rollback; pull request by Scott Stahl. + +Bug fixes +--------- + +* Fix SSL-related parameters for MySQL-connector (connector uses + a different param style). Bug reported by Christophe Popov. + +Drivers +------- + +* Remove psycopg1. Driver ``psycopg`` is now just an alias for ``psycopg2``. + +Tests +----- + +* Install psycopg2 from `psycopg2-binary`_ package. + +.. _`psycopg2-binary`: https://pypi.org/project/psycopg2-binary/ + +SQLObject 3.6.0 +=============== + +Released 24 Feb 2018. + +Minor features +-------------- + +* Close cursors after using to free resources immediately + instead of waiting for gc. + +Bug fixes +--------- + +* Fix for TypeError using selectBy on a BLOBCol. PR by Michael S. Root. + +Drivers +------- + +* Extend support for oursql and Python 3 (requires our fork of the driver). + +* Fix cursor.arraysize - pymssql doesn't have arraysize. + +* Set timeout for ODBC with MSSQL. + +* Fix _setAutoCommit for MSSQL. + +Documentation +------------- + +* Document extras that are available for installation. + +Build +----- + +* Use ``python_version`` environment marker in ``setup.py`` to make + ``install_requires`` and ``extras_require`` declarative. This makes + the universal wheel truly universal. + +* Use ``python_requires`` keyword in ``setup.py``. + +SQLObject 3.5.0 +=============== + +Released 15 Nov 2017. + +Minor features +-------------- + +* Add Python3 special methods for division to SQLExpression. + Pull request by Michael S. Root. + +Drivers +------- + +* Add support for `pg8000 `_ + PostgreSQL driver. + +* Fix autoreconnect with pymysql driver. Contributed by Shailesh Mungikar. + +Documentation +------------- + +* Remove generated HTML from eggs/wheels (docs are installed into wrong + place). Generated docs are still included in the source distribution. + +Tests +----- + +* Add tests for PyGreSQL, py-postgresql and pg8000 at AppVeyor. + +* Fixed bugs in py-postgresql at AppVeyor. SQLObject requires + the latest version of the driver from our fork. + +SQLObject 3.4.0 +=============== + +Released 5 Aug 2017. + +Features +-------- + +* Python 2.6 is no longer supported. The minimal supported version is + Python 2.7. + +Drivers (work in progress) +-------------------------- + +* Encode binary values for py-postgresql driver. This fixes the + last remaining problems with the driver. + +* Encode binary values for PyGreSQL driver using the same encoding as for + py-postgresql driver. This fixes the last remaining problems with the driver. + + Our own encoding is needed because unescape_bytea(escape_bytea()) is not + idempotent. See the comment for PQunescapeBytea at + https://www.postgresql.org/docs/9.6/static/libpq-exec.html: + + This conversion is not exactly the inverse of PQescapeBytea, because the + string is not expected to be "escaped" when received from PQgetvalue. In + particular this means there is no need for string quoting considerations. + +* List all drivers in extras_require in setup.py. + +Minor features +-------------- + +* Use base64.b64encode/b64decode instead of deprecated + encodestring/decodestring. + +Tests +----- + +* Fix a bug with sqlite-memory: rollback transaction and close connection. + The solution was found by Dr. Neil Muller. + +* Use remove-old-files.py from ppu to cleanup pip cache + at Travis and AppVeyor. + +* Add test_csvimport.py more as an example how to use load_csv + from sqlobject.util.csvimport. + +SQLObject 3.3.0 +=============== + +Released 7 May 2017. + +Features +-------- + +* Support for Python 2.6 is declared obsolete and will be removed + in the next release. + +Minor features +-------------- + +* Convert scripts repository to devscripts subdirectory. + Some of thses scripts are version-dependent so it's better to have them + in the main repo. + +* Test for __nonzero__ under Python 2, __bool__ under Python 3 in BoolCol. + +Drivers (work in progress) +-------------------------- + +* Add support for PyODBC and PyPyODBC (pure-python ODBC DB API driver) for + MySQL, PostgreSQL and MS SQL. Driver names are ``pyodbc``, ``pypyodbc`` + or ``odbc`` (try ``pyodbc`` and ``pypyodbc``). There are some problems + with pyodbc and many problems with pypyodbc. + +Documentation +------------- + +* Stop updating http://sqlobject.readthedocs.org/ - it's enough to have + http://sqlobject.org/ + +Tests +----- + +* Run tests at Travis CI and AppVeyor with Python 3.6, x86 and x64. + +* Stop running tests at Travis with Python 2.6. + +* Stop running tests at AppVeyor with pymssql - too many timeouts and + problems. + +SQLObject 3.2.0 +=============== + +Released 11 Mar 2017. + +Minor features +-------------- + +* Drop table name from ``VACUUM`` command in SQLiteConnection: SQLite + doesn't vacuum a single table and SQLite 3.15 uses the supplied name as + the name of the attached database to vacuum. + +* Remove ``driver`` keyword from RdbhostConnection as it allows one driver + ``rdbhdb``. + +* Add ``driver`` keyword for FirebirdConnection. Allowed values are 'fdb', + 'kinterbasdb' and 'pyfirebirdsql'. Default is to test 'fdb' and + 'kinterbasdb' in that order. pyfirebirdsql is supported but has problems. + +* Add ``driver`` keyword for MySQLConnection. Allowed values are 'mysqldb', + 'connector', 'connector-python', 'oursql' and 'pymysql'. Default is to + test for mysqldb only. + +* Add support for `MySQL Connector + `_ (pure python; `binary + packages `_ are not at + PyPI and hence are hard to install and test). + +* Add support for `oursql `_ MySQL + driver (only Python 2.6 and 2.7 until oursql author fixes Python 3 + compatibility). + +* Add support for `PyMySQL `_ - pure + python mysql interface). + +* Add parameter ``timeout`` for MSSQLConnection (usable only with pymssql + driver); timeouts are in seconds. + +* Remove deprecated ez_setup.py. + +Drivers (work in progress) +-------------------------- + +* Extend support for PyGreSQL driver. There are still some problems. + +* Add support for `py-postgresql + `_ PostgreSQL driver. There + are still problems with the driver. + +* Add support for `pyfirebirdsql + `_.There are still problems with + the driver. + +Bug fixes +--------- + +* Fix MSSQLConnection.columnsFromSchema: remove `(` and `)` from default + value. + +* Fix MSSQLConnection and SybaseConnection: insert default values into a table + with just one IDENTITY column. + +* Remove excessive NULLs from ``CREATE TABLE`` for MSSQL/Sybase. + +* Fix concatenation operator for MSSQL/Sybase (it's ``+``, not ``||``). + +* Fix MSSQLConnection.server_version() under Py3 (decode version to str). + +Documentation +------------- + +* The docs are now generated with Sphinx. + +* Move ``docs/LICENSE`` to the top-level directory so that Github + recognizes it. + +Tests +----- + +* Rename ``py.test`` -> ``pytest`` in tests and docs. + +* Great Renaming: fix ``pytest`` warnings by renaming ``TestXXX`` classes + to ``SOTestXXX`` to prevent ``pytest`` to recognize them as test classes. + +* Fix ``pytest`` warnings by converting yield tests to plain calls: yield + tests were deprecated in ``pytest``. + +* Tests are now run at CIs with Python 3.5. + +* Drop ``Circle CI``. + +* Run at Travis CI tests with Firebird backend (server version 2.5; + drivers fdb and firebirdsql). There are problems with tests. + +* Run tests at AppVeyor for windows testing. Run tests with MS SQL, + MySQL, Postgres and SQLite backends; use Python 2.7, 3.4 and 3.5, + x86 and x64. There are problems with MS SQL and MySQL. + +SQLObject 3.1.0 +=============== + +Released 16 Aug 2016. + +Features +-------- + +* Add UuidCol. + +* Add JsonbCol. Only for PostgreSQL. + Requires psycopg2 >= 2.5.4 and PostgreSQL >= 9.2. + +* Add JSONCol, a universal json column. + +* For Python >= 3.4 minimal FormEncode version is now 1.3.1. + +* If mxDateTime is in use, convert timedelta (returned by MySQL) to + mxDateTime.Time. + +Documentation +------------- + +* Developer's Guide is extended to explain SQLObject architecture + and how to create a new column type. + +* Fix URLs that can be found; remove missing links. + +* Rename reStructuredText files from \*.txt to \*.rst. + +Source code +----------- + +* Fix all `import *` using https://github.com/zestyping/star-destroyer. + +Tests +----- + +* Tests are now run at Circle CI. + +* Use pytest-cov for test coverage. Report test coverage + via coveralls.io and codecov.io. + +* Install mxDateTime to run date/time tests with it. + +SQLObject 3.0.0 +=============== + +Released 1 Jun 2016. + +Features +-------- + +* Support for Python 2 and Python 3 with one codebase! + (Python version >= 3.4 currently required.) + +Minor features +-------------- + +* PyDispatcher (>=2.0.4) was made an external dependency. + +Development +----------- + +* Source code was made flake8-clean. + +Documentation +------------- + +* Documentation is published at http://sqlobject.readthedocs.org/ in + Sphinx format. + +`Older news`__ + +.. __: News5.html + +.. image:: https://sourceforge.net/sflogo.php?group_id=74338&type=10 + :target: https://sourceforge.net/projects/sqlobject + :class: noborder + :align: center + :height: 15 + :width: 80 + :alt: Get SQLObject at SourceForge.net. Fast, secure and Free Open Source software downloads From db162aa7542a1be03d8a3a5f93f17038d7979ead Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 26 Dec 2022 20:07:18 +0300 Subject: [PATCH 389/509] Docs(News): Add forgotten release date SQLObject 3.10.1 was released at 2022 Dec 22. [skip ci] --- docs/News.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/News.rst b/docs/News.rst index a0ebdf7f..230e7db8 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -11,6 +11,8 @@ SQLObject (master) SQLObject 3.10.1 ================ +Released 2022 Dec 22. + Minor features -------------- From 423a0f74a5a995e6b1de1a9c861641ecfd836d7d Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 18 Jul 2023 15:50:51 +0300 Subject: [PATCH 390/509] CI(GHActions): Install all Python and PyPy versions from `conda-forge` --- .github/workflows/run-tests.yaml | 10 +++++++--- devscripts/requirements/requirements.txt | 2 -- docs/News.rst | 5 +++++ 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 31b170bc..60b41884 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -4,6 +4,8 @@ on: [push, pull_request] jobs: run-tests: + env: + not_in_conda: "[]" strategy: matrix: @@ -40,12 +42,13 @@ jobs: - uses: actions/checkout@v2 - uses: s-weigand/setup-conda@v1 with: + conda-channels: conda-forge python-version: ${{ matrix.python-version }} - if: ${{ runner.os == 'Linux' && matrix.python-version != '3.11' }} + if: ${{ !contains(fromJSON(env.not_in_conda), matrix.python-version) }} - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - if: ${{ runner.os != 'Linux' || matrix.python-version == '3.11' }} + if: ${{ contains(fromJSON(env.not_in_conda), matrix.python-version) }} - name: Cache pip uses: actions/cache@v3 with: @@ -56,9 +59,10 @@ jobs: - name: Install dependencies run: | python --version + python -m ensurepip python -m pip install --upgrade pip setuptools wheel pip --version - pip install --upgrade virtualenv "tox < 4" + pip install --upgrade virtualenv "tox >= 3.15, < 4" - name: Set PYVER run: | import os, sys diff --git a/devscripts/requirements/requirements.txt b/devscripts/requirements/requirements.txt index f77d60a2..a419296d 100644 --- a/devscripts/requirements/requirements.txt +++ b/devscripts/requirements/requirements.txt @@ -1,5 +1,3 @@ ---install-option=-O2 - # DateTime from Zope DateTime diff --git a/docs/News.rst b/docs/News.rst index 230e7db8..507a370c 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,11 @@ News SQLObject (master) ================== +CI +-- + +* Install all Python and PyPy versions from ``conda-forge``. + SQLObject 3.10.1 ================ From 79294e3d5d6f2d728093a873265d035496c9349f Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 28 Jul 2023 23:38:37 +0300 Subject: [PATCH 391/509] Feat(SQLBuilder): Add method `Alias.select()` --- ANNOUNCE.rst | 5 +++++ docs/News.rst | 5 +++++ sqlobject/sqlbuilder.py | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 0040aed7..3d251d9b 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -21,6 +21,11 @@ What's new in SQLObject Contributors for this release are +Minor features +-------------- + +* Class ``Alias`` grows a method ``.select()`` to match ``SQLObject.select()``. + For a more complete list, please see the news: http://sqlobject.org/News.html diff --git a/docs/News.rst b/docs/News.rst index 507a370c..9a0a05af 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,11 @@ News SQLObject (master) ================== +Minor features +-------------- + +* Class ``Alias`` grows a method ``.select()`` to match ``SQLObject.select()``. + CI -- diff --git a/sqlobject/sqlbuilder.py b/sqlobject/sqlbuilder.py index 9eabcf52..22118ffc 100644 --- a/sqlobject/sqlbuilder.py +++ b/sqlobject/sqlbuilder.py @@ -638,16 +638,54 @@ def __sqlrepr__(self, db): self.alias) +class AliasSQLMeta(): + def __init__(self, table, alias): + self.__table = table + self.__alias = alias + + def __getattr__(self, attr): + if attr.startswith('__'): + raise AttributeError + table = self.__table + if (attr == "table"): + return '%s %s' % (table.sqlmeta.table, self.__alias) + return getattr(table.sqlmeta, attr) + + class Alias(SQLExpression): def __init__(self, table, alias=None): self.q = AliasTable(table, alias) + def __getattr__(self, attr): + table = self.q.table + if (attr == "sqlmeta") and hasattr(table, "sqlmeta"): + alias = self.q.alias + return AliasSQLMeta(table, alias) + return getattr(table, attr) + def __sqlrepr__(self, db): return sqlrepr(self.q, db) def components(self): return [self.q] + def select(self, clause=None, clauseTables=None, + orderBy=NoDefault, limit=None, + lazyColumns=False, reversed=False, + distinct=False, connection=None, + join=None, forUpdate=False): + # Import here to avoid circular import + from .sresults import SelectResults + return SelectResults(self, clause, + clauseTables=clauseTables, + orderBy=orderBy, + limit=limit, + lazyColumns=lazyColumns, + reversed=reversed, + distinct=distinct, + connection=connection, + join=join, forUpdate=forUpdate) + class Union(SQLExpression): def __init__(self, *tables): From 0ecd7da093be2152e2da955004bd66003e3dad8f Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 29 Jul 2023 00:08:16 +0300 Subject: [PATCH 392/509] Feat(SQLBuilder): Add detailed error message --- sqlobject/sqlbuilder.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/sqlobject/sqlbuilder.py b/sqlobject/sqlbuilder.py index 22118ffc..f998c0a9 100644 --- a/sqlobject/sqlbuilder.py +++ b/sqlobject/sqlbuilder.py @@ -480,7 +480,8 @@ def __init__(self, tableName): def __getattr__(self, attr): if attr.startswith('__'): - raise AttributeError + raise AttributeError("Attribute '%s' is forbidden in '%s'" % ( + attr, self.__class__.__name__)) return self.FieldClass(self.tableName, attr) def __sqlrepr__(self, db): @@ -502,7 +503,8 @@ def __init__(self, soClass): def __getattr__(self, attr): if attr.startswith('__'): - raise AttributeError + raise AttributeError("Attribute '%s' is forbidden in '%s'" % ( + attr, self.__class__.__name__)) if attr == 'id': return self._getattrFromID(attr) elif attr in self.soClass.sqlmeta.columns: @@ -565,14 +567,16 @@ class TableSpace: def __getattr__(self, attr): if attr.startswith('__'): - raise AttributeError + raise AttributeError("Attribute '%s' is forbidden in '%s'" % ( + attr, self.__class__.__name__)) return self.TableClass(attr) class ConstantSpace: def __getattr__(self, attr): if attr.startswith('__'): - raise AttributeError + raise AttributeError("Attribute '%s' is forbidden in '%s'" % ( + attr, self.__class__.__name__)) return SQLConstant(attr) @@ -628,7 +632,8 @@ def __init__(self, table, alias=None): def __getattr__(self, attr): if attr.startswith('__'): - raise AttributeError + raise AttributeError("Attribute '%s' is forbidden in '%s'" % ( + attr, self.__class__.__name__)) if self.table: attr = getattr(self.table.q, attr).fieldName return self.FieldClass(self.tableName, attr, self.alias, self) @@ -645,7 +650,8 @@ def __init__(self, table, alias): def __getattr__(self, attr): if attr.startswith('__'): - raise AttributeError + raise AttributeError("Attribute '%s' is forbidden in '%s'" % ( + attr, self.__class__.__name__)) table = self.__table if (attr == "table"): return '%s %s' % (table.sqlmeta.table, self.__alias) From a4ee6cdb15c8e253db0d81cd766396d66bfd2e61 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 28 Jul 2023 23:54:08 +0300 Subject: [PATCH 393/509] Fix(SQLRelatedJoin): Fixed a bug when the table joins with itself In the resulting SQL two instances of the table must use different aliases. Fixes: #185. --- ANNOUNCE.rst | 9 ++++++- docs/News.rst | 7 ++++++ sqlobject/joins.py | 35 +++++++++++++++++--------- sqlobject/tests/test_SQLRelatedJoin.py | 29 ++++++++++++++++++++- 4 files changed, 66 insertions(+), 14 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 3d251d9b..1b1914ee 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -19,13 +19,20 @@ I'm pleased to announce version 3.10.2, the first bugfix release of branch What's new in SQLObject ======================= -Contributors for this release are +The contributor for this release is Igor Yudytskiy. Minor features -------------- * Class ``Alias`` grows a method ``.select()`` to match ``SQLObject.select()``. +Bug fixes +--------- + +* Fixed a bug in ``SQLRelatedJoin`` in the case where the table joins with + itself; in the resulting SQL two instances of the table must use different + aliases. Thanks to Igor Yudytskiy for providing an elaborated bug report. + For a more complete list, please see the news: http://sqlobject.org/News.html diff --git a/docs/News.rst b/docs/News.rst index 9a0a05af..3525ea25 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -13,6 +13,13 @@ Minor features * Class ``Alias`` grows a method ``.select()`` to match ``SQLObject.select()``. +Bug fixes +--------- + +* Fixed a bug in ``SQLRelatedJoin`` in the case where the table joins with + itself; in the resulting SQL two instances of the table must use different + aliases. + CI -- diff --git a/sqlobject/joins.py b/sqlobject/joins.py index e2c835a6..fa2b337c 100644 --- a/sqlobject/joins.py +++ b/sqlobject/joins.py @@ -298,11 +298,14 @@ def __init__(self, otherTable, otherIdName, interTable, joinColumn): self.joinColumn = joinColumn def tablesUsedImmediate(self): - return [self.otherTable, self.interTable] + return [ + '%s _SO_SQLRelatedJoin_OtherTable' % self.otherTable, + self.interTable, + ] def __sqlrepr__(self, db): - return '%s.%s = %s.%s' % (self.otherTable, self.otherIdName, - self.interTable, self.joinColumn) + return '_SO_SQLRelatedJoin_OtherTable.%s = %s.%s' % ( + self.otherIdName, self.interTable, self.joinColumn) class JoinToTable(sqlbuilder.SQLExpression): @@ -313,11 +316,14 @@ def __init__(self, table, idName, interTable, joinColumn): self.joinColumn = joinColumn def tablesUsedImmediate(self): - return [self.table, self.interTable] + return [ + '%s _SO_SQLRelatedJoin_ThisTable' % self.table, + self.interTable, + ] def __sqlrepr__(self, db): - return '%s.%s = %s.%s' % (self.interTable, self.joinColumn, self.table, - self.idName) + return '%s.%s = _SO_SQLRelatedJoin_ThisTable.%s' % ( + self.interTable, self.joinColumn, self.idName) class TableToId(sqlbuilder.SQLExpression): @@ -327,10 +333,11 @@ def __init__(self, table, idName, idValue): self.idValue = idValue def tablesUsedImmediate(self): - return [self.table] + return ['%s _SO_SQLRelatedJoin_ThisTable' % self.table] def __sqlrepr__(self, db): - return '%s.%s = %s' % (self.table, self.idName, self.idValue) + return '_SO_SQLRelatedJoin_ThisTable.%s = %s' % ( + self.idName, self.idValue) class SOSQLRelatedJoin(SORelatedJoin): @@ -339,7 +346,9 @@ def performJoin(self, inst): conn = inst._connection else: conn = None - results = self.otherClass.select(sqlbuilder.AND( + results = sqlbuilder.Alias( + self.otherClass, '_SO_SQLRelatedJoin_OtherTable' + ).select(sqlbuilder.AND( OtherTableToJoin( self.otherClass.sqlmeta.table, self.otherClass.sqlmeta.idName, self.intermediateTable, self.otherColumn @@ -350,9 +359,11 @@ def performJoin(self, inst): ), TableToId(self.soClass.sqlmeta.table, self.soClass.sqlmeta.idName, inst.id), - ), clauseTables=(self.soClass.sqlmeta.table, - self.otherClass.sqlmeta.table, - self.intermediateTable), + ), clauseTables=( + '%s _SO_SQLRelatedJoin_ThisTable' % self.soClass.sqlmeta.table, + '%s _SO_SQLRelatedJoin_OtherTable' % + self.otherClass.sqlmeta.table, + self.intermediateTable), connection=conn) return results.orderBy(self.orderBy) diff --git a/sqlobject/tests/test_SQLRelatedJoin.py b/sqlobject/tests/test_SQLRelatedJoin.py index 7620258f..5e235dde 100644 --- a/sqlobject/tests/test_SQLRelatedJoin.py +++ b/sqlobject/tests/test_SQLRelatedJoin.py @@ -1,5 +1,6 @@ import pytest -from sqlobject import RelatedJoin, SQLObject, SQLRelatedJoin, StringCol +from sqlobject import RelatedJoin, SQLObject, SQLRelatedJoin, StringCol, \ + ForeignKey from sqlobject.tests.dbtest import setupClass, supports @@ -62,3 +63,29 @@ def test_related_join_transaction(): finally: trans.commit(True) Tourtment._connection.autoCommit = True + + +class RecursiveGroup(SQLObject): + name = StringCol(length=255, unique=True) + subgroups = SQLRelatedJoin( + 'RecursiveGroup', + otherColumn='group_id', + intermediateTable='rec_group_map', + createRelatedTable=False, + ) + + +class RecGroupMap(SQLObject): + recursive_group = ForeignKey('RecursiveGroup') + group = ForeignKey('RecursiveGroup') + + +def test_rec_group(): + setupClass([RecursiveGroup, RecGroupMap]) + a = RecursiveGroup(name='a') + a1 = RecursiveGroup(name='a1') + a.addRecursiveGroup(a1) + a2 = RecursiveGroup(name='a2') + a.addRecursiveGroup(a2) + + assert sorted(a.subgroups, key=lambda x: x.name) == [a1, a2] From e628604d8aa2a796883a020abd3c52a54b477d8f Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 9 Aug 2023 14:01:26 +0300 Subject: [PATCH 394/509] Release 3.10.2 --- ANNOUNCE.rst | 16 ++-------------- README.rst | 4 ++-- devscripts/build-all-docs | 2 +- docs/News.rst | 6 ++++-- sqlobject/__version__.py | 4 ++-- 5 files changed, 11 insertions(+), 21 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 1b1914ee..d5bdebc0 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,19 +1,7 @@ Hello! -I'm pleased to announce version 3.10.2a1, the first alpha of the upcoming -release of branch 3.10 of SQLObject. - -I'm pleased to announce version 3.10.2a2, the second alpha of the upcoming -release of branch 3.10 of SQLObject. - -I'm pleased to announce version 3.10.2b1, the first beta of the upcoming -release of branch 3.10 of SQLObject. - -I'm pleased to announce version 3.10.2rc1, the first release candidate -of the upcoming release of branch 3.10 of SQLObject. - -I'm pleased to announce version 3.10.2, the first bugfix release of branch -3.10 of SQLObject. +I'm pleased to announce version 3.10.2, a minor feature release +and the second bugfix release of branch 3.10 of SQLObject. What's new in SQLObject diff --git a/README.rst b/README.rst index 3896cef6..e3ff798e 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.10.2a0 -================== +SQLObject 3.10.2 +================ SQLObject is a free and open-source (LGPL) Python object-relational mapper. Your database tables are described as classes, and rows are diff --git a/devscripts/build-all-docs b/devscripts/build-all-docs index 8da2c52b..d633b097 100755 --- a/devscripts/build-all-docs +++ b/devscripts/build-all-docs @@ -10,7 +10,7 @@ cd "`dirname \"$0\"`" && PROG_DIR="`pwd`" && cd .. && -build_docs 3.10.1 && +build_docs 3.10.2 && build_docs master devel && rm -rf docs/html && diff --git a/docs/News.rst b/docs/News.rst index 3525ea25..5180fbc7 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,8 +5,10 @@ News .. contents:: Contents: :backlinks: none -SQLObject (master) -================== +SQLObject 3.10.2 +================ + +Released 2023 Aug 09. Minor features -------------- diff --git a/sqlobject/__version__.py b/sqlobject/__version__.py index 7753d960..8bf191f3 100644 --- a/sqlobject/__version__.py +++ b/sqlobject/__version__.py @@ -1,8 +1,8 @@ -version = '3.10.1' +version = '3.10.2' major = 3 minor = 10 -micro = 1 +micro = 2 release_level = 'final' serial = 0 version_info = (major, minor, micro, release_level, serial) From 00ed0745fd94cf2a030083cc6d09c97a9fc5be22 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 9 Aug 2023 15:11:03 +0300 Subject: [PATCH 395/509] Build: Prepare for the next release [skip ci] --- ANNOUNCE.rst | 20 ++++++++++++++++---- README.rst | 4 ++-- docs/News.rst | 3 +++ 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index d5bdebc0..f6bb586e 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,13 +1,25 @@ Hello! -I'm pleased to announce version 3.10.2, a minor feature release -and the second bugfix release of branch 3.10 of SQLObject. +I'm pleased to announce version 3.10.3a1, the first alpha of the upcoming +release of branch 3.10 of SQLObject. + +I'm pleased to announce version 3.10.3a2, the second alpha of the upcoming +release of branch 3.10 of SQLObject. + +I'm pleased to announce version 3.10.3b1, the first beta of the upcoming +release of branch 3.10 of SQLObject. + +I'm pleased to announce version 3.10.3rc1, the first release candidate +of the upcoming release of branch 3.10 of SQLObject. + +I'm pleased to announce version 3.10.3, the first bugfix release of branch +3.10 of SQLObject. What's new in SQLObject ======================= -The contributor for this release is Igor Yudytskiy. +The contributors for this release are ... Thanks! Minor features -------------- @@ -51,7 +63,7 @@ Site: http://sqlobject.org Download: -https://pypi.org/project/SQLObject/3.10.2a0.dev20221222/ +https://pypi.org/project/SQLObject/3.10.3a0.dev20230810/ News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index e3ff798e..3b336e9f 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.10.2 -================ +SQLObject 3.10.3a0 +================== SQLObject is a free and open-source (LGPL) Python object-relational mapper. Your database tables are described as classes, and rows are diff --git a/docs/News.rst b/docs/News.rst index 5180fbc7..2d052000 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,6 +5,9 @@ News .. contents:: Contents: :backlinks: none +SQLObject (master) +================== + SQLObject 3.10.2 ================ From 0d633b72642bace7da86a51470aca1044b82c808 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 17 Sep 2023 19:32:32 +0300 Subject: [PATCH 396/509] CI(GHActions): Ensure `pip` only if needed This is to work around a problem in conda with Python 3.7 - it brings in wrong version of `setuptools` incompatible with Python 3.7. --- .github/workflows/run-tests.yaml | 2 +- docs/News.rst | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 60b41884..392147f2 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -59,7 +59,7 @@ jobs: - name: Install dependencies run: | python --version - python -m ensurepip + python -m pip || python -m ensurepip --default-pip --upgrade python -m pip install --upgrade pip setuptools wheel pip --version pip install --upgrade virtualenv "tox >= 3.15, < 4" diff --git a/docs/News.rst b/docs/News.rst index 2d052000..f37f366e 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,14 @@ News SQLObject (master) ================== +CI +-- + +* GHActions: Ensure ``pip`` only if needed + + This is to work around a problem in conda with Python 3.7 - + it brings in wrong version of ``setuptools`` incompatible with Python 3.7. + SQLObject 3.10.2 ================ From ae1ca49def118ed7a0aa897e6613ef8563ef4d3f Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 18 Sep 2023 02:29:36 +0300 Subject: [PATCH 397/509] Fix(SQLiteConnection): Clear `_threadOrigination` --- sqlobject/sqlite/sqliteconnection.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sqlobject/sqlite/sqliteconnection.py b/sqlobject/sqlite/sqliteconnection.py index 06cf3c43..89635e36 100644 --- a/sqlobject/sqlite/sqliteconnection.py +++ b/sqlobject/sqlite/sqliteconnection.py @@ -181,6 +181,8 @@ def releaseConnection(self, conn, explicit=False): else: if self._pool and conn in self._pool: self._pool.remove(conn) + if threadid: + del self._threadOrigination[id(conn)] conn.close() def _setAutoCommit(self, conn, auto): @@ -214,6 +216,7 @@ def makeConnection(self): def close(self): DBAPI.close(self) self._threadPool = {} + self._threadOrigination = {} if self._memory: self._memoryConn.close() self.makeMemoryConnection() From a37239b87bfedd8bc72b62431412a9cf5a17e48e Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 18 Sep 2023 19:36:16 +0300 Subject: [PATCH 398/509] Fix(SQLiteConnection): Release connections to fix memory leak Release connections from threads that are no longer active. This fixes memory leak in multithreaded programs in Windows. `SQLite` requires different connections per thread so `SQLiteConnection` creates and stores a connection per thread. When a thread finishes its connections should be closed. But if a program doesn't cooperate and doesn't close connections at the end of a thread SQLObject leaks memory as connection objects are stuck in `SQLiteConnection`. On Linux the leak is negligible as Linux reuses thread IDs so new connections replace old ones and old connections are garbage collected. But Windows doesn't reuse thread IDs so old connections pile and never released. To fix the problem `SQLiteConnection` now enumerates threads and releases connections from non-existing threads. Fixes: #186. --- docs/News.rst | 19 +++++++++++++++++++ sqlobject/sqlite/sqliteconnection.py | 16 ++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/docs/News.rst b/docs/News.rst index f37f366e..34aabe4f 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,25 @@ News SQLObject (master) ================== +Drivers +------- + +* Fix(SQLiteConnection): Release connections from threads that are + no longer active. This fixes memory leak in multithreaded programs + in Windows. + + ``SQLite`` requires different connections per thread so + ``SQLiteConnection`` creates and stores a connection per thread. + When a thread finishes its connections should be closed. + But if a program doesn't cooperate and doesn't close connections at + the end of a thread SQLObject leaks memory as connection objects are + stuck in ``SQLiteConnection``. On Linux the leak is negligible as + Linux reuses thread IDs so new connections replace old ones and old + connections are garbage collected. But Windows doesn't reuse thread + IDs so old connections pile and never released. To fix the problem + ``SQLiteConnection`` now enumerates threads and releases connections + from non-existing threads. + CI -- diff --git a/sqlobject/sqlite/sqliteconnection.py b/sqlobject/sqlite/sqliteconnection.py index 89635e36..80da75e2 100644 --- a/sqlobject/sqlite/sqliteconnection.py +++ b/sqlobject/sqlite/sqliteconnection.py @@ -4,6 +4,7 @@ from _thread import get_ident except ImportError: from thread import get_ident +from threading import enumerate as enumerate_threads try: from urllib import quote except ImportError: @@ -150,6 +151,7 @@ def getConnection(self): self._connectionNumbers[id(conn)] = self._connectionCount self._connectionCount += 1 return conn + self._releaseUnusedConnections() threadid = get_ident() if (self._pool is not None and threadid in self._threadPool): conn = self._threadPool[threadid] @@ -183,6 +185,7 @@ def releaseConnection(self, conn, explicit=False): self._pool.remove(conn) if threadid: del self._threadOrigination[id(conn)] + del self._threadPool[threadid] conn.close() def _setAutoCommit(self, conn, auto): @@ -213,6 +216,19 @@ def makeConnection(self): conn.text_factory = str # Convert text data to str, not unicode return conn + def _releaseUnusedConnections(self): + """Release connections from threads that're no longer active""" + thread_ids = set(t.ident for t in enumerate_threads()) + tp_set = set(self._threadPool) + unused_connections = [ + self._threadPool[tid] for tid in tp_set - thread_ids + ] + for unused_connection in unused_connections: + try: + self.releaseConnection(unused_connection, explicit=True) + except self.module.ProgrammingError: + pass # Ignore error in `conn.close()` from a different thread + def close(self): DBAPI.close(self) self._threadPool = {} From 8c2a92e206a4352c8cc4332f148a5566eadf3526 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 19 Oct 2023 11:38:06 +0300 Subject: [PATCH 399/509] Build(devscripts): Delete `test-sqlobject.cmd` --- devscripts/test-sqlobject.cmd | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 devscripts/test-sqlobject.cmd diff --git a/devscripts/test-sqlobject.cmd b/devscripts/test-sqlobject.cmd deleted file mode 100644 index f227bf09..00000000 --- a/devscripts/test-sqlobject.cmd +++ /dev/null @@ -1,16 +0,0 @@ -@echo off - -SetLocal EnableDelayedExpansion -set SavePATH=%PATH% - -for %%V in (27 34 35 36 37 38 39 310 311) do ( - for %%s in (32 64) do ( - set PATH=C:\Python%%V-%%s;C:\Python%%V-%%s\Scripts;!SavePATH! - set TOXPYTHON=C:\Python%%V-%%s\python.exe - !TOXPYTHON! -m tox -e "py%%V-sqlite{-memory,}-w32" - if !ERRORLEVEL! EQU 0 (echo Ok) else (echo Error && goto Quit) - ) -) - -:Quit -set PATH=%SavePATH% From 633532ca1d2fc743cb64d2087359b8659a9bdb4a Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 19 Oct 2023 11:46:05 +0300 Subject: [PATCH 400/509] Style: Fix `flame8` warnings "invalid escape sequence" Make strings raw. --- sqlobject/firebird/firebirdconnection.py | 2 +- sqlobject/mssql/mssqlconnection.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sqlobject/firebird/firebirdconnection.py b/sqlobject/firebird/firebirdconnection.py index 4624b487..9c36f7af 100644 --- a/sqlobject/firebird/firebirdconnection.py +++ b/sqlobject/firebird/firebirdconnection.py @@ -11,7 +11,7 @@ class FirebirdConnection(DBAPI): dbName = 'firebird' schemes = [dbName] - limit_re = re.compile('^\s*(select )(.*)', re.IGNORECASE) + limit_re = re.compile(r'^\s*(select )(.*)', re.IGNORECASE) def __init__(self, host, db, port='3050', user='sysdba', password='masterkey', autoCommit=1, diff --git a/sqlobject/mssql/mssqlconnection.py b/sqlobject/mssql/mssqlconnection.py index b135fe44..9c179e93 100644 --- a/sqlobject/mssql/mssqlconnection.py +++ b/sqlobject/mssql/mssqlconnection.py @@ -10,7 +10,7 @@ class MSSQLConnection(DBAPI): dbName = 'mssql' schemes = [dbName] - limit_re = re.compile('^\s*(select )(.*)', re.IGNORECASE) + limit_re = re.compile(r'^\s*(select )(.*)', re.IGNORECASE) odbc_keywords = ('Server', 'Port', 'User Id', 'Password', 'Database') From 4faa6b208560bedd676e785839c0368b8a511887 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 19 Oct 2023 11:53:39 +0300 Subject: [PATCH 401/509] Tests: Do not install `pendulum` for Python 3.12+ --- devscripts/requirements/requirements_tests.txt | 3 +++ tox.ini | 2 -- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/devscripts/requirements/requirements_tests.txt b/devscripts/requirements/requirements_tests.txt index d6a51173..b4390fd0 100644 --- a/devscripts/requirements/requirements_tests.txt +++ b/devscripts/requirements/requirements_tests.txt @@ -6,3 +6,6 @@ pytest < 5.0; python_version == '2.7' or python_version == '3.4' # https://github.com/pytest-dev/pytest/issues/9620 pytest < 7.0; python_version >= '3.5' + +pendulum < 2.1; python_version == '3.4' +pendulum; python_version == '2.7' or (python_version >= '3.5' and python_version <= '3.11') diff --git a/tox.ini b/tox.ini index 9d1bd95f..0b16290b 100644 --- a/tox.ini +++ b/tox.ini @@ -12,9 +12,7 @@ commands = {envpython} -m pytest --version deps = -rdevscripts/requirements/requirements_tests.txt - py34: pendulum < 2.1 py34: zope.datetime < 4.3 - !py34: pendulum !py34: zope.datetime mysqldb: mysql-python mysqlclient: mysqlclient From ab2df13ad1841d8314d1325a1f2963d82041468b Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 19 Oct 2023 13:10:23 +0300 Subject: [PATCH 402/509] Drivers: Drop `supersqlite` --- ANNOUNCE.rst | 2 +- README.rst | 2 +- docs/News.rst | 3 +++ docs/SQLObject.rst | 7 +++---- docs/download.rst | 2 +- setup.py | 1 - sqlobject/sqlite/sqliteconnection.py | 9 +++------ tox.ini | 16 ---------------- 8 files changed, 12 insertions(+), 30 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index f6bb586e..216844c3 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -49,7 +49,7 @@ SQLObject supports a number of backends: MySQL/MariaDB (with a number of DB API drivers: ``MySQLdb``, ``mysqlclient``, ``mysql-connector``, ``PyMySQL``, ``mariadb``), PostgreSQL (``psycopg2``, ``PyGreSQL``, partially ``pg8000`` and ``py-postgresql``), SQLite (builtin ``sqlite``, -``pysqlite``, partially ``supersqlite``); connections to other backends +``pysqlite``); connections to other backends - Firebird, Sybase, MSSQL and MaxDB (also known as SAPDB) - are less debugged). diff --git a/README.rst b/README.rst index 3b336e9f..074d26ae 100644 --- a/README.rst +++ b/README.rst @@ -10,7 +10,7 @@ SQLObject supports a number of backends: MySQL/MariaDB (with a number of DB API drivers: ``MySQLdb``, ``mysqlclient``, ``mysql-connector``, ``PyMySQL``, ``mariadb``), PostgreSQL (``psycopg2``, ``PyGreSQL``, partially ``pg8000`` and ``py-postgresql``), SQLite (builtin ``sqlite``, -``pysqlite``, partially ``supersqlite``); connections to other backends +``pysqlite``); connections to other backends - Firebird, Sybase, MSSQL and MaxDB (also known as SAPDB) - are less debugged). diff --git a/docs/News.rst b/docs/News.rst index 34aabe4f..fe8c9f75 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -27,6 +27,9 @@ Drivers ``SQLiteConnection`` now enumerates threads and releases connections from non-existing threads. +* Dropped ``supersqlite``. It seems abandoned. + The last version 0.0.78 was released in 2018. + CI -- diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index 56f25415..cba7db16 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -50,7 +50,7 @@ Currently SQLObject supports MySQL_ and MariaDB_ via MySQLdb_ aka MySQL-python (called mysqlclient_ for Python 3), `MySQL Connector`_, oursql_, PyMySQL_, `mariadb connector`_, PyODBC_ and PyPyODBC_. For PostgreSQL_ psycopg2_ is recommended; PyGreSQL_, py-postgresql_ and pg8000_ -are supported; SQLite_ has a built-in driver, PySQLite_ or supersqlite_. +are supported; SQLite_ has a built-in driver or PySQLite_. Firebird_ is supported via fdb_ or kinterbasdb_; pyfirebirdsql_ is supported but has problems. `MAX DB`_ (also known as SAP DB) is supported via sapdb_. Sybase via Sybase_. `MSSQL Server`_ via pymssql_ (+ FreeTDS_) @@ -72,7 +72,6 @@ PostgreSQL and MSSQL but have problems (not all tests passed). .. _pg8000: https://pypi.org/project/pg8000/ .. _SQLite: https://sqlite.org/ .. _PySQLite: https://github.com/ghaering/pysqlite -.. _supersqlite: https://github.com/plasticityai/supersqlite .. _Firebird: http://www.firebirdsql.org/en/python-driver/ .. _fdb: http://www.firebirdsql.org/en/devel-python-driver/ .. _kinterbasdb: http://kinterbasdb.sourceforge.net/ @@ -1861,8 +1860,8 @@ multi-threaded environment. The user can choose a DB API driver for SQLite by using a ``driver`` parameter in DB URI or SQLiteConnection that can be a comma-separated list of driver names. Possible drivers are: ``pysqlite2`` (alias ``sqlite2``), -``sqlite3``, ``sqlite`` (alias ``sqlite1``), ``supersqlite``. Default is to -test supersqlite, pysqlite2, sqlite3 and sqlite in that order. +``sqlite3``, ``sqlite`` (alias ``sqlite1``). Default is to +test pysqlite2, sqlite3 and sqlite in that order. Connection-specific parameters are: ``encoding``, ``mode``, ``timeout``, ``check_same_thread``, ``use_table_info``. diff --git a/docs/download.rst b/docs/download.rst index 69069dd9..77f46159 100644 --- a/docs/download.rst +++ b/docs/download.rst @@ -79,7 +79,7 @@ pygresql pypostgresql py-postgresql pg8000 SQLite ^^^^^^ -sqlite pysqlite supersqlite +pysqlite sqlite The rest ^^^^^^^^ diff --git a/setup.py b/setup.py index db824658..d6a04e77 100755 --- a/setup.py +++ b/setup.py @@ -142,7 +142,6 @@ # 'sapdb': ['sapdb'], 'sqlite': ['pysqlite'], - 'supersqlite': ['supersqlite'], 'sybase': ['Sybase'], }, ) diff --git a/sqlobject/sqlite/sqliteconnection.py b/sqlobject/sqlite/sqliteconnection.py index 80da75e2..6285c44c 100644 --- a/sqlobject/sqlite/sqliteconnection.py +++ b/sqlobject/sqlite/sqliteconnection.py @@ -34,16 +34,13 @@ class SQLiteConnection(DBAPI): def __init__(self, filename, autoCommit=1, **kw): drivers = kw.pop('driver', None) or \ - 'supersqlite,pysqlite2,sqlite3,sqlite' + 'pysqlite2,sqlite3,sqlite' for driver in drivers.split(','): driver = driver.strip() if not driver: continue try: - if driver == 'supersqlite': - from supersqlite import sqlite3 as sqlite - self.using_sqlite2 = True - elif driver in ('sqlite2', 'pysqlite2'): + if driver in ('sqlite2', 'pysqlite2'): from pysqlite2 import dbapi2 as sqlite self.using_sqlite2 = True elif driver == 'sqlite3': @@ -55,7 +52,7 @@ def __init__(self, filename, autoCommit=1, **kw): else: raise ValueError( 'Unknown SQLite driver "%s", ' - 'expected supersqlite, pysqlite2, sqlite3 ' + 'expected pysqlite2, sqlite3 ' 'or sqlite' % driver) except ImportError: pass diff --git a/tox.ini b/tox.ini index 0b16290b..7a24ecc2 100644 --- a/tox.ini +++ b/tox.ini @@ -29,7 +29,6 @@ deps = pg8000: -rdevscripts/requirements/requirements_pg8000.txt pyodbc: pyodbc pypyodbc: pypyodbc - supersqlite: supersqlite firebird-fdb: fdb firebirdsql: firebirdsql passenv = CI @@ -322,21 +321,6 @@ commands = [testenv:py3{4,5,6,7,8,9,10,11}-sqlite-memory] commands = {[sqlite-memory]commands} -[sqlite-supersqlite] -commands = - {[testenv]commands} - -rm -f /tmp/sqlobject_test.sqdb - -pytest -D "sqlite:///tmp/sqlobject_test.sqdb?driver=supersqlite&debug=1" - rm -f /tmp/sqlobject_test.sqdb - -[testenv:py27-sqlite-supersqlite] -commands = - easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base - {[sqlite-supersqlite]commands} - -[testenv:py3{4,5,6,7,8,9,10,11}-sqlite-supersqlite] -commands = {[sqlite-supersqlite]commands} - # Firebird database test environments [fdb] From 59a0894945676fd175d3c2206eefbdb7446be2bb Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 19 Oct 2023 11:43:37 +0300 Subject: [PATCH 403/509] Tests,CI: Python 3.12 --- .github/workflows/run-tests.yaml | 2 +- .../requirements_connector_python.txt | 3 +- .../requirements/requirements_tests.txt | 8 +-- docs/News.rst | 5 ++ setup.py | 1 + tox.ini | 70 +++++++++---------- 6 files changed, 46 insertions(+), 43 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 392147f2..3593f6a6 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -10,7 +10,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest] - python-version: ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11"] + python-version: ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12"] include: - os: ubuntu-latest os-name: Linux diff --git a/devscripts/requirements/requirements_connector_python.txt b/devscripts/requirements/requirements_connector_python.txt index e4bffe7a..0cee2ac1 100644 --- a/devscripts/requirements/requirements_connector_python.txt +++ b/devscripts/requirements/requirements_connector_python.txt @@ -7,5 +7,4 @@ mysql-connector-python <= 8.0.29, >= 8.0.13; python_version == '3.7' mysql-connector-python <= 8.0.29, >= 8.0.19; python_version == '3.8' mysql-connector-python <= 8.0.29, >= 8.0.24; python_version == '3.9' mysql-connector-python <= 8.0.29, >= 8.0.28; python_version == '3.10' -#mysql-connector-python >= 8.0.31; python_version >= '3.11' -mysql-connector-python == 8.0.29; python_version >= '3.11' +mysql-connector-python >= 8.0.29; python_version >= '3.11' diff --git a/devscripts/requirements/requirements_tests.txt b/devscripts/requirements/requirements_tests.txt index b4390fd0..c328e74a 100644 --- a/devscripts/requirements/requirements_tests.txt +++ b/devscripts/requirements/requirements_tests.txt @@ -1,11 +1,9 @@ -r requirements.txt +setuptools pytest < 5.0; python_version == '2.7' or python_version == '3.4' - -# Pytest 7.0 introduced a major bug; see -# https://github.com/pytest-dev/pytest/issues/9620 - -pytest < 7.0; python_version >= '3.5' +pytest < 7.0; python_version >= '3.5' and python_version <= '3.11' +pytest; python_version >= '3.12' pendulum < 2.1; python_version == '3.4' pendulum; python_version == '2.7' or (python_version >= '3.5' and python_version <= '3.11') diff --git a/docs/News.rst b/docs/News.rst index fe8c9f75..b7c8e233 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -30,6 +30,11 @@ Drivers * Dropped ``supersqlite``. It seems abandoned. The last version 0.0.78 was released in 2018. +Tests +----- + +* Run tests with Python 3.12. + CI -- diff --git a/setup.py b/setup.py index d6a04e77..b1dea834 100755 --- a/setup.py +++ b/setup.py @@ -63,6 +63,7 @@ "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", "Topic :: Database", "Topic :: Database :: Front-Ends", "Topic :: Software Development :: Libraries :: Python Modules", diff --git a/tox.ini b/tox.ini index 7a24ecc2..caa5945c 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 3.15 -envlist = py27,py3{4,5,6,7,8,9,10,11}-sqlite{,-memory},py{27,36,311}-flake8 +envlist = py27,py3{4,5,6,7,8,9,10,11,12}-sqlite{,-memory},py{27,37,312}-flake8 # Base test environment settings [testenv] @@ -60,7 +60,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysqldb]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-mysqldb] +[testenv:py3{4,5,6,7,8,9,10,11,12}-mysqldb] commands = {envpython} -c "print('MySQL-python requires Python 2.7')" deps = @@ -76,7 +76,7 @@ commands = commands = {envpython} -c "print('mysqlclient requires Python 3.4+')" deps = -[testenv:py3{4,5,6,7,8,9,10,11}-mysqlclient] +[testenv:py3{4,5,6,7,8,9,10,11,12}-mysqlclient] commands = {[mysqlclient]commands} [mysql-connector] @@ -92,7 +92,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-connector]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-mysql-connector] +[testenv:py3{4,5,6,7,8,9,10,11,12}-mysql-connector] commands = {[mysql-connector]commands} [mysql-connector-python] @@ -108,7 +108,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-connector-python]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-mysql-connector-python{,-w32}] +[testenv:py3{4,5,6,7,8,9,10,11,12}-mysql-connector-python{,-w32}] commands = {[mysql-connector-python]commands} [oursql] @@ -124,7 +124,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[oursql]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-mysql-oursql3-noauto] +[testenv:py3{4,5,6,7,8,9,10,11,12}-mysql-oursql3-noauto] commands = {[oursql]commands} [pymysql] @@ -140,7 +140,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pymysql]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-mysql-pymysql] +[testenv:py3{4,5,6,7,8,9,10,11,12}-mysql-pymysql] commands = {[pymysql]commands} [mariadb] @@ -155,7 +155,7 @@ commands = commands = {envpython} -c "print('mariadb requires Python 3.6+')" deps = -[testenv:py3{6,7,8,9,10,11}-mariadb] +[testenv:py3{6,7,8,9,10,11,12}-mariadb] commands = {[mariadb]commands} [mysql-pyodbc] @@ -172,7 +172,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pyodbc]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-mysql-pyodbc-noauto] +[testenv:py3{4,5,6,7,8,9,10,11,12}-mysql-pyodbc-noauto] commands = {[mysql-pyodbc]commands} [mysql-pypyodbc] @@ -188,7 +188,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pypyodbc]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-mysql-pypyodbc-noauto] +[testenv:py3{4,5,6,7,8,9,10,11,12}-mysql-pypyodbc-noauto] commands = {[mysql-pypyodbc]commands} # PostgreSQL test environments @@ -205,7 +205,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[psycopg]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-postgres-psycopg] +[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-psycopg] commands = {[psycopg]commands} [pygresql] @@ -221,7 +221,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pygresql]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-postgres-pygresql] +[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-pygresql] commands = {[pygresql]commands} [pypostgresql] @@ -236,7 +236,7 @@ commands = commands = {envpython} -c "print('pypostgresql requires Python 3.4+')" deps = -[testenv:py3{4,5,6,7,8,9,10,11}-postgres-pypostgresql-noauto] +[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-pypostgresql-noauto] commands = {[pypostgresql]commands} [pg8000] @@ -255,7 +255,7 @@ commands = [testenv:py3{4,5,6}-postgres-pg8000] commands = {[pg8000]commands} -[testenv:py3{7,8,9,10,11}-postgres-pg8000-noauto] +[testenv:py3{7,8,9,10,11,12}-postgres-pg8000-noauto] commands = {[pg8000]commands} [postgres-pyodbc] @@ -272,7 +272,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pyodbc]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-postgres-pyodbc-noauto] +[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-pyodbc-noauto] commands = {[postgres-pyodbc]commands} [postgres-pypyodbc] @@ -288,7 +288,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pypyodbc]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-postgres-pypyodbc-noauto] +[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-pypyodbc-noauto] commands = {[postgres-pypyodbc]commands} @@ -305,7 +305,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-sqlite] +[testenv:py3{4,5,6,7,8,9,10,11,12}-sqlite] commands = {[sqlite]commands} [sqlite-memory] @@ -318,7 +318,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite-memory]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-sqlite-memory] +[testenv:py3{4,5,6,7,8,9,10,11,12}-sqlite-memory] commands = {[sqlite-memory]commands} @@ -336,7 +336,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[fdb]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-firebird-fdb] +[testenv:py3{4,5,6,7,8,9,10,11,12}-firebird-fdb] commands = {[fdb]commands} [firebirdsql] @@ -352,12 +352,12 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[firebirdsql]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-firebirdsql] +[testenv:py3{4,5,6,7,8,9,10,11,12}-firebirdsql] commands = {[firebirdsql]commands} # Special test environments -[testenv:py{27,34,35,36,37,38,39,310,311}-flake8] +[testenv:py{27,34,35,36,37,38,39,310,311,312}-flake8] changedir = ./ deps = flake8 @@ -383,7 +383,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mssql-pyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-mssql-pyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12}-mssql-pyodbc-noauto-w32] platform = win32 commands = {[mssql-pyodbc-w32]commands} @@ -402,7 +402,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-connector-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-mysql-connector-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12}-mysql-connector-w32] platform = win32 commands = {[mysql-connector-w32]commands} @@ -421,7 +421,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pymysql-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-mysql-pymysql-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12}-mysql-pymysql-w32] platform = win32 commands = {[pymysql-w32]commands} @@ -439,7 +439,7 @@ platform = win32 commands = {envpython} -c "print('mariadb requires Python 3.6+')" deps = -[testenv:py3{6,7,8,9,10,11}-mariadb-w32] +[testenv:py3{6,7,8,9,10,11,12}-mariadb-w32] platform = win32 commands = {[mariadb-w32]commands} @@ -459,7 +459,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-mysql-pyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12}-mysql-pyodbc-noauto-w32] platform = win32 commands = {[mysql-pyodbc-w32]commands} @@ -479,7 +479,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pypyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-mysql-pypyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12}-mysql-pypyodbc-noauto-w32] platform = win32 commands = {[mysql-pypyodbc-w32]commands} @@ -498,7 +498,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[psycopg-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-postgres-psycopg-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-psycopg-w32] platform = win32 commands = {[psycopg-w32]commands} @@ -517,7 +517,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pygresql-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-postgres-pygresql-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-pygresql-w32] platform = win32 commands = {[pygresql-w32]commands} @@ -535,7 +535,7 @@ platform = win32 commands = {envpython} -c "print('pypostgresql requires Python 3.4+')" deps = -[testenv:py3{4,5,6,7,8,9,10,11}-postgres-pypostgresql-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-pypostgresql-noauto-w32] platform = win32 commands = {[pypostgresql-w32]commands} @@ -554,7 +554,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pg8000-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-postgres-pg8000-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-pg8000-w32] platform = win32 commands = {[pg8000-w32]commands} @@ -574,7 +574,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-postgres-pyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-pyodbc-noauto-w32] platform = win32 commands = {[postgres-pyodbc-w32]commands} @@ -594,7 +594,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pypyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-postgres-pypyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-pypyodbc-noauto-w32] platform = win32 commands = {[postgres-pypyodbc-w32]commands} @@ -611,7 +611,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-sqlite-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12}-sqlite-w32] platform = win32 commands = {[sqlite-w32]commands} @@ -627,6 +627,6 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite-memory-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-sqlite-memory-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12}-sqlite-memory-w32] platform = win32 commands = {[sqlite-memory-w32]commands} From e151c186e647aa111254eecbd900462933733984 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 19 Oct 2023 16:53:52 +0300 Subject: [PATCH 404/509] Fix(SQLRelatedJoin): Relax aliasing Relaxed aliasing in `SQLRelatedJoin` introduced in 3.10.2 - aliasing is required only when the table joins with itself. When there're two tables to join aliasing prevents filtering -- wrong SQL is generated in `relJoinCol.filter(thisClass.q.column)`. --- docs/News.rst | 8 ++++ sqlobject/joins.py | 59 +++++++++++++++++--------- sqlobject/tests/test_SQLRelatedJoin.py | 27 +++++++++++- 3 files changed, 73 insertions(+), 21 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index b7c8e233..e8ee45c4 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,14 @@ News SQLObject (master) ================== +Bug fixes +--------- + +* Relaxed aliasing in ``SQLRelatedJoin`` introduced in 3.10.2 - aliasing + is required only when the table joins with itself. When there're two + tables to join aliasing prevents filtering -- wrong SQL is generated + in ``relJoinCol.filter(thisClass.q.column)``. + Drivers ------- diff --git a/sqlobject/joins.py b/sqlobject/joins.py index fa2b337c..34d9c59f 100644 --- a/sqlobject/joins.py +++ b/sqlobject/joins.py @@ -291,52 +291,63 @@ class RelatedJoin(MultipleJoin): class OtherTableToJoin(sqlbuilder.SQLExpression): - def __init__(self, otherTable, otherIdName, interTable, joinColumn): + def __init__(self, otherTable, otherIdName, interTable, joinColumn, alias): self.otherTable = otherTable self.otherIdName = otherIdName self.interTable = interTable self.joinColumn = joinColumn + self.alias = alias def tablesUsedImmediate(self): return [ - '%s _SO_SQLRelatedJoin_OtherTable' % self.otherTable, + '%s %s' % (self.otherTable, self.alias) + if self.alias else self.otherTable, self.interTable, ] def __sqlrepr__(self, db): - return '_SO_SQLRelatedJoin_OtherTable.%s = %s.%s' % ( + return '%s.%s = %s.%s' % ( + self.alias if self.alias else self.otherTable, self.otherIdName, self.interTable, self.joinColumn) class JoinToTable(sqlbuilder.SQLExpression): - def __init__(self, table, idName, interTable, joinColumn): + def __init__(self, table, idName, interTable, joinColumn, alias): self.table = table self.idName = idName self.interTable = interTable self.joinColumn = joinColumn + self.alias = alias def tablesUsedImmediate(self): return [ - '%s _SO_SQLRelatedJoin_ThisTable' % self.table, + '%s %s' % (self.table, self.alias) + if self.alias else self.table, self.interTable, ] def __sqlrepr__(self, db): - return '%s.%s = _SO_SQLRelatedJoin_ThisTable.%s' % ( - self.interTable, self.joinColumn, self.idName) + return '%s.%s = %s.%s' % ( + self.interTable, self.joinColumn, + self.alias if self.alias else self.table, self.idName) class TableToId(sqlbuilder.SQLExpression): - def __init__(self, table, idName, idValue): + def __init__(self, table, idName, idValue, alias): self.table = table self.idName = idName self.idValue = idValue + self.alias = alias def tablesUsedImmediate(self): - return ['%s _SO_SQLRelatedJoin_ThisTable' % self.table] + return [ + '%s %s' % (self.table, self.alias) + if self.alias else self.table, + ] def __sqlrepr__(self, db): - return '_SO_SQLRelatedJoin_ThisTable.%s = %s' % ( + return '%s.%s = %s' % ( + self.alias if self.alias else self.table, self.idName, self.idValue) @@ -346,23 +357,33 @@ def performJoin(self, inst): conn = inst._connection else: conn = None - results = sqlbuilder.Alias( - self.otherClass, '_SO_SQLRelatedJoin_OtherTable' - ).select(sqlbuilder.AND( + needAlias = self.soClass is self.otherClass + if needAlias: + source = sqlbuilder.Alias( + self.otherClass, '_SO_SQLRelatedJoin_OtherTable') + else: + source = self.otherClass + results = source.select(sqlbuilder.AND( OtherTableToJoin( self.otherClass.sqlmeta.table, self.otherClass.sqlmeta.idName, - self.intermediateTable, self.otherColumn + self.intermediateTable, self.otherColumn, + '_SO_SQLRelatedJoin_OtherTable' if needAlias else '', ), JoinToTable( self.soClass.sqlmeta.table, self.soClass.sqlmeta.idName, - self.intermediateTable, self.joinColumn + self.intermediateTable, self.joinColumn, + '_SO_SQLRelatedJoin_ThisTable' if needAlias else '', + ), + TableToId( + self.soClass.sqlmeta.table, self.soClass.sqlmeta.idName, + inst.id, '_SO_SQLRelatedJoin_ThisTable' if needAlias else '', ), - TableToId(self.soClass.sqlmeta.table, self.soClass.sqlmeta.idName, - inst.id), ), clauseTables=( - '%s _SO_SQLRelatedJoin_ThisTable' % self.soClass.sqlmeta.table, + '%s _SO_SQLRelatedJoin_ThisTable' % self.soClass.sqlmeta.table + if needAlias else self.soClass.sqlmeta.table, '%s _SO_SQLRelatedJoin_OtherTable' % - self.otherClass.sqlmeta.table, + self.otherClass.sqlmeta.table + if needAlias else self.otherClass.sqlmeta.table, self.intermediateTable), connection=conn) return results.orderBy(self.orderBy) diff --git a/sqlobject/tests/test_SQLRelatedJoin.py b/sqlobject/tests/test_SQLRelatedJoin.py index 5e235dde..e7d7e414 100644 --- a/sqlobject/tests/test_SQLRelatedJoin.py +++ b/sqlobject/tests/test_SQLRelatedJoin.py @@ -1,6 +1,7 @@ import pytest from sqlobject import RelatedJoin, SQLObject, SQLRelatedJoin, StringCol, \ ForeignKey +from sqlobject.sqlbuilder import Alias from sqlobject.tests.dbtest import setupClass, supports @@ -24,7 +25,7 @@ def createAllTables(): setupClass(Tourtment) -def test_1(): +def createData(): createAllTables() # create some tourtments t1 = Tourtment(name='Tourtment #1') @@ -44,7 +45,11 @@ def test_1(): t2.addFighter(trunks) t3.addFighter(gohan) t3.addFighter(trunks) - # do some selects + return t1, t2, t3, gokou, vegeta, gohan, trunks + + +def test_1(): + t1, t2, t3, gokou, vegeta, gohan, trunks = createData() for i, j in zip(t1.fightersAsList, t1.fightersAsSResult): assert i is j assert len(t2.fightersAsList) == t2.fightersAsSResult.count() @@ -65,6 +70,15 @@ def test_related_join_transaction(): Tourtment._connection.autoCommit = True +def test_related_join_filter(): + t1, t2, t3, gokou, vegeta, gohan, trunks = createData() + filteredFighters = t1.fightersAsSResult.filter( + Fighter.q.name.startswith('go') + ).orderBy('id') + for i, j in zip(filteredFighters, [gokou, gohan]): + assert i is j + + class RecursiveGroup(SQLObject): name = StringCol(length=255, unique=True) subgroups = SQLRelatedJoin( @@ -89,3 +103,12 @@ def test_rec_group(): a.addRecursiveGroup(a2) assert sorted(a.subgroups, key=lambda x: x.name) == [a1, a2] + + # Please note this is a wrong result! + # Do not filter by the table, use alias. See the example below. + assert list( + a.subgroups.filter(RecursiveGroup.q.name == 'a1').orderBy('name') + ) == [a1, a2] + + rgroupAlias = Alias(RecursiveGroup, '_SO_SQLRelatedJoin_OtherTable') + assert list(a.subgroups.filter(rgroupAlias.q.name == 'a1')) == [a1] From 27d347f0d25f29fbd8245d860d387cc306398c42 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 25 Oct 2023 19:16:19 +0300 Subject: [PATCH 405/509] Release 3.10.3 --- ANNOUNCE.rst | 65 ++++++++++++++++++++++++++------------- README.rst | 4 +-- devscripts/build-all-docs | 2 +- docs/News.rst | 6 ++-- sqlobject/__version__.py | 4 +-- 5 files changed, 52 insertions(+), 29 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 216844c3..4b6d859d 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,37 +1,58 @@ Hello! -I'm pleased to announce version 3.10.3a1, the first alpha of the upcoming -release of branch 3.10 of SQLObject. +I'm pleased to announce version 3.10.3, the 3rd bugfix release of branch +3.10 of SQLObject. -I'm pleased to announce version 3.10.3a2, the second alpha of the upcoming -release of branch 3.10 of SQLObject. -I'm pleased to announce version 3.10.3b1, the first beta of the upcoming -release of branch 3.10 of SQLObject. +What's new in SQLObject +======================= -I'm pleased to announce version 3.10.3rc1, the first release candidate -of the upcoming release of branch 3.10 of SQLObject. +The contributors for this release are +Igor Yudytskiy and shuffle (github.com/shuffleyxf). +Thanks! -I'm pleased to announce version 3.10.3, the first bugfix release of branch -3.10 of SQLObject. +Bug fixes +--------- +* Relaxed aliasing in ``SQLRelatedJoin`` introduced in 3.10.2 - aliasing + is required only when the table joins with itself. When there're two + tables to join aliasing prevents filtering -- wrong SQL is generated + in ``relJoinCol.filter(thisClass.q.column)``. -What's new in SQLObject -======================= +Drivers +------- -The contributors for this release are ... Thanks! +* Fix(SQLiteConnection): Release connections from threads that are + no longer active. This fixes memory leak in multithreaded programs + in Windows. -Minor features --------------- + ``SQLite`` requires different connections per thread so + ``SQLiteConnection`` creates and stores a connection per thread. + When a thread finishes its connections should be closed. + But if a program doesn't cooperate and doesn't close connections at + the end of a thread SQLObject leaks memory as connection objects are + stuck in ``SQLiteConnection``. On Linux the leak is negligible as + Linux reuses thread IDs so new connections replace old ones and old + connections are garbage collected. But Windows doesn't reuse thread + IDs so old connections pile and never released. To fix the problem + ``SQLiteConnection`` now enumerates threads and releases connections + from non-existing threads. -* Class ``Alias`` grows a method ``.select()`` to match ``SQLObject.select()``. +* Dropped ``supersqlite``. It seems abandoned. + The last version 0.0.78 was released in 2018. -Bug fixes ---------- +Tests +----- + +* Run tests with Python 3.12. + +CI +-- + +* GHActions: Ensure ``pip`` only if needed -* Fixed a bug in ``SQLRelatedJoin`` in the case where the table joins with - itself; in the resulting SQL two instances of the table must use different - aliases. Thanks to Igor Yudytskiy for providing an elaborated bug report. + This is to work around a problem in conda with Python 3.7 - + it brings in wrong version of ``setuptools`` incompatible with Python 3.7. For a more complete list, please see the news: http://sqlobject.org/News.html @@ -63,7 +84,7 @@ Site: http://sqlobject.org Download: -https://pypi.org/project/SQLObject/3.10.3a0.dev20230810/ +https://pypi.org/project/SQLObject/3.10.3 News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 074d26ae..39ece0be 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.10.3a0 -================== +SQLObject 3.10.3 +================ SQLObject is a free and open-source (LGPL) Python object-relational mapper. Your database tables are described as classes, and rows are diff --git a/devscripts/build-all-docs b/devscripts/build-all-docs index d633b097..4e7aaa5d 100755 --- a/devscripts/build-all-docs +++ b/devscripts/build-all-docs @@ -10,7 +10,7 @@ cd "`dirname \"$0\"`" && PROG_DIR="`pwd`" && cd .. && -build_docs 3.10.2 && +build_docs 3.10.3 && build_docs master devel && rm -rf docs/html && diff --git a/docs/News.rst b/docs/News.rst index e8ee45c4..dabc1938 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,8 +5,10 @@ News .. contents:: Contents: :backlinks: none -SQLObject (master) -================== +SQLObject 3.10.3 +================ + +Released 2023 Oct 25. Bug fixes --------- diff --git a/sqlobject/__version__.py b/sqlobject/__version__.py index 8bf191f3..c1c41ab7 100644 --- a/sqlobject/__version__.py +++ b/sqlobject/__version__.py @@ -1,8 +1,8 @@ -version = '3.10.2' +version = '3.10.3' major = 3 minor = 10 -micro = 2 +micro = 3 release_level = 'final' serial = 0 version_info = (major, minor, micro, release_level, serial) From 25e4fac9844618f54fdb3ecf8cf3114071b7ecf8 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 25 Oct 2023 19:23:36 +0300 Subject: [PATCH 406/509] Build: Prepare for the next release [skip ci] --- ANNOUNCE.rst | 60 ++++++++++++--------------------------------------- README.rst | 4 ++-- docs/News.rst | 3 +++ 3 files changed, 19 insertions(+), 48 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 4b6d859d..c2d4289a 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,58 +1,26 @@ Hello! -I'm pleased to announce version 3.10.3, the 3rd bugfix release of branch -3.10 of SQLObject. - - -What's new in SQLObject -======================= - -The contributors for this release are -Igor Yudytskiy and shuffle (github.com/shuffleyxf). -Thanks! +I'm pleased to announce version 3.10.4a1, the first alpha of the upcoming +release of branch 3.10 of SQLObject. -Bug fixes ---------- +I'm pleased to announce version 3.10.4a2, the second alpha of the upcoming +release of branch 3.10 of SQLObject. -* Relaxed aliasing in ``SQLRelatedJoin`` introduced in 3.10.2 - aliasing - is required only when the table joins with itself. When there're two - tables to join aliasing prevents filtering -- wrong SQL is generated - in ``relJoinCol.filter(thisClass.q.column)``. +I'm pleased to announce version 3.10.4b1, the first beta of the upcoming +release of branch 3.10 of SQLObject. -Drivers -------- +I'm pleased to announce version 3.10.4rc1, the first release candidate +of the upcoming release of branch 3.10 of SQLObject. -* Fix(SQLiteConnection): Release connections from threads that are - no longer active. This fixes memory leak in multithreaded programs - in Windows. - - ``SQLite`` requires different connections per thread so - ``SQLiteConnection`` creates and stores a connection per thread. - When a thread finishes its connections should be closed. - But if a program doesn't cooperate and doesn't close connections at - the end of a thread SQLObject leaks memory as connection objects are - stuck in ``SQLiteConnection``. On Linux the leak is negligible as - Linux reuses thread IDs so new connections replace old ones and old - connections are garbage collected. But Windows doesn't reuse thread - IDs so old connections pile and never released. To fix the problem - ``SQLiteConnection`` now enumerates threads and releases connections - from non-existing threads. - -* Dropped ``supersqlite``. It seems abandoned. - The last version 0.0.78 was released in 2018. - -Tests ------ +I'm pleased to announce version 3.10.4, the fourth bugfix release of branch +3.10 of SQLObject. -* Run tests with Python 3.12. -CI --- +What's new in SQLObject +======================= -* GHActions: Ensure ``pip`` only if needed +The contributors for this release are ... Thanks! - This is to work around a problem in conda with Python 3.7 - - it brings in wrong version of ``setuptools`` incompatible with Python 3.7. For a more complete list, please see the news: http://sqlobject.org/News.html @@ -84,7 +52,7 @@ Site: http://sqlobject.org Download: -https://pypi.org/project/SQLObject/3.10.3 +https://pypi.org/project/SQLObject/3.10.4a0.dev20231025/ News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 39ece0be..e6db9d4a 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.10.3 -================ +SQLObject 3.10.4a0 +================== SQLObject is a free and open-source (LGPL) Python object-relational mapper. Your database tables are described as classes, and rows are diff --git a/docs/News.rst b/docs/News.rst index dabc1938..c6a01e48 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,6 +5,9 @@ News .. contents:: Contents: :backlinks: none +SQLObject (master) +================== + SQLObject 3.10.3 ================ From 15bda4c25923597b0371b5af50d42c4db78fb206 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 25 Oct 2023 22:33:53 +0300 Subject: [PATCH 407/509] Build(devscripts): Feat `prerelease`: set trove classifier [skip ci] --- devscripts/prerelease | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/devscripts/prerelease b/devscripts/prerelease index dd788c6f..196e9d7e 100755 --- a/devscripts/prerelease +++ b/devscripts/prerelease @@ -22,5 +22,18 @@ micro = $micro release_level = '$state' serial = $serial version_info = (major, minor, micro, release_level, serial)" > sqlobject/__version__.py && + +if [ "$state" = alpha ]; then + trove_cls='3 - Alpha' +elif [ "$state" = beta -o "$state" = 'release candidate' ]; then + trove_cls='4 - Beta' +elif [ "$state" = final -o "$state" = post ]; then + trove_cls='5 - Production/Stable' +else + echo "Error: unknown state $state" >&2 + exit 1 +fi && +sed -Ei "s/Development Status :: .+\",\$/Development Status :: $trove_cls\",/" setup.py && + `git var GIT_EDITOR` devscripts/build-all-docs docs/News.rst ANNOUNCE.rst sqlobject/__version__.py README.rst setup.cfg setup.py && exec git commit --message="Release $tag" devscripts/build-all-docs docs/News.rst ANNOUNCE.rst sqlobject/__version__.py README.rst setup.cfg setup.py From d07860bdf349573c993da82f5b154f7e67dbd1d6 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 25 Oct 2023 23:52:47 +0300 Subject: [PATCH 408/509] Build(devscripts): Feat `prerelease`: Set version in `README.rst` [skip ci] --- devscripts/prerelease | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/devscripts/prerelease b/devscripts/prerelease index 196e9d7e..f3f5c219 100755 --- a/devscripts/prerelease +++ b/devscripts/prerelease @@ -23,6 +23,11 @@ release_level = '$state' serial = $serial version_info = (major, minor, micro, release_level, serial)" > sqlobject/__version__.py && +sqlo_tag="SQLObject $tag" && +sqlo_tag_len=${#sqlo_tag} && +sed -Ei "1s/^SQLObject [1-9].+\$/$sqlo_tag/" README.rst && +sed -Ei "2s/^==========+\$/`python -c \"print('='*$sqlo_tag_len)\"`/" README.rst && + if [ "$state" = alpha ]; then trove_cls='3 - Alpha' elif [ "$state" = beta -o "$state" = 'release candidate' ]; then From 99e0d142b7d00f3f3232aa9ce21de1a764117dba Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 28 Oct 2023 13:59:03 +0300 Subject: [PATCH 409/509] Refactor(SOSQLRelatedJoin): Pass `orderBy` right in `SelectResults.clone()` copies a lot. It's more efficient to pass all arguments at once. --- sqlobject/joins.py | 51 ++++++++++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/sqlobject/joins.py b/sqlobject/joins.py index 34d9c59f..85cdf878 100644 --- a/sqlobject/joins.py +++ b/sqlobject/joins.py @@ -363,30 +363,37 @@ def performJoin(self, inst): self.otherClass, '_SO_SQLRelatedJoin_OtherTable') else: source = self.otherClass - results = source.select(sqlbuilder.AND( - OtherTableToJoin( - self.otherClass.sqlmeta.table, self.otherClass.sqlmeta.idName, - self.intermediateTable, self.otherColumn, - '_SO_SQLRelatedJoin_OtherTable' if needAlias else '', + results = source.select( + sqlbuilder.AND( + OtherTableToJoin( + self.otherClass.sqlmeta.table, + self.otherClass.sqlmeta.idName, + self.intermediateTable, self.otherColumn, + '_SO_SQLRelatedJoin_OtherTable' if needAlias else '', + ), + JoinToTable( + self.soClass.sqlmeta.table, self.soClass.sqlmeta.idName, + self.intermediateTable, self.joinColumn, + '_SO_SQLRelatedJoin_ThisTable' if needAlias else '', + ), + TableToId( + self.soClass.sqlmeta.table, self.soClass.sqlmeta.idName, + inst.id, + '_SO_SQLRelatedJoin_ThisTable' if needAlias else '', + ), ), - JoinToTable( - self.soClass.sqlmeta.table, self.soClass.sqlmeta.idName, - self.intermediateTable, self.joinColumn, - '_SO_SQLRelatedJoin_ThisTable' if needAlias else '', + clauseTables=( + '%s _SO_SQLRelatedJoin_ThisTable' % self.soClass.sqlmeta.table + if needAlias else self.soClass.sqlmeta.table, + '%s _SO_SQLRelatedJoin_OtherTable' % + self.otherClass.sqlmeta.table + if needAlias else self.otherClass.sqlmeta.table, + self.intermediateTable, ), - TableToId( - self.soClass.sqlmeta.table, self.soClass.sqlmeta.idName, - inst.id, '_SO_SQLRelatedJoin_ThisTable' if needAlias else '', - ), - ), clauseTables=( - '%s _SO_SQLRelatedJoin_ThisTable' % self.soClass.sqlmeta.table - if needAlias else self.soClass.sqlmeta.table, - '%s _SO_SQLRelatedJoin_OtherTable' % - self.otherClass.sqlmeta.table - if needAlias else self.otherClass.sqlmeta.table, - self.intermediateTable), - connection=conn) - return results.orderBy(self.orderBy) + connection=conn, + orderBy=self.orderBy, + ) + return results class SQLRelatedJoin(RelatedJoin): From 391d4b180bd8493bc75cec97cf0b972586c74fcc Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 28 Oct 2023 16:06:33 +0300 Subject: [PATCH 410/509] Refactor(SOSQLRelatedJoin): Directly use `SelectResults` --- sqlobject/joins.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sqlobject/joins.py b/sqlobject/joins.py index 85cdf878..de479e7e 100644 --- a/sqlobject/joins.py +++ b/sqlobject/joins.py @@ -363,7 +363,8 @@ def performJoin(self, inst): self.otherClass, '_SO_SQLRelatedJoin_OtherTable') else: source = self.otherClass - results = source.select( + results = self.otherClass.SelectResultsClass( + source, sqlbuilder.AND( OtherTableToJoin( self.otherClass.sqlmeta.table, From b29ab6e30703a0458a72e01262ff903e539356c5 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 28 Oct 2023 16:39:25 +0300 Subject: [PATCH 411/509] Feat(SOSQLRelatedJoin): Raise error for filter without alias Closes: #187. --- docs/News.rst | 8 ++++++++ sqlobject/joins.py | 21 ++++++++++++++++++++- sqlobject/tests/test_SQLRelatedJoin.py | 10 +++++----- 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index c6a01e48..20213a34 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,14 @@ News SQLObject (master) ================== +Features +-------- + +* Continue working on ``SQLRelatedJoin`` aliasing introduced in 3.10.2. + When a table joins with itself calling + ``relJoinCol.filter(thisClass.q.column)`` raises ``ValueError`` + hinting that an alias is required for filtering. + SQLObject 3.10.3 ================ diff --git a/sqlobject/joins.py b/sqlobject/joins.py index de479e7e..948d04d3 100644 --- a/sqlobject/joins.py +++ b/sqlobject/joins.py @@ -2,6 +2,7 @@ from . import boundattributes from . import classregistry from . import events +from . import sresults from . import styles from . import sqlbuilder from .styles import capword @@ -351,6 +352,21 @@ def __sqlrepr__(self, db): self.idName, self.idValue) +class SQLJoinSelectResults(sresults.SelectResults): + def filter(self, filter_clause): + clause_tables = filter_clause.tablesUsed(None) + if self._SOSQLRelatedJoin_realSourceClass.sqlmeta.table \ + in clause_tables: + tableClass = self._SOSQLRelatedJoin_realSourceClass.__name__ + raise ValueError( + "Using table '%s' in the filter expression without an alias " + "could produce wrong SQL. Most probably you need " + "Alias(%s, '_SO_SQLRelatedJoin_OtherTable') instead." + % (tableClass, tableClass) + ) + return sresults.SelectResults.filter(self, filter_clause) + + class SOSQLRelatedJoin(SORelatedJoin): def performJoin(self, inst): if inst.sqlmeta._perConnection: @@ -361,9 +377,11 @@ def performJoin(self, inst): if needAlias: source = sqlbuilder.Alias( self.otherClass, '_SO_SQLRelatedJoin_OtherTable') + sresultsClass = SQLJoinSelectResults else: source = self.otherClass - results = self.otherClass.SelectResultsClass( + sresultsClass = self.otherClass.SelectResultsClass + results = sresultsClass( source, sqlbuilder.AND( OtherTableToJoin( @@ -394,6 +412,7 @@ def performJoin(self, inst): connection=conn, orderBy=self.orderBy, ) + results._SOSQLRelatedJoin_realSourceClass = self.otherClass return results diff --git a/sqlobject/tests/test_SQLRelatedJoin.py b/sqlobject/tests/test_SQLRelatedJoin.py index e7d7e414..babd9f6b 100644 --- a/sqlobject/tests/test_SQLRelatedJoin.py +++ b/sqlobject/tests/test_SQLRelatedJoin.py @@ -104,11 +104,11 @@ def test_rec_group(): assert sorted(a.subgroups, key=lambda x: x.name) == [a1, a2] - # Please note this is a wrong result! - # Do not filter by the table, use alias. See the example below. - assert list( - a.subgroups.filter(RecursiveGroup.q.name == 'a1').orderBy('name') - ) == [a1, a2] + pytest.raises( + ValueError, + a.subgroups.filter, + RecursiveGroup.q.name == 'a1', + ) rgroupAlias = Alias(RecursiveGroup, '_SO_SQLRelatedJoin_OtherTable') assert list(a.subgroups.filter(rgroupAlias.q.name == 'a1')) == [a1] From c830a55eb4bb55521b5393acfac099c4c6e110c0 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 29 Oct 2023 14:35:24 +0300 Subject: [PATCH 412/509] Feat: `idType` must be either `int` or `str` --- docs/News.rst | 2 ++ docs/SQLObject.rst | 5 +++-- sqlobject/main.py | 3 +++ sqlobject/mysql/mysqlconnection.py | 5 ++++- sqlobject/sqlite/sqliteconnection.py | 5 ++++- sqlobject/tests/test_basic.py | 10 ++++++++++ 6 files changed, 26 insertions(+), 4 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index 20213a34..66bc112f 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -16,6 +16,8 @@ Features ``relJoinCol.filter(thisClass.q.column)`` raises ``ValueError`` hinting that an alias is required for filtering. +* Test that ``idType`` is either ``int`` or ``str``. + SQLObject 3.10.3 ================ diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index cba7db16..e2350d79 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -764,8 +764,9 @@ values are: is ``id``. `idType`: - A function that coerces/normalizes IDs when setting IDs. This - is ``int`` by default (all IDs are normalized to integers). + A type that coerces/normalizes IDs when setting IDs. Must be ``int`` + or ``str``. This is ``int`` by default (all IDs are normalized to + integers). `style`: A style object -- this object allows you to use other algorithms diff --git a/sqlobject/main.py b/sqlobject/main.py index 827db2cd..c0f8a881 100644 --- a/sqlobject/main.py +++ b/sqlobject/main.py @@ -268,6 +268,9 @@ def send(cls, signal, *args, **kw): @classmethod def setClass(cls, soClass): + if cls.idType not in (int, str): + raise TypeError('sqlmeta.idType must be int or str, not %r' + % cls.idType) cls.soClass = soClass if not cls.style: cls.style = styles.defaultStyle diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index 76b11724..b1ab6c24 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -359,8 +359,11 @@ def createIndexSQL(self, soClass, index): return index.mysqlCreateIndexSQL(soClass) def createIDColumn(self, soClass): - if soClass.sqlmeta.idType == str: + if soClass.sqlmeta.idType is str: return '%s TEXT PRIMARY KEY' % soClass.sqlmeta.idName + if soClass.sqlmeta.idType is not int: + raise TypeError('sqlmeta.idType must be int or str, not %r' + % soClass.sqlmeta.idType) return '%s INT PRIMARY KEY AUTO_INCREMENT' % soClass.sqlmeta.idName def joinSQLType(self, join): diff --git a/sqlobject/sqlite/sqliteconnection.py b/sqlobject/sqlite/sqliteconnection.py index 6285c44c..d6df5c58 100644 --- a/sqlobject/sqlite/sqliteconnection.py +++ b/sqlobject/sqlite/sqliteconnection.py @@ -311,8 +311,11 @@ def createIDColumn(self, soClass): return self._createIDColumn(soClass.sqlmeta) def _createIDColumn(self, sqlmeta): - if sqlmeta.idType == str: + if sqlmeta.idType is str: return '%s TEXT PRIMARY KEY' % sqlmeta.idName + if sqlmeta.idType is not int: + raise TypeError('sqlmeta.idType must be int or str, not %r' + % sqlmeta.idType) return '%s INTEGER PRIMARY KEY AUTOINCREMENT' % sqlmeta.idName def joinSQLType(self, join): diff --git a/sqlobject/tests/test_basic.py b/sqlobject/tests/test_basic.py index d9d1a2e4..12dff999 100644 --- a/sqlobject/tests/test_basic.py +++ b/sqlobject/tests/test_basic.py @@ -337,3 +337,13 @@ class SOTestSO13(SQLObject): assert SOTestSO13._connection.uri() == 'sqlite:///db2' del sqlhub.processConnection + + +def _test_wrong_sqlmeta_idType(): + class SOTestSO13(SQLObject): + class sqlmeta: + idType = dict + + +def test_wrong_sqlmeta_idType(): + pytest.raises(TypeError, _test_wrong_sqlmeta_idType) From a0459c0f93bdd0bda61a172ed8e717e2a239b7d2 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 29 Oct 2023 15:16:52 +0300 Subject: [PATCH 413/509] Feat: `sqlmeta.idSize` to set `id` size --- docs/News.rst | 7 +++++++ docs/SQLObject.rst | 7 +++++++ sqlobject/main.py | 5 +++++ sqlobject/mysql/mysqlconnection.py | 11 ++++++++++- sqlobject/postgres/pgconnection.py | 17 ++++++++++++++++- sqlobject/tests/test_basic.py | 10 ++++++++++ sqlobject/tests/test_mysql.py | 10 ++++++++++ sqlobject/tests/test_postgres.py | 10 ++++++++++ 8 files changed, 75 insertions(+), 2 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index 66bc112f..d644a2d4 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -18,6 +18,13 @@ Features * Test that ``idType`` is either ``int`` or ``str``. +* Added ``sqlmeta.idSize``. This sets the size of integer column ``id`` + for MySQL and PostgreSQL. Allowed values are ``'TINY'``, ``'SMALL'``, + ``'MEDIUM'``, ``'BIG'``, ``None``; default is ``None``. For Postgres + mapped to ``smallserial``/``serial``/``bigserial``. For other backends + it's currently ignored. Feature request by Meet Gujrathi at + https://stackoverflow.com/q/77360075/7976758 + SQLObject 3.10.3 ================ diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index e2350d79..e67aea23 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -768,6 +768,13 @@ values are: or ``str``. This is ``int`` by default (all IDs are normalized to integers). +`idSize`: + This sets the size of integer column ``id`` for MySQL and PostgreSQL. + Allowed values are ``'TINY'``, ``'SMALL'``, ``'MEDIUM'``, ``'BIG'``, + ``None``; default is ``None``. For Postgres mapped to + ``smallserial``/``serial``/``bigserial``. For other backends it's + currently ignored. + `style`: A style object -- this object allows you to use other algorithms for translating between Python attribute and class names, and the diff --git a/sqlobject/main.py b/sqlobject/main.py index c0f8a881..7d2fd1c3 100644 --- a/sqlobject/main.py +++ b/sqlobject/main.py @@ -190,6 +190,7 @@ class sqlmeta(with_metaclass(declarative.DeclarativeMeta, object)): table = None idName = None + idSize = None # Allowed values are 'TINY/SMALL/MEDIUM/BIG/None' idSequence = None # This function is used to coerce IDs into the proper format, # so you should replace it with str, or another function, if you @@ -271,6 +272,10 @@ def setClass(cls, soClass): if cls.idType not in (int, str): raise TypeError('sqlmeta.idType must be int or str, not %r' % cls.idType) + if cls.idSize not in ('TINY', 'SMALL', 'MEDIUM', 'BIG', None): + raise ValueError( + "sqlmeta.idType must be 'TINY', 'SMALL', 'MEDIUM', 'BIG' " + "or None, not %r" % cls.idSize) cls.soClass = soClass if not cls.style: cls.style = styles.defaultStyle diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index b1ab6c24..1fcf0a7b 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -364,7 +364,16 @@ def createIDColumn(self, soClass): if soClass.sqlmeta.idType is not int: raise TypeError('sqlmeta.idType must be int or str, not %r' % soClass.sqlmeta.idType) - return '%s INT PRIMARY KEY AUTO_INCREMENT' % soClass.sqlmeta.idName + if soClass.sqlmeta.idSize is None: + mysql_int_type = 'INT' + elif soClass.sqlmeta.idSize in ('TINY', 'SMALL', 'MEDIUM', 'BIG'): + mysql_int_type = '%sINT' % soClass.sqlmeta.idSize + else: + raise ValueError( + "sqlmeta.idSize must be 'TINY', 'SMALL', 'MEDIUM', 'BIG' " + "or None, not %r" % soClass.sqlmeta.idSize) + return '%s %s PRIMARY KEY AUTO_INCREMENT' \ + % (soClass.sqlmeta.idName, mysql_int_type) def joinSQLType(self, join): return 'INT NOT NULL' diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index 722f3d4e..5bc6778d 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -341,7 +341,22 @@ def createIndexSQL(self, soClass, index): return index.postgresCreateIndexSQL(soClass) def createIDColumn(self, soClass): - key_type = {int: "SERIAL", str: "TEXT"}[soClass.sqlmeta.idType] + if soClass.sqlmeta.idType is int: + if soClass.sqlmeta.idSize in ('TINY', 'SMALL'): + key_type = 'SMALLSERIAL' + elif soClass.sqlmeta.idSize in ('MEDIUM', None): + key_type = 'SERIAL' + elif soClass.sqlmeta.idSize == 'BIG': + key_type = 'BIGSERIAL' + else: + raise ValueError( + "sqlmeta.idSize must be 'TINY', 'SMALL', 'MEDIUM', 'BIG' " + "or None, not %r" % soClass.sqlmeta.idSize) + elif soClass.sqlmeta.idType is str: + key_type = "TEXT" + else: + raise TypeError('sqlmeta.idType must be int or str, not %r' + % soClass.sqlmeta.idType) return '%s %s PRIMARY KEY' % (soClass.sqlmeta.idName, key_type) def dropTable(self, tableName, cascade=False): diff --git a/sqlobject/tests/test_basic.py b/sqlobject/tests/test_basic.py index 12dff999..361bf935 100644 --- a/sqlobject/tests/test_basic.py +++ b/sqlobject/tests/test_basic.py @@ -347,3 +347,13 @@ class sqlmeta: def test_wrong_sqlmeta_idType(): pytest.raises(TypeError, _test_wrong_sqlmeta_idType) + + +def _test_wrong_sqlmeta_idSize(): + class SOTestSO14(SQLObject): + class sqlmeta: + idSize = 'DEFAULT' + + +def test_wrong_sqlmeta_idSize(): + pytest.raises(ValueError, _test_wrong_sqlmeta_idSize) diff --git a/sqlobject/tests/test_mysql.py b/sqlobject/tests/test_mysql.py index 5f41bd96..5a15aca0 100644 --- a/sqlobject/tests/test_mysql.py +++ b/sqlobject/tests/test_mysql.py @@ -38,3 +38,13 @@ def test_ANY(): SOTestANY(value=30) assert len(list(SOTestANY.select( SOTestANY.q.value > ANY(Select([SOTestANY.q.value]))))) == 2 + + +class SOTestMySQLidSize(SQLObject): + class sqlmeta: + idSize = 'BIG' + + +def test_idSize(): + assert 'id BIGINT PRIMARY KEY AUTO_INCREMENT' \ + in SOTestMySQLidSize.createTableSQL(connection=connection)[0] diff --git a/sqlobject/tests/test_postgres.py b/sqlobject/tests/test_postgres.py index dbe62c04..037a78a8 100644 --- a/sqlobject/tests/test_postgres.py +++ b/sqlobject/tests/test_postgres.py @@ -70,3 +70,13 @@ def test_SOME(): SOTestSOME(value=30) assert len(list(SOTestSOME.select( SOTestSOME.q.value > SOME(Select([SOTestSOME.q.value]))))) == 2 + + +class SOTestPgidSize(SQLObject): + class sqlmeta: + idSize = 'BIG' + + +def test_idSize(): + assert 'id BIGSERIAL PRIMARY KEY' \ + in SOTestPgidSize.createTableSQL(connection=connection)[0] From ee9624c5f76e5458876cd624fae9010ac4ad32b4 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 4 Nov 2023 14:45:56 +0300 Subject: [PATCH 414/509] Release 3.11.0b1 --- ANNOUNCE.rst | 34 ++++++++++++++++++---------------- README.rst | 2 +- setup.py | 2 +- sqlobject/__version__.py | 10 +++++----- 4 files changed, 25 insertions(+), 23 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index c2d4289a..9677b854 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,26 +1,28 @@ Hello! -I'm pleased to announce version 3.10.4a1, the first alpha of the upcoming -release of branch 3.10 of SQLObject. - -I'm pleased to announce version 3.10.4a2, the second alpha of the upcoming -release of branch 3.10 of SQLObject. - -I'm pleased to announce version 3.10.4b1, the first beta of the upcoming -release of branch 3.10 of SQLObject. - -I'm pleased to announce version 3.10.4rc1, the first release candidate -of the upcoming release of branch 3.10 of SQLObject. - -I'm pleased to announce version 3.10.4, the fourth bugfix release of branch -3.10 of SQLObject. +I'm pleased to announce version 3.11.0b1, the first beta of the upcoming +release of branch 3.11 of SQLObject. What's new in SQLObject ======================= -The contributors for this release are ... Thanks! +Features +-------- + +* Continue working on ``SQLRelatedJoin`` aliasing introduced in 3.10.2. + When a table joins with itself calling + ``relJoinCol.filter(thisClass.q.column)`` raises ``ValueError`` + hinting that an alias is required for filtering. + +* Test that ``idType`` is either ``int`` or ``str``. +* Added ``sqlmeta.idSize``. This sets the size of integer column ``id`` + for MySQL and PostgreSQL. Allowed values are ``'TINY'``, ``'SMALL'``, + ``'MEDIUM'``, ``'BIG'``, ``None``; default is ``None``. For Postgres + mapped to ``smallserial``/``serial``/``bigserial``. For other backends + it's currently ignored. Feature request by Meet Gujrathi at + https://stackoverflow.com/q/77360075/7976758 For a more complete list, please see the news: http://sqlobject.org/News.html @@ -52,7 +54,7 @@ Site: http://sqlobject.org Download: -https://pypi.org/project/SQLObject/3.10.4a0.dev20231025/ +https://pypi.org/project/SQLObject/3.11.0b1 News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index e6db9d4a..1ac14c48 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,4 @@ -SQLObject 3.10.4a0 +SQLObject 3.11.0b1 ================== SQLObject is a free and open-source (LGPL) Python object-relational diff --git a/setup.py b/setup.py index b1dea834..cf98bf0d 100755 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ """, # noqa: E501 line too long long_description_content_type="text/x-rst", classifiers=[ - "Development Status :: 5 - Production/Stable", + "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: " "GNU Library or Lesser General Public License (LGPL)", diff --git a/sqlobject/__version__.py b/sqlobject/__version__.py index c1c41ab7..eb595220 100644 --- a/sqlobject/__version__.py +++ b/sqlobject/__version__.py @@ -1,8 +1,8 @@ -version = '3.10.3' +version = '3.11.0b1' major = 3 -minor = 10 -micro = 3 -release_level = 'final' -serial = 0 +minor = 11 +micro = 0 +release_level = 'beta' +serial = 1 version_info = (major, minor, micro, release_level, serial) From 2dddc9e4d9421f1b4dc8f438c96cdd24567a4864 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 4 Nov 2023 14:54:29 +0300 Subject: [PATCH 415/509] Build: Prepare for the next release [skip ci] --- ANNOUNCE.rst | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 9677b854..d29e8755 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,28 +1,26 @@ Hello! +I'm pleased to announce version 3.11.0a1, the first alpha of the upcoming +release of branch 3.11 of SQLObject. + +I'm pleased to announce version 3.11.0a2, the second alpha of the upcoming +release of branch 3.11 of SQLObject. + I'm pleased to announce version 3.11.0b1, the first beta of the upcoming release of branch 3.11 of SQLObject. +I'm pleased to announce version 3.11.0rc1, the first release candidate +of the upcoming release of branch 3.11 of SQLObject. -What's new in SQLObject -======================= +I'm pleased to announce version 3.11.0, the fourth bugfix release of branch +3.11 of SQLObject. -Features --------- -* Continue working on ``SQLRelatedJoin`` aliasing introduced in 3.10.2. - When a table joins with itself calling - ``relJoinCol.filter(thisClass.q.column)`` raises ``ValueError`` - hinting that an alias is required for filtering. +What's new in SQLObject +======================= -* Test that ``idType`` is either ``int`` or ``str``. +The contributors for this release are ... Thanks! -* Added ``sqlmeta.idSize``. This sets the size of integer column ``id`` - for MySQL and PostgreSQL. Allowed values are ``'TINY'``, ``'SMALL'``, - ``'MEDIUM'``, ``'BIG'``, ``None``; default is ``None``. For Postgres - mapped to ``smallserial``/``serial``/``bigserial``. For other backends - it's currently ignored. Feature request by Meet Gujrathi at - https://stackoverflow.com/q/77360075/7976758 For a more complete list, please see the news: http://sqlobject.org/News.html @@ -54,7 +52,7 @@ Site: http://sqlobject.org Download: -https://pypi.org/project/SQLObject/3.11.0b1 +https://pypi.org/project/SQLObject/3.11.0a0.dev20231105/ News and changes: http://sqlobject.org/News.html From bcc6084516541c73dd8b2e467e30b4ff7118ea82 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 11 Nov 2023 16:05:59 +0300 Subject: [PATCH 416/509] Build(devscripts/prerelease): Fix replace expression Escape a slash. [skip ci] --- devscripts/prerelease | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devscripts/prerelease b/devscripts/prerelease index f3f5c219..53e8956d 100755 --- a/devscripts/prerelease +++ b/devscripts/prerelease @@ -33,7 +33,7 @@ if [ "$state" = alpha ]; then elif [ "$state" = beta -o "$state" = 'release candidate' ]; then trove_cls='4 - Beta' elif [ "$state" = final -o "$state" = post ]; then - trove_cls='5 - Production/Stable' + trove_cls='5 - Production\/Stable' else echo "Error: unknown state $state" >&2 exit 1 From cc185d98ac00892335778446c5f554a16e9122dd Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 11 Nov 2023 16:05:53 +0300 Subject: [PATCH 417/509] Release 3.11.0 --- ANNOUNCE.rst | 34 ++++++++++++++++++---------------- README.rst | 4 ++-- devscripts/build-all-docs | 2 +- docs/News.rst | 4 ++-- setup.py | 2 +- sqlobject/__version__.py | 6 +++--- 6 files changed, 27 insertions(+), 25 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index d29e8755..fbb6112a 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,26 +1,28 @@ Hello! -I'm pleased to announce version 3.11.0a1, the first alpha of the upcoming -release of branch 3.11 of SQLObject. - -I'm pleased to announce version 3.11.0a2, the second alpha of the upcoming -release of branch 3.11 of SQLObject. - -I'm pleased to announce version 3.11.0b1, the first beta of the upcoming -release of branch 3.11 of SQLObject. - -I'm pleased to announce version 3.11.0rc1, the first release candidate -of the upcoming release of branch 3.11 of SQLObject. - -I'm pleased to announce version 3.11.0, the fourth bugfix release of branch -3.11 of SQLObject. +I'm pleased to announce version 3.11.0, the first stable release +of branch 3.11 of SQLObject. What's new in SQLObject ======================= -The contributors for this release are ... Thanks! +Features +-------- + +* Continue working on ``SQLRelatedJoin`` aliasing introduced in 3.10.2. + When a table joins with itself calling + ``relJoinCol.filter(thisClass.q.column)`` raises ``ValueError`` + hinting that an alias is required for filtering. + +* Test that ``idType`` is either ``int`` or ``str``. +* Added ``sqlmeta.idSize``. This sets the size of integer column ``id`` + for MySQL and PostgreSQL. Allowed values are ``'TINY'``, ``'SMALL'``, + ``'MEDIUM'``, ``'BIG'``, ``None``; default is ``None``. For Postgres + mapped to ``smallserial``/``serial``/``bigserial``. For other backends + it's currently ignored. Feature request by Meet Gujrathi at + https://stackoverflow.com/q/77360075/7976758 For a more complete list, please see the news: http://sqlobject.org/News.html @@ -52,7 +54,7 @@ Site: http://sqlobject.org Download: -https://pypi.org/project/SQLObject/3.11.0a0.dev20231105/ +https://pypi.org/project/SQLObject/3.11.0 News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 1ac14c48..8e895397 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.11.0b1 -================== +SQLObject 3.11.0 +================ SQLObject is a free and open-source (LGPL) Python object-relational mapper. Your database tables are described as classes, and rows are diff --git a/devscripts/build-all-docs b/devscripts/build-all-docs index 4e7aaa5d..63d78c2b 100755 --- a/devscripts/build-all-docs +++ b/devscripts/build-all-docs @@ -10,7 +10,7 @@ cd "`dirname \"$0\"`" && PROG_DIR="`pwd`" && cd .. && -build_docs 3.10.3 && +build_docs 3.11.0 && build_docs master devel && rm -rf docs/html && diff --git a/docs/News.rst b/docs/News.rst index d644a2d4..e5aa90e6 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,8 +5,8 @@ News .. contents:: Contents: :backlinks: none -SQLObject (master) -================== +SQLObject 3.11.0 +================ Features -------- diff --git a/setup.py b/setup.py index cf98bf0d..b1dea834 100755 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ """, # noqa: E501 line too long long_description_content_type="text/x-rst", classifiers=[ - "Development Status :: 4 - Beta", + "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: " "GNU Library or Lesser General Public License (LGPL)", diff --git a/sqlobject/__version__.py b/sqlobject/__version__.py index eb595220..19a73b78 100644 --- a/sqlobject/__version__.py +++ b/sqlobject/__version__.py @@ -1,8 +1,8 @@ -version = '3.11.0b1' +version = '3.11.0' major = 3 minor = 11 micro = 0 -release_level = 'beta' -serial = 1 +release_level = 'final' +serial = 0 version_info = (major, minor, micro, release_level, serial) From c714f55a9aa4990020711494d2d3911faf9566c4 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 11 Nov 2023 16:13:36 +0300 Subject: [PATCH 418/509] Build: Prepare for the next release [skip ci] --- ANNOUNCE.rst | 34 ++++++++++++++++------------------ README.rst | 4 ++-- docs/News.rst | 5 +++++ setup.py | 2 +- 4 files changed, 24 insertions(+), 21 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index fbb6112a..2faac814 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,28 +1,26 @@ Hello! -I'm pleased to announce version 3.11.0, the first stable release -of branch 3.11 of SQLObject. +I'm pleased to announce version 3.11.1a1, the first alpha of the upcoming +release of branch 3.11 of SQLObject. +I'm pleased to announce version 3.11.1a2, the second alpha of the upcoming +release of branch 3.11 of SQLObject. -What's new in SQLObject -======================= +I'm pleased to announce version 3.11.1b1, the first beta of the upcoming +release of branch 3.11 of SQLObject. + +I'm pleased to announce version 3.11.1rc1, the first release candidate +of the upcoming release of branch 3.11 of SQLObject. -Features --------- +I'm pleased to announce version 3.11.1, the first bugfix release of branch +3.11 of SQLObject. -* Continue working on ``SQLRelatedJoin`` aliasing introduced in 3.10.2. - When a table joins with itself calling - ``relJoinCol.filter(thisClass.q.column)`` raises ``ValueError`` - hinting that an alias is required for filtering. -* Test that ``idType`` is either ``int`` or ``str``. +What's new in SQLObject +======================= + +The contributors for this release are ... Thanks! -* Added ``sqlmeta.idSize``. This sets the size of integer column ``id`` - for MySQL and PostgreSQL. Allowed values are ``'TINY'``, ``'SMALL'``, - ``'MEDIUM'``, ``'BIG'``, ``None``; default is ``None``. For Postgres - mapped to ``smallserial``/``serial``/``bigserial``. For other backends - it's currently ignored. Feature request by Meet Gujrathi at - https://stackoverflow.com/q/77360075/7976758 For a more complete list, please see the news: http://sqlobject.org/News.html @@ -54,7 +52,7 @@ Site: http://sqlobject.org Download: -https://pypi.org/project/SQLObject/3.11.0 +https://pypi.org/project/SQLObject/3.11.1a0.dev20231112/ News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 8e895397..d9390c7f 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.11.0 -================ +SQLObject 3.11.1a0 +================== SQLObject is a free and open-source (LGPL) Python object-relational mapper. Your database tables are described as classes, and rows are diff --git a/docs/News.rst b/docs/News.rst index e5aa90e6..270a44a7 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,9 +5,14 @@ News .. contents:: Contents: :backlinks: none +SQLObject (master) +================== + SQLObject 3.11.0 ================ +Released 2023 Nov 11. + Features -------- diff --git a/setup.py b/setup.py index b1dea834..28a634b5 100755 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ """, # noqa: E501 line too long long_description_content_type="text/x-rst", classifiers=[ - "Development Status :: 5 - Production/Stable", + "Development Status :: 3 - Alpha", "Intended Audience :: Developers", "License :: OSI Approved :: " "GNU Library or Lesser General Public License (LGPL)", From 61151b8015d67de07a7a1e19d9161e7534b00800 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 11 Nov 2023 16:19:51 +0300 Subject: [PATCH 419/509] Build(devscripts/postrelease): Restore alpha state [skip ci] --- devscripts/postrelease | 3 +++ 1 file changed, 3 insertions(+) diff --git a/devscripts/postrelease b/devscripts/postrelease index 0a9c73a5..246e9e3f 100755 --- a/devscripts/postrelease +++ b/devscripts/postrelease @@ -2,5 +2,8 @@ git checkout HEAD~ ANNOUNCE.rst setup.cfg && +trove_cls='3 - Alpha' && +sed -Ei "s/Development Status :: .+\",\$/Development Status :: $trove_cls\",/" setup.py && + `git var GIT_EDITOR` ANNOUNCE.rst setup.cfg README.rst docs/News.rst && exec git commit --message="Build: Prepare for the next release" --message="[skip ci]" ANNOUNCE.rst setup.cfg README.rst docs/News.rst From 782091b5712fdaadbc4ae8b88a4a52562bfc5d2b Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 14 Dec 2023 23:15:05 +0300 Subject: [PATCH 420/509] Build(setup.cfg): Remove `validators.py` We no longer carry `validators.py` with us. [skip ci] --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index af28274e..461bc50f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -10,7 +10,7 @@ tag_date = 0 tag_svn_revision = 0 [flake8] -exclude = .git,.tox,docs/europython/*.py,validators.py +exclude = .git,.tox,docs/europython/*.py # E305: expected 2 blank lines after class or function definition, found 1 # W503 line break before binary operator # W605 invalid escape sequence From 5396e8151f13215a6a2076ea24c52482489af5b8 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 3 Jan 2024 02:02:14 +0300 Subject: [PATCH 421/509] Build(GHActions): Use `checkout@v4` instead of outdated `v2` --- .github/workflows/run-tests.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 3593f6a6..b38d006a 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -39,7 +39,7 @@ jobs: if: ${{ runner.os == 'Windows' }} # Setup Python/pip - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - uses: s-weigand/setup-conda@v1 with: conda-channels: conda-forge From 06901b4af66de626daaa8ae35bc370bf3d787f50 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 23 Jan 2024 11:37:53 +0300 Subject: [PATCH 422/509] Build(git): Simplify regular expressions for `compileall` [skip ci] --- devscripts/git-hooks/post-checkout | 4 ++-- devscripts/git-hooks/post-merge | 4 ++-- devscripts/git-hooks/post-rewrite | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/devscripts/git-hooks/post-checkout b/devscripts/git-hooks/post-checkout index 40f7bd71..c615fc8b 100755 --- a/devscripts/git-hooks/post-checkout +++ b/devscripts/git-hooks/post-checkout @@ -16,7 +16,7 @@ if [ "$new_branch" = 1 ]; then rm -rf docs/_build/html docs/html fi && -python -m compileall -q -x '\.tox/.+' . && -python -O -m compileall -q -x '\.tox/.+' . +python -m compileall -q -x '\.tox/' . && +python -O -m compileall -q -x '\.tox/' . exit 0 diff --git a/devscripts/git-hooks/post-merge b/devscripts/git-hooks/post-merge index 633a1d0d..2df0670c 100755 --- a/devscripts/git-hooks/post-merge +++ b/devscripts/git-hooks/post-merge @@ -2,7 +2,7 @@ # post-merge hook that compiles python files to byte code -python -m compileall -q -x '\.tox/.+' . && -python -O -m compileall -q -x '\.tox/.+' . +python -m compileall -q -x '\.tox/' . && +python -O -m compileall -q -x '\.tox/' . exit 0 diff --git a/devscripts/git-hooks/post-rewrite b/devscripts/git-hooks/post-rewrite index df284420..59efb3dc 100755 --- a/devscripts/git-hooks/post-rewrite +++ b/devscripts/git-hooks/post-rewrite @@ -2,7 +2,7 @@ # post-rewrite hook that compiles python files to byte code -python -m compileall -q -x '\.tox/.+' . && -python -O -m compileall -q -x '\.tox/.+' . +python -m compileall -q -x '\.tox/' . && +python -O -m compileall -q -x '\.tox/' . exit 0 From 3dc10840dbf50bee098ec9cc006fb41380ed45cb Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 24 Feb 2024 21:48:12 +0300 Subject: [PATCH 423/509] CI: Run tests with `PyGreSQL` --- docs/News.rst | 5 +++++ tox.ini | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index 270a44a7..d65b6e55 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,11 @@ News SQLObject (master) ================== +CI +-- + +* Run tests with ``PyGreSQL`` on w32, do not ignore errors. + SQLObject 3.11.0 ================ diff --git a/tox.ini b/tox.ini index caa5945c..c660a752 100644 --- a/tox.ini +++ b/tox.ini @@ -508,10 +508,10 @@ commands = {[testenv]commands} -dropdb --username=runner --no-password sqlobject_test createdb --username=runner --no-password sqlobject_test - -pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1" + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py27-postgres-pygresql-noauto-w32] +[testenv:py27-postgres-pygresql-w32] platform = win32 commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base From 93864e0f548ef3a70e0d5640bcaa74718aa52bec Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 24 Feb 2024 22:20:24 +0300 Subject: [PATCH 424/509] CI: Skip tests with `pg8000` --- docs/News.rst | 2 ++ tox.ini | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/News.rst b/docs/News.rst index d65b6e55..1060920d 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -13,6 +13,8 @@ CI * Run tests with ``PyGreSQL`` on w32, do not ignore errors. +* Skip tests with ``pg8000`` on w32. + SQLObject 3.11.0 ================ diff --git a/tox.ini b/tox.ini index c660a752..4d1b6197 100644 --- a/tox.ini +++ b/tox.ini @@ -554,7 +554,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pg8000-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-pg8000-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-pg8000-noauto-w32] platform = win32 commands = {[pg8000-w32]commands} From 5e5f588771c94dea2a40829726000ef6917a1b32 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 21 May 2024 23:19:20 +0300 Subject: [PATCH 425/509] Build(requirements): PyMySQL 1.0.3 dropped support for Python 3.6 --- devscripts/requirements/requirements_pymysql.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/devscripts/requirements/requirements_pymysql.txt b/devscripts/requirements/requirements_pymysql.txt index b8c7bc6a..4333b47c 100644 --- a/devscripts/requirements/requirements_pymysql.txt +++ b/devscripts/requirements/requirements_pymysql.txt @@ -1,3 +1,4 @@ pymysql < 1.0; python_version == '2.7' or python_version == '3.5' pymysql < 0.10.0; python_version == '3.4' -pymysql; python_version >= '3.6' +pymysql < 1.0.3; python_version == '3.6' +pymysql; python_version >= '3.7' From 1b9b3aa51986028bbc203e111f78846cafbd524c Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 24 Jul 2024 20:57:21 +0300 Subject: [PATCH 426/509] CI(GHActions): Switch to `setup-miniconda` --- .github/workflows/run-tests.yaml | 16 +++++++++++++--- docs/News.rst | 2 ++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index b38d006a..10d845be 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -40,15 +40,19 @@ jobs: # Setup Python/pip - uses: actions/checkout@v4 - - uses: s-weigand/setup-conda@v1 + - uses: conda-incubator/setup-miniconda@v3 with: - conda-channels: conda-forge + miniforge-version: latest python-version: ${{ matrix.python-version }} if: ${{ !contains(fromJSON(env.not_in_conda), matrix.python-version) }} - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} if: ${{ contains(fromJSON(env.not_in_conda), matrix.python-version) }} + - uses: actions/cache@v3 + with: + path: ~/conda_pkgs_dir + key: ${{ runner.os }}-conda - name: Cache pip uses: actions/cache@v3 with: @@ -63,8 +67,10 @@ jobs: python -m pip install --upgrade pip setuptools wheel pip --version pip install --upgrade virtualenv "tox >= 3.15, < 4" + shell: bash -el {0} - name: Set PYVER run: | + python -c " import os, sys ld_library_path = None pyver = '%d%d' % tuple(sys.version_info[:2]) @@ -77,11 +83,13 @@ jobs: f.write('LD_LIBRARY_PATH=' + ld_library_path + '\n') f.write('PYVER=' + pyver + '\n') f.write('PGPASSWORD=test\n') - shell: python + " + shell: bash -el {0} - name: tox version run: | tox --version + shell: bash -el {0} - name: Run tox @ Linux run: | devscripts/tox-select-envs $PYVER-mysql @@ -89,9 +97,11 @@ jobs: devscripts/tox-select-envs $PYVER-sqlite devscripts/tox-select-envs $PYVER-flake8 if: ${{ runner.os == 'Linux' }} + shell: bash -el {0} - name: Run tox @ w32 run: | devscripts\tox-select-envs.cmd %PYVER%-mysql devscripts\tox-select-envs.cmd %PYVER%-postgres devscripts\tox-select-envs.cmd %PYVER%-sqlite if: ${{ runner.os == 'Windows' }} + shell: cmd /C CALL {0} diff --git a/docs/News.rst b/docs/News.rst index 1060920d..6d75172b 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -15,6 +15,8 @@ CI * Skip tests with ``pg8000`` on w32. +* GHActions: Switch to ``setup-miniconda``. + SQLObject 3.11.0 ================ From f34450feec071f0b9495d0919b929d06204b4eea Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 24 Jul 2024 18:23:04 +0300 Subject: [PATCH 427/509] CI(GHActions): Exclude Python 2.7 at w32 It requires VC9 and cannot be installed. --- .github/workflows/run-tests.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 10d845be..4439ef23 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -11,6 +11,9 @@ jobs: matrix: os: [ubuntu-latest, windows-latest] python-version: ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12"] + exclude: + - os: windows-latest + python-version: "2.7" include: - os: ubuntu-latest os-name: Linux From ba965063611f185dff46d0bb27659408efef1c6c Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 28 Aug 2024 20:49:02 +0300 Subject: [PATCH 428/509] Build(git-hooks): Remove `python -m compileall` The project is developed for a range of different Pythons, recompilation for all supported versions takes too long and must be done in a separate step. [skip ci] --- devscripts/git-hooks/post-checkout | 7 +------ devscripts/git-hooks/post-merge | 8 -------- devscripts/git-hooks/post-rewrite | 8 -------- 3 files changed, 1 insertion(+), 22 deletions(-) delete mode 100755 devscripts/git-hooks/post-merge delete mode 100755 devscripts/git-hooks/post-rewrite diff --git a/devscripts/git-hooks/post-checkout b/devscripts/git-hooks/post-checkout index c615fc8b..4192e0d6 100755 --- a/devscripts/git-hooks/post-checkout +++ b/devscripts/git-hooks/post-checkout @@ -14,9 +14,4 @@ if [ "$new_branch" = 1 ]; then if [ "`echo $d/*`" = "$d/*" ]; then rm -rf $d; fi done && rm -rf docs/_build/html docs/html -fi && - -python -m compileall -q -x '\.tox/' . && -python -O -m compileall -q -x '\.tox/' . - -exit 0 +fi diff --git a/devscripts/git-hooks/post-merge b/devscripts/git-hooks/post-merge deleted file mode 100755 index 2df0670c..00000000 --- a/devscripts/git-hooks/post-merge +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -# post-merge hook that compiles python files to byte code - -python -m compileall -q -x '\.tox/' . && -python -O -m compileall -q -x '\.tox/' . - -exit 0 diff --git a/devscripts/git-hooks/post-rewrite b/devscripts/git-hooks/post-rewrite deleted file mode 100755 index 59efb3dc..00000000 --- a/devscripts/git-hooks/post-rewrite +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -# post-rewrite hook that compiles python files to byte code - -python -m compileall -q -x '\.tox/' . && -python -O -m compileall -q -x '\.tox/' . - -exit 0 From d365886888d1fcde1c7886a09493b5f1ec7ad8a7 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 28 Aug 2024 20:51:37 +0300 Subject: [PATCH 429/509] Build(git-hooks/post-checkout): Use `rmdir` [skip ci] --- devscripts/git-hooks/post-checkout | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devscripts/git-hooks/post-checkout b/devscripts/git-hooks/post-checkout index 4192e0d6..7b065f5a 100755 --- a/devscripts/git-hooks/post-checkout +++ b/devscripts/git-hooks/post-checkout @@ -11,7 +11,7 @@ if [ "$new_branch" = 1 ]; then # empty directories and outdated docs find . -name '*.py[co]' -delete && for d in sqlobject/include/pydispatch sqlobject/include/tests; do - if [ "`echo $d/*`" = "$d/*" ]; then rm -rf $d; fi + if [ "`echo $d/*`" = "$d/*" ]; then rmdir $d; fi done && rm -rf docs/_build/html docs/html fi From cf96c5e4974cd2241f182e61abd955bdc189fa8c Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 24 Sep 2024 22:53:22 +0300 Subject: [PATCH 430/509] Tests, CI(GHActions): Run tests with Python 3.13 Excluding psycopg2 -- it's not yet compatible. Excluding PyMySQL under w32 -- it's also not yet compatible. --- .github/workflows/run-tests.yaml | 3 +- devscripts/requirements/requirements.txt | 4 +- docs/News.rst | 7 +++ setup.py | 8 ++- tox.ini | 64 ++++++++++++------------ 5 files changed, 50 insertions(+), 36 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 4439ef23..e61a0c4e 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -10,7 +10,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest] - python-version: ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12"] + python-version: ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13"] exclude: - os: windows-latest python-version: "2.7" @@ -45,6 +45,7 @@ jobs: - uses: actions/checkout@v4 - uses: conda-incubator/setup-miniconda@v3 with: + channels: conda-forge, conda-forge/label/python_rc miniforge-version: latest python-version: ${{ matrix.python-version }} if: ${{ !contains(fromJSON(env.not_in_conda), matrix.python-version) }} diff --git a/devscripts/requirements/requirements.txt b/devscripts/requirements/requirements.txt index a419296d..befc10e6 100644 --- a/devscripts/requirements/requirements.txt +++ b/devscripts/requirements/requirements.txt @@ -2,5 +2,7 @@ DateTime FormEncode >= 1.1.1, != 1.3.0; python_version >= '2.7' and python_version < '3.0' -FormEncode >= 1.3.1; python_version >= '3.4' +FormEncode >= 1.3.1; python_version >= '3.4' and python_version < '3.13' +git+https://github.com/formencode/formencode.git; python_version >= '3.13' + PyDispatcher >= 2.0.4 diff --git a/docs/News.rst b/docs/News.rst index 6d75172b..631d418f 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,11 @@ News SQLObject (master) ================== +Tests +----- + +* Run tests with Python 3.13. + CI -- @@ -17,6 +22,8 @@ CI * GHActions: Switch to ``setup-miniconda``. +* GHActions: Python 3.13. + SQLObject 3.11.0 ================ diff --git a/setup.py b/setup.py index 28a634b5..356331ca 100755 --- a/setup.py +++ b/setup.py @@ -64,6 +64,7 @@ "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Topic :: Database", "Topic :: Database :: Front-Ends", "Topic :: Software Development :: Libraries :: Python Modules", @@ -103,9 +104,12 @@ requires=['FormEncode', 'PyDispatcher'], install_requires=[ "FormEncode>=1.1.1,!=1.3.0; python_version=='2.7'", - "FormEncode>=1.3.1; python_version>='3.4'", + "FormEncode>=1.3.1; python_version>='3.4' and python_version < '3.13'", "PyDispatcher>=2.0.4", - ], + ] + [ + "formencode @ " + "git+https://github.com/formencode/formencode.git#egg=formencode" + ] if sys.version_info >= (3, 13) else [], extras_require={ # Firebird/Interbase 'fdb': ['fdb'], diff --git a/tox.ini b/tox.ini index 4d1b6197..91dce16b 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 3.15 -envlist = py27,py3{4,5,6,7,8,9,10,11,12}-sqlite{,-memory},py{27,37,312}-flake8 +envlist = py27,py3{4,5,6,7,8,9,10,11,12,13}-sqlite{,-memory},py{27,37,312}-flake8 # Base test environment settings [testenv] @@ -60,7 +60,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysqldb]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-mysqldb] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysqldb] commands = {envpython} -c "print('MySQL-python requires Python 2.7')" deps = @@ -76,7 +76,7 @@ commands = commands = {envpython} -c "print('mysqlclient requires Python 3.4+')" deps = -[testenv:py3{4,5,6,7,8,9,10,11,12}-mysqlclient] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysqlclient] commands = {[mysqlclient]commands} [mysql-connector] @@ -92,7 +92,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-connector]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-mysql-connector] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-connector] commands = {[mysql-connector]commands} [mysql-connector-python] @@ -108,7 +108,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-connector-python]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-mysql-connector-python{,-w32}] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-connector-python{,-w32}] commands = {[mysql-connector-python]commands} [oursql] @@ -124,7 +124,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[oursql]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-mysql-oursql3-noauto] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-oursql3-noauto] commands = {[oursql]commands} [pymysql] @@ -140,7 +140,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pymysql]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-mysql-pymysql] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-pymysql] commands = {[pymysql]commands} [mariadb] @@ -155,7 +155,7 @@ commands = commands = {envpython} -c "print('mariadb requires Python 3.6+')" deps = -[testenv:py3{6,7,8,9,10,11,12}-mariadb] +[testenv:py3{6,7,8,9,10,11,12,13}-mariadb] commands = {[mariadb]commands} [mysql-pyodbc] @@ -172,7 +172,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pyodbc]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-mysql-pyodbc-noauto] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-pyodbc-noauto] commands = {[mysql-pyodbc]commands} [mysql-pypyodbc] @@ -188,7 +188,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pypyodbc]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-mysql-pypyodbc-noauto] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-pypyodbc-noauto] commands = {[mysql-pypyodbc]commands} # PostgreSQL test environments @@ -221,7 +221,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pygresql]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-pygresql] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pygresql] commands = {[pygresql]commands} [pypostgresql] @@ -236,7 +236,7 @@ commands = commands = {envpython} -c "print('pypostgresql requires Python 3.4+')" deps = -[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-pypostgresql-noauto] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pypostgresql-noauto] commands = {[pypostgresql]commands} [pg8000] @@ -255,7 +255,7 @@ commands = [testenv:py3{4,5,6}-postgres-pg8000] commands = {[pg8000]commands} -[testenv:py3{7,8,9,10,11,12}-postgres-pg8000-noauto] +[testenv:py3{7,8,9,10,11,12,13}-postgres-pg8000-noauto] commands = {[pg8000]commands} [postgres-pyodbc] @@ -272,7 +272,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pyodbc]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-pyodbc-noauto] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pyodbc-noauto] commands = {[postgres-pyodbc]commands} [postgres-pypyodbc] @@ -288,7 +288,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pypyodbc]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-pypyodbc-noauto] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pypyodbc-noauto] commands = {[postgres-pypyodbc]commands} @@ -305,7 +305,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-sqlite] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-sqlite] commands = {[sqlite]commands} [sqlite-memory] @@ -318,7 +318,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite-memory]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-sqlite-memory] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-sqlite-memory] commands = {[sqlite-memory]commands} @@ -336,7 +336,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[fdb]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-firebird-fdb] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-firebird-fdb] commands = {[fdb]commands} [firebirdsql] @@ -352,12 +352,12 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[firebirdsql]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-firebirdsql] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-firebirdsql] commands = {[firebirdsql]commands} # Special test environments -[testenv:py{27,34,35,36,37,38,39,310,311,312}-flake8] +[testenv:py{27,34,35,36,37,38,39,310,311,312,313}-flake8] changedir = ./ deps = flake8 @@ -383,7 +383,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mssql-pyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-mssql-pyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mssql-pyodbc-noauto-w32] platform = win32 commands = {[mssql-pyodbc-w32]commands} @@ -402,7 +402,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-connector-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-mysql-connector-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-connector-w32] platform = win32 commands = {[mysql-connector-w32]commands} @@ -439,7 +439,7 @@ platform = win32 commands = {envpython} -c "print('mariadb requires Python 3.6+')" deps = -[testenv:py3{6,7,8,9,10,11,12}-mariadb-w32] +[testenv:py3{6,7,8,9,10,11,12,13}-mariadb-w32] platform = win32 commands = {[mariadb-w32]commands} @@ -459,7 +459,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-mysql-pyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-pyodbc-noauto-w32] platform = win32 commands = {[mysql-pyodbc-w32]commands} @@ -479,7 +479,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pypyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-mysql-pypyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-pypyodbc-noauto-w32] platform = win32 commands = {[mysql-pypyodbc-w32]commands} @@ -517,7 +517,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pygresql-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-pygresql-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pygresql-w32] platform = win32 commands = {[pygresql-w32]commands} @@ -535,7 +535,7 @@ platform = win32 commands = {envpython} -c "print('pypostgresql requires Python 3.4+')" deps = -[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-pypostgresql-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pypostgresql-noauto-w32] platform = win32 commands = {[pypostgresql-w32]commands} @@ -554,7 +554,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pg8000-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-pg8000-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pg8000-noauto-w32] platform = win32 commands = {[pg8000-w32]commands} @@ -574,7 +574,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-pyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pyodbc-noauto-w32] platform = win32 commands = {[postgres-pyodbc-w32]commands} @@ -594,7 +594,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pypyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-pypyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pypyodbc-noauto-w32] platform = win32 commands = {[postgres-pypyodbc-w32]commands} @@ -611,7 +611,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-sqlite-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-sqlite-w32] platform = win32 commands = {[sqlite-w32]commands} @@ -627,6 +627,6 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite-memory-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-sqlite-memory-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-sqlite-memory-w32] platform = win32 commands = {[sqlite-memory-w32]commands} From 8fb726180c7c0a1a60003efc8ba45edcc79b5e20 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 25 Sep 2024 16:53:58 +0300 Subject: [PATCH 431/509] Feat(Pg): Separate `psycopg` and `psycopg2` --- docs/News.rst | 6 ++++ docs/SQLObject.rst | 23 +++++++-------- docs/download.rst | 3 +- setup.py | 2 +- sqlobject/postgres/pgconnection.py | 12 ++++++-- sqlobject/tests/test_exceptions.py | 2 -- tox.ini | 45 +++++++++++++++++++++++------- 7 files changed, 65 insertions(+), 28 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index 631d418f..6e4fbeb2 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,12 @@ News SQLObject (master) ================== +Drivers +------- + +* Separate ``psycopg`` and ``psycopg2``; + ``psycopg`` is actually ``psycopg3`` now. + Tests ----- diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index e67aea23..94a41420 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -49,13 +49,13 @@ Requirements Currently SQLObject supports MySQL_ and MariaDB_ via MySQLdb_ aka MySQL-python (called mysqlclient_ for Python 3), `MySQL Connector`_, oursql_, PyMySQL_, `mariadb connector`_, PyODBC_ and PyPyODBC_. For -PostgreSQL_ psycopg2_ is recommended; PyGreSQL_, py-postgresql_ and pg8000_ -are supported; SQLite_ has a built-in driver or PySQLite_. -Firebird_ is supported via fdb_ or kinterbasdb_; pyfirebirdsql_ is -supported but has problems. `MAX DB`_ (also known as SAP DB) is supported -via sapdb_. Sybase via Sybase_. `MSSQL Server`_ via pymssql_ (+ FreeTDS_) -or adodbapi_ (Win32). PyODBC_ and PyPyODBC_ are supported for MySQL, -PostgreSQL and MSSQL but have problems (not all tests passed). +PostgreSQL_ psycopg_ and psycopg2_ are recommended; PyGreSQL_, +py-postgresql_ and pg8000_ are supported; SQLite_ has a built-in driver or +PySQLite_. Firebird_ is supported via fdb_ or kinterbasdb_; pyfirebirdsql_ +is supported but has problems. `MAX DB`_ (also known as SAP DB) is +supported via sapdb_. Sybase via Sybase_. `MSSQL Server`_ via pymssql_ (+ +FreeTDS_) or adodbapi_ (Win32). PyODBC_ and PyPyODBC_ are supported for +MySQL, PostgreSQL and MSSQL but have problems (not all tests passed). .. _MySQL: https://www.mysql.com/ .. _MariaDB: https://mariadb.org/ @@ -66,7 +66,8 @@ PostgreSQL and MSSQL but have problems (not all tests passed). .. _PyMySQL: https://github.com/PyMySQL/PyMySQL/ .. _mariadb connector: https://pypi.org/project/mariadb/ .. _PostgreSQL: https://postgresql.org -.. _psycopg2: http://initd.org/psycopg/ +.. _psycopg: https://pypi.org/project/psycopg/ +.. _psycopg2: https://www.psycopg.org/ .. _PyGreSQL: http://www.pygresql.org/ .. _py-postgresql: https://pypi.org/project/py-postgresql/ .. _pg8000: https://pypi.org/project/pg8000/ @@ -1843,9 +1844,9 @@ PostgresConnection supports transactions and all other features. The user can choose a DB API driver for PostgreSQL by using a ``driver`` parameter in DB URI or PostgresConnection that can be a comma-separated -list of driver names. Possible drivers are: ``psycopg2``, -``psycopg`` (alias for ``psycopg2``), ``pygresql``, ``pypostgresql``, -``pg8000``, ``pyodbc``, ``pypyodbc`` or ``odbc`` (try ``pyodbc`` and +list of driver names. Possible drivers are: ``psycopg``, ``psycopg2``, +``pygresql``, ``pypostgresql``, ``pg8000``, +``pyodbc``, ``pypyodbc`` or ``odbc`` (try ``pyodbc`` and ``pypyodbc``). Default is ``psycopg``. Connection-specific parameters are: ``sslmode``, ``unicodeCols``, diff --git a/docs/download.rst b/docs/download.rst index 77f46159..bc283155 100644 --- a/docs/download.rst +++ b/docs/download.rst @@ -73,7 +73,8 @@ pyodbc pypyodbc odbc (synonym for pyodbc) PostgreSQL ^^^^^^^^^^ -psycopg2 psycopg postgres postgresql (synonyms for psycopg2) +psycopg +psycopg2 postgres postgresql (synonyms for psycopg2) pygresql pypostgresql py-postgresql pg8000 SQLite diff --git a/setup.py b/setup.py index 356331ca..e90c10f6 100755 --- a/setup.py +++ b/setup.py @@ -134,8 +134,8 @@ 'pyodbc': ['pyodbc'], 'pypyodbc': ['pypyodbc'], # PostgreSQL + 'psycopg:python_version>="3.6"': ['psycopg[binary]'], 'psycopg2': ['psycopg2'], - 'psycopg': ['psycopg2'], 'postgres': ['psycopg2'], 'postgresql': ['psycopg2'], 'pygresql': ['pygresql'], diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index 5bc6778d..87921c26 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -60,9 +60,12 @@ def __init__(self, dsn=None, host=None, port=None, db=None, if not driver: continue try: - if driver in ('psycopg', 'psycopg2'): - import psycopg2 as psycopg + if driver == 'psycopg': + import psycopg self.module = psycopg + elif driver == 'psycopg2': + import psycopg2 + self.module = psycopg2 elif driver == 'pygresql': import pgdb self.module = pgdb @@ -133,7 +136,10 @@ def __init__(self, dsn=None, host=None, port=None, db=None, else: dsn_dict["port"] = port if db: - dsn_dict["database"] = db + if driver == 'psycopg': + dsn_dict["dbname"] = db + else: + dsn_dict["database"] = db if user: dsn_dict["user"] = user if password: diff --git a/sqlobject/tests/test_exceptions.py b/sqlobject/tests/test_exceptions.py index 42dd134c..86559efe 100644 --- a/sqlobject/tests/test_exceptions.py +++ b/sqlobject/tests/test_exceptions.py @@ -25,8 +25,6 @@ def test_exceptions(): raises(DuplicateEntryError, SOTestException, name="test") connection = getConnection() - if connection.module.__name__ != 'psycopg2': - return SOTestExceptionWithNonexistingTable.setConnection(connection) try: list(SOTestExceptionWithNonexistingTable.select()) diff --git a/tox.ini b/tox.ini index 91dce16b..1b64b4c7 100644 --- a/tox.ini +++ b/tox.ini @@ -22,8 +22,9 @@ deps = mysql-oursql3: git+https://github.com/sqlobject/oursql.git@py3k#egg=oursql pymysql: -rdevscripts/requirements/requirements_pymysql.txt mariadb: mariadb - py34-psycopg: psycopg2-binary==2.8.4 - !py34-psycopg: psycopg2-binary + psycopg: psycopg[binary] + py34-psycopg2: psycopg2-binary==2.8.4 + !py34-psycopg2: psycopg2-binary pygresql: -rdevscripts/requirements/requirements_pygresql.txt pypostgresql: git+https://github.com/sqlobject/py-postgresql.git@combined-fixes#egg=py-postgresql pg8000: -rdevscripts/requirements/requirements_pg8000.txt @@ -200,13 +201,24 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py27-postgres-psycopg] +[testenv:py3{6,7,8,9,10,11,12}-postgres-psycopg-noauto] +commands = {[psycopg]commands} + +[psycopg2] +commands = + {[testenv]commands} + -dropdb --username=runner --no-password sqlobject_test + createdb --username=runner --no-password sqlobject_test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg2&charset=utf-8&debug=1" + dropdb --username=runner --no-password sqlobject_test + +[testenv:py27-postgres-psycopg2] commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base - {[psycopg]commands} + {[psycopg2]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-psycopg] -commands = {[psycopg]commands} +[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-psycopg2] +commands = {[psycopg2]commands} [pygresql] commands = @@ -485,6 +497,19 @@ commands = {[mysql-pypyodbc-w32]commands} [psycopg-w32] platform = win32 +commands = + {[testenv]commands} + -dropdb --username=runner --no-password sqlobject_test + createdb --username=runner --no-password sqlobject_test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" + dropdb --username=runner --no-password sqlobject_test + +[testenv:py3{6,7,8,9,10,11,12}-postgres-psycopg-noauto-w32] +platform = win32 +commands = {[psycopg-w32]commands} + +[psycopg2-w32] +platform = win32 commands = {[testenv]commands} -dropdb --username=runner --no-password sqlobject_test @@ -492,15 +517,15 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg2&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py27-postgres-psycopg-w32] +[testenv:py27-postgres-psycopg2-w32] platform = win32 commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base - {[psycopg-w32]commands} + {[psycopg2-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-psycopg-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-psycopg2-w32] platform = win32 -commands = {[psycopg-w32]commands} +commands = {[psycopg2-w32]commands} [pygresql-w32] platform = win32 From 07e74e51d5877217aa6af5413371a6e5ac1055b6 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 25 Sep 2024 17:45:32 +0300 Subject: [PATCH 432/509] Tests(test_exceptions): MariaDB returns a different error code --- docs/News.rst | 2 ++ sqlobject/tests/test_exceptions.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/News.rst b/docs/News.rst index 6e4fbeb2..fd0fbdf6 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -19,6 +19,8 @@ Tests * Run tests with Python 3.13. +* Fix ``test_exceptions.py``: MariaDB returns a different error code. + CI -- diff --git a/sqlobject/tests/test_exceptions.py b/sqlobject/tests/test_exceptions.py index 86559efe..72991919 100644 --- a/sqlobject/tests/test_exceptions.py +++ b/sqlobject/tests/test_exceptions.py @@ -29,6 +29,6 @@ def test_exceptions(): try: list(SOTestExceptionWithNonexistingTable.select()) except ProgrammingError as e: - assert e.args[0].code == '42P01' + assert e.args[0].code in (1146, '42P01') else: assert False, "DID NOT RAISE" From 48eb837ded57b314f73d2dc7f4bf1defcdc2ec9a Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 25 Sep 2024 18:12:16 +0300 Subject: [PATCH 433/509] Fix(Pg): Minor fix in getting error code from PyGreSQL --- docs/News.rst | 2 ++ sqlobject/postgres/pgconnection.py | 3 +++ 2 files changed, 5 insertions(+) diff --git a/docs/News.rst b/docs/News.rst index fd0fbdf6..a4c11e15 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -14,6 +14,8 @@ Drivers * Separate ``psycopg`` and ``psycopg2``; ``psycopg`` is actually ``psycopg3`` now. +* Minor fix in getting error code from PyGreSQL. + Tests ----- diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index 87921c26..bb76afa4 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -21,6 +21,9 @@ def __new__(cls, e, append_msg=''): # pg8000 for Python 3.5+ ecode = eargs0['C'] eerror = emessage = eargs0['M'] + elif e.__module__ == 'pg': # PyGreSQL + ecode = e.sqlstate + eerror = emessage = e.args[0] elif hasattr(e, 'pgcode'): # psycopg2 or psycopg2.errors ecode = getattr(e, 'pgcode', None) eerror = getattr(e, 'pgerror', None) From 9429cdd5f33d7293fb1f751f9e88a61d3071674e Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 25 Sep 2024 18:37:46 +0300 Subject: [PATCH 434/509] Tests(test_exceptions): Fix under SQLite --- docs/News.rst | 2 +- sqlobject/tests/test_exceptions.py | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index a4c11e15..6685d9cf 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -21,7 +21,7 @@ Tests * Run tests with Python 3.13. -* Fix ``test_exceptions.py``: MariaDB returns a different error code. +* Fix ``test_exceptions.py`` under MariaDB, PostgreSQL and SQLite. CI -- diff --git a/sqlobject/tests/test_exceptions.py b/sqlobject/tests/test_exceptions.py index 72991919..169ca188 100644 --- a/sqlobject/tests/test_exceptions.py +++ b/sqlobject/tests/test_exceptions.py @@ -1,6 +1,7 @@ import pytest from sqlobject import SQLObject, StringCol -from sqlobject.dberrors import DuplicateEntryError, ProgrammingError +from sqlobject.dberrors import DuplicateEntryError, OperationalError, \ + ProgrammingError from sqlobject.tests.dbtest import getConnection, raises, setupClass, supports @@ -30,5 +31,7 @@ def test_exceptions(): list(SOTestExceptionWithNonexistingTable.select()) except ProgrammingError as e: assert e.args[0].code in (1146, '42P01') + except OperationalError: + assert connection.dbName == 'sqlite' else: assert False, "DID NOT RAISE" From bfcc0f135bb0008692bf57ad3e31e8aeb08b8c8a Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 26 Sep 2024 13:45:50 +0300 Subject: [PATCH 435/509] Build(requirements): Fix Python version at 2.7 There will never be 2.8. [skip ci] --- devscripts/requirements/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devscripts/requirements/requirements.txt b/devscripts/requirements/requirements.txt index befc10e6..ce36de21 100644 --- a/devscripts/requirements/requirements.txt +++ b/devscripts/requirements/requirements.txt @@ -1,7 +1,7 @@ # DateTime from Zope DateTime -FormEncode >= 1.1.1, != 1.3.0; python_version >= '2.7' and python_version < '3.0' +FormEncode >= 1.1.1, != 1.3.0; python_version == '2.7' FormEncode >= 1.3.1; python_version >= '3.4' and python_version < '3.13' git+https://github.com/formencode/formencode.git; python_version >= '3.13' From 5b3832184e19308c3712d9393eb7540e74dab8ed Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 26 Sep 2024 17:10:01 +0300 Subject: [PATCH 436/509] Feat(MySQL): Drop `oursql` --- docs/News.rst | 2 ++ docs/SQLObject.rst | 5 ++--- docs/download.rst | 2 +- setup.py | 4 ---- sqlobject/mysql/mysqlconnection.py | 21 +++------------------ tox.ini | 18 ------------------ 6 files changed, 8 insertions(+), 44 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index 6685d9cf..2afb1855 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -16,6 +16,8 @@ Drivers * Minor fix in getting error code from PyGreSQL. +* Dropped ``oursql``. It wasn't updated in years. + Tests ----- diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index 94a41420..699020bc 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -48,7 +48,7 @@ Requirements Currently SQLObject supports MySQL_ and MariaDB_ via MySQLdb_ aka MySQL-python (called mysqlclient_ for Python 3), `MySQL Connector`_, -oursql_, PyMySQL_, `mariadb connector`_, PyODBC_ and PyPyODBC_. For +PyMySQL_, `mariadb connector`_, PyODBC_ and PyPyODBC_. For PostgreSQL_ psycopg_ and psycopg2_ are recommended; PyGreSQL_, py-postgresql_ and pg8000_ are supported; SQLite_ has a built-in driver or PySQLite_. Firebird_ is supported via fdb_ or kinterbasdb_; pyfirebirdsql_ @@ -62,7 +62,6 @@ MySQL, PostgreSQL and MSSQL but have problems (not all tests passed). .. _MySQLdb: https://sourceforge.net/projects/mysql-python/ .. _mysqlclient: https://pypi.org/project/mysqlclient/ .. _`MySQL Connector`: https://pypi.org/project/mysql-connector/ -.. _oursql: https://github.com/python-oursql/oursql .. _PyMySQL: https://github.com/PyMySQL/PyMySQL/ .. _mariadb connector: https://pypi.org/project/mariadb/ .. _PostgreSQL: https://postgresql.org @@ -1798,7 +1797,7 @@ MySQLConnection supports all the features, though MySQL only supports transactions_ when using the InnoDB backend; SQLObject can explicitly define the backend using ``sqlmeta.createSQL``. -Supported drivers are ``mysqldb``, ``connector``, ``oursql``, ``pymysql`` +Supported drivers are ``mysqldb``, ``connector``, ``pymysql`` and ``mariadb``, ``pyodbc``, ``pypyodbc`` or ``odbc`` (try ``pyodbc`` and ``pypyodbc``); defualt is ``mysqldb``. diff --git a/docs/download.rst b/docs/download.rst index bc283155..d3dd39f4 100644 --- a/docs/download.rst +++ b/docs/download.rst @@ -63,7 +63,7 @@ MySQL ^^^^^ mysql (installs MySQL-python for Python 2.7 and mysqlclient for Python 3.4+) -mysql-connector oursql pymysql mariadb +mysql-connector pymysql mariadb ODBC ^^^^ diff --git a/setup.py b/setup.py index e90c10f6..be078818 100755 --- a/setup.py +++ b/setup.py @@ -123,10 +123,6 @@ 'mysql:python_version>="3.4"': ['mysqlclient'], 'mysql-connector': ['mysql-connector'], 'mysql-connector-python': ['mysql-connector-python'], - 'oursql:python_version=="2.7"': [ - 'oursql @ git+https://github.com/sqlobject/oursql.git@master'], - 'oursql:python_version>="3.4"': [ - 'oursql3 @ git+https://github.com/sqlobject/oursql.git@py3k'], 'pymysql': ['pymysql'], 'mariadb': ['mariadb'], # ODBC diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index 1fcf0a7b..4f2a85d5 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -71,13 +71,6 @@ def __init__(self, db, user, password='', host='localhost', port=0, **kw): self.connector_type = 'mysql.connector-python' else: self.connector_type = 'mysql.connector' - elif driver == 'oursql': - import oursql - self.module = oursql - self.CR_SERVER_GONE_ERROR = \ - oursql.errnos['CR_SERVER_GONE_ERROR'] - self.CR_SERVER_LOST = oursql.errnos['CR_SERVER_LOST'] - self.ER_DUP_ENTRY = oursql.errnos['ER_DUP_ENTRY'] elif driver == 'mariadb': import mariadb self.module = mariadb @@ -97,7 +90,7 @@ def __init__(self, db, user, password='', host='localhost', port=0, **kw): raise ValueError( 'Unknown MySQL driver "%s", ' 'expected mysqldb, connector, connector-python, ' - 'oursql, pymysql, mariadb, ' + 'pymysql, mariadb, ' 'odbc, pyodbc or pypyodbc' % driver) except ImportError: pass @@ -149,12 +142,6 @@ def __init__(self, db, user, password='', host='localhost', port=0, **kw): db, host, port, user, password ) - elif driver == 'oursql': - if "use_unicode" not in self.kw: - self.kw["use_unicode"] = not PY2 - # oursql doesn't implement ping(True) yet - self.kw["autoreconnect"] = True - elif driver == 'mariadb': self.kw.pop("charset", None) @@ -206,7 +193,7 @@ def character_set_name(self): # mariadb doesn't implement ping(True) conn.auto_reconnect = True conn.ping() - elif self.driver != 'oursql': + else: # Attempt to reconnect. This setting is persistent. conn.ping(True) except self.module.OperationalError as e: @@ -228,8 +215,6 @@ def character_set_name(self): conn.setencoding(encoding=dbEncoding) elif hasattr(conn, 'set_character_set'): conn.set_character_set(dbEncoding) - elif self.driver == 'oursql': - conn.charset = dbEncoding elif hasattr(conn, 'query'): # works along with monkeypatching code above conn.query("SET NAMES %s" % dbEncoding) @@ -257,7 +242,7 @@ def _executeRetry(self, conn, cursor, query): dbEncoding = self.dbEncoding if dbEncoding and not isinstance(query, bytes) and ( self.driver in ('mysqldb', 'connector', 'connector-python', - 'oursql', 'mariadb')): + 'mariadb')): query = query.encode(dbEncoding, 'surrogateescape') # When a server connection is lost and a query is attempted, most of # the time the query will raise a SERVER_LOST exception, then at the diff --git a/tox.ini b/tox.ini index 1b64b4c7..632b9d72 100644 --- a/tox.ini +++ b/tox.ini @@ -18,8 +18,6 @@ deps = mysqlclient: mysqlclient mysql-connector: mysql-connector <= 2.2.2 mysql-connector-python: -rdevscripts/requirements/requirements_connector_python.txt - mysql-oursql: git+https://github.com/sqlobject/oursql.git@master#egg=oursql - mysql-oursql3: git+https://github.com/sqlobject/oursql.git@py3k#egg=oursql pymysql: -rdevscripts/requirements/requirements_pymysql.txt mariadb: mariadb psycopg: psycopg[binary] @@ -112,22 +110,6 @@ commands = [testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-connector-python{,-w32}] commands = {[mysql-connector-python]commands} -[oursql] -commands = - {[testenv]commands} - -mysql --execute="drop database sqlobject_test;" - mysql --execute="create database sqlobject_test;" - pytest -D "mysql://localhost/sqlobject_test?driver=oursql&charset=utf8&debug=1" - mysql --execute="drop database sqlobject_test;" - -[testenv:py27-mysql-oursql-noauto] -commands = - easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base - {[oursql]commands} - -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-oursql3-noauto] -commands = {[oursql]commands} - [pymysql] commands = {[testenv]commands} From 321ba16a6deb93285c43913ed60d971e4d8897de Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 26 Sep 2024 17:34:59 +0300 Subject: [PATCH 437/509] Feat(SQLite): Dropped `PySQLite2` Only builtin ``sqlite3`` is supported. --- ANNOUNCE.rst | 4 +- README.rst | 4 +- docs/News.rst | 2 + docs/SQLObject.rst | 13 ++--- docs/download.rst | 5 -- setup.py | 1 - sqlobject/sqlite/sqliteconnection.py | 81 +++++++--------------------- sqlobject/tests/test_datetime.py | 7 ++- sqlobject/tests/test_select.py | 5 +- sqlobject/tests/test_sqlite.py | 14 ----- 10 files changed, 31 insertions(+), 105 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 2faac814..404614f1 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -37,8 +37,8 @@ quick to get started with. SQLObject supports a number of backends: MySQL/MariaDB (with a number of DB API drivers: ``MySQLdb``, ``mysqlclient``, ``mysql-connector``, ``PyMySQL``, ``mariadb``), PostgreSQL (``psycopg2``, ``PyGreSQL``, -partially ``pg8000`` and ``py-postgresql``), SQLite (builtin ``sqlite``, -``pysqlite``); connections to other backends +partially ``pg8000`` and ``py-postgresql``), SQLite (builtin ``sqlite3``); +connections to other backends - Firebird, Sybase, MSSQL and MaxDB (also known as SAPDB) - are less debugged). diff --git a/README.rst b/README.rst index d9390c7f..b657d322 100644 --- a/README.rst +++ b/README.rst @@ -9,8 +9,8 @@ quick to get started with. SQLObject supports a number of backends: MySQL/MariaDB (with a number of DB API drivers: ``MySQLdb``, ``mysqlclient``, ``mysql-connector``, ``PyMySQL``, ``mariadb``), PostgreSQL (``psycopg2``, ``PyGreSQL``, -partially ``pg8000`` and ``py-postgresql``), SQLite (builtin ``sqlite``, -``pysqlite``); connections to other backends +partially ``pg8000`` and ``py-postgresql``), SQLite (builtin ``sqlite3``); +connections to other backends - Firebird, Sybase, MSSQL and MaxDB (also known as SAPDB) - are less debugged). diff --git a/docs/News.rst b/docs/News.rst index 2afb1855..f235b381 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -18,6 +18,8 @@ Drivers * Dropped ``oursql``. It wasn't updated in years. +* Dropped ``PySQLite2``. Only builtin ``sqlite3`` is supported. + Tests ----- diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index 699020bc..fe94aa6d 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -50,8 +50,8 @@ Currently SQLObject supports MySQL_ and MariaDB_ via MySQLdb_ aka MySQL-python (called mysqlclient_ for Python 3), `MySQL Connector`_, PyMySQL_, `mariadb connector`_, PyODBC_ and PyPyODBC_. For PostgreSQL_ psycopg_ and psycopg2_ are recommended; PyGreSQL_, -py-postgresql_ and pg8000_ are supported; SQLite_ has a built-in driver or -PySQLite_. Firebird_ is supported via fdb_ or kinterbasdb_; pyfirebirdsql_ +py-postgresql_ and pg8000_ are supported; SQLite_ has a built-in driver. +Firebird_ is supported via fdb_ or kinterbasdb_; pyfirebirdsql_ is supported but has problems. `MAX DB`_ (also known as SAP DB) is supported via sapdb_. Sybase via Sybase_. `MSSQL Server`_ via pymssql_ (+ FreeTDS_) or adodbapi_ (Win32). PyODBC_ and PyPyODBC_ are supported for @@ -62,7 +62,7 @@ MySQL, PostgreSQL and MSSQL but have problems (not all tests passed). .. _MySQLdb: https://sourceforge.net/projects/mysql-python/ .. _mysqlclient: https://pypi.org/project/mysqlclient/ .. _`MySQL Connector`: https://pypi.org/project/mysql-connector/ -.. _PyMySQL: https://github.com/PyMySQL/PyMySQL/ +.. _PyMySQL: https://pypi.org/project/PyMySQL/ .. _mariadb connector: https://pypi.org/project/mariadb/ .. _PostgreSQL: https://postgresql.org .. _psycopg: https://pypi.org/project/psycopg/ @@ -71,7 +71,6 @@ MySQL, PostgreSQL and MSSQL but have problems (not all tests passed). .. _py-postgresql: https://pypi.org/project/py-postgresql/ .. _pg8000: https://pypi.org/project/pg8000/ .. _SQLite: https://sqlite.org/ -.. _PySQLite: https://github.com/ghaering/pysqlite .. _Firebird: http://www.firebirdsql.org/en/python-driver/ .. _fdb: http://www.firebirdsql.org/en/devel-python-driver/ .. _kinterbasdb: http://kinterbasdb.sourceforge.net/ @@ -1865,12 +1864,6 @@ column -- strings can go in integer columns, dates in integers, etc. SQLite may have concurrency issues, depending on your usage in a multi-threaded environment. -The user can choose a DB API driver for SQLite by using a ``driver`` -parameter in DB URI or SQLiteConnection that can be a comma-separated list -of driver names. Possible drivers are: ``pysqlite2`` (alias ``sqlite2``), -``sqlite3``, ``sqlite`` (alias ``sqlite1``). Default is to -test pysqlite2, sqlite3 and sqlite in that order. - Connection-specific parameters are: ``encoding``, ``mode``, ``timeout``, ``check_same_thread``, ``use_table_info``. diff --git a/docs/download.rst b/docs/download.rst index d3dd39f4..88bc739c 100644 --- a/docs/download.rst +++ b/docs/download.rst @@ -77,11 +77,6 @@ psycopg psycopg2 postgres postgresql (synonyms for psycopg2) pygresql pypostgresql py-postgresql pg8000 -SQLite -^^^^^^ - -pysqlite sqlite - The rest ^^^^^^^^ diff --git a/setup.py b/setup.py index be078818..b5847d13 100755 --- a/setup.py +++ b/setup.py @@ -142,7 +142,6 @@ 'pg8000:python_version>="3.5"': ['pg8000'], # 'sapdb': ['sapdb'], - 'sqlite': ['pysqlite'], 'sybase': ['Sybase'], }, ) diff --git a/sqlobject/sqlite/sqliteconnection.py b/sqlobject/sqlite/sqliteconnection.py index d6df5c58..9d491d94 100644 --- a/sqlobject/sqlite/sqliteconnection.py +++ b/sqlobject/sqlite/sqliteconnection.py @@ -33,67 +33,27 @@ class SQLiteConnection(DBAPI): schemes = [dbName] def __init__(self, filename, autoCommit=1, **kw): - drivers = kw.pop('driver', None) or \ - 'pysqlite2,sqlite3,sqlite' - for driver in drivers.split(','): - driver = driver.strip() - if not driver: - continue - try: - if driver in ('sqlite2', 'pysqlite2'): - from pysqlite2 import dbapi2 as sqlite - self.using_sqlite2 = True - elif driver == 'sqlite3': - import sqlite3 as sqlite - self.using_sqlite2 = True - elif driver in ('sqlite', 'sqlite1'): - import sqlite - self.using_sqlite2 = False - else: - raise ValueError( - 'Unknown SQLite driver "%s", ' - 'expected pysqlite2, sqlite3 ' - 'or sqlite' % driver) - except ImportError: - pass - else: - break - else: - raise ImportError( - 'Cannot find an SQLite driver, tried %s' % drivers) - if self.using_sqlite2: - sqlite.encode = base64.b64encode - sqlite.decode = base64.b64decode + import sqlite3 as sqlite + sqlite.encode = base64.b64encode + sqlite.decode = base64.b64decode self.module = sqlite self.filename = filename # full path to sqlite-db-file self._memory = filename == ':memory:' - if self._memory and not self.using_sqlite2: - raise ValueError("You must use sqlite2 to use in-memory databases") # connection options opts = {} - if self.using_sqlite2: - if autoCommit: - opts["isolation_level"] = None - global sqlite2_Binary - if sqlite2_Binary is None: - sqlite2_Binary = sqlite.Binary - sqlite.Binary = lambda s: sqlite2_Binary(sqlite.encode(s)) - if 'factory' in kw: - factory = kw.pop('factory') - if isinstance(factory, str): - factory = globals()[factory] - opts['factory'] = factory(sqlite) - else: - opts['autocommit'] = Boolean(autoCommit) - if 'encoding' in kw: - opts['encoding'] = kw.pop('encoding') - if 'mode' in kw: - opts['mode'] = int(kw.pop('mode'), 0) + if autoCommit: + opts["isolation_level"] = None + global sqlite2_Binary + if sqlite2_Binary is None: + sqlite2_Binary = sqlite.Binary + sqlite.Binary = lambda s: sqlite2_Binary(sqlite.encode(s)) + if 'factory' in kw: + factory = kw.pop('factory') + if isinstance(factory, str): + factory = globals()[factory] + opts['factory'] = factory(sqlite) if 'timeout' in kw: - if self.using_sqlite2: - opts['timeout'] = float(kw.pop('timeout')) - else: - opts['timeout'] = int(float(kw.pop('timeout')) * 1000) + opts['timeout'] = float(kw.pop('timeout')) if 'check_same_thread' in kw: opts["check_same_thread"] = Boolean(kw.pop('check_same_thread')) # use only one connection for sqlite - supports multiple) @@ -186,17 +146,12 @@ def releaseConnection(self, conn, explicit=False): conn.close() def _setAutoCommit(self, conn, auto): - if self.using_sqlite2: - if auto: - conn.isolation_level = None - else: - conn.isolation_level = "" + if auto: + conn.isolation_level = None else: - conn.autocommit = auto + conn.isolation_level = "" def _setIsolationLevel(self, conn, level): - if not self.using_sqlite2: - return conn.isolation_level = level def makeMemoryConnection(self): diff --git a/sqlobject/tests/test_datetime.py b/sqlobject/tests/test_datetime.py index b40e4dd4..ae22adce 100644 --- a/sqlobject/tests/test_datetime.py +++ b/sqlobject/tests/test_datetime.py @@ -93,10 +93,9 @@ def test_microseconds(): pass else: if connection.dbName == "sqlite": - if connection.using_sqlite2: - # mxDateTime sends and PySQLite2 returns - # full date/time for dates - dateFormat = "%Y-%m-%d %H:%M:%S.%f" + # mxDateTime sends and sqlite3 returns + # full date/time for dates + dateFormat = "%Y-%m-%d %H:%M:%S.%f" class DateTime2(SQLObject): col1 = DateTimeCol() diff --git a/sqlobject/tests/test_select.py b/sqlobject/tests/test_select.py index 12677063..ab132768 100644 --- a/sqlobject/tests/test_select.py +++ b/sqlobject/tests/test_select.py @@ -183,10 +183,7 @@ def test_select_RLIKE(): setupClass(IterTest) if IterTest._connection.dbName == "sqlite": - if not IterTest._connection.using_sqlite2: - pytest.skip("These tests require SQLite v2+") - - # Implement regexp() function for SQLite; only works with PySQLite2 + # Implement regexp() function for SQLite import re def regexp(regexp, test): diff --git a/sqlobject/tests/test_sqlite.py b/sqlobject/tests/test_sqlite.py index 2ec1d422..8858bcab 100644 --- a/sqlobject/tests/test_sqlite.py +++ b/sqlobject/tests/test_sqlite.py @@ -25,10 +25,6 @@ class SQLiteFactoryTest(SQLObject): def test_sqlite_factory(): setupClass(SQLiteFactoryTest) - - if not SQLiteFactoryTest._connection.using_sqlite2: - pytest.skip("These tests require SQLite v2+") - factory = [None] def SQLiteConnectionFactory(sqlite): @@ -46,10 +42,6 @@ class MyConnection(sqlite.Connection): def test_sqlite_factory_str(): setupClass(SQLiteFactoryTest) - - if not SQLiteFactoryTest._connection.using_sqlite2: - pytest.skip("These tests require SQLite v2+") - factory = [None] def SQLiteConnectionFactory(sqlite): @@ -72,9 +64,6 @@ class MyConnection(sqlite.Connection): def test_sqlite_aggregate(): setupClass(SQLiteFactoryTest) - if not SQLiteFactoryTest._connection.using_sqlite2: - pytest.skip("These tests require SQLite v2+") - def SQLiteConnectionFactory(sqlite): class MyConnection(sqlite.Connection): def __init__(self, *args, **kwargs): @@ -156,9 +145,6 @@ def test_truediv(): setupClass(SQLiteTruedivTest) if SQLiteTruedivTest._connection.dbName == "sqlite": - if not SQLiteTruedivTest._connection.using_sqlite2: - pytest.skip("These tests require SQLite v2+") - def SQLiteConnectionFactory(sqlite): class MyConnection(sqlite.Connection): def __init__(self, *args, **kwargs): From 44e92542e66b985adec84c96387446483f880037 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 29 Sep 2024 13:15:45 +0300 Subject: [PATCH 438/509] Refactor(mysqlconnection): Call `driver.lower()` once globally --- sqlobject/mysql/mysqlconnection.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index 4f2a85d5..07961e30 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -32,23 +32,23 @@ class MySQLConnection(DBAPI): def __init__(self, db, user, password='', host='localhost', port=0, **kw): drivers = kw.pop('driver', None) or 'mysqldb' for driver in drivers.split(','): - driver = driver.strip() + driver = driver.strip().lower() if not driver: continue try: - if driver.lower() in ('mysqldb', 'pymysql'): - if driver.lower() == 'pymysql': + if driver in ('mysqldb', 'pymysql'): + if driver == 'pymysql': import pymysql pymysql.install_as_MySQLdb() import MySQLdb - if driver.lower() == 'mysqldb': + if driver == 'mysqldb': if MySQLdb.version_info[:3] < (1, 2, 2): raise ValueError( 'SQLObject requires MySQLdb 1.2.2 or later') import MySQLdb.constants.CR import MySQLdb.constants.ER self.module = MySQLdb - if driver.lower() == 'mysqldb': + if driver == 'mysqldb': self.CR_SERVER_GONE_ERROR = \ MySQLdb.constants.CR.SERVER_GONE_ERROR self.CR_SERVER_LOST = \ @@ -169,7 +169,7 @@ def _connectionFromParams(cls, user, password, host, port, path, args): def makeConnection(self): dbEncoding = self.dbEncoding if dbEncoding: - if self.driver.lower() in ('mysqldb', 'pymysql'): + if self.driver in ('mysqldb', 'pymysql'): from MySQLdb.connections import Connection if not hasattr(Connection, 'set_character_set'): # monkeypatch pre MySQLdb 1.2.1 @@ -230,7 +230,7 @@ def _setAutoCommit(self, conn, auto): conn.autocommit = auto def _force_reconnect(self, conn): - if self.driver.lower() == 'pymysql': + if self.driver == 'pymysql': conn.ping(True) self._setAutoCommit(conn, bool(self.autoCommit)) if self.dbEncoding: @@ -268,7 +268,7 @@ def _executeRetry(self, conn, cursor, query): raise dberrors.OperationalError(ErrorMessage(e)) if self.debug: self.printDebug(conn, str(e), 'ERROR') - if self.driver.lower() == 'pymysql': + if self.driver == 'pymysql': self._force_reconnect(conn) else: raise dberrors.OperationalError(ErrorMessage(e)) From d16586274a3834e651f4c5715d8143ba27956f6a Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 29 Sep 2024 13:27:24 +0300 Subject: [PATCH 439/509] Feat(MySQL): Add support for CyMySQL --- docs/News.rst | 2 ++ docs/SQLObject.rst | 7 ++--- docs/download.rst | 2 +- setup.py | 1 + sqlobject/mysql/mysqlconnection.py | 43 +++++++++++++++++++++--------- tox.ini | 36 +++++++++++++++++++++++++ 6 files changed, 75 insertions(+), 16 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index f235b381..37fb94cb 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -11,6 +11,8 @@ SQLObject (master) Drivers ------- +* Add support for CyMySQL; there're some problems with unicode yet. + * Separate ``psycopg`` and ``psycopg2``; ``psycopg`` is actually ``psycopg3`` now. diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index fe94aa6d..13485ae5 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -48,7 +48,7 @@ Requirements Currently SQLObject supports MySQL_ and MariaDB_ via MySQLdb_ aka MySQL-python (called mysqlclient_ for Python 3), `MySQL Connector`_, -PyMySQL_, `mariadb connector`_, PyODBC_ and PyPyODBC_. For +PyMySQL_, CyMySQL_, `mariadb connector`_, PyODBC_ and PyPyODBC_. For PostgreSQL_ psycopg_ and psycopg2_ are recommended; PyGreSQL_, py-postgresql_ and pg8000_ are supported; SQLite_ has a built-in driver. Firebird_ is supported via fdb_ or kinterbasdb_; pyfirebirdsql_ @@ -63,6 +63,7 @@ MySQL, PostgreSQL and MSSQL but have problems (not all tests passed). .. _mysqlclient: https://pypi.org/project/mysqlclient/ .. _`MySQL Connector`: https://pypi.org/project/mysql-connector/ .. _PyMySQL: https://pypi.org/project/PyMySQL/ +.. _CyMySQL: https://pypi.org/project/CyMySQL/ .. _mariadb connector: https://pypi.org/project/mariadb/ .. _PostgreSQL: https://postgresql.org .. _psycopg: https://pypi.org/project/psycopg/ @@ -1796,8 +1797,8 @@ MySQLConnection supports all the features, though MySQL only supports transactions_ when using the InnoDB backend; SQLObject can explicitly define the backend using ``sqlmeta.createSQL``. -Supported drivers are ``mysqldb``, ``connector``, ``pymysql`` -and ``mariadb``, ``pyodbc``, ``pypyodbc`` or ``odbc`` (try ``pyodbc`` and +Supported drivers are ``mysqldb``, ``connector``, ``pymysql``, ``cymysql``, +``mariadb``, ``pyodbc``, ``pypyodbc`` or ``odbc`` (try ``pyodbc`` and ``pypyodbc``); defualt is ``mysqldb``. diff --git a/docs/download.rst b/docs/download.rst index 88bc739c..da11fa1a 100644 --- a/docs/download.rst +++ b/docs/download.rst @@ -63,7 +63,7 @@ MySQL ^^^^^ mysql (installs MySQL-python for Python 2.7 and mysqlclient for Python 3.4+) -mysql-connector pymysql mariadb +mysql-connector pymysql cymysql mariadb ODBC ^^^^ diff --git a/setup.py b/setup.py index b5847d13..717b4773 100755 --- a/setup.py +++ b/setup.py @@ -124,6 +124,7 @@ 'mysql-connector': ['mysql-connector'], 'mysql-connector-python': ['mysql-connector-python'], 'pymysql': ['pymysql'], + 'cymysql': ['cymysql'], 'mariadb': ['mariadb'], # ODBC 'odbc': ['pyodbc'], diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index 07961e30..557adb95 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -1,19 +1,28 @@ from sqlobject import col, dberrors -from sqlobject.compat import PY2 +from sqlobject.compat import PY2, string_type from sqlobject.converters import registerConverter, StringLikeConverter from sqlobject.dbconnection import DBAPI class ErrorMessage(str): def __new__(cls, e, append_msg=''): - if len(e.args) > 1: - obj = str.__new__(cls, e.args[1] + append_msg) + if e.__module__ == 'cymysql.err': + if isinstance(e.errmsg, string_type): + errmsg = e.errmsg + else: + errmsg = e.errmsg.reason + errcode = e.errno else: - obj = str.__new__(cls, append_msg) - try: - obj.code = int(e.args[0]) - except ValueError: - obj.code = e.args[0] + if len(e.args) > 1: + errmsg = e.args[1] + else: + errmsg = '' + try: + errcode = int(e.args[0]) + except ValueError: + errcode = e.args[0] + obj = str.__new__(cls, errmsg + append_msg) + obj.code = errcode obj.module = e.__module__ obj.exception = e.__class__.__name__ return obj @@ -59,6 +68,16 @@ def __init__(self, db, user, password='', host='localhost', port=0, **kw): self.CR_SERVER_LOST = \ MySQLdb.constants.CR.CR_SERVER_LOST self.ER_DUP_ENTRY = MySQLdb.constants.ER.DUP_ENTRY + elif driver == 'cymysql': + import cymysql + import cymysql.constants.CR + import cymysql.constants.ER + self.module = cymysql + self.CR_SERVER_GONE_ERROR = \ + cymysql.constants.CR.CR_SERVER_GONE_ERROR + self.CR_SERVER_LOST = \ + cymysql.constants.CR.CR_SERVER_LOST + self.ER_DUP_ENTRY = cymysql.constants.ER.DUP_ENTRY elif driver in ('connector', 'connector-python'): import mysql.connector self.module = mysql.connector @@ -90,7 +109,7 @@ def __init__(self, db, user, password='', host='localhost', port=0, **kw): raise ValueError( 'Unknown MySQL driver "%s", ' 'expected mysqldb, connector, connector-python, ' - 'pymysql, mariadb, ' + 'pymysql, cymysql, mariadb, ' 'odbc, pyodbc or pypyodbc' % driver) except ImportError: pass @@ -230,7 +249,7 @@ def _setAutoCommit(self, conn, auto): conn.autocommit = auto def _force_reconnect(self, conn): - if self.driver == 'pymysql': + if self.driver in ('pymysql', 'cymysql'): conn.ping(True) self._setAutoCommit(conn, bool(self.autoCommit)) if self.dbEncoding: @@ -256,7 +275,7 @@ def _executeRetry(self, conn, cursor, query): # reconnect flag must be set when making the connection to indicate # that autoreconnecting is desired. In MySQLdb 1.2.2 or newer this is # done by calling ping(True) on the connection. - # PyMySQL needs explicit reconnect + # [PC]yMySQL need explicit reconnect # each time we detect connection timeout. for count in range(3): try: @@ -268,7 +287,7 @@ def _executeRetry(self, conn, cursor, query): raise dberrors.OperationalError(ErrorMessage(e)) if self.debug: self.printDebug(conn, str(e), 'ERROR') - if self.driver == 'pymysql': + if self.driver in ('pymysql', 'cymysql'): self._force_reconnect(conn) else: raise dberrors.OperationalError(ErrorMessage(e)) diff --git a/tox.ini b/tox.ini index 632b9d72..caf1d035 100644 --- a/tox.ini +++ b/tox.ini @@ -19,6 +19,7 @@ deps = mysql-connector: mysql-connector <= 2.2.2 mysql-connector-python: -rdevscripts/requirements/requirements_connector_python.txt pymysql: -rdevscripts/requirements/requirements_pymysql.txt + cymysql: cymysql mariadb: mariadb psycopg: psycopg[binary] py34-psycopg2: psycopg2-binary==2.8.4 @@ -126,6 +127,22 @@ commands = [testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-pymysql] commands = {[pymysql]commands} +[cymysql] +commands = + {[testenv]commands} + -mysql --execute="drop database sqlobject_test;" + mysql --execute="create database sqlobject_test;" + pytest -D "mysql://localhost/sqlobject_test?driver=cymysql&charset=utf8&debug=1" + mysql --execute="drop database sqlobject_test;" + +[testenv:py27-mysql-cymysql-noauto] +commands = + easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base + {[cymysql]commands} + +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-cymysql-noauto] +commands = {[cymysql]commands} + [mariadb] commands = {[testenv]commands} @@ -419,6 +436,25 @@ commands = platform = win32 commands = {[pymysql-w32]commands} +[cymysql-w32] +platform = win32 +commands = + {[testenv]commands} + -mysql --user=ODBC -e "drop database sqlobject_test;" + mysql --user=ODBC -e "create database sqlobject_test;" + pytest -D "mysql://ODBC@localhost/sqlobject_test?driver=cymysql&charset=utf8&debug=1" + mysql --user=ODBC -e "drop database sqlobject_test;" + +[testenv:py27-mysql-cymysql-w32-noauto] +platform = win32 +commands = + easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base + {[cymysql-w32]commands} + +[testenv:py3{4,5,6,7,8,9,10,11,12}-mysql-cymysql-w32-noauto] +platform = win32 +commands = {[cymysql-w32]commands} + [mariadb-w32] platform = win32 commands = From 8bae132a9f988e06cbf9f21116182dfd2215ea69 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 1 Oct 2024 16:31:42 +0300 Subject: [PATCH 440/509] Build(setup.py): Always install `psycopg2-binary` [skip ci] --- docs/SQLObject.rst | 4 +++- setup.py | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index 13485ae5..8969c38d 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -49,7 +49,7 @@ Requirements Currently SQLObject supports MySQL_ and MariaDB_ via MySQLdb_ aka MySQL-python (called mysqlclient_ for Python 3), `MySQL Connector`_, PyMySQL_, CyMySQL_, `mariadb connector`_, PyODBC_ and PyPyODBC_. For -PostgreSQL_ psycopg_ and psycopg2_ are recommended; PyGreSQL_, +PostgreSQL_ psycopg_ and psycopg2_ are recommended, especially their precompiled wheels psycopg-binary_ and psycopg2-binary_; PyGreSQL_, py-postgresql_ and pg8000_ are supported; SQLite_ has a built-in driver. Firebird_ is supported via fdb_ or kinterbasdb_; pyfirebirdsql_ is supported but has problems. `MAX DB`_ (also known as SAP DB) is @@ -67,7 +67,9 @@ MySQL, PostgreSQL and MSSQL but have problems (not all tests passed). .. _mariadb connector: https://pypi.org/project/mariadb/ .. _PostgreSQL: https://postgresql.org .. _psycopg: https://pypi.org/project/psycopg/ +.. _psycopg-binary: https://pypi.org/project/psycopg-binary/ .. _psycopg2: https://www.psycopg.org/ +.. _psycopg2-binary: https://pypi.org/project/psycopg2-binary/ .. _PyGreSQL: http://www.pygresql.org/ .. _py-postgresql: https://pypi.org/project/py-postgresql/ .. _pg8000: https://pypi.org/project/pg8000/ diff --git a/setup.py b/setup.py index 717b4773..c8f24e32 100755 --- a/setup.py +++ b/setup.py @@ -132,9 +132,9 @@ 'pypyodbc': ['pypyodbc'], # PostgreSQL 'psycopg:python_version>="3.6"': ['psycopg[binary]'], - 'psycopg2': ['psycopg2'], - 'postgres': ['psycopg2'], - 'postgresql': ['psycopg2'], + 'psycopg2': ['psycopg2-binary'], + 'postgres': ['psycopg2-binary'], + 'postgresql': ['psycopg2-binary'], 'pygresql': ['pygresql'], 'pypostgresql': ['py-postgresql'], 'py-postgresql': ['py-postgresql'], From 32c1ce111d56025594083a8c8889994f205acc9c Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 1 Oct 2024 16:43:08 +0300 Subject: [PATCH 441/509] Tests(Pg): Run tests with `psycopg-c` [skip ci] --- docs/News.rst | 4 +++- docs/SQLObject.rst | 17 ++++++++++------- setup.py | 1 + tox.ini | 25 +++++++++++++++++++++++++ 4 files changed, 39 insertions(+), 8 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index 37fb94cb..69fedec6 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -14,7 +14,7 @@ Drivers * Add support for CyMySQL; there're some problems with unicode yet. * Separate ``psycopg`` and ``psycopg2``; - ``psycopg`` is actually ``psycopg3`` now. + ``psycopg`` is actually ``psycopg3`` now; not all tests pass. * Minor fix in getting error code from PyGreSQL. @@ -27,6 +27,8 @@ Tests * Run tests with Python 3.13. +* Run tests with ``psycopg-c``; not all tests pass. + * Fix ``test_exceptions.py`` under MariaDB, PostgreSQL and SQLite. CI diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index 8969c38d..c6bbd17b 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -49,13 +49,15 @@ Requirements Currently SQLObject supports MySQL_ and MariaDB_ via MySQLdb_ aka MySQL-python (called mysqlclient_ for Python 3), `MySQL Connector`_, PyMySQL_, CyMySQL_, `mariadb connector`_, PyODBC_ and PyPyODBC_. For -PostgreSQL_ psycopg_ and psycopg2_ are recommended, especially their precompiled wheels psycopg-binary_ and psycopg2-binary_; PyGreSQL_, -py-postgresql_ and pg8000_ are supported; SQLite_ has a built-in driver. -Firebird_ is supported via fdb_ or kinterbasdb_; pyfirebirdsql_ -is supported but has problems. `MAX DB`_ (also known as SAP DB) is -supported via sapdb_. Sybase via Sybase_. `MSSQL Server`_ via pymssql_ (+ -FreeTDS_) or adodbapi_ (Win32). PyODBC_ and PyPyODBC_ are supported for -MySQL, PostgreSQL and MSSQL but have problems (not all tests passed). +PostgreSQL_ psycopg_ and psycopg2_ are recommended, especially their +precompiled wheels psycopg-binary_ and psycopg2-binary_; see also optimized +psycopg-c_; PyGreSQL_, py-postgresql_ and pg8000_ are supported; SQLite_ +has a built-in driver. Firebird_ is supported via fdb_ or kinterbasdb_; +pyfirebirdsql_ is supported but has problems. `MAX DB`_ (also known as SAP +DB) is supported via sapdb_. Sybase via Sybase_. `MSSQL Server`_ via +pymssql_ (+ FreeTDS_) or adodbapi_ (Win32). PyODBC_ and PyPyODBC_ are +supported for MySQL, PostgreSQL and MSSQL but have problems (not all tests +passed). .. _MySQL: https://www.mysql.com/ .. _MariaDB: https://mariadb.org/ @@ -68,6 +70,7 @@ MySQL, PostgreSQL and MSSQL but have problems (not all tests passed). .. _PostgreSQL: https://postgresql.org .. _psycopg: https://pypi.org/project/psycopg/ .. _psycopg-binary: https://pypi.org/project/psycopg-binary/ +.. _psycopg-c: https://pypi.org/project/psycopg-c/ .. _psycopg2: https://www.psycopg.org/ .. _psycopg2-binary: https://pypi.org/project/psycopg2-binary/ .. _PyGreSQL: http://www.pygresql.org/ diff --git a/setup.py b/setup.py index c8f24e32..899e333b 100755 --- a/setup.py +++ b/setup.py @@ -132,6 +132,7 @@ 'pypyodbc': ['pypyodbc'], # PostgreSQL 'psycopg:python_version>="3.6"': ['psycopg[binary]'], + 'psycopg-c:python_version>="3.6"': ['psycopg-c'], 'psycopg2': ['psycopg2-binary'], 'postgres': ['psycopg2-binary'], 'postgresql': ['psycopg2-binary'], diff --git a/tox.ini b/tox.ini index caf1d035..5dc9d1b6 100644 --- a/tox.ini +++ b/tox.ini @@ -22,6 +22,7 @@ deps = cymysql: cymysql mariadb: mariadb psycopg: psycopg[binary] + psycopg_c: psycopg[c] py34-psycopg2: psycopg2-binary==2.8.4 !py34-psycopg2: psycopg2-binary pygresql: -rdevscripts/requirements/requirements_pygresql.txt @@ -203,6 +204,17 @@ commands = [testenv:py3{6,7,8,9,10,11,12}-postgres-psycopg-noauto] commands = {[psycopg]commands} +[psycopg_c] +commands = + {[testenv]commands} + -dropdb --username=runner --no-password sqlobject_test + createdb --username=runner --no-password sqlobject_test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" + dropdb --username=runner --no-password sqlobject_test + +[testenv:py3{6,7,8,9,10,11,12}-postgres-psycopg_c-noauto] +commands = {[psycopg_c]commands} + [psycopg2] commands = {[testenv]commands} @@ -526,6 +538,19 @@ commands = platform = win32 commands = {[psycopg-w32]commands} +[psycopg_c-w32] +platform = win32 +commands = + {[testenv]commands} + -dropdb --username=runner --no-password sqlobject_test + createdb --username=runner --no-password sqlobject_test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" + dropdb --username=runner --no-password sqlobject_test + +[testenv:py3{6,7,8,9,10,11,12}-postgres-psycopg_c-noauto-w32] +platform = win32 +commands = {[psycopg_c-w32]commands} + [psycopg2-w32] platform = win32 commands = From 7a114b78a43c5f3c19df7f0299347b4d651727f5 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 4 Dec 2024 17:02:46 +0300 Subject: [PATCH 442/509] Build(setup.py): Use declarative syntax for FormEnode under Python 3.13 --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 899e333b..5c60cd8d 100755 --- a/setup.py +++ b/setup.py @@ -106,10 +106,10 @@ "FormEncode>=1.1.1,!=1.3.0; python_version=='2.7'", "FormEncode>=1.3.1; python_version>='3.4' and python_version < '3.13'", "PyDispatcher>=2.0.4", - ] + [ "formencode @ " "git+https://github.com/formencode/formencode.git#egg=formencode" - ] if sys.version_info >= (3, 13) else [], + " ; python_version >= '3.13'", + ], extras_require={ # Firebird/Interbase 'fdb': ['fdb'], From 7f7c368ec8fc72a4e527aab0df9c5e6ddb8d82f8 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 4 Dec 2024 17:38:45 +0300 Subject: [PATCH 443/509] Build(setup.py): Improve declarative dependencies --- setup.py | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/setup.py b/setup.py index 5c60cd8d..9f5bea09 100755 --- a/setup.py +++ b/setup.py @@ -122,8 +122,29 @@ 'mysql:python_version=="2.7"': ['MySQL-python'], 'mysql:python_version>="3.4"': ['mysqlclient'], 'mysql-connector': ['mysql-connector'], - 'mysql-connector-python': ['mysql-connector-python'], - 'pymysql': ['pymysql'], + 'mysql-connector-python:python_version=="2.7"': + ['mysql-connector-python <= 8.0.23'], + 'mysql-connector-python:python_version=="3.4"': + ['mysql-connector-python <= 8.0.22, > 2.0', 'protobuf < 3.19'], + 'mysql-connector-python:python_version=="3.5"': + ['mysql-connector-python <= 8.0.23, >= 8.0.5'], + 'mysql-connector-python:python_version=="3.6"': + ['mysql-connector-python <= 8.0.28, >= 8.0.6'], + 'mysql-connector-python:python_version=="3.7"': + ['mysql-connector-python <= 8.0.29, >= 8.0.13'], + 'mysql-connector-python:python_version=="3.8"': + ['mysql-connector-python <= 8.0.29, >= 8.0.19'], + 'mysql-connector-python:python_version=="3.9"': + ['mysql-connector-python <= 8.0.29, >= 8.0.24'], + 'mysql-connector-python:python_version=="3.10"': + ['mysql-connector-python <= 8.0.29, >= 8.0.28'], + 'mysql-connector-python:python_version>="3.11"': + ['mysql-connector-python >= 8.0.29'], + 'pymysql:python_version == "2.7" or python_version == "3.5"': + ['pymysql < 1.0'], + 'pymysql:python_version == "3.4"': ['pymysql < 0.10.0'], + 'pymysql:python_version == "3.6"': ['pymysql < 1.0.3'], + 'pymysql:python_version >= "3.7"': ['pymysql'], 'cymysql': ['cymysql'], 'mariadb': ['mariadb'], # ODBC @@ -136,15 +157,21 @@ 'psycopg2': ['psycopg2-binary'], 'postgres': ['psycopg2-binary'], 'postgresql': ['psycopg2-binary'], - 'pygresql': ['pygresql'], + 'psycopg2-binary:python_version=="3.4"': ['psycopg2-binary == 2.8.4'], + 'psycopg2-binary:python_version!="3.4"': ['psycopg2-binary'], + 'pygresql:python_version=="3.4"': ['pygresql < 5.2'], + 'pygresql:python_version!="3.4"': ['pygresql'], 'pypostgresql': ['py-postgresql'], 'py-postgresql': ['py-postgresql'], - 'pg8000:python_version=="2.7"': ['pg8000<1.13'], - 'pg8000:python_version=="3.4"': ['pg8000<1.12.4'], + 'pg8000:python_version=="2.7"': ['pg8000 < 1.13'], + 'pg8000:python_version=="3.4"': ['pg8000 < 1.12.4'], 'pg8000:python_version>="3.5"': ['pg8000'], # 'sapdb': ['sapdb'], 'sybase': ['Sybase'], + # Non-DB API drivers + 'zope-dt:python_version=="3.4"': ['zope.datetime < 4.3'], + 'zope-dt:python_version!="3.4"': ['zope.datetime'], }, ) From 60b8683d88cdd59d18ff7c74e38c94948fa19b8f Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 4 Dec 2024 19:25:12 +0300 Subject: [PATCH 444/509] Tests(tox): Run tests with psycopg under Python 3.13 There're still some problems so the tests are not ran automatically. --- tox.ini | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tox.ini b/tox.ini index 5dc9d1b6..86641b93 100644 --- a/tox.ini +++ b/tox.ini @@ -201,7 +201,7 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py3{6,7,8,9,10,11,12}-postgres-psycopg-noauto] +[testenv:py3{6,7,8,9,10,11,12,13}-postgres-psycopg-noauto] commands = {[psycopg]commands} [psycopg_c] @@ -212,7 +212,7 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py3{6,7,8,9,10,11,12}-postgres-psycopg_c-noauto] +[testenv:py3{6,7,8,9,10,11,12,13}-postgres-psycopg_c-noauto] commands = {[psycopg_c]commands} [psycopg2] @@ -534,7 +534,7 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py3{6,7,8,9,10,11,12}-postgres-psycopg-noauto-w32] +[testenv:py3{6,7,8,9,10,11,12,13}-postgres-psycopg-noauto-w32] platform = win32 commands = {[psycopg-w32]commands} @@ -547,7 +547,7 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py3{6,7,8,9,10,11,12}-postgres-psycopg_c-noauto-w32] +[testenv:py3{6,7,8,9,10,11,12,13}-postgres-psycopg_c-noauto-w32] platform = win32 commands = {[psycopg_c-w32]commands} From 7ebf297f6e1bbcaec2cf58fd4b859d2d78f0ef7e Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 5 Dec 2024 17:26:58 +0300 Subject: [PATCH 445/509] Tests(py-postgres): Set `sslmode` to `allow` Upstream changed default to `prefer`. [skip ci] --- docs/News.rst | 3 +++ tox.ini | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index 69fedec6..84597bd3 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -31,6 +31,9 @@ Tests * Fix ``test_exceptions.py`` under MariaDB, PostgreSQL and SQLite. +* ``py-postgres``: Set ``sslmode`` to ``allow``; + upstream changed default to ``prefer``. + CI -- diff --git a/tox.ini b/tox.ini index 86641b93..82b39a49 100644 --- a/tox.ini +++ b/tox.ini @@ -252,7 +252,7 @@ commands = {[testenv]commands} -dropdb --username=runner --no-password sqlobject_test createdb --username=runner --no-password sqlobject_test - pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1" + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pypostgresql&sslmode=allow&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-pypostgresql-noauto] @@ -595,7 +595,7 @@ commands = {[testenv]commands} -dropdb --username=runner --no-password sqlobject_test createdb --username=runner --no-password sqlobject_test - pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1" + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pypostgresql&sslmode=allow&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-pypostgresql-noauto-w32] From e4d9aadd81a703877161537a757839b9ef708221 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 18 Dec 2024 14:33:04 +0300 Subject: [PATCH 446/509] Build(devscripts/release): PEP 625 [skip ci] --- devscripts/release | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/devscripts/release b/devscripts/release index 8893a52f..cb4ce229 100755 --- a/devscripts/release +++ b/devscripts/release @@ -24,5 +24,9 @@ if [ "$state" = final ]; then devscripts/sftp-frs fi && +cd dist && +mv SQLObject-$version.tar.gz sqlobject-$version.tar.gz && +cd .. && + twine upload --disable-progress-bar --skip-existing dist/* && exec rm -rf build dist docs/html SQLObject.egg-info From fd927abafd29bb6261d2603b73b3fefcb8efdbec Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 18 Dec 2024 14:43:51 +0300 Subject: [PATCH 447/509] Release 3.12.0b1 --- ANNOUNCE.rst | 50 +++++++++++++++++++++++++++++----------- README.rst | 2 +- docs/News.rst | 2 +- setup.cfg | 5 ---- setup.py | 2 +- sqlobject/__version__.py | 8 +++---- 6 files changed, 43 insertions(+), 26 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 404614f1..9528f2ea 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,26 +1,48 @@ Hello! -I'm pleased to announce version 3.11.1a1, the first alpha of the upcoming -release of branch 3.11 of SQLObject. +I'm pleased to announce version 3.12.0b1, the first beta of the upcoming +release of branch 3.12 of SQLObject. -I'm pleased to announce version 3.11.1a2, the second alpha of the upcoming -release of branch 3.11 of SQLObject. -I'm pleased to announce version 3.11.1b1, the first beta of the upcoming -release of branch 3.11 of SQLObject. +What's new in SQLObject +======================= -I'm pleased to announce version 3.11.1rc1, the first release candidate -of the upcoming release of branch 3.11 of SQLObject. +Drivers +------- -I'm pleased to announce version 3.11.1, the first bugfix release of branch -3.11 of SQLObject. +* Add support for CyMySQL; there're some problems with unicode yet. +* Separate ``psycopg`` and ``psycopg2``; + ``psycopg`` is actually ``psycopg3`` now; not all tests pass. -What's new in SQLObject -======================= +* Minor fix in getting error code from PyGreSQL. + +* Dropped ``oursql``. It wasn't updated in years. + +* Dropped ``PySQLite2``. Only builtin ``sqlite3`` is supported. + +Tests +----- + +* Run tests with Python 3.13. + +* Run tests with ``psycopg-c``; not all tests pass. + +* Fix ``test_exceptions.py`` under MariaDB, PostgreSQL and SQLite. + +* ``py-postgres``: Set ``sslmode`` to ``allow``; + upstream changed default to ``prefer``. + +CI +-- + +* Run tests with ``PyGreSQL`` on w32, do not ignore errors. + +* Skip tests with ``pg8000`` on w32. -The contributors for this release are ... Thanks! +* GHActions: Switch to ``setup-miniconda``. +* GHActions: Python 3.13. For a more complete list, please see the news: http://sqlobject.org/News.html @@ -52,7 +74,7 @@ Site: http://sqlobject.org Download: -https://pypi.org/project/SQLObject/3.11.1a0.dev20231112/ +https://pypi.org/project/SQLObject/3.12.0b1 News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index b657d322..7ed8189c 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,4 @@ -SQLObject 3.11.1a0 +SQLObject 3.12.0b1 ================== SQLObject is a free and open-source (LGPL) Python object-relational diff --git a/docs/News.rst b/docs/News.rst index 84597bd3..c90ef06e 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,7 +5,7 @@ News .. contents:: Contents: :backlinks: none -SQLObject (master) +SQLObject 3.12.0b1 ================== Drivers diff --git a/setup.cfg b/setup.cfg index 461bc50f..43bae0f3 100644 --- a/setup.cfg +++ b/setup.cfg @@ -4,11 +4,6 @@ universal = 1 [easy_install] optimize = 2 -[egg_info] -tag_build = -tag_date = 0 -tag_svn_revision = 0 - [flake8] exclude = .git,.tox,docs/europython/*.py # E305: expected 2 blank lines after class or function definition, found 1 diff --git a/setup.py b/setup.py index 9f5bea09..1a755e67 100755 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ """, # noqa: E501 line too long long_description_content_type="text/x-rst", classifiers=[ - "Development Status :: 3 - Alpha", + "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: " "GNU Library or Lesser General Public License (LGPL)", diff --git a/sqlobject/__version__.py b/sqlobject/__version__.py index 19a73b78..d38b7048 100644 --- a/sqlobject/__version__.py +++ b/sqlobject/__version__.py @@ -1,8 +1,8 @@ -version = '3.11.0' +version = '3.12.0b1' major = 3 -minor = 11 +minor = 12 micro = 0 -release_level = 'final' -serial = 0 +release_level = 'beta' +serial = 1 version_info = (major, minor, micro, release_level, serial) From 3e265f765ea2395cc4b66834aca47bf6e33c1412 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 18 Dec 2024 14:50:12 +0300 Subject: [PATCH 448/509] Build: Prepare for the next release [skip ci] --- ANNOUNCE.rst | 48 +++++++++++++----------------------------------- setup.cfg | 5 +++++ setup.py | 2 +- 3 files changed, 19 insertions(+), 36 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 9528f2ea..92e72480 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,48 +1,26 @@ Hello! -I'm pleased to announce version 3.12.0b1, the first beta of the upcoming +I'm pleased to announce version 3.12.1a1, the first alpha of the upcoming release of branch 3.12 of SQLObject. +I'm pleased to announce version 3.12.1a2, the second alpha of the upcoming +release of branch 3.12 of SQLObject. -What's new in SQLObject -======================= - -Drivers -------- - -* Add support for CyMySQL; there're some problems with unicode yet. - -* Separate ``psycopg`` and ``psycopg2``; - ``psycopg`` is actually ``psycopg3`` now; not all tests pass. - -* Minor fix in getting error code from PyGreSQL. - -* Dropped ``oursql``. It wasn't updated in years. - -* Dropped ``PySQLite2``. Only builtin ``sqlite3`` is supported. - -Tests ------ - -* Run tests with Python 3.13. - -* Run tests with ``psycopg-c``; not all tests pass. - -* Fix ``test_exceptions.py`` under MariaDB, PostgreSQL and SQLite. +I'm pleased to announce version 3.12.1b1, the first beta of the upcoming +release of branch 3.12 of SQLObject. -* ``py-postgres``: Set ``sslmode`` to ``allow``; - upstream changed default to ``prefer``. +I'm pleased to announce version 3.12.1rc1, the first release candidate +of the upcoming release of branch 3.12 of SQLObject. -CI --- +I'm pleased to announce version 3.12.1, the first bugfix release of branch +3.12 of SQLObject. -* Run tests with ``PyGreSQL`` on w32, do not ignore errors. -* Skip tests with ``pg8000`` on w32. +What's new in SQLObject +======================= -* GHActions: Switch to ``setup-miniconda``. +The contributors for this release are ... Thanks! -* GHActions: Python 3.13. For a more complete list, please see the news: http://sqlobject.org/News.html @@ -74,7 +52,7 @@ Site: http://sqlobject.org Download: -https://pypi.org/project/SQLObject/3.12.0b1 +https://pypi.org/project/SQLObject/3.12.1a0.dev20241218/ News and changes: http://sqlobject.org/News.html diff --git a/setup.cfg b/setup.cfg index 43bae0f3..461bc50f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -4,6 +4,11 @@ universal = 1 [easy_install] optimize = 2 +[egg_info] +tag_build = +tag_date = 0 +tag_svn_revision = 0 + [flake8] exclude = .git,.tox,docs/europython/*.py # E305: expected 2 blank lines after class or function definition, found 1 diff --git a/setup.py b/setup.py index 1a755e67..9f5bea09 100755 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ """, # noqa: E501 line too long long_description_content_type="text/x-rst", classifiers=[ - "Development Status :: 4 - Beta", + "Development Status :: 3 - Alpha", "Intended Audience :: Developers", "License :: OSI Approved :: " "GNU Library or Lesser General Public License (LGPL)", From fcb25a4b17af178c4980f200fe33ab6a15c2e5a2 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 18 Dec 2024 14:51:51 +0300 Subject: [PATCH 449/509] Build(devscripts/postrelease): Commit `setup.py` [skip ci] --- devscripts/postrelease | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devscripts/postrelease b/devscripts/postrelease index 246e9e3f..a799b553 100755 --- a/devscripts/postrelease +++ b/devscripts/postrelease @@ -6,4 +6,4 @@ trove_cls='3 - Alpha' && sed -Ei "s/Development Status :: .+\",\$/Development Status :: $trove_cls\",/" setup.py && `git var GIT_EDITOR` ANNOUNCE.rst setup.cfg README.rst docs/News.rst && -exec git commit --message="Build: Prepare for the next release" --message="[skip ci]" ANNOUNCE.rst setup.cfg README.rst docs/News.rst +exec git commit --message="Build: Prepare for the next release" --message="[skip ci]" ANNOUNCE.rst setup.cfg README.rst docs/News.rst setup.py From a6a9cac105522ee8781dd6a67626590912419ba0 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 18 Dec 2024 15:06:37 +0300 Subject: [PATCH 450/509] Build(devscripts/prerelease): For prerelease do not edit `build-all-docs` For alpha/beta versions do not change stable version docs. [skip ci] --- devscripts/prerelease | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/devscripts/prerelease b/devscripts/prerelease index 53e8956d..7fe520db 100755 --- a/devscripts/prerelease +++ b/devscripts/prerelease @@ -40,5 +40,9 @@ else fi && sed -Ei "s/Development Status :: .+\",\$/Development Status :: $trove_cls\",/" setup.py && -`git var GIT_EDITOR` devscripts/build-all-docs docs/News.rst ANNOUNCE.rst sqlobject/__version__.py README.rst setup.cfg setup.py && +if [ "$state" = final -o "$state" = post ]; then + dbad=devscripts/build-all-docs +fi && + +`git var GIT_EDITOR` $dbad docs/News.rst ANNOUNCE.rst sqlobject/__version__.py README.rst setup.cfg setup.py && exec git commit --message="Release $tag" devscripts/build-all-docs docs/News.rst ANNOUNCE.rst sqlobject/__version__.py README.rst setup.cfg setup.py From 784592927509ebc7365227cba4366e0aef54463b Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 19 Dec 2024 17:02:52 +0300 Subject: [PATCH 451/509] Build(devscripts/release): Check if sdist is (not) PEP-625 compatible [skip ci] --- devscripts/release | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/devscripts/release b/devscripts/release index cb4ce229..f5a2e576 100755 --- a/devscripts/release +++ b/devscripts/release @@ -24,9 +24,11 @@ if [ "$state" = final ]; then devscripts/sftp-frs fi && -cd dist && -mv SQLObject-$version.tar.gz sqlobject-$version.tar.gz && -cd .. && +if [ -f dist/SQLObject-$version.tar.gz ]; then + cd dist && + mv SQLObject-$version.tar.gz sqlobject-$version.tar.gz && + cd .. +fi && twine upload --disable-progress-bar --skip-existing dist/* && exec rm -rf build dist docs/html SQLObject.egg-info From 0ead85f0d058a4e0ada04f80bd41cc942a5f18df Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 20 Dec 2024 15:16:34 +0300 Subject: [PATCH 452/509] Release 3.12.0 --- ANNOUNCE.rst | 16 ++-------------- README.rst | 4 ++-- devscripts/build-all-docs | 2 +- docs/News.rst | 6 ++++-- setup.cfg | 5 ----- setup.py | 2 +- sqlobject/__version__.py | 6 +++--- 7 files changed, 13 insertions(+), 28 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 92e72480..0ebac766 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,18 +1,6 @@ Hello! -I'm pleased to announce version 3.12.1a1, the first alpha of the upcoming -release of branch 3.12 of SQLObject. - -I'm pleased to announce version 3.12.1a2, the second alpha of the upcoming -release of branch 3.12 of SQLObject. - -I'm pleased to announce version 3.12.1b1, the first beta of the upcoming -release of branch 3.12 of SQLObject. - -I'm pleased to announce version 3.12.1rc1, the first release candidate -of the upcoming release of branch 3.12 of SQLObject. - -I'm pleased to announce version 3.12.1, the first bugfix release of branch +I'm pleased to announce version 3.12.0, the release of branch 3.12 of SQLObject. @@ -52,7 +40,7 @@ Site: http://sqlobject.org Download: -https://pypi.org/project/SQLObject/3.12.1a0.dev20241218/ +https://pypi.org/project/SQLObject/3.12.0 News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 7ed8189c..980aae82 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.12.0b1 -================== +SQLObject 3.12.0 +================ SQLObject is a free and open-source (LGPL) Python object-relational mapper. Your database tables are described as classes, and rows are diff --git a/devscripts/build-all-docs b/devscripts/build-all-docs index 63d78c2b..648f2f18 100755 --- a/devscripts/build-all-docs +++ b/devscripts/build-all-docs @@ -10,7 +10,7 @@ cd "`dirname \"$0\"`" && PROG_DIR="`pwd`" && cd .. && -build_docs 3.11.0 && +build_docs 3.12.0 && build_docs master devel && rm -rf docs/html && diff --git a/docs/News.rst b/docs/News.rst index c90ef06e..86c19145 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,8 +5,10 @@ News .. contents:: Contents: :backlinks: none -SQLObject 3.12.0b1 -================== +SQLObject 3.12.0 +================ + +Released 2024 Dec 20. Drivers ------- diff --git a/setup.cfg b/setup.cfg index 461bc50f..43bae0f3 100644 --- a/setup.cfg +++ b/setup.cfg @@ -4,11 +4,6 @@ universal = 1 [easy_install] optimize = 2 -[egg_info] -tag_build = -tag_date = 0 -tag_svn_revision = 0 - [flake8] exclude = .git,.tox,docs/europython/*.py # E305: expected 2 blank lines after class or function definition, found 1 diff --git a/setup.py b/setup.py index 9f5bea09..52811dc8 100755 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ """, # noqa: E501 line too long long_description_content_type="text/x-rst", classifiers=[ - "Development Status :: 3 - Alpha", + "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: " "GNU Library or Lesser General Public License (LGPL)", diff --git a/sqlobject/__version__.py b/sqlobject/__version__.py index d38b7048..767a40ea 100644 --- a/sqlobject/__version__.py +++ b/sqlobject/__version__.py @@ -1,8 +1,8 @@ -version = '3.12.0b1' +version = '3.12.0' major = 3 minor = 12 micro = 0 -release_level = 'beta' -serial = 1 +release_level = 'final' +serial = 0 version_info = (major, minor, micro, release_level, serial) From 500a70b21b62956202aeea8059e2a17889a2a919 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 20 Dec 2024 15:36:21 +0300 Subject: [PATCH 453/509] Build: Prepare for the next release [skip ci] --- ANNOUNCE.rst | 16 ++++++++++++++-- docs/News.rst | 3 +++ setup.cfg | 5 +++++ setup.py | 2 +- 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 0ebac766..8fb113f5 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,6 +1,18 @@ Hello! -I'm pleased to announce version 3.12.0, the release of branch +I'm pleased to announce version 3.12.1a1, the first alpha of the upcoming +release of branch 3.12 of SQLObject. + +I'm pleased to announce version 3.12.1a2, the second alpha of the upcoming +release of branch 3.12 of SQLObject. + +I'm pleased to announce version 3.12.1b1, the first beta of the upcoming +release of branch 3.12 of SQLObject. + +I'm pleased to announce version 3.12.1rc1, the first release candidate +of the upcoming release of branch 3.12 of SQLObject. + +I'm pleased to announce version 3.12.1, the first bugfix release of branch 3.12 of SQLObject. @@ -40,7 +52,7 @@ Site: http://sqlobject.org Download: -https://pypi.org/project/SQLObject/3.12.0 +https://pypi.org/project/SQLObject/3.12.1a0.dev20241220/ News and changes: http://sqlobject.org/News.html diff --git a/docs/News.rst b/docs/News.rst index 86c19145..030a6513 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,6 +5,9 @@ News .. contents:: Contents: :backlinks: none +SQLObject (master) +================== + SQLObject 3.12.0 ================ diff --git a/setup.cfg b/setup.cfg index 43bae0f3..461bc50f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -4,6 +4,11 @@ universal = 1 [easy_install] optimize = 2 +[egg_info] +tag_build = +tag_date = 0 +tag_svn_revision = 0 + [flake8] exclude = .git,.tox,docs/europython/*.py # E305: expected 2 blank lines after class or function definition, found 1 diff --git a/setup.py b/setup.py index 52811dc8..9f5bea09 100755 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ """, # noqa: E501 line too long long_description_content_type="text/x-rst", classifiers=[ - "Development Status :: 5 - Production/Stable", + "Development Status :: 3 - Alpha", "Intended Audience :: Developers", "License :: OSI Approved :: " "GNU Library or Lesser General Public License (LGPL)", From 194151f2670321684e34bbfb7d77c501492725b5 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 13 Jan 2025 19:29:22 +0300 Subject: [PATCH 454/509] CI(GHActions): Upgrade `setup-python` and `cache` actions --- .github/workflows/run-tests.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index e61a0c4e..16119295 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -49,16 +49,16 @@ jobs: miniforge-version: latest python-version: ${{ matrix.python-version }} if: ${{ !contains(fromJSON(env.not_in_conda), matrix.python-version) }} - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} if: ${{ contains(fromJSON(env.not_in_conda), matrix.python-version) }} - - uses: actions/cache@v3 + - uses: actions/cache@v4 with: path: ~/conda_pkgs_dir key: ${{ runner.os }}-conda - name: Cache pip - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{ matrix.pip-cache-path }} key: ${{ runner.os }}-pip From 7f5284a05e1de651fdf99d90bdcaddfd10f68128 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 14 Jan 2025 00:20:58 +0300 Subject: [PATCH 455/509] Tests(tox): Change syntax for `envlist` `[testenv:]` doesn't allow lists like `[testenv:py27,py3{4,5}]`; it only allows syntax like `[testenv:py{27,34,35}]`. This commit changes syntax for `envlist` to make it closer to `[testenv:]`. --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 82b39a49..a0df8f37 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 3.15 -envlist = py27,py3{4,5,6,7,8,9,10,11,12,13}-sqlite{,-memory},py{27,37,312}-flake8 +envlist = py{27,34,35,36,37,38,39,310,311,312,313}-sqlite{,-memory},py{27,37,312}-flake8 # Base test environment settings [testenv] From 738920611f57aefb355d6551863eb3a3aba34a2b Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 1 Feb 2025 21:17:42 +0300 Subject: [PATCH 456/509] Build(requirements): Use `FormEncode` 2.1.1 for Python 3.13 --- devscripts/requirements/requirements.txt | 4 ++-- docs/News.rst | 5 +++++ setup.py | 6 ++---- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/devscripts/requirements/requirements.txt b/devscripts/requirements/requirements.txt index ce36de21..02833990 100644 --- a/devscripts/requirements/requirements.txt +++ b/devscripts/requirements/requirements.txt @@ -2,7 +2,7 @@ DateTime FormEncode >= 1.1.1, != 1.3.0; python_version == '2.7' -FormEncode >= 1.3.1; python_version >= '3.4' and python_version < '3.13' -git+https://github.com/formencode/formencode.git; python_version >= '3.13' +FormEncode >= 1.3.1; python_version >= '3.4' +FormEncode >= 2.1.1; python_version >= '3.13' PyDispatcher >= 2.0.4 diff --git a/docs/News.rst b/docs/News.rst index 030a6513..95ed3c4b 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,11 @@ News SQLObject (master) ================== +Installation/dependencies +------------------------- + +* Use ``FormEncode`` 2.1.1 for Python 3.13. + SQLObject 3.12.0 ================ diff --git a/setup.py b/setup.py index 9f5bea09..1eeb42c7 100755 --- a/setup.py +++ b/setup.py @@ -104,11 +104,9 @@ requires=['FormEncode', 'PyDispatcher'], install_requires=[ "FormEncode>=1.1.1,!=1.3.0; python_version=='2.7'", - "FormEncode>=1.3.1; python_version>='3.4' and python_version < '3.13'", + "FormEncode>=1.3.1; python_version>='3.4'", + "FormEncode>=2.1.1; python_version >= '3.13'", "PyDispatcher>=2.0.4", - "formencode @ " - "git+https://github.com/formencode/formencode.git#egg=formencode" - " ; python_version >= '3.13'", ], extras_require={ # Firebird/Interbase From 749f3c83307895ac556f1eb30e437a5c5a3e2f40 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 1 Feb 2025 21:46:43 +0300 Subject: [PATCH 457/509] Release 3.12.0.post2 --- ANNOUNCE.rst | 22 ++++++---------------- README.rst | 4 ++-- devscripts/build-all-docs | 2 +- docs/News.rst | 6 ++++-- setup.cfg | 5 ----- setup.py | 2 +- sqlobject/__version__.py | 6 +++--- 7 files changed, 17 insertions(+), 30 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 8fb113f5..d0b2fc13 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,26 +1,16 @@ Hello! -I'm pleased to announce version 3.12.1a1, the first alpha of the upcoming -release of branch 3.12 of SQLObject. - -I'm pleased to announce version 3.12.1a2, the second alpha of the upcoming -release of branch 3.12 of SQLObject. - -I'm pleased to announce version 3.12.1b1, the first beta of the upcoming -release of branch 3.12 of SQLObject. - -I'm pleased to announce version 3.12.1rc1, the first release candidate -of the upcoming release of branch 3.12 of SQLObject. - -I'm pleased to announce version 3.12.1, the first bugfix release of branch -3.12 of SQLObject. +I'm pleased to announce version 3.12.0.post2, the second post-release +of release 3.12.0 of branch 3.12 of SQLObject. What's new in SQLObject ======================= -The contributors for this release are ... Thanks! +Installation/dependencies +------------------------- +* Use ``FormEncode`` 2.1.1 for Python 3.13. For a more complete list, please see the news: http://sqlobject.org/News.html @@ -52,7 +42,7 @@ Site: http://sqlobject.org Download: -https://pypi.org/project/SQLObject/3.12.1a0.dev20241220/ +https://pypi.org/project/SQLObject/3.12.0.post2 News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 980aae82..1829efc9 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.12.0 -================ +SQLObject 3.12.0.post2 +====================== SQLObject is a free and open-source (LGPL) Python object-relational mapper. Your database tables are described as classes, and rows are diff --git a/devscripts/build-all-docs b/devscripts/build-all-docs index 648f2f18..8d508b27 100755 --- a/devscripts/build-all-docs +++ b/devscripts/build-all-docs @@ -10,7 +10,7 @@ cd "`dirname \"$0\"`" && PROG_DIR="`pwd`" && cd .. && -build_docs 3.12.0 && +build_docs 3.12.0.post2 && build_docs master devel && rm -rf docs/html && diff --git a/docs/News.rst b/docs/News.rst index 95ed3c4b..bc14736c 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,8 +5,10 @@ News .. contents:: Contents: :backlinks: none -SQLObject (master) -================== +SQLObject 3.12.0.post2 +====================== + +Released 2025 Feb 01. Installation/dependencies ------------------------- diff --git a/setup.cfg b/setup.cfg index 461bc50f..43bae0f3 100644 --- a/setup.cfg +++ b/setup.cfg @@ -4,11 +4,6 @@ universal = 1 [easy_install] optimize = 2 -[egg_info] -tag_build = -tag_date = 0 -tag_svn_revision = 0 - [flake8] exclude = .git,.tox,docs/europython/*.py # E305: expected 2 blank lines after class or function definition, found 1 diff --git a/setup.py b/setup.py index 1eeb42c7..48e7a9d8 100755 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ """, # noqa: E501 line too long long_description_content_type="text/x-rst", classifiers=[ - "Development Status :: 3 - Alpha", + "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: " "GNU Library or Lesser General Public License (LGPL)", diff --git a/sqlobject/__version__.py b/sqlobject/__version__.py index 767a40ea..9a310a1e 100644 --- a/sqlobject/__version__.py +++ b/sqlobject/__version__.py @@ -1,8 +1,8 @@ -version = '3.12.0' +version = '3.12.0.post2' major = 3 minor = 12 micro = 0 -release_level = 'final' -serial = 0 +release_level = 'post' +serial = 2 version_info = (major, minor, micro, release_level, serial) From d13705e34c49158b2c23675958752b779165ba1d Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 1 Feb 2025 22:18:34 +0300 Subject: [PATCH 458/509] Build: Prepare for the next release [skip ci] --- ANNOUNCE.rst | 22 ++++++++++++++++------ docs/News.rst | 3 +++ setup.cfg | 5 +++++ setup.py | 2 +- 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index d0b2fc13..47a37342 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,16 +1,26 @@ Hello! -I'm pleased to announce version 3.12.0.post2, the second post-release -of release 3.12.0 of branch 3.12 of SQLObject. +I'm pleased to announce version 3.12.1a1, the first alpha of the upcoming +release of branch 3.12 of SQLObject. + +I'm pleased to announce version 3.12.1a2, the second alpha of the upcoming +release of branch 3.12 of SQLObject. + +I'm pleased to announce version 3.12.1b1, the first beta of the upcoming +release of branch 3.12 of SQLObject. + +I'm pleased to announce version 3.12.1rc1, the first release candidate +of the upcoming release of branch 3.12 of SQLObject. + +I'm pleased to announce version 3.12.1, the first bugfix release of branch +3.12 of SQLObject. What's new in SQLObject ======================= -Installation/dependencies -------------------------- +The contributors for this release are ... Thanks! -* Use ``FormEncode`` 2.1.1 for Python 3.13. For a more complete list, please see the news: http://sqlobject.org/News.html @@ -42,7 +52,7 @@ Site: http://sqlobject.org Download: -https://pypi.org/project/SQLObject/3.12.0.post2 +https://pypi.org/project/SQLObject/3.12.1a0.dev20250201/ News and changes: http://sqlobject.org/News.html diff --git a/docs/News.rst b/docs/News.rst index bc14736c..83a60ba1 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,6 +5,9 @@ News .. contents:: Contents: :backlinks: none +SQLObject (development) +======================= + SQLObject 3.12.0.post2 ====================== diff --git a/setup.cfg b/setup.cfg index 43bae0f3..461bc50f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -4,6 +4,11 @@ universal = 1 [easy_install] optimize = 2 +[egg_info] +tag_build = +tag_date = 0 +tag_svn_revision = 0 + [flake8] exclude = .git,.tox,docs/europython/*.py # E305: expected 2 blank lines after class or function definition, found 1 diff --git a/setup.py b/setup.py index 48e7a9d8..1eeb42c7 100755 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ """, # noqa: E501 line too long long_description_content_type="text/x-rst", classifiers=[ - "Development Status :: 5 - Production/Stable", + "Development Status :: 3 - Alpha", "Intended Audience :: Developers", "License :: OSI Approved :: " "GNU Library or Lesser General Public License (LGPL)", From 6ac086505501cb878066577072be951539db4b2d Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 13 Jan 2025 21:05:30 +0300 Subject: [PATCH 459/509] Feat(MySQL): Extend default list of drivers The list is now `mysqldb`, `mysqlclient`, `mysql-connector`, `mysql-connector-python`, `pymysql`. --- docs/News.rst | 6 ++++++ docs/SQLObject.rst | 3 ++- sqlobject/mysql/mysqlconnection.py | 3 ++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index 83a60ba1..3cba1662 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,12 @@ News SQLObject (development) ======================= +Drivers +------- + +* Extended default list of MySQL drivers to ``mysqldb``, ``mysqlclient``, + ``mysql-connector``, ``mysql-connector-python``, ``pymysql``. + SQLObject 3.12.0.post2 ====================== diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index c6bbd17b..8f089413 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -1804,7 +1804,8 @@ define the backend using ``sqlmeta.createSQL``. Supported drivers are ``mysqldb``, ``connector``, ``pymysql``, ``cymysql``, ``mariadb``, ``pyodbc``, ``pypyodbc`` or ``odbc`` (try ``pyodbc`` and -``pypyodbc``); defualt is ``mysqldb``. +``pypyodbc``); default are ``mysqldb``, ``mysqlclient``, +``mysql-connector``, ``mysql-connector-python``, ``pymysql``. Keyword argument ``conv`` allows to pass a list of custom converters. diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index 557adb95..8ba4a99e 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -39,7 +39,8 @@ class MySQLConnection(DBAPI): odbc_keywords = ('Server', 'Port', 'UID', 'Password', 'Database') def __init__(self, db, user, password='', host='localhost', port=0, **kw): - drivers = kw.pop('driver', None) or 'mysqldb' + drivers = kw.pop('driver', None) or 'mysqldb,mysqlclient,' + \ + 'mysql-connector,mysql-connector-python,pymysql' for driver in drivers.split(','): driver = driver.strip().lower() if not driver: From edb3970a31c93033b7e12b0f40b7cda52b7c3b6d Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 13 Jan 2025 21:10:20 +0300 Subject: [PATCH 460/509] Feat(Pg): Extend default list of drivers The list is now `psycopg`, `psycopg2`, `pygresql`. --- docs/News.rst | 3 +++ docs/SQLObject.rst | 2 +- sqlobject/postgres/pgconnection.py | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index 3cba1662..53e959cf 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -14,6 +14,9 @@ Drivers * Extended default list of MySQL drivers to ``mysqldb``, ``mysqlclient``, ``mysql-connector``, ``mysql-connector-python``, ``pymysql``. +* Extended default list of PostgreSQL drivers to ``psycopg``, ``psycopg2``, + ``pygresql``. + SQLObject 3.12.0.post2 ====================== diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index 8f089413..9f46fa30 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -1852,7 +1852,7 @@ parameter in DB URI or PostgresConnection that can be a comma-separated list of driver names. Possible drivers are: ``psycopg``, ``psycopg2``, ``pygresql``, ``pypostgresql``, ``pg8000``, ``pyodbc``, ``pypyodbc`` or ``odbc`` (try ``pyodbc`` and -``pypyodbc``). Default is ``psycopg``. +``pypyodbc``). Default are ``psycopg``, ``psycopg2``, ``pygresql``. Connection-specific parameters are: ``sslmode``, ``unicodeCols``, ``schema``, ``charset``. diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index bb76afa4..fb24f951 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -57,7 +57,7 @@ class PostgresConnection(DBAPI): def __init__(self, dsn=None, host=None, port=None, db=None, user=None, password=None, **kw): - drivers = kw.pop('driver', None) or 'psycopg' + drivers = kw.pop('driver', None) or 'psycopg,psycopg2,pygresql' for driver in drivers.split(','): driver = driver.strip() if not driver: From 33a25016093e8cbdaddbf14715ab60ecb13084de Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 21 Feb 2025 12:42:46 +0300 Subject: [PATCH 461/509] Fix(mysqlconnection): Drop support for CyMySQL Its author refused to fix unicode-related problems. --- docs/News.rst | 3 +++ docs/SQLObject.rst | 5 ++-- docs/download.rst | 2 +- setup.py | 1 - sqlobject/mysql/mysqlconnection.py | 39 +++++++++--------------------- tox.ini | 36 --------------------------- 6 files changed, 17 insertions(+), 69 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index 53e959cf..faf967ff 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -17,6 +17,9 @@ Drivers * Extended default list of PostgreSQL drivers to ``psycopg``, ``psycopg2``, ``pygresql``. +* Dropped support for CyMySQL; + its author refused to fix unicode-related problems. + SQLObject 3.12.0.post2 ====================== diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index 9f46fa30..896686be 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -48,7 +48,7 @@ Requirements Currently SQLObject supports MySQL_ and MariaDB_ via MySQLdb_ aka MySQL-python (called mysqlclient_ for Python 3), `MySQL Connector`_, -PyMySQL_, CyMySQL_, `mariadb connector`_, PyODBC_ and PyPyODBC_. For +PyMySQL_, `mariadb connector`_, PyODBC_ and PyPyODBC_. For PostgreSQL_ psycopg_ and psycopg2_ are recommended, especially their precompiled wheels psycopg-binary_ and psycopg2-binary_; see also optimized psycopg-c_; PyGreSQL_, py-postgresql_ and pg8000_ are supported; SQLite_ @@ -65,7 +65,6 @@ passed). .. _mysqlclient: https://pypi.org/project/mysqlclient/ .. _`MySQL Connector`: https://pypi.org/project/mysql-connector/ .. _PyMySQL: https://pypi.org/project/PyMySQL/ -.. _CyMySQL: https://pypi.org/project/CyMySQL/ .. _mariadb connector: https://pypi.org/project/mariadb/ .. _PostgreSQL: https://postgresql.org .. _psycopg: https://pypi.org/project/psycopg/ @@ -1802,7 +1801,7 @@ MySQLConnection supports all the features, though MySQL only supports transactions_ when using the InnoDB backend; SQLObject can explicitly define the backend using ``sqlmeta.createSQL``. -Supported drivers are ``mysqldb``, ``connector``, ``pymysql``, ``cymysql``, +Supported drivers are ``mysqldb``, ``connector``, ``pymysql``, ``mariadb``, ``pyodbc``, ``pypyodbc`` or ``odbc`` (try ``pyodbc`` and ``pypyodbc``); default are ``mysqldb``, ``mysqlclient``, ``mysql-connector``, ``mysql-connector-python``, ``pymysql``. diff --git a/docs/download.rst b/docs/download.rst index da11fa1a..88bc739c 100644 --- a/docs/download.rst +++ b/docs/download.rst @@ -63,7 +63,7 @@ MySQL ^^^^^ mysql (installs MySQL-python for Python 2.7 and mysqlclient for Python 3.4+) -mysql-connector pymysql cymysql mariadb +mysql-connector pymysql mariadb ODBC ^^^^ diff --git a/setup.py b/setup.py index 1eeb42c7..82699846 100755 --- a/setup.py +++ b/setup.py @@ -143,7 +143,6 @@ 'pymysql:python_version == "3.4"': ['pymysql < 0.10.0'], 'pymysql:python_version == "3.6"': ['pymysql < 1.0.3'], 'pymysql:python_version >= "3.7"': ['pymysql'], - 'cymysql': ['cymysql'], 'mariadb': ['mariadb'], # ODBC 'odbc': ['pyodbc'], diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index 8ba4a99e..04490aa7 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -1,26 +1,19 @@ from sqlobject import col, dberrors -from sqlobject.compat import PY2, string_type +from sqlobject.compat import PY2 from sqlobject.converters import registerConverter, StringLikeConverter from sqlobject.dbconnection import DBAPI class ErrorMessage(str): def __new__(cls, e, append_msg=''): - if e.__module__ == 'cymysql.err': - if isinstance(e.errmsg, string_type): - errmsg = e.errmsg - else: - errmsg = e.errmsg.reason - errcode = e.errno + if len(e.args) > 1: + errmsg = e.args[1] else: - if len(e.args) > 1: - errmsg = e.args[1] - else: - errmsg = '' - try: - errcode = int(e.args[0]) - except ValueError: - errcode = e.args[0] + errmsg = '' + try: + errcode = int(e.args[0]) + except ValueError: + errcode = e.args[0] obj = str.__new__(cls, errmsg + append_msg) obj.code = errcode obj.module = e.__module__ @@ -69,16 +62,6 @@ def __init__(self, db, user, password='', host='localhost', port=0, **kw): self.CR_SERVER_LOST = \ MySQLdb.constants.CR.CR_SERVER_LOST self.ER_DUP_ENTRY = MySQLdb.constants.ER.DUP_ENTRY - elif driver == 'cymysql': - import cymysql - import cymysql.constants.CR - import cymysql.constants.ER - self.module = cymysql - self.CR_SERVER_GONE_ERROR = \ - cymysql.constants.CR.CR_SERVER_GONE_ERROR - self.CR_SERVER_LOST = \ - cymysql.constants.CR.CR_SERVER_LOST - self.ER_DUP_ENTRY = cymysql.constants.ER.DUP_ENTRY elif driver in ('connector', 'connector-python'): import mysql.connector self.module = mysql.connector @@ -110,7 +93,7 @@ def __init__(self, db, user, password='', host='localhost', port=0, **kw): raise ValueError( 'Unknown MySQL driver "%s", ' 'expected mysqldb, connector, connector-python, ' - 'pymysql, cymysql, mariadb, ' + 'pymysql, mariadb, ' 'odbc, pyodbc or pypyodbc' % driver) except ImportError: pass @@ -250,7 +233,7 @@ def _setAutoCommit(self, conn, auto): conn.autocommit = auto def _force_reconnect(self, conn): - if self.driver in ('pymysql', 'cymysql'): + if self.driver in ('pymysql',): conn.ping(True) self._setAutoCommit(conn, bool(self.autoCommit)) if self.dbEncoding: @@ -288,7 +271,7 @@ def _executeRetry(self, conn, cursor, query): raise dberrors.OperationalError(ErrorMessage(e)) if self.debug: self.printDebug(conn, str(e), 'ERROR') - if self.driver in ('pymysql', 'cymysql'): + if self.driver in ('pymysql',): self._force_reconnect(conn) else: raise dberrors.OperationalError(ErrorMessage(e)) diff --git a/tox.ini b/tox.ini index a0df8f37..086e7890 100644 --- a/tox.ini +++ b/tox.ini @@ -19,7 +19,6 @@ deps = mysql-connector: mysql-connector <= 2.2.2 mysql-connector-python: -rdevscripts/requirements/requirements_connector_python.txt pymysql: -rdevscripts/requirements/requirements_pymysql.txt - cymysql: cymysql mariadb: mariadb psycopg: psycopg[binary] psycopg_c: psycopg[c] @@ -128,22 +127,6 @@ commands = [testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-pymysql] commands = {[pymysql]commands} -[cymysql] -commands = - {[testenv]commands} - -mysql --execute="drop database sqlobject_test;" - mysql --execute="create database sqlobject_test;" - pytest -D "mysql://localhost/sqlobject_test?driver=cymysql&charset=utf8&debug=1" - mysql --execute="drop database sqlobject_test;" - -[testenv:py27-mysql-cymysql-noauto] -commands = - easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base - {[cymysql]commands} - -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-cymysql-noauto] -commands = {[cymysql]commands} - [mariadb] commands = {[testenv]commands} @@ -448,25 +431,6 @@ commands = platform = win32 commands = {[pymysql-w32]commands} -[cymysql-w32] -platform = win32 -commands = - {[testenv]commands} - -mysql --user=ODBC -e "drop database sqlobject_test;" - mysql --user=ODBC -e "create database sqlobject_test;" - pytest -D "mysql://ODBC@localhost/sqlobject_test?driver=cymysql&charset=utf8&debug=1" - mysql --user=ODBC -e "drop database sqlobject_test;" - -[testenv:py27-mysql-cymysql-w32-noauto] -platform = win32 -commands = - easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base - {[cymysql-w32]commands} - -[testenv:py3{4,5,6,7,8,9,10,11,12}-mysql-cymysql-w32-noauto] -platform = win32 -commands = {[cymysql-w32]commands} - [mariadb-w32] platform = win32 commands = From d2c26075783a42d9103dee8e783b7f770a981543 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 28 Feb 2025 17:47:00 +0300 Subject: [PATCH 462/509] Fix(psycopg): Convert Binary type --- sqlobject/postgres/pgconnection.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index fb24f951..df478d52 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -104,7 +104,11 @@ def __init__(self, dsn=None, host=None, port=None, db=None, raise ImportError( 'Cannot find a PostgreSQL driver, tried %s' % drivers) - if driver.startswith('psycopg'): + if driver.startswith('psycopg2'): + # Register a converter for psycopg2 Binary type. + registerConverter(type(self.module.Binary('')), + Psyco2BinaryConverter) + elif driver.startswith('psycopg'): # Register a converter for psycopg Binary type. registerConverter(type(self.module.Binary('')), PsycoBinaryConverter) @@ -588,8 +592,8 @@ def dropDatabase(self): self._createOrDropDatabase(op="DROP") -# Converter for Binary types -def PsycoBinaryConverter(value, db): +# Converters for Binary types +def Psyco2BinaryConverter(value, db): assert db == 'postgres' return str(value) @@ -608,6 +612,11 @@ def escape_bytea(value): ) +def PsycoBinaryConverter(value, db): + assert db == 'postgres' + return sqlrepr(escape_bytea(value.obj), db) + + def PostgresBinaryConverter(value, db): assert db == 'postgres' return sqlrepr(escape_bytea(value), db) From 07b0ca4b2551fe01654beb96e13a107841137762 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 28 Feb 2025 17:57:45 +0300 Subject: [PATCH 463/509] Fix(psycopg): Extract error code/message --- sqlobject/postgres/pgconnection.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index df478d52..2354142e 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -21,7 +21,7 @@ def __new__(cls, e, append_msg=''): # pg8000 for Python 3.5+ ecode = eargs0['C'] eerror = emessage = eargs0['M'] - elif e.__module__ == 'pg': # PyGreSQL + elif e.__module__ in ('psycopg.errors', 'pg'): # psycopg, PyGreSQL ecode = e.sqlstate eerror = emessage = e.args[0] elif hasattr(e, 'pgcode'): # psycopg2 or psycopg2.errors From f592d97f048387106352782dfbfa90409024b2e5 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 28 Feb 2025 18:05:48 +0300 Subject: [PATCH 464/509] Fix outstanding problems with `psycopg` It's now the first class driver. --- docs/News.rst | 2 ++ tox.ini | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index faf967ff..faf06bd8 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -17,6 +17,8 @@ Drivers * Extended default list of PostgreSQL drivers to ``psycopg``, ``psycopg2``, ``pygresql``. +* Fixed outstanding problems with ``psycopg``. It's now the first class driver. + * Dropped support for CyMySQL; its author refused to fix unicode-related problems. diff --git a/tox.ini b/tox.ini index 086e7890..e450374d 100644 --- a/tox.ini +++ b/tox.ini @@ -184,7 +184,7 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py3{6,7,8,9,10,11,12,13}-postgres-psycopg-noauto] +[testenv:py3{6,7,8,9,10,11,12,13}-postgres-psycopg] commands = {[psycopg]commands} [psycopg_c] @@ -498,7 +498,7 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py3{6,7,8,9,10,11,12,13}-postgres-psycopg-noauto-w32] +[testenv:py3{6,7,8,9,10,11,12,13}-postgres-psycopg-w32] platform = win32 commands = {[psycopg-w32]commands} From c2374e64a0540b8ae3ac38a0b72d6b6c66ec26c8 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 28 Feb 2025 19:52:11 +0300 Subject: [PATCH 465/509] Tests(GHActions): Fix old bug in the workflow on w32 If a bat/cmd file is simply executed from another it replaces the caller. To execute a few ones in a row each must be `call`ed. --- .github/workflows/run-tests.yaml | 6 +++--- docs/News.rst | 5 +++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 16119295..760ec89e 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -104,8 +104,8 @@ jobs: shell: bash -el {0} - name: Run tox @ w32 run: | - devscripts\tox-select-envs.cmd %PYVER%-mysql - devscripts\tox-select-envs.cmd %PYVER%-postgres - devscripts\tox-select-envs.cmd %PYVER%-sqlite + call devscripts\tox-select-envs.cmd %PYVER%-mysql + call devscripts\tox-select-envs.cmd %PYVER%-postgres + call devscripts\tox-select-envs.cmd %PYVER%-sqlite if: ${{ runner.os == 'Windows' }} shell: cmd /C CALL {0} diff --git a/docs/News.rst b/docs/News.rst index faf06bd8..dd0e7514 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -22,6 +22,11 @@ Drivers * Dropped support for CyMySQL; its author refused to fix unicode-related problems. +CI +-- + +* Tests(GHActions): Fixed old bug in the workflow on w32. + SQLObject 3.12.0.post2 ====================== From f5c41a4a0c1033fcb73d4a4300302cdac6a9e1fa Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 28 Feb 2025 21:43:23 +0300 Subject: [PATCH 466/509] Tests(tox): Rename `mysql-connector` tests to `mysql-cnx` This is to avoid installing `mysql-connector` into `mysql-connector-python` tests. --- tox.ini | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tox.ini b/tox.ini index e450374d..89c6c7c6 100644 --- a/tox.ini +++ b/tox.ini @@ -16,7 +16,7 @@ deps = !py34: zope.datetime mysqldb: mysql-python mysqlclient: mysqlclient - mysql-connector: mysql-connector <= 2.2.2 + mysql-cnx: mysql-connector <= 2.2.2 mysql-connector-python: -rdevscripts/requirements/requirements_connector_python.txt pymysql: -rdevscripts/requirements/requirements_pymysql.txt mariadb: mariadb @@ -79,7 +79,7 @@ deps = [testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysqlclient] commands = {[mysqlclient]commands} -[mysql-connector] +[mysql-cnx] commands = {[testenv]commands} -mysql --execute="drop database sqlobject_test;" @@ -87,13 +87,13 @@ commands = pytest -D "mysql://runner:@localhost/sqlobject_test?driver=connector&charset=utf8&debug=1" mysql --execute="drop database sqlobject_test;" -[testenv:py27-mysql-connector] +[testenv:py27-mysql-cnx] commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base - {[mysql-connector]commands} + {[mysql-cnx]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-connector] -commands = {[mysql-connector]commands} +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-cnx] +commands = {[mysql-cnx]commands} [mysql-connector-python] commands = @@ -393,7 +393,7 @@ commands = platform = win32 commands = {[mssql-pyodbc-w32]commands} -[mysql-connector-w32] +[mysql-cnx-w32] platform = win32 commands = {[testenv]commands} From 9cc652db6516aadb1dcebb395d1de53d95a1421b Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 28 Feb 2025 21:49:52 +0300 Subject: [PATCH 467/509] Tests(tox): Improve tests of `mysql-connector` --- docs/News.rst | 5 +++++ tox.ini | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/News.rst b/docs/News.rst index dd0e7514..9b573dab 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -22,6 +22,11 @@ Drivers * Dropped support for CyMySQL; its author refused to fix unicode-related problems. +Tests +----- + +* Improved tests of ``mysql-connector``. + CI -- diff --git a/tox.ini b/tox.ini index 89c6c7c6..48ce6eba 100644 --- a/tox.ini +++ b/tox.ini @@ -16,7 +16,7 @@ deps = !py34: zope.datetime mysqldb: mysql-python mysqlclient: mysqlclient - mysql-cnx: mysql-connector <= 2.2.2 + mysql-cnx: mysql-connector mysql-connector-python: -rdevscripts/requirements/requirements_connector_python.txt pymysql: -rdevscripts/requirements/requirements_pymysql.txt mariadb: mariadb From 9d3e36f8a282c915cffb6068ef13e4aaeb5dec4c Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 28 Feb 2025 21:45:13 +0300 Subject: [PATCH 468/509] Tests(tox): Fix `mysql-connector-python-w32` tests --- docs/News.rst | 2 +- tox.ini | 31 +++++++++++++++++++++++++------ 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index 9b573dab..955ed2f5 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -25,7 +25,7 @@ Drivers Tests ----- -* Improved tests of ``mysql-connector``. +* Improved tests of ``mysql-connector`` and ``mysql-connector-python``. CI -- diff --git a/tox.ini b/tox.ini index 48ce6eba..069a7c7f 100644 --- a/tox.ini +++ b/tox.ini @@ -103,12 +103,12 @@ commands = pytest -D "mysql://runner:@localhost/sqlobject_test?driver=connector-python&charset=utf8&debug=1" mysql --execute="drop database sqlobject_test;" -[testenv:py27-mysql-connector-python{,-w32}] +[testenv:py27-mysql-connector-python] commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-connector-python]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-connector-python{,-w32}] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-connector-python] commands = {[mysql-connector-python]commands} [pymysql] @@ -402,15 +402,34 @@ commands = pytest -D "mysql://ODBC@localhost/sqlobject_test?driver=connector&charset=utf8&debug=1" mysql --user=ODBC -e "drop database sqlobject_test;" -[testenv:py27-mysql-connector-w32] +[testenv:py27-mysql-cnx-w32] platform = win32 commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base - {[mysql-connector-w32]commands} + {[mysql-cnx-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-connector-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-cnx-w32] platform = win32 -commands = {[mysql-connector-w32]commands} +commands = {[mysql-cnx-w32]commands} + +[mysql-connector-python-w32] +platform = win32 +commands = + {[testenv]commands} + -mysql --user=ODBC -e "drop database sqlobject_test;" + mysql --user=ODBC -e "create database sqlobject_test;" + pytest -D "mysql://ODBC@localhost/sqlobject_test?driver=connector-python&charset=utf8&debug=1" + mysql --user=ODBC -e "drop database sqlobject_test;" + +[testenv:py27-mysql-connector-python-w32] +platform = win32 +commands = + easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base + {[mysql-connector-python-w32]commands} + +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-connector-python-w32] +platform = win32 +commands = {[mysql-connector-python-w32]commands} [pymysql-w32] platform = win32 From 6fd55a0e884c6c60f7ac811fc223740f50b47268 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 28 Feb 2025 22:44:05 +0300 Subject: [PATCH 469/509] Tests(tox): Run `psycopg2` tests under Py 3.13 --- tox.ini | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tox.ini b/tox.ini index 069a7c7f..f410030d 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 3.15 -envlist = py{27,34,35,36,37,38,39,310,311,312,313}-sqlite{,-memory},py{27,37,312}-flake8 +envlist = py{27,34,35,36,37,38,39,310,311,312,313}-sqlite{,-memory},py{27,37,313}-flake8 # Base test environment settings [testenv] @@ -211,7 +211,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[psycopg2]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-psycopg2] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-psycopg2] commands = {[psycopg2]commands} [pygresql] @@ -549,7 +549,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[psycopg2-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-psycopg2-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-psycopg2-w32] platform = win32 commands = {[psycopg2-w32]commands} From 5c8fe5b2a97c5049f04b68ee6a97d1fcc13206e5 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 28 Feb 2025 23:23:29 +0300 Subject: [PATCH 470/509] Tests(GHActions): Better error handling Abort chain of tests on any error and fail the entire workflow. --- .github/workflows/run-tests.yaml | 14 +++++++------- docs/News.rst | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 760ec89e..d81585f4 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -96,16 +96,16 @@ jobs: shell: bash -el {0} - name: Run tox @ Linux run: | - devscripts/tox-select-envs $PYVER-mysql - devscripts/tox-select-envs $PYVER-postgres - devscripts/tox-select-envs $PYVER-sqlite + devscripts/tox-select-envs $PYVER-mysql && + devscripts/tox-select-envs $PYVER-postgres && + devscripts/tox-select-envs $PYVER-sqlite && devscripts/tox-select-envs $PYVER-flake8 if: ${{ runner.os == 'Linux' }} shell: bash -el {0} - name: Run tox @ w32 - run: | - call devscripts\tox-select-envs.cmd %PYVER%-mysql - call devscripts\tox-select-envs.cmd %PYVER%-postgres - call devscripts\tox-select-envs.cmd %PYVER%-sqlite + run: > + devscripts\\tox-select-envs.cmd %PYVER%-mysql && + devscripts\\tox-select-envs.cmd %PYVER%-postgres && + devscripts\\tox-select-envs.cmd %PYVER%-sqlite if: ${{ runner.os == 'Windows' }} shell: cmd /C CALL {0} diff --git a/docs/News.rst b/docs/News.rst index 955ed2f5..a88fac97 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -30,7 +30,7 @@ Tests CI -- -* Tests(GHActions): Fixed old bug in the workflow on w32. +* Tests(GHActions): Fixed old bugs in the workflow on w32. SQLObject 3.12.0.post2 ====================== From 3186b3d6121e93d6787754fdc569e9da4adf4aed Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 1 Mar 2025 07:54:29 +0300 Subject: [PATCH 471/509] Tests(tox): Skip `psycopg2` test under Py 3.8 on w32 Somehow Python cannot import `psycopg2`; could be a buggy wheel. --- tox.ini | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index f410030d..0ddc4c65 100644 --- a/tox.ini +++ b/tox.ini @@ -549,7 +549,12 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[psycopg2-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-psycopg2-w32] +[testenv:py38-postgres-psycopg2-noauto-w32] +platform = win32 +commands = {envpython} -c "print('Skipped...')" +deps = + +[testenv:py3{4,5,6,7,9,10,11,12,13}-postgres-psycopg2-w32] platform = win32 commands = {[psycopg2-w32]commands} From ecbb61d11bda8b795167e9c78e56ed38aeb2cd91 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 1 Mar 2025 08:03:21 +0300 Subject: [PATCH 472/509] Tests: Add tests for `mysqldb` and `mysqlclient` on w32 --- .../requirements/requirements_mysqlclient.txt | 9 +++++ docs/News.rst | 3 ++ tox.ini | 40 ++++++++++++++++++- 3 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 devscripts/requirements/requirements_mysqlclient.txt diff --git a/devscripts/requirements/requirements_mysqlclient.txt b/devscripts/requirements/requirements_mysqlclient.txt new file mode 100644 index 00000000..53611366 --- /dev/null +++ b/devscripts/requirements/requirements_mysqlclient.txt @@ -0,0 +1,9 @@ +mysqlclient == 2.0.3; python_version == '3.6' and sys_platform == 'win32' +mysqlclient == 2.0.3; python_version == '3.7' and sys_platform == 'win32' +mysqlclient == 2.1.1; python_version == '3.8' and sys_platform == 'win32' +mysqlclient >= 2.2.7; python_version == '3.9' and sys_platform == 'win32' +mysqlclient >= 2.2.7; python_version == '3.10' and sys_platform == 'win32' +mysqlclient >= 2.2.7; python_version == '3.11' and sys_platform == 'win32' +mysqlclient >= 2.2.7; python_version == '3.12' and sys_platform == 'win32' +mysqlclient >= 2.2.7; python_version == '3.13' and sys_platform == 'win32' +mysqlclient; sys_platform != 'win32' diff --git a/docs/News.rst b/docs/News.rst index a88fac97..372b6130 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -25,6 +25,9 @@ Drivers Tests ----- +* Added tests for ``mysqldb`` (aka ``mysql-python``) + and ``mysqlclient`` on w32. + * Improved tests of ``mysql-connector`` and ``mysql-connector-python``. CI diff --git a/tox.ini b/tox.ini index 0ddc4c65..0df772c8 100644 --- a/tox.ini +++ b/tox.ini @@ -15,7 +15,7 @@ deps = py34: zope.datetime < 4.3 !py34: zope.datetime mysqldb: mysql-python - mysqlclient: mysqlclient + mysqlclient: -rdevscripts/requirements/requirements_mysqlclient.txt mysql-cnx: mysql-connector mysql-connector-python: -rdevscripts/requirements/requirements_connector_python.txt pymysql: -rdevscripts/requirements/requirements_pymysql.txt @@ -393,6 +393,44 @@ commands = platform = win32 commands = {[mssql-pyodbc-w32]commands} +[mysqldb-w32] +platform = win32 +commands = + {[testenv]commands} + -mysql --user=ODBC -e "drop database sqlobject_test;" + mysql --user=ODBC -e "create database sqlobject_test;" + pytest -D "mysql://ODBC@localhost/sqlobject_test?driver=mysqldb&charset=utf8&debug=1" + mysql --user=ODBC -e "drop database sqlobject_test;" + +[testenv:py27-mysqldb-noauto-w32] +platform = win32 +commands = + easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base + {[mysqldb-w32]commands} + +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysqldb-w32] +platform = win32 +commands = {envpython} -c "print('MySQL-python requires Python 2.7')" +deps = + +[mysqlclient-w32] +platform = win32 +commands = + {[testenv]commands} + -mysql --user=ODBC -e "drop database sqlobject_test;" + mysql --user=ODBC -e "create database sqlobject_test;" + pytest -D "mysql://ODBC@localhost/sqlobject_test?driver=mysqldb&charset=utf8&debug=1" + mysql --user=ODBC -e "drop database sqlobject_test;" + +[testenv:py27,py3{4,5}-mysqlclient-noauto-w32] +platform = win32 +commands = {envpython} -c "print('mysqlclient requires Python 3.6+')" +deps = + +[testenv:py3{6,7,8,9,10,11,12,13}-mysqlclient-w32] +platform = win32 +commands = {[mysqlclient-w32]commands} + [mysql-cnx-w32] platform = win32 commands = From 2cc558e355b57a0abe15130444d5e3f843b609f6 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 1 Mar 2025 18:30:10 +0300 Subject: [PATCH 473/509] Tests(tox): Remove dummy environments --- tox.ini | 41 ----------------------------------------- 1 file changed, 41 deletions(-) diff --git a/tox.ini b/tox.ini index 0df772c8..331278a3 100644 --- a/tox.ini +++ b/tox.ini @@ -60,10 +60,6 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysqldb]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysqldb] -commands = {envpython} -c "print('MySQL-python requires Python 2.7')" -deps = - [mysqlclient] commands = {[testenv]commands} @@ -72,10 +68,6 @@ commands = pytest -D "mysql://localhost/sqlobject_test?driver=mysqldb&charset=utf8&debug=1" mysql --execute="drop database sqlobject_test;" -[testenv:py27-mysqlclient] -commands = {envpython} -c "print('mysqlclient requires Python 3.4+')" -deps = - [testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysqlclient] commands = {[mysqlclient]commands} @@ -135,10 +127,6 @@ commands = pytest -D "mysql://localhost/sqlobject_test?driver=mariadb&charset=utf8&debug=1" mysql --execute="drop database sqlobject_test;" -[testenv:py{27,34,35}-mariadb] -commands = {envpython} -c "print('mariadb requires Python 3.6+')" -deps = - [testenv:py3{6,7,8,9,10,11,12,13}-mariadb] commands = {[mariadb]commands} @@ -238,10 +226,6 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pypostgresql&sslmode=allow&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py27-postgres-pypostgresql-noauto] -commands = {envpython} -c "print('pypostgresql requires Python 3.4+')" -deps = - [testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pypostgresql-noauto] commands = {[pypostgresql]commands} @@ -408,11 +392,6 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysqldb-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysqldb-w32] -platform = win32 -commands = {envpython} -c "print('MySQL-python requires Python 2.7')" -deps = - [mysqlclient-w32] platform = win32 commands = @@ -422,11 +401,6 @@ commands = pytest -D "mysql://ODBC@localhost/sqlobject_test?driver=mysqldb&charset=utf8&debug=1" mysql --user=ODBC -e "drop database sqlobject_test;" -[testenv:py27,py3{4,5}-mysqlclient-noauto-w32] -platform = win32 -commands = {envpython} -c "print('mysqlclient requires Python 3.6+')" -deps = - [testenv:py3{6,7,8,9,10,11,12,13}-mysqlclient-w32] platform = win32 commands = {[mysqlclient-w32]commands} @@ -497,11 +471,6 @@ commands = pytest -D "mysql://ODBC@localhost/sqlobject_test?driver=mariadb&charset=utf8&debug=1" mysql --user=ODBC -e "drop database sqlobject_test;" -[testenv:py{27,34,35}-mariadb-w32] -platform = win32 -commands = {envpython} -c "print('mariadb requires Python 3.6+')" -deps = - [testenv:py3{6,7,8,9,10,11,12,13}-mariadb-w32] platform = win32 commands = {[mariadb-w32]commands} @@ -587,11 +556,6 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[psycopg2-w32]commands} -[testenv:py38-postgres-psycopg2-noauto-w32] -platform = win32 -commands = {envpython} -c "print('Skipped...')" -deps = - [testenv:py3{4,5,6,7,9,10,11,12,13}-postgres-psycopg2-w32] platform = win32 commands = {[psycopg2-w32]commands} @@ -624,11 +588,6 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pypostgresql&sslmode=allow&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py27-postgres-pypostgresql-noauto-w32] -platform = win32 -commands = {envpython} -c "print('pypostgresql requires Python 3.4+')" -deps = - [testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pypostgresql-noauto-w32] platform = win32 commands = {[pypostgresql-w32]commands} From 90d193dbf3cad7679c2f277efa792207a35e7cde Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 1 Mar 2025 18:35:13 +0300 Subject: [PATCH 474/509] Tests(tox): Run tests with `psycopg[c]` --- docs/News.rst | 2 ++ tox.ini | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index 372b6130..54a40fea 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -35,6 +35,8 @@ CI * Tests(GHActions): Fixed old bugs in the workflow on w32. +* Run tests with ``psycopg[c]``. + SQLObject 3.12.0.post2 ====================== diff --git a/tox.ini b/tox.ini index 331278a3..5d38525a 100644 --- a/tox.ini +++ b/tox.ini @@ -183,7 +183,7 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py3{6,7,8,9,10,11,12,13}-postgres-psycopg_c-noauto] +[testenv:py3{6,7,8,9,10,11,12,13}-postgres-psycopg_c] commands = {[psycopg_c]commands} [psycopg2] @@ -537,7 +537,7 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py3{6,7,8,9,10,11,12,13}-postgres-psycopg_c-noauto-w32] +[testenv:py3{6,7,8,9,10,11,12,13}-postgres-psycopg_c-w32] platform = win32 commands = {[psycopg_c-w32]commands} From 2db031376148d5153994cfd3ff5ff59e135ccc17 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 3 Mar 2025 22:48:19 +0300 Subject: [PATCH 475/509] Docs(News): Fix literal --- docs/News.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/News.rst b/docs/News.rst index 54a40fea..0233fcaa 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -19,7 +19,7 @@ Drivers * Fixed outstanding problems with ``psycopg``. It's now the first class driver. -* Dropped support for CyMySQL; +* Dropped support for ``CyMySQL``; its author refused to fix unicode-related problems. Tests From efd01ad9d8bc56a5820852f5c6bdc7550c6f1793 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 3 Mar 2025 22:49:06 +0300 Subject: [PATCH 476/509] Feat(Pg): Dropped support for `py-postgresql` It's completely broken with debianized `Postgres` and the authors reject fixes. --- ANNOUNCE.rst | 9 ++++----- README.rst | 9 ++++----- docs/News.rst | 3 +++ docs/SQLObject.rst | 9 ++++----- docs/download.rst | 5 ++--- setup.py | 2 -- sqlobject/postgres/pgconnection.py | 19 ++----------------- tox.ini | 25 ------------------------- 8 files changed, 19 insertions(+), 62 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 47a37342..7e3a6637 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -36,11 +36,10 @@ quick to get started with. SQLObject supports a number of backends: MySQL/MariaDB (with a number of DB API drivers: ``MySQLdb``, ``mysqlclient``, ``mysql-connector``, -``PyMySQL``, ``mariadb``), PostgreSQL (``psycopg2``, ``PyGreSQL``, -partially ``pg8000`` and ``py-postgresql``), SQLite (builtin ``sqlite3``); -connections to other backends -- Firebird, Sybase, MSSQL and MaxDB (also known as SAPDB) - are less -debugged). +``PyMySQL``, ``mariadb``), PostgreSQL (``psycopg``, ``psycopg2``, ``PyGreSQL``, +partially ``pg8000``), SQLite (builtin ``sqlite3``); +connections to other backends - Firebird, Sybase, MSSQL and MaxDB (also +known as SAPDB) - are less debugged). Python 2.7 or 3.4+ is required. diff --git a/README.rst b/README.rst index 1829efc9..3fde456b 100644 --- a/README.rst +++ b/README.rst @@ -8,11 +8,10 @@ quick to get started with. SQLObject supports a number of backends: MySQL/MariaDB (with a number of DB API drivers: ``MySQLdb``, ``mysqlclient``, ``mysql-connector``, -``PyMySQL``, ``mariadb``), PostgreSQL (``psycopg2``, ``PyGreSQL``, -partially ``pg8000`` and ``py-postgresql``), SQLite (builtin ``sqlite3``); -connections to other backends -- Firebird, Sybase, MSSQL and MaxDB (also known as SAPDB) - are less -debugged). +``PyMySQL``, ``mariadb``), PostgreSQL (``psycopg``, ``psycopg2``, ``PyGreSQL``, +partially ``pg8000``), SQLite (builtin ``sqlite3``); +connections to other backends - Firebird, Sybase, MSSQL and MaxDB (also +known as SAPDB) - are less debugged). Python 2.7 or 3.4+ is required. diff --git a/docs/News.rst b/docs/News.rst index 0233fcaa..a6065413 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -22,6 +22,9 @@ Drivers * Dropped support for ``CyMySQL``; its author refused to fix unicode-related problems. +* Dropped support for ``py-postgresql``; it's completely broken + with debianized ``Postgres`` and the authors reject fixes. + Tests ----- diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index 896686be..1dd4dcd7 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -51,7 +51,7 @@ MySQL-python (called mysqlclient_ for Python 3), `MySQL Connector`_, PyMySQL_, `mariadb connector`_, PyODBC_ and PyPyODBC_. For PostgreSQL_ psycopg_ and psycopg2_ are recommended, especially their precompiled wheels psycopg-binary_ and psycopg2-binary_; see also optimized -psycopg-c_; PyGreSQL_, py-postgresql_ and pg8000_ are supported; SQLite_ +psycopg-c_; PyGreSQL_ and pg8000_ are supported; SQLite_ has a built-in driver. Firebird_ is supported via fdb_ or kinterbasdb_; pyfirebirdsql_ is supported but has problems. `MAX DB`_ (also known as SAP DB) is supported via sapdb_. Sybase via Sybase_. `MSSQL Server`_ via @@ -73,7 +73,6 @@ passed). .. _psycopg2: https://www.psycopg.org/ .. _psycopg2-binary: https://pypi.org/project/psycopg2-binary/ .. _PyGreSQL: http://www.pygresql.org/ -.. _py-postgresql: https://pypi.org/project/py-postgresql/ .. _pg8000: https://pypi.org/project/pg8000/ .. _SQLite: https://sqlite.org/ .. _Firebird: http://www.firebirdsql.org/en/python-driver/ @@ -1849,9 +1848,9 @@ PostgresConnection supports transactions and all other features. The user can choose a DB API driver for PostgreSQL by using a ``driver`` parameter in DB URI or PostgresConnection that can be a comma-separated list of driver names. Possible drivers are: ``psycopg``, ``psycopg2``, -``pygresql``, ``pypostgresql``, ``pg8000``, -``pyodbc``, ``pypyodbc`` or ``odbc`` (try ``pyodbc`` and -``pypyodbc``). Default are ``psycopg``, ``psycopg2``, ``pygresql``. +``pygresql``, ``pg8000``, ``pyodbc``, ``pypyodbc`` or ``odbc`` (try +``pyodbc`` and ``pypyodbc``). Default are ``psycopg``, ``psycopg2``, +``pygresql``. Connection-specific parameters are: ``sslmode``, ``unicodeCols``, ``schema``, ``charset``. diff --git a/docs/download.rst b/docs/download.rst index 88bc739c..d873d0bd 100644 --- a/docs/download.rst +++ b/docs/download.rst @@ -73,9 +73,8 @@ pyodbc pypyodbc odbc (synonym for pyodbc) PostgreSQL ^^^^^^^^^^ -psycopg -psycopg2 postgres postgresql (synonyms for psycopg2) -pygresql pypostgresql py-postgresql pg8000 +psycopg psycopg2 postgres postgresql (synonyms for psycopg2) +pygresql pg8000 The rest ^^^^^^^^ diff --git a/setup.py b/setup.py index 82699846..bc6a45a8 100755 --- a/setup.py +++ b/setup.py @@ -158,8 +158,6 @@ 'psycopg2-binary:python_version!="3.4"': ['psycopg2-binary'], 'pygresql:python_version=="3.4"': ['pygresql < 5.2'], 'pygresql:python_version!="3.4"': ['pygresql'], - 'pypostgresql': ['py-postgresql'], - 'py-postgresql': ['py-postgresql'], 'pg8000:python_version=="2.7"': ['pg8000 < 1.13'], 'pg8000:python_version=="3.4"': ['pg8000 < 1.12.4'], 'pg8000:python_version>="3.5"': ['pg8000'], diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index 2354142e..a128ab8e 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -72,9 +72,6 @@ def __init__(self, dsn=None, host=None, port=None, db=None, elif driver == 'pygresql': import pgdb self.module = pgdb - elif driver in ('py-postgresql', 'pypostgresql'): - from postgresql.driver import dbapi20 - self.module = dbapi20 elif driver == 'pg8000': import pg8000 self.module = pg8000 @@ -94,7 +91,7 @@ def __init__(self, dsn=None, host=None, port=None, db=None, raise ValueError( 'Unknown PostgreSQL driver "%s", ' 'expected psycopg, psycopg2, ' - 'pygresql, pypostgresql, pg8000, ' + 'pygresql, pg8000, ' 'odbc, pyodbc or pypyodbc' % driver) except ImportError: pass @@ -112,7 +109,7 @@ def __init__(self, dsn=None, host=None, port=None, db=None, # Register a converter for psycopg Binary type. registerConverter(type(self.module.Binary('')), PsycoBinaryConverter) - elif driver in ('pygresql', 'py-postgresql', 'pypostgresql', 'pg8000'): + elif driver in ('pygresql', 'pg8000'): registerConverter(type(self.module.Binary(b'')), PostgresBinaryConverter) elif driver in ('odbc', 'pyodbc', 'pypyodbc'): @@ -184,13 +181,6 @@ def __init__(self, dsn=None, host=None, port=None, db=None, if sslmode: dsn.append('sslmode=%s' % sslmode) dsn = ' '.join(dsn) - if driver in ('py-postgresql', 'pypostgresql'): - if host and host.startswith('/'): - dsn_dict["host"] = dsn_dict["port"] = None - dsn_dict["unix"] = host - else: - if "unix" in dsn_dict: - del dsn_dict["unix"] if driver == 'pg8000': if host and host.startswith('/'): dsn_dict["host"] = None @@ -312,11 +302,6 @@ def _queryInsertID(self, conn, soInstance, id, names, values): table = soInstance.sqlmeta.table idName = soInstance.sqlmeta.idName c = conn.cursor() - if id is None and self.driver in ('py-postgresql', 'pypostgresql'): - sequenceName = soInstance.sqlmeta.idSequence or \ - '%s_%s_seq' % (table, idName) - self._executeRetry(conn, c, "SELECT NEXTVAL('%s')" % sequenceName) - id = c.fetchone()[0] if id is not None: names = [idName] + names values = [id] + values diff --git a/tox.ini b/tox.ini index 5d38525a..24b235b6 100644 --- a/tox.ini +++ b/tox.ini @@ -25,7 +25,6 @@ deps = py34-psycopg2: psycopg2-binary==2.8.4 !py34-psycopg2: psycopg2-binary pygresql: -rdevscripts/requirements/requirements_pygresql.txt - pypostgresql: git+https://github.com/sqlobject/py-postgresql.git@combined-fixes#egg=py-postgresql pg8000: -rdevscripts/requirements/requirements_pg8000.txt pyodbc: pyodbc pypyodbc: pypyodbc @@ -218,17 +217,6 @@ commands = [testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pygresql] commands = {[pygresql]commands} -[pypostgresql] -commands = - {[testenv]commands} - -dropdb --username=runner --no-password sqlobject_test - createdb --username=runner --no-password sqlobject_test - pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pypostgresql&sslmode=allow&charset=utf-8&debug=1" - dropdb --username=runner --no-password sqlobject_test - -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pypostgresql-noauto] -commands = {[pypostgresql]commands} - [pg8000] commands = {[testenv]commands} @@ -579,19 +567,6 @@ commands = platform = win32 commands = {[pygresql-w32]commands} -[pypostgresql-w32] -platform = win32 -commands = - {[testenv]commands} - -dropdb --username=runner --no-password sqlobject_test - createdb --username=runner --no-password sqlobject_test - pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pypostgresql&sslmode=allow&charset=utf-8&debug=1" - dropdb --username=runner --no-password sqlobject_test - -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pypostgresql-noauto-w32] -platform = win32 -commands = {[pypostgresql-w32]commands} - [pg8000-w32] platform = win32 commands = From e2dfa497451a7c6d010ac754fbe4644527811726 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 3 Mar 2025 21:58:45 +0300 Subject: [PATCH 477/509] Fix(pg8000): Fixed all problems --- docs/News.rst | 3 +++ sqlobject/postgres/pgconnection.py | 8 ++++++-- sqlobject/tests/dbtest.py | 3 +++ sqlobject/tests/test_exceptions.py | 7 +++++-- sqlobject/tests/test_schema.py | 10 ++++++---- tox.ini | 9 +++------ 6 files changed, 26 insertions(+), 14 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index a6065413..fd4cacc3 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -19,6 +19,9 @@ Drivers * Fixed outstanding problems with ``psycopg``. It's now the first class driver. +* Fixed all problems with ``pg8000``. It's now close to become + the first class driver. + * Dropped support for ``CyMySQL``; its author refused to fix unicode-related problems. diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index a128ab8e..ac18a6f8 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -73,8 +73,12 @@ def __init__(self, dsn=None, host=None, port=None, db=None, import pgdb self.module = pgdb elif driver == 'pg8000': - import pg8000 - self.module = pg8000 + try: + import pg8000.dbapi + self.module = pg8000.dbapi + except ImportError: + import pg8000 + self.module = pg8000 elif driver == 'pyodbc': import pyodbc self.module = pyodbc diff --git a/sqlobject/tests/dbtest.py b/sqlobject/tests/dbtest.py index e934ac51..e2693f1d 100644 --- a/sqlobject/tests/dbtest.py +++ b/sqlobject/tests/dbtest.py @@ -101,6 +101,9 @@ def getConnection(**kw): conn.debug = True if conftest.option.show_sql_output: conn.debugOutput = True + if (conn.dbName == 'postgres') and (conn.driver == 'pg8000') \ + and conn._pool is not None: + conn._pool = None if (conn.dbName == 'sqlite') and not conn._memory: speedupSQLiteConnection(conn) return conn diff --git a/sqlobject/tests/test_exceptions.py b/sqlobject/tests/test_exceptions.py index 169ca188..ff05bd0e 100644 --- a/sqlobject/tests/test_exceptions.py +++ b/sqlobject/tests/test_exceptions.py @@ -1,7 +1,7 @@ import pytest from sqlobject import SQLObject, StringCol -from sqlobject.dberrors import DuplicateEntryError, OperationalError, \ - ProgrammingError +from sqlobject.dberrors import DatabaseError, DuplicateEntryError, \ + OperationalError, ProgrammingError from sqlobject.tests.dbtest import getConnection, raises, setupClass, supports @@ -33,5 +33,8 @@ def test_exceptions(): assert e.args[0].code in (1146, '42P01') except OperationalError: assert connection.dbName == 'sqlite' + except DatabaseError: + assert connection.dbName == 'postgres' \ + and connection.driver == 'pg8000' else: assert False, "DID NOT RAISE" diff --git a/sqlobject/tests/test_schema.py b/sqlobject/tests/test_schema.py index 4a7887d4..5d4e3ad6 100644 --- a/sqlobject/tests/test_schema.py +++ b/sqlobject/tests/test_schema.py @@ -22,7 +22,9 @@ def test_connection_schema(): conn.query('SET search_path TO test') setupClass(SOTestSchema) assert SOTestSchema._connection is conn - SOTestSchema(foo='bar') - assert conn.queryAll("SELECT * FROM test.so_test_schema") - conn.schema = None - conn.query('SET search_path TO public') + try: + SOTestSchema(foo='bar') + assert conn.queryAll("SELECT * FROM test.so_test_schema") + finally: + conn.schema = None + conn.query('SET search_path TO public') diff --git a/tox.ini b/tox.ini index 24b235b6..c918dd8e 100644 --- a/tox.ini +++ b/tox.ini @@ -230,10 +230,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pg8000]commands} -[testenv:py3{4,5,6}-postgres-pg8000] -commands = {[pg8000]commands} - -[testenv:py3{7,8,9,10,11,12,13}-postgres-pg8000-noauto] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pg8000] commands = {[pg8000]commands} [postgres-pyodbc] @@ -576,13 +573,13 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pg8000&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py27-postgres-pg8000-noauto-w32] +[testenv:py27-postgres-pg8000-w32] platform = win32 commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pg8000-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pg8000-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pg8000-w32] platform = win32 commands = {[pg8000-w32]commands} From c61aa5a4a23cecd712a0836ec0c2afe628795271 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 7 Mar 2025 15:47:18 +0300 Subject: [PATCH 478/509] Tests(tox): Rename `mysql-connector-python` tests to `mysql-connector_py` Restored `mysql-connector`. This is to avoid confusing `mysql-connector` and `mysql-connector-python` tests. --- tox.ini | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/tox.ini b/tox.ini index c918dd8e..bb8ed529 100644 --- a/tox.ini +++ b/tox.ini @@ -16,8 +16,8 @@ deps = !py34: zope.datetime mysqldb: mysql-python mysqlclient: -rdevscripts/requirements/requirements_mysqlclient.txt - mysql-cnx: mysql-connector - mysql-connector-python: -rdevscripts/requirements/requirements_connector_python.txt + mysql-connector: mysql-connector + mysql-connector_py: -rdevscripts/requirements/requirements_connector_python.txt pymysql: -rdevscripts/requirements/requirements_pymysql.txt mariadb: mariadb psycopg: psycopg[binary] @@ -70,7 +70,7 @@ commands = [testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysqlclient] commands = {[mysqlclient]commands} -[mysql-cnx] +[mysql-connector] commands = {[testenv]commands} -mysql --execute="drop database sqlobject_test;" @@ -78,15 +78,15 @@ commands = pytest -D "mysql://runner:@localhost/sqlobject_test?driver=connector&charset=utf8&debug=1" mysql --execute="drop database sqlobject_test;" -[testenv:py27-mysql-cnx] +[testenv:py27-mysql-connector] commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base - {[mysql-cnx]commands} + {[mysql-connector]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-cnx] -commands = {[mysql-cnx]commands} +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-connector] +commands = {[mysql-connector]commands} -[mysql-connector-python] +[mysql-connector_py] commands = {[testenv]commands} -mysql --execute="drop database sqlobject_test;" @@ -94,13 +94,13 @@ commands = pytest -D "mysql://runner:@localhost/sqlobject_test?driver=connector-python&charset=utf8&debug=1" mysql --execute="drop database sqlobject_test;" -[testenv:py27-mysql-connector-python] +[testenv:py27-mysql-connector_py] commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base - {[mysql-connector-python]commands} + {[mysql-connector_py]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-connector-python] -commands = {[mysql-connector-python]commands} +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-connector_py] +commands = {[mysql-connector_py]commands} [pymysql] commands = @@ -390,7 +390,7 @@ commands = platform = win32 commands = {[mysqlclient-w32]commands} -[mysql-cnx-w32] +[mysql-connector-w32] platform = win32 commands = {[testenv]commands} @@ -399,17 +399,17 @@ commands = pytest -D "mysql://ODBC@localhost/sqlobject_test?driver=connector&charset=utf8&debug=1" mysql --user=ODBC -e "drop database sqlobject_test;" -[testenv:py27-mysql-cnx-w32] +[testenv:py27-mysql-connector-w32] platform = win32 commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base - {[mysql-cnx-w32]commands} + {[mysql-connector-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-cnx-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-connector-w32] platform = win32 -commands = {[mysql-cnx-w32]commands} +commands = {[mysql-connector-w32]commands} -[mysql-connector-python-w32] +[mysql-connector_py-w32] platform = win32 commands = {[testenv]commands} @@ -418,15 +418,15 @@ commands = pytest -D "mysql://ODBC@localhost/sqlobject_test?driver=connector-python&charset=utf8&debug=1" mysql --user=ODBC -e "drop database sqlobject_test;" -[testenv:py27-mysql-connector-python-w32] +[testenv:py27-mysql-connector_py-w32] platform = win32 commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base - {[mysql-connector-python-w32]commands} + {[mysql-connector_py-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-connector-python-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-connector_py-w32] platform = win32 -commands = {[mysql-connector-python-w32]commands} +commands = {[mysql-connector_py-w32]commands} [pymysql-w32] platform = win32 From e16bb5901cfb1916c23ed441435b22723a006d25 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 7 Mar 2025 15:50:53 +0300 Subject: [PATCH 479/509] Feat(pg8000): Declare it the first class driver --- docs/News.rst | 5 ++--- sqlobject/postgres/pgconnection.py | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index fd4cacc3..9d2940eb 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -15,12 +15,11 @@ Drivers ``mysql-connector``, ``mysql-connector-python``, ``pymysql``. * Extended default list of PostgreSQL drivers to ``psycopg``, ``psycopg2``, - ``pygresql``. + ``pygresql``, ``pg8000``. * Fixed outstanding problems with ``psycopg``. It's now the first class driver. -* Fixed all problems with ``pg8000``. It's now close to become - the first class driver. +* Fixed all problems with ``pg8000``. It's now the first class driver. * Dropped support for ``CyMySQL``; its author refused to fix unicode-related problems. diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index ac18a6f8..7d9f918b 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -57,7 +57,7 @@ class PostgresConnection(DBAPI): def __init__(self, dsn=None, host=None, port=None, db=None, user=None, password=None, **kw): - drivers = kw.pop('driver', None) or 'psycopg,psycopg2,pygresql' + drivers = kw.pop('driver', None) or 'psycopg,psycopg2,pygresql,pg8000' for driver in drivers.split(','): driver = driver.strip() if not driver: From 0217eb3c33bf7106ffd32b8c4919a86ad71a5de2 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 7 Mar 2025 16:34:59 +0300 Subject: [PATCH 480/509] Release 3.13.0 --- ANNOUNCE.rst | 48 +++++++++++++++++++++++++++------------ README.rst | 4 ++-- devscripts/build-all-docs | 2 +- docs/News.rst | 6 +++-- setup.py | 2 +- sqlobject/__version__.py | 8 +++---- 6 files changed, 46 insertions(+), 24 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 7e3a6637..f6dc6fee 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,25 +1,45 @@ Hello! -I'm pleased to announce version 3.12.1a1, the first alpha of the upcoming -release of branch 3.12 of SQLObject. +I'm pleased to announce version 3.13.0, the first release of branch +3.13 of SQLObject. -I'm pleased to announce version 3.12.1a2, the second alpha of the upcoming -release of branch 3.12 of SQLObject. -I'm pleased to announce version 3.12.1b1, the first beta of the upcoming -release of branch 3.12 of SQLObject. +What's new in SQLObject +======================= -I'm pleased to announce version 3.12.1rc1, the first release candidate -of the upcoming release of branch 3.12 of SQLObject. +Drivers +------- -I'm pleased to announce version 3.12.1, the first bugfix release of branch -3.12 of SQLObject. +* Extended default list of MySQL drivers to ``mysqldb``, ``mysqlclient``, + ``mysql-connector``, ``mysql-connector-python``, ``pymysql``. +* Extended default list of PostgreSQL drivers to ``psycopg``, ``psycopg2``, + ``pygresql``, ``pg8000``. -What's new in SQLObject -======================= +* Fixed outstanding problems with ``psycopg``. It's now the first class driver. + +* Fixed all problems with ``pg8000``. It's now the first class driver. + +* Dropped support for ``CyMySQL``; + its author refused to fix unicode-related problems. + +* Dropped support for ``py-postgresql``; it's completely broken + with debianized ``Postgres`` and the authors reject fixes. + +Tests +----- + +* Added tests for ``mysqldb`` (aka ``mysql-python``) + and ``mysqlclient`` on w32. + +* Improved tests of ``mysql-connector`` and ``mysql-connector-python``. + +CI +-- + +* Tests(GHActions): Fixed old bugs in the workflow on w32. -The contributors for this release are ... Thanks! +* Run tests with ``psycopg[c]``. For a more complete list, please see the news: @@ -51,7 +71,7 @@ Site: http://sqlobject.org Download: -https://pypi.org/project/SQLObject/3.12.1a0.dev20250201/ +https://pypi.org/project/SQLObject/3.13.0 News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 3fde456b..4e7af749 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.12.0.post2 -====================== +SQLObject 3.13.0 +================ SQLObject is a free and open-source (LGPL) Python object-relational mapper. Your database tables are described as classes, and rows are diff --git a/devscripts/build-all-docs b/devscripts/build-all-docs index 8d508b27..3e3cda0e 100755 --- a/devscripts/build-all-docs +++ b/devscripts/build-all-docs @@ -10,7 +10,7 @@ cd "`dirname \"$0\"`" && PROG_DIR="`pwd`" && cd .. && -build_docs 3.12.0.post2 && +build_docs 3.13.0 && build_docs master devel && rm -rf docs/html && diff --git a/docs/News.rst b/docs/News.rst index 9d2940eb..f4a3f403 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,8 +5,10 @@ News .. contents:: Contents: :backlinks: none -SQLObject (development) -======================= +SQLObject 3.13.0 +================ + +Released 2025 Mar 07. Drivers ------- diff --git a/setup.py b/setup.py index bc6a45a8..1bd4ea19 100755 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ """, # noqa: E501 line too long long_description_content_type="text/x-rst", classifiers=[ - "Development Status :: 3 - Alpha", + "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: " "GNU Library or Lesser General Public License (LGPL)", diff --git a/sqlobject/__version__.py b/sqlobject/__version__.py index 9a310a1e..cc6e4c51 100644 --- a/sqlobject/__version__.py +++ b/sqlobject/__version__.py @@ -1,8 +1,8 @@ -version = '3.12.0.post2' +version = '3.13.0' major = 3 -minor = 12 +minor = 13 micro = 0 -release_level = 'post' -serial = 2 +release_level = 'final' +serial = 0 version_info = (major, minor, micro, release_level, serial) From 27b78f03439786ac5b9366755fc6a227bbcf1051 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 7 Mar 2025 16:47:14 +0300 Subject: [PATCH 481/509] Build: Prepare for the next release [skip ci] --- ANNOUNCE.rst | 49 ++++++++++++++++--------------------------------- docs/News.rst | 3 +++ setup.py | 2 +- 3 files changed, 20 insertions(+), 34 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index f6dc6fee..dfdda2c5 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,45 +1,28 @@ Hello! -I'm pleased to announce version 3.13.0, the first release of branch -3.13 of SQLObject. - - -What's new in SQLObject -======================= - -Drivers -------- - -* Extended default list of MySQL drivers to ``mysqldb``, ``mysqlclient``, - ``mysql-connector``, ``mysql-connector-python``, ``pymysql``. +I'm pleased to announce version 3.13.1a1, the first alpha of the upcoming +release of branch 3.13 of SQLObject. -* Extended default list of PostgreSQL drivers to ``psycopg``, ``psycopg2``, - ``pygresql``, ``pg8000``. +I'm pleased to announce version 3.13.1a2, the second alpha of the upcoming +release of branch 3.13 of SQLObject. -* Fixed outstanding problems with ``psycopg``. It's now the first class driver. +I'm pleased to announce version 3.13.1b1, the first beta of the upcoming +release of branch 3.13 of SQLObject. -* Fixed all problems with ``pg8000``. It's now the first class driver. +I'm pleased to announce version 3.13.1rc1, the first release candidate +of the upcoming release of branch 3.13 of SQLObject. -* Dropped support for ``CyMySQL``; - its author refused to fix unicode-related problems. - -* Dropped support for ``py-postgresql``; it's completely broken - with debianized ``Postgres`` and the authors reject fixes. - -Tests ------ - -* Added tests for ``mysqldb`` (aka ``mysql-python``) - and ``mysqlclient`` on w32. +I'm pleased to announce version 3.13.1, the first bugfix release of branch +3.13 of SQLObject. -* Improved tests of ``mysql-connector`` and ``mysql-connector-python``. +I'm pleased to announce version 3.13.0, the first release of branch +3.13 of SQLObject. -CI --- -* Tests(GHActions): Fixed old bugs in the workflow on w32. +What's new in SQLObject +======================= -* Run tests with ``psycopg[c]``. +The contributors for this release are ... Thanks! For a more complete list, please see the news: @@ -71,7 +54,7 @@ Site: http://sqlobject.org Download: -https://pypi.org/project/SQLObject/3.13.0 +https://pypi.org/project/SQLObject/3.13.1a0.dev20250307/ News and changes: http://sqlobject.org/News.html diff --git a/docs/News.rst b/docs/News.rst index f4a3f403..217097af 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,6 +5,9 @@ News .. contents:: Contents: :backlinks: none +SQLObject development (master) +============================== + SQLObject 3.13.0 ================ diff --git a/setup.py b/setup.py index 1bd4ea19..bc6a45a8 100755 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ """, # noqa: E501 line too long long_description_content_type="text/x-rst", classifiers=[ - "Development Status :: 5 - Production/Stable", + "Development Status :: 3 - Alpha", "Intended Audience :: Developers", "License :: OSI Approved :: " "GNU Library or Lesser General Public License (LGPL)", From f6b1c42b2046e77b20b502068b1d5a486abac726 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=AE=D0=B4=D1=8B=D1=86=D0=BA=D0=B8=D0=B9=20=D0=98=D0=B3?= =?UTF-8?q?=D0=BE=D1=80=D1=8C?= Date: Wed, 9 Apr 2025 10:15:19 +0300 Subject: [PATCH 482/509] fix: connect to old mssql versions via set tds_version uri parameter --- sqlobject/mssql/mssqlconnection.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sqlobject/mssql/mssqlconnection.py b/sqlobject/mssql/mssqlconnection.py index 9c179e93..d2fff311 100644 --- a/sqlobject/mssql/mssqlconnection.py +++ b/sqlobject/mssql/mssqlconnection.py @@ -105,6 +105,8 @@ def _make_conn_str(keys): ('host', keys.host), ('port', keys.port), ('timeout', keys.timeout), + ('charset', keys.charset), + ('tds_version', keys.tds_version), ): if value: keys_dict[attr] = value @@ -118,6 +120,8 @@ def _make_conn_str(keys): self.host = host self.port = port self.db = db + self.charset = kw.pop("charset", None) + self.tds_version = kw.pop("tds_version", None) self._server_version = None self._can_use_max_types = None self._can_use_microseconds = None From 6041aa6a0e2364718094b2ce0a2f67276c5fbfce Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 9 Apr 2025 14:30:17 +0300 Subject: [PATCH 483/509] Docs(Authors): Add Igor Yudytskiy [skip ci] --- docs/Authors.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Authors.rst b/docs/Authors.rst index 6c5b23c9..89a9e374 100644 --- a/docs/Authors.rst +++ b/docs/Authors.rst @@ -40,6 +40,7 @@ Contributions have been made by: * James Hudson * Juergen Gmach * Hugo van Kemenade +* Igor Yudytskiy * Oleg Broytman .. image:: https://sourceforge.net/sflogo.php?group_id=74338&type=10 From 8435099637695ab96c2e00cb17f45e08a8214e95 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 11 Apr 2025 14:47:32 +0300 Subject: [PATCH 484/509] Build(release): Fix path to include script [skip ci] --- devscripts/release | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devscripts/release b/devscripts/release index f5a2e576..ed981234 100755 --- a/devscripts/release +++ b/devscripts/release @@ -15,7 +15,7 @@ find build -name '*.py[co]' -delete && python setup.py bdist_wheel --universal && version=`python setup.py --version` -. `dirname $0`/split_tag.sh && +. devscripts/split_tag.sh && split_tag $version if [ "$state" = final ]; then From affe990d0ced03f9e7f904461873c6f501ba87c1 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 11 Apr 2025 14:48:01 +0300 Subject: [PATCH 485/509] Build(release): Rename both sdist and wheel files to lower-case [skip ci] --- devscripts/release | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/devscripts/release b/devscripts/release index ed981234..2df10e0f 100755 --- a/devscripts/release +++ b/devscripts/release @@ -24,11 +24,15 @@ if [ "$state" = final ]; then devscripts/sftp-frs fi && -if [ -f dist/SQLObject-$version.tar.gz ]; then - cd dist && - mv SQLObject-$version.tar.gz sqlobject-$version.tar.gz && - cd .. +cd dist && +if [ -f SQLObject-$version.tar.gz ]; then + mv SQLObject-$version.tar.gz sqlobject-$version.tar.gz fi && +if [ -f SQLObject-$version-py2.py3-none-any.whl ]; then + mv SQLObject-$version-py2.py3-none-any.whl \ + sqlobject-$version-py2.py3-none-any.whl +fi && +cd .. && twine upload --disable-progress-bar --skip-existing dist/* && exec rm -rf build dist docs/html SQLObject.egg-info From 49a7268d44f86d356496d637a7d211b2504ea9e0 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 24 Jul 2025 15:34:45 +0300 Subject: [PATCH 486/509] Tested with Python 3.14 --- .github/workflows/run-tests.yaml | 2 +- docs/News.rst | 2 + setup.py | 1 + tox.ini | 74 ++++++++++++++++---------------- 4 files changed, 41 insertions(+), 38 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index d81585f4..54f2658f 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -10,7 +10,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest] - python-version: ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13"] + python-version: ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] exclude: - os: windows-latest python-version: "2.7" diff --git a/docs/News.rst b/docs/News.rst index 217097af..0d67c1da 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,8 @@ News SQLObject development (master) ============================== +* Tested with Python 3.14. + SQLObject 3.13.0 ================ diff --git a/setup.py b/setup.py index bc6a45a8..02b384c1 100755 --- a/setup.py +++ b/setup.py @@ -65,6 +65,7 @@ "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", "Topic :: Database", "Topic :: Database :: Front-Ends", "Topic :: Software Development :: Libraries :: Python Modules", diff --git a/tox.ini b/tox.ini index bb8ed529..fb681afe 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 3.15 -envlist = py{27,34,35,36,37,38,39,310,311,312,313}-sqlite{,-memory},py{27,37,313}-flake8 +envlist = py{27,34,35,36,37,38,39,310,311,312,313,314}-sqlite{,-memory},py{27,37,313}-flake8 # Base test environment settings [testenv] @@ -67,7 +67,7 @@ commands = pytest -D "mysql://localhost/sqlobject_test?driver=mysqldb&charset=utf8&debug=1" mysql --execute="drop database sqlobject_test;" -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysqlclient] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-mysqlclient] commands = {[mysqlclient]commands} [mysql-connector] @@ -83,7 +83,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-connector]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-connector] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-mysql-connector] commands = {[mysql-connector]commands} [mysql-connector_py] @@ -99,7 +99,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-connector_py]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-connector_py] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-mysql-connector_py] commands = {[mysql-connector_py]commands} [pymysql] @@ -115,7 +115,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pymysql]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-pymysql] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-mysql-pymysql] commands = {[pymysql]commands} [mariadb] @@ -126,7 +126,7 @@ commands = pytest -D "mysql://localhost/sqlobject_test?driver=mariadb&charset=utf8&debug=1" mysql --execute="drop database sqlobject_test;" -[testenv:py3{6,7,8,9,10,11,12,13}-mariadb] +[testenv:py3{6,7,8,9,10,11,12,13,14}-mariadb] commands = {[mariadb]commands} [mysql-pyodbc] @@ -143,7 +143,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pyodbc]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-pyodbc-noauto] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-mysql-pyodbc-noauto] commands = {[mysql-pyodbc]commands} [mysql-pypyodbc] @@ -159,7 +159,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pypyodbc]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-pypyodbc-noauto] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-mysql-pypyodbc-noauto] commands = {[mysql-pypyodbc]commands} # PostgreSQL test environments @@ -171,7 +171,7 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py3{6,7,8,9,10,11,12,13}-postgres-psycopg] +[testenv:py3{6,7,8,9,10,11,12,13,14}-postgres-psycopg] commands = {[psycopg]commands} [psycopg_c] @@ -182,7 +182,7 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py3{6,7,8,9,10,11,12,13}-postgres-psycopg_c] +[testenv:py3{6,7,8,9,10,11,12,13,14}-postgres-psycopg_c] commands = {[psycopg_c]commands} [psycopg2] @@ -198,7 +198,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[psycopg2]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-psycopg2] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-postgres-psycopg2] commands = {[psycopg2]commands} [pygresql] @@ -214,7 +214,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pygresql]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pygresql] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-postgres-pygresql] commands = {[pygresql]commands} [pg8000] @@ -230,7 +230,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pg8000]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pg8000] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-postgres-pg8000] commands = {[pg8000]commands} [postgres-pyodbc] @@ -247,7 +247,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pyodbc]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pyodbc-noauto] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-postgres-pyodbc-noauto] commands = {[postgres-pyodbc]commands} [postgres-pypyodbc] @@ -263,7 +263,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pypyodbc]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pypyodbc-noauto] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-postgres-pypyodbc-noauto] commands = {[postgres-pypyodbc]commands} @@ -280,7 +280,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-sqlite] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-sqlite] commands = {[sqlite]commands} [sqlite-memory] @@ -293,7 +293,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite-memory]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-sqlite-memory] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-sqlite-memory] commands = {[sqlite-memory]commands} @@ -311,7 +311,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[fdb]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-firebird-fdb] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-firebird-fdb] commands = {[fdb]commands} [firebirdsql] @@ -327,16 +327,16 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[firebirdsql]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-firebirdsql] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-firebirdsql] commands = {[firebirdsql]commands} # Special test environments -[testenv:py{27,34,35,36,37,38,39,310,311,312,313}-flake8] +[testenv:py{27,34,35,36,37,38,39,310,311,312,313,314}-flake8] changedir = ./ deps = flake8 - pytest < 7.0 + pytest commands = {[testenv]commands} flake8 . @@ -358,7 +358,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mssql-pyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mssql-pyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-mssql-pyodbc-noauto-w32] platform = win32 commands = {[mssql-pyodbc-w32]commands} @@ -386,7 +386,7 @@ commands = pytest -D "mysql://ODBC@localhost/sqlobject_test?driver=mysqldb&charset=utf8&debug=1" mysql --user=ODBC -e "drop database sqlobject_test;" -[testenv:py3{6,7,8,9,10,11,12,13}-mysqlclient-w32] +[testenv:py3{6,7,8,9,10,11,12,13,14}-mysqlclient-w32] platform = win32 commands = {[mysqlclient-w32]commands} @@ -405,7 +405,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-connector-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-connector-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-mysql-connector-w32] platform = win32 commands = {[mysql-connector-w32]commands} @@ -424,7 +424,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-connector_py-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-connector_py-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-mysql-connector_py-w32] platform = win32 commands = {[mysql-connector_py-w32]commands} @@ -456,7 +456,7 @@ commands = pytest -D "mysql://ODBC@localhost/sqlobject_test?driver=mariadb&charset=utf8&debug=1" mysql --user=ODBC -e "drop database sqlobject_test;" -[testenv:py3{6,7,8,9,10,11,12,13}-mariadb-w32] +[testenv:py3{6,7,8,9,10,11,12,13,14}-mariadb-w32] platform = win32 commands = {[mariadb-w32]commands} @@ -476,7 +476,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-pyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-mysql-pyodbc-noauto-w32] platform = win32 commands = {[mysql-pyodbc-w32]commands} @@ -496,7 +496,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pypyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-pypyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-mysql-pypyodbc-noauto-w32] platform = win32 commands = {[mysql-pypyodbc-w32]commands} @@ -509,7 +509,7 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py3{6,7,8,9,10,11,12,13}-postgres-psycopg-w32] +[testenv:py3{6,7,8,9,10,11,12,13,14}-postgres-psycopg-w32] platform = win32 commands = {[psycopg-w32]commands} @@ -522,7 +522,7 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py3{6,7,8,9,10,11,12,13}-postgres-psycopg_c-w32] +[testenv:py3{6,7,8,9,10,11,12,13,14}-postgres-psycopg_c-w32] platform = win32 commands = {[psycopg_c-w32]commands} @@ -541,7 +541,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[psycopg2-w32]commands} -[testenv:py3{4,5,6,7,9,10,11,12,13}-postgres-psycopg2-w32] +[testenv:py3{4,5,6,7,9,10,11,12,13,14}-postgres-psycopg2-w32] platform = win32 commands = {[psycopg2-w32]commands} @@ -560,7 +560,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pygresql-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pygresql-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-postgres-pygresql-w32] platform = win32 commands = {[pygresql-w32]commands} @@ -579,7 +579,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pg8000-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pg8000-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-postgres-pg8000-w32] platform = win32 commands = {[pg8000-w32]commands} @@ -599,7 +599,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-postgres-pyodbc-noauto-w32] platform = win32 commands = {[postgres-pyodbc-w32]commands} @@ -619,7 +619,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pypyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pypyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-postgres-pypyodbc-noauto-w32] platform = win32 commands = {[postgres-pypyodbc-w32]commands} @@ -636,7 +636,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-sqlite-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-sqlite-w32] platform = win32 commands = {[sqlite-w32]commands} @@ -652,6 +652,6 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite-memory-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-sqlite-memory-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-sqlite-memory-w32] platform = win32 commands = {[sqlite-memory-w32]commands} From eb3fab55fbec873cafe53b7e17336756a930ac34 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 24 Jul 2025 17:12:16 +0300 Subject: [PATCH 487/509] Style(cmp): Fix `flake8` warning F824 The warning was "`global hub` is unused: name is never assigned in scope." Ok, let's remove it. --- sqlobject/tests/dbtest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlobject/tests/dbtest.py b/sqlobject/tests/dbtest.py index e2693f1d..65fcb273 100644 --- a/sqlobject/tests/dbtest.py +++ b/sqlobject/tests/dbtest.py @@ -63,7 +63,7 @@ def setupClass(soClasses, force=False): If force is true, then the database will be recreated no matter what. """ - global hub + # global hub if not isinstance(soClasses, (list, tuple)): soClasses = [soClasses] connection = getConnection() From e582afa447b43ca6c73512f842d06f7ed5bd94c3 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 15 Aug 2025 22:02:37 +0300 Subject: [PATCH 488/509] Tests(tox): Upgrade pip/setuptools/wheel --- tox.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tox.ini b/tox.ini index fb681afe..885867f1 100644 --- a/tox.ini +++ b/tox.ini @@ -30,6 +30,8 @@ deps = pypyodbc: pypyodbc firebird-fdb: fdb firebirdsql: firebirdsql +# Upgrade pip/setuptools/wheel +download = true passenv = CI setenv = PGPASSWORD = test From 4cc7daec2ff9e981db4605261ac0ee2d55e1f7e9 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 16 Aug 2025 16:24:46 +0300 Subject: [PATCH 489/509] Tests(tox): Run tests with non-binary `psycopg` and `psycopg2` --- docs/News.rst | 2 ++ tox.ini | 67 ++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 66 insertions(+), 3 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index 0d67c1da..dc7665d5 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -10,6 +10,8 @@ SQLObject development (master) * Tested with Python 3.14. +* Run tests with non-binary ``psycopg`` and ``psycopg2``. + SQLObject 3.13.0 ================ diff --git a/tox.ini b/tox.ini index 885867f1..2edb614b 100644 --- a/tox.ini +++ b/tox.ini @@ -20,10 +20,12 @@ deps = mysql-connector_py: -rdevscripts/requirements/requirements_connector_python.txt pymysql: -rdevscripts/requirements/requirements_pymysql.txt mariadb: mariadb - psycopg: psycopg[binary] + psycopg: psycopg + psycopg-binary: psycopg[binary] psycopg_c: psycopg[c] - py34-psycopg2: psycopg2-binary==2.8.4 - !py34-psycopg2: psycopg2-binary + psycopg2: psycopg2 + py34-psycopg2-binary: psycopg2-binary==2.8.4 + !py34-psycopg2-binary: psycopg2-binary pygresql: -rdevscripts/requirements/requirements_pygresql.txt pg8000: -rdevscripts/requirements/requirements_pg8000.txt pyodbc: pyodbc @@ -176,6 +178,17 @@ commands = [testenv:py3{6,7,8,9,10,11,12,13,14}-postgres-psycopg] commands = {[psycopg]commands} +[psycopg-binary] +commands = + {[testenv]commands} + -dropdb --username=runner --no-password sqlobject_test + createdb --username=runner --no-password sqlobject_test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" + dropdb --username=runner --no-password sqlobject_test + +[testenv:py3{6,7,8,9,10,11,12,13,14}-postgres-psycopg-binary] +commands = {[psycopg-binary]commands} + [psycopg_c] commands = {[testenv]commands} @@ -203,6 +216,22 @@ commands = [testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-postgres-psycopg2] commands = {[psycopg2]commands} +[psycopg2-binary] +commands = + {[testenv]commands} + -dropdb --username=runner --no-password sqlobject_test + createdb --username=runner --no-password sqlobject_test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg2&charset=utf-8&debug=1" + dropdb --username=runner --no-password sqlobject_test + +[testenv:py27-postgres-psycopg2-binary] +commands = + easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base + {[psycopg2-binary]commands} + +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-postgres-psycopg2-binary] +commands = {[psycopg2-binary]commands} + [pygresql] commands = {[testenv]commands} @@ -515,6 +544,19 @@ commands = platform = win32 commands = {[psycopg-w32]commands} +[psycopg-binary-w32] +platform = win32 +commands = + {[testenv]commands} + -dropdb --username=runner --no-password sqlobject_test + createdb --username=runner --no-password sqlobject_test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" + dropdb --username=runner --no-password sqlobject_test + +[testenv:py3{6,7,8,9,10,11,12,13,14}-postgres-psycopg-binary-w32] +platform = win32 +commands = {[psycopg-binary-w32]commands} + [psycopg_c-w32] platform = win32 commands = @@ -547,6 +589,25 @@ commands = platform = win32 commands = {[psycopg2-w32]commands} +[psycopg2-binary-w32] +platform = win32 +commands = + {[testenv]commands} + -dropdb --username=runner --no-password sqlobject_test + createdb --username=runner --no-password sqlobject_test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg2&charset=utf-8&debug=1" + dropdb --username=runner --no-password sqlobject_test + +[testenv:py27-postgres-psycopg2-binary-w32] +platform = win32 +commands = + easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base + {[psycopg2-binary-w32]commands} + +[testenv:py3{4,5,6,7,9,10,11,12,13}-postgres-psycopg2-binary-w32] +platform = win32 +commands = {[psycopg2-binary-w32]commands} + [pygresql-w32] platform = win32 commands = From 57839aa1eac3ed43a5626b5d2109a4756586b194 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 16 Aug 2025 17:47:24 +0300 Subject: [PATCH 490/509] Tests(tox): Run default flake8 tests under Py 3.14 --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 2edb614b..6cbc8df3 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 3.15 -envlist = py{27,34,35,36,37,38,39,310,311,312,313,314}-sqlite{,-memory},py{27,37,313}-flake8 +envlist = py{27,34,35,36,37,38,39,310,311,312,313,314}-sqlite{,-memory},py{27,37,314}-flake8 # Base test environment settings [testenv] From a6210a6e123140380312415d0efefd2a5e19d91a Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 17 Aug 2025 22:43:06 +0300 Subject: [PATCH 491/509] Tests(GHActions): Do not exclude Python 2.7 on w32 --- .github/workflows/run-tests.yaml | 3 --- tox.ini | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 54f2658f..0c9f7daf 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -11,9 +11,6 @@ jobs: matrix: os: [ubuntu-latest, windows-latest] python-version: ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] - exclude: - - os: windows-latest - python-version: "2.7" include: - os: ubuntu-latest os-name: Linux diff --git a/tox.ini b/tox.ini index 6cbc8df3..d36eb7be 100644 --- a/tox.ini +++ b/tox.ini @@ -636,7 +636,7 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pg8000&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py27-postgres-pg8000-w32] +[testenv:py27-postgres-pg8000-noauto-w32] platform = win32 commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base From 1909f2109fd0ffdb7ae59b98b120902b38a37b2a Mon Sep 17 00:00:00 2001 From: DaveMulligan95060 <73315851+DaveMulligan95060@users.noreply.github.com> Date: Fri, 12 Sep 2025 17:44:34 -0700 Subject: [PATCH 492/509] Fix issue 195 --- sqlobject/postgres/pgconnection.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index 7d9f918b..3ce5ef99 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -139,7 +139,7 @@ def __init__(self, dsn=None, host=None, port=None, db=None, if driver == 'pygresql': dsn_dict["host"] = "%s:%d" % (host, port) elif driver.startswith('psycopg') and \ - psycopg.__version__.split('.')[0] == '1': + self.module.__version__.split('.')[0] == '1': dsn_dict["port"] = str(port) else: dsn_dict["port"] = port From 4d949f49e3f45958e3166154b6a9a74813919fc1 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 13 Sep 2025 13:00:08 +0300 Subject: [PATCH 493/509] Docs(News): Minor update "Non-binary" means "source-only". [skip ci] --- docs/News.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/News.rst b/docs/News.rst index dc7665d5..c5e0dd87 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -10,7 +10,7 @@ SQLObject development (master) * Tested with Python 3.14. -* Run tests with non-binary ``psycopg`` and ``psycopg2``. +* Run tests with source-only (non-binary) ``psycopg`` and ``psycopg2``. SQLObject 3.13.0 ================ From 04b36e4fb0a10bbe2876faf14db3ef3ea1d4d1de Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 13 Sep 2025 13:03:00 +0300 Subject: [PATCH 494/509] Docs(DeveloperGuide): Fix outdated `git://` URL `git://` protocol was disabled at GitHub long ago. Use `https://` instead. [skip ci] --- docs/DeveloperGuide.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/DeveloperGuide.rst b/docs/DeveloperGuide.rst index 2cd0f8f6..777aea14 100644 --- a/docs/DeveloperGuide.rst +++ b/docs/DeveloperGuide.rst @@ -14,13 +14,13 @@ Development Installation First install `FormEncode `_:: - $ git clone git://github.com/formencode/formencode.git + $ git clone https://github.com/formencode/formencode.git $ cd formencode $ sudo python setup.py develop Then do the same for SQLObject:: - $ git clone git clone git://github.com/sqlobject/sqlobject.git + $ git clone git clone https://github.com/sqlobject/sqlobject.git $ cd sqlobject $ sudo python setup.py develop From caa7098b471dfefa8f64eef1e61fc334676ee2e5 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 13 Sep 2025 13:11:25 +0300 Subject: [PATCH 495/509] Docs(Authors,News): Fixed #195 [skip ci] --- docs/Authors.rst | 1 + docs/News.rst | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/docs/Authors.rst b/docs/Authors.rst index 89a9e374..46d00465 100644 --- a/docs/Authors.rst +++ b/docs/Authors.rst @@ -41,6 +41,7 @@ Contributions have been made by: * Juergen Gmach * Hugo van Kemenade * Igor Yudytskiy +* Dave Mulligan (https://github.com/DaveMulligan95060) * Oleg Broytman .. image:: https://sourceforge.net/sflogo.php?group_id=74338&type=10 diff --git a/docs/News.rst b/docs/News.rst index c5e0dd87..2c418b43 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,15 @@ News SQLObject development (master) ============================== +Bug fixes +--------- + +* Fixed #195: Minor ``NameError`` in ``pgconnection.py`` + when using ``psycopg`` version 1 with a non-default port. + +Tests +----- + * Tested with Python 3.14. * Run tests with source-only (non-binary) ``psycopg`` and ``psycopg2``. From cc5e39ec0e13f01b466463c246a5fe73d64392cb Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 11 Nov 2025 21:00:48 +0300 Subject: [PATCH 496/509] Fixes a bug in `dbconnection.ConnectionURIOpener.registerConnection` Fixes a bug triggered by non-empty instance's `name`. Fixes: #197. --- ANNOUNCE.rst | 4 ++-- docs/News.rst | 4 ++++ sqlobject/dbconnection.py | 6 +++--- sqlobject/tests/test_dbconnection.py | 17 +++++++++++++++++ 4 files changed, 26 insertions(+), 5 deletions(-) create mode 100644 sqlobject/tests/test_dbconnection.py diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index dfdda2c5..e221f252 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -22,8 +22,8 @@ I'm pleased to announce version 3.13.0, the first release of branch What's new in SQLObject ======================= -The contributors for this release are ... Thanks! - +The contributor for this release is GH user ghaushe-ampere. +Thanks for finding an obscure bug! For a more complete list, please see the news: http://sqlobject.org/News.html diff --git a/docs/News.rst b/docs/News.rst index 2c418b43..0d55db2c 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -11,6 +11,10 @@ SQLObject development (master) Bug fixes --------- +* Fixed #197: a bug in ``dbconnection.ConnectionURIOpener.registerConnection`` + triggered by non-empty instance's ``name``. The bug was inserted in 2004 so + it seems nobody ever used named instances. Fixed anyway. + * Fixed #195: Minor ``NameError`` in ``pgconnection.py`` when using ``psycopg`` version 1 with a non-default port. diff --git a/sqlobject/dbconnection.py b/sqlobject/dbconnection.py index e691f2d4..75176479 100644 --- a/sqlobject/dbconnection.py +++ b/sqlobject/dbconnection.py @@ -1080,12 +1080,12 @@ def registerConnection(self, schemes, builder): def registerConnectionInstance(self, inst): if inst.name: assert (inst.name not in self.instanceNames - or self.instanceNames[inst.name] is cls # noqa - ), ("A instance has already been registered " + or self.instanceNames[inst.name] is self.__class__ + ), ("An instance has already been registered " "with the name %s" % inst.name) assert inst.name.find(':') == -1, \ "You cannot include ':' " \ - "in your class names (%r)" % cls.name # noqa + "in your DB connection names (%r)" % inst.name self.instanceNames[inst.name] = inst def connectionForURI(self, uri, oldUri=False, **args): diff --git a/sqlobject/tests/test_dbconnection.py b/sqlobject/tests/test_dbconnection.py new file mode 100644 index 00000000..6e2dfc87 --- /dev/null +++ b/sqlobject/tests/test_dbconnection.py @@ -0,0 +1,17 @@ +from pytest import raises +from sqlobject.dbconnection import DBConnection + + +def test_name(): + connection = DBConnection(name='test') + connection.close = lambda: True + + with raises(AssertionError) as error: + DBConnection(name='test') + assert str(error.value) == 'An instance has already been registered ' \ + 'with the name test' + + with raises(AssertionError) as error: + DBConnection(name='test:test') + assert str(error.value) == "You cannot include ':' " \ + "in your DB connection names ('test:test')" From 1fd8272fd8861ed7b7d9011d11720d417216f30b Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 11 Nov 2025 21:22:16 +0300 Subject: [PATCH 497/509] CI(GHActions): Exclude Python 2.7 on Windows --- .github/workflows/run-tests.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 0c9f7daf..54f2658f 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -11,6 +11,9 @@ jobs: matrix: os: [ubuntu-latest, windows-latest] python-version: ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] + exclude: + - os: windows-latest + python-version: "2.7" include: - os: ubuntu-latest os-name: Linux From 806c0a919a14a86997c0c4fec1237fdb5914505d Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 11 Nov 2025 21:42:25 +0300 Subject: [PATCH 498/509] Tests(tox): Exclude some tests Exclude mysqlclient under Python 3.14; still is not released. Exclude psycopg[c] under Python 3.6 and 3.7; seems incompatible with GCC running at GH. --- tox.ini | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tox.ini b/tox.ini index d36eb7be..032df079 100644 --- a/tox.ini +++ b/tox.ini @@ -197,7 +197,7 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py3{6,7,8,9,10,11,12,13,14}-postgres-psycopg_c] +[testenv:py3{8,9,10,11,12,13,14}-postgres-psycopg_c] commands = {[psycopg_c]commands} [psycopg2] @@ -417,7 +417,7 @@ commands = pytest -D "mysql://ODBC@localhost/sqlobject_test?driver=mysqldb&charset=utf8&debug=1" mysql --user=ODBC -e "drop database sqlobject_test;" -[testenv:py3{6,7,8,9,10,11,12,13,14}-mysqlclient-w32] +[testenv:py3{6,7,8,9,10,11,12,13}-mysqlclient-w32] platform = win32 commands = {[mysqlclient-w32]commands} @@ -566,7 +566,7 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py3{6,7,8,9,10,11,12,13,14}-postgres-psycopg_c-w32] +[testenv:py3{8,9,10,11,12,13,14}-postgres-psycopg_c-w32] platform = win32 commands = {[psycopg_c-w32]commands} From 5f9b61c58dd1d50f7f2871a833843256bf5f4f65 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 12 Nov 2025 00:12:04 +0300 Subject: [PATCH 499/509] Docs(ANNOUNCE): Add Dave Mulligan as a contributor [skip ci] --- ANNOUNCE.rst | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index e221f252..5632cfeb 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -22,8 +22,12 @@ I'm pleased to announce version 3.13.0, the first release of branch What's new in SQLObject ======================= -The contributor for this release is GH user ghaushe-ampere. -Thanks for finding an obscure bug! +The contributors for this release are: + +* Dave Mulligan fixed #195: Minor ``NameError`` in ``pgconnection.py`` + when using ``psycopg`` version 1 with a non-default port. Many thanks! + +* GH user ghaushe-ampere. Thanks for finding an obscure bug! For a more complete list, please see the news: http://sqlobject.org/News.html From 21243137a981eaac7bba32135f183f9e696f5315 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 13 Nov 2025 20:15:31 +0300 Subject: [PATCH 500/509] Docs(ANNOUNCE): Thanks Igor Yudytskiy for PR #194 [skip ci] --- ANNOUNCE.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 5632cfeb..22d6a34e 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -24,11 +24,15 @@ What's new in SQLObject The contributors for this release are: +* Igor Yudytskiy. Thanks for PR #194: + fix: connect to old mssql versions via set tds_version uri parameter. + * Dave Mulligan fixed #195: Minor ``NameError`` in ``pgconnection.py`` - when using ``psycopg`` version 1 with a non-default port. Many thanks! + when using ``psycopg`` version 1 with a non-default port. Thanks! * GH user ghaushe-ampere. Thanks for finding an obscure bug! + For a more complete list, please see the news: http://sqlobject.org/News.html From db991816a85a704e4b8edf6978561c1f248a5388 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 21 Nov 2025 00:43:29 +0300 Subject: [PATCH 501/509] Fix(col): `UuidValidator.from_python` accepts strings as valid input Fixes: #199. --- ANNOUNCE.rst | 2 ++ docs/News.rst | 3 +++ sqlobject/col.py | 2 ++ sqlobject/tests/test_uuidcol.py | 16 ++++++++++++++-- 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 22d6a34e..ad13b0f5 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -30,6 +30,8 @@ The contributors for this release are: * Dave Mulligan fixed #195: Minor ``NameError`` in ``pgconnection.py`` when using ``psycopg`` version 1 with a non-default port. Thanks! +* Chris Kauffman found a minor bug in ``UuidValidator``. + * GH user ghaushe-ampere. Thanks for finding an obscure bug! diff --git a/docs/News.rst b/docs/News.rst index 0d55db2c..96c5f77b 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -11,6 +11,9 @@ SQLObject development (master) Bug fixes --------- +* ``UuidValidator.from_python()`` now accepts strings as a valid input. + This fixes #199. + * Fixed #197: a bug in ``dbconnection.ConnectionURIOpener.registerConnection`` triggered by non-empty instance's ``name``. The bug was inserted in 2004 so it seems nobody ever used named instances. Fixed anyway. diff --git a/sqlobject/col.py b/sqlobject/col.py index cf9705de..49cd709a 100644 --- a/sqlobject/col.py +++ b/sqlobject/col.py @@ -2022,6 +2022,8 @@ def to_python(self, value, state): def from_python(self, value, state): if value is None: return None + if isinstance(value, str): + return value if isinstance(value, UUID): return str(value) raise validators.Invalid( diff --git a/sqlobject/tests/test_uuidcol.py b/sqlobject/tests/test_uuidcol.py index 117d80ec..d1e2c22f 100644 --- a/sqlobject/tests/test_uuidcol.py +++ b/sqlobject/tests/test_uuidcol.py @@ -12,11 +12,11 @@ class UuidContainer(SQLObject): - uuiddata = UuidCol(default=None) + uuiddata = UuidCol(alternateID=True, default=None) def test_uuidCol(): - setupClass([UuidContainer], force=True) + setupClass([UuidContainer]) my_uuid = UuidContainer(uuiddata=testuuid) iid = my_uuid.id @@ -26,3 +26,15 @@ def test_uuidCol(): my_uuid_2 = UuidContainer.get(iid) assert my_uuid_2.uuiddata == testuuid + + +def test_alternate_id(): + setupClass([UuidContainer]) + + UuidContainer(uuiddata=testuuid) + + UuidContainer._connection.cache.clear() + + my_uuid_2 = UuidContainer.byUuiddata(testuuid) + + assert my_uuid_2.uuiddata == testuuid From 69e9604b7906a53ca4771e2b0d6da2d1da2f48ed Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 23 Nov 2025 14:22:14 +0300 Subject: [PATCH 502/509] Release 3.13.1b1 --- ANNOUNCE.rst | 17 +---------------- README.rst | 4 ++-- setup.py | 2 +- sqlobject/__version__.py | 8 ++++---- 4 files changed, 8 insertions(+), 23 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index ad13b0f5..18ed7f4d 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,22 +1,7 @@ Hello! -I'm pleased to announce version 3.13.1a1, the first alpha of the upcoming -release of branch 3.13 of SQLObject. - -I'm pleased to announce version 3.13.1a2, the second alpha of the upcoming -release of branch 3.13 of SQLObject. - I'm pleased to announce version 3.13.1b1, the first beta of the upcoming -release of branch 3.13 of SQLObject. - -I'm pleased to announce version 3.13.1rc1, the first release candidate -of the upcoming release of branch 3.13 of SQLObject. - -I'm pleased to announce version 3.13.1, the first bugfix release of branch -3.13 of SQLObject. - -I'm pleased to announce version 3.13.0, the first release of branch -3.13 of SQLObject. +bugfix release 3.13.1 of SQLObject. What's new in SQLObject diff --git a/README.rst b/README.rst index 4e7af749..840351f2 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.13.0 -================ +SQLObject 3.13.1b1 +================== SQLObject is a free and open-source (LGPL) Python object-relational mapper. Your database tables are described as classes, and rows are diff --git a/setup.py b/setup.py index 02b384c1..1a9d772b 100755 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ """, # noqa: E501 line too long long_description_content_type="text/x-rst", classifiers=[ - "Development Status :: 3 - Alpha", + "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: " "GNU Library or Lesser General Public License (LGPL)", diff --git a/sqlobject/__version__.py b/sqlobject/__version__.py index cc6e4c51..44d9bc73 100644 --- a/sqlobject/__version__.py +++ b/sqlobject/__version__.py @@ -1,8 +1,8 @@ -version = '3.13.0' +version = '3.13.1b1' major = 3 minor = 13 -micro = 0 -release_level = 'final' -serial = 0 +micro = 1 +release_level = 'beta' +serial = 1 version_info = (major, minor, micro, release_level, serial) From ebd8e4e85510ba8dcea94f8ef320cc95ec770f4d Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 23 Nov 2025 14:33:38 +0300 Subject: [PATCH 503/509] Build: Evil PyPI enforces lower-case distribution names Rename the distribution to `sqlobject`. --- devscripts/release | 12 +----------- setup.py | 8 ++++---- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/devscripts/release b/devscripts/release index 2df10e0f..664b68b0 100755 --- a/devscripts/release +++ b/devscripts/release @@ -24,15 +24,5 @@ if [ "$state" = final ]; then devscripts/sftp-frs fi && -cd dist && -if [ -f SQLObject-$version.tar.gz ]; then - mv SQLObject-$version.tar.gz sqlobject-$version.tar.gz -fi && -if [ -f SQLObject-$version-py2.py3-none-any.whl ]; then - mv SQLObject-$version-py2.py3-none-any.whl \ - sqlobject-$version-py2.py3-none-any.whl -fi && -cd .. && - twine upload --disable-progress-bar --skip-existing dist/* && -exec rm -rf build dist docs/html SQLObject.egg-info +exec rm -rf build dist docs/html sqlobject.egg-info diff --git a/setup.py b/setup.py index 1a9d772b..22fbd0ea 100755 --- a/setup.py +++ b/setup.py @@ -23,7 +23,7 @@ 'versioning', 'versioning.test'] setup( - name="SQLObject", + name="sqlobject", version=sqlobject_version['version'], description="Object-Relational Manager, aka database wrapper", long_description="""\ @@ -75,12 +75,12 @@ maintainer="Oleg Broytman", maintainer_email="phd@phdru.name", url="http://sqlobject.org/", - download_url="https://pypi.org/project/SQLObject/%s/" % + download_url="https://pypi.org/project/sqlobject/%s/" % sqlobject_version['version'], project_urls={ 'Homepage': 'http://sqlobject.org/', 'Development docs': 'http://sqlobject.org/devel/', - 'Download': 'https://pypi.org/project/SQLObject/%s/' % + 'Download': 'https://pypi.org/project/sqlobject/%s/' % sqlobject_version['version'], 'Github repo': 'https://github.com/sqlobject', 'Issue tracker': 'https://github.com/sqlobject/sqlobject/issues', @@ -213,7 +213,7 @@ https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Download: -https://pypi.org/project/SQLObject/@@/ +https://pypi.org/project/sqlobject/@@/ News and changes: http://sqlobject.org/docs/News.html From e9561de92bdd8c2fd2b30ed19905dc49ff12f918 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 23 Nov 2025 14:41:43 +0300 Subject: [PATCH 504/509] Build: Prepare for the next release [skip ci] --- ANNOUNCE.rst | 6 +++--- README.rst | 4 ++-- setup.py | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 18ed7f4d..9220969c 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,7 +1,7 @@ Hello! -I'm pleased to announce version 3.13.1b1, the first beta of the upcoming -bugfix release 3.13.1 of SQLObject. +I'm pleased to announce version 3.13.1, the first bugfix of the +branch 3.13 of SQLObject. What's new in SQLObject @@ -49,7 +49,7 @@ Site: http://sqlobject.org Download: -https://pypi.org/project/SQLObject/3.13.1a0.dev20250307/ +https://pypi.org/project/SQLObject/3.13.1a0.dev20251124/ News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 840351f2..157519af 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.13.1b1 -================== +SQLObject 3.13.1 +================ SQLObject is a free and open-source (LGPL) Python object-relational mapper. Your database tables are described as classes, and rows are diff --git a/setup.py b/setup.py index 22fbd0ea..9158ff54 100755 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ """, # noqa: E501 line too long long_description_content_type="text/x-rst", classifiers=[ - "Development Status :: 4 - Beta", + "Development Status :: 3 - Alpha", "Intended Audience :: Developers", "License :: OSI Approved :: " "GNU Library or Lesser General Public License (LGPL)", From 7fa955ace8ece7fd1e2635c9c993494508d3757e Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 28 Nov 2025 23:19:42 +0300 Subject: [PATCH 505/509] Build(devscripts/release): Fix `.git/objects` permissions [skip ci] --- devscripts/release | 1 + 1 file changed, 1 insertion(+) diff --git a/devscripts/release b/devscripts/release index 664b68b0..44ad33a1 100755 --- a/devscripts/release +++ b/devscripts/release @@ -3,6 +3,7 @@ cd "`dirname \"$0\"`"/.. && umask 022 && chmod -R a+rX . && +find .git/objects -type f -exec chmod u=r,go= '{}' \+ && set-commit-date.py && devscripts/build-docs && From 2402bfd127a490aad486e1d247e58cfceede3fc0 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 28 Nov 2025 23:45:28 +0300 Subject: [PATCH 506/509] CI(GHActions): Upgrade `checkout` and `setup-python` actions --- .github/workflows/run-tests.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 54f2658f..5c2b60c0 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -42,8 +42,8 @@ jobs: if: ${{ runner.os == 'Windows' }} # Setup Python/pip - - uses: actions/checkout@v4 - - uses: conda-incubator/setup-miniconda@v3 + - uses: actions/checkout@v5 + - uses: conda-incubator/setup-miniconda@v3.2.0 with: channels: conda-forge, conda-forge/label/python_rc miniforge-version: latest From 901e7e13dbe3113fd6d1589d6c13321565d7031b Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 28 Nov 2025 23:46:01 +0300 Subject: [PATCH 507/509] Tests(tox): Run tests with `psycopg2-binary` under Py 3.14 --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 032df079..04bc01f5 100644 --- a/tox.ini +++ b/tox.ini @@ -604,7 +604,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[psycopg2-binary-w32]commands} -[testenv:py3{4,5,6,7,9,10,11,12,13}-postgres-psycopg2-binary-w32] +[testenv:py3{4,5,6,7,9,10,11,12,13,14}-postgres-psycopg2-binary-w32] platform = win32 commands = {[psycopg2-binary-w32]commands} From c4026af7c94274107bb1550a4bb482d9abf628b9 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 8 Dec 2025 22:15:51 +0300 Subject: [PATCH 508/509] Release 3.13.1 --- ANNOUNCE.rst | 23 +++++++++++++++++++++-- devscripts/build-all-docs | 2 +- docs/News.rst | 6 ++++-- setup.cfg | 5 ----- setup.py | 2 +- sqlobject/__version__.py | 6 +++--- 6 files changed, 30 insertions(+), 14 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 9220969c..7088f66e 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,6 +1,6 @@ Hello! -I'm pleased to announce version 3.13.1, the first bugfix of the +I'm pleased to announce version 3.13.1, the first bugfix release of the branch 3.13 of SQLObject. @@ -19,6 +19,25 @@ The contributors for this release are: * GH user ghaushe-ampere. Thanks for finding an obscure bug! +Bug fixes +--------- + +* ``UuidValidator.from_python()`` now accepts strings as a valid input. + This fixes #199. + +* Fixed #197: a bug in ``dbconnection.ConnectionURIOpener.registerConnection`` + triggered by non-empty instance's ``name``. The bug was inserted in 2004 so + it seems nobody ever used named instances. Fixed anyway. + +* Fixed #195: Minor ``NameError`` in ``pgconnection.py`` + when using ``psycopg`` version 1 with a non-default port. + +Tests +----- + +* Tested with Python 3.14. + +* Run tests with source-only (non-binary) ``psycopg`` and ``psycopg2``. For a more complete list, please see the news: http://sqlobject.org/News.html @@ -49,7 +68,7 @@ Site: http://sqlobject.org Download: -https://pypi.org/project/SQLObject/3.13.1a0.dev20251124/ +https://pypi.org/project/SQLObject/3.13.1 News and changes: http://sqlobject.org/News.html diff --git a/devscripts/build-all-docs b/devscripts/build-all-docs index 3e3cda0e..62020c9d 100755 --- a/devscripts/build-all-docs +++ b/devscripts/build-all-docs @@ -10,7 +10,7 @@ cd "`dirname \"$0\"`" && PROG_DIR="`pwd`" && cd .. && -build_docs 3.13.0 && +build_docs 3.13.1 && build_docs master devel && rm -rf docs/html && diff --git a/docs/News.rst b/docs/News.rst index 96c5f77b..59cd5963 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,8 +5,10 @@ News .. contents:: Contents: :backlinks: none -SQLObject development (master) -============================== +SQLObject 3.13.1 +================ + +Released 2025 Dec 08. Bug fixes --------- diff --git a/setup.cfg b/setup.cfg index 461bc50f..43bae0f3 100644 --- a/setup.cfg +++ b/setup.cfg @@ -4,11 +4,6 @@ universal = 1 [easy_install] optimize = 2 -[egg_info] -tag_build = -tag_date = 0 -tag_svn_revision = 0 - [flake8] exclude = .git,.tox,docs/europython/*.py # E305: expected 2 blank lines after class or function definition, found 1 diff --git a/setup.py b/setup.py index 9158ff54..8d37606e 100755 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ """, # noqa: E501 line too long long_description_content_type="text/x-rst", classifiers=[ - "Development Status :: 3 - Alpha", + "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: " "GNU Library or Lesser General Public License (LGPL)", diff --git a/sqlobject/__version__.py b/sqlobject/__version__.py index 44d9bc73..37af2a9e 100644 --- a/sqlobject/__version__.py +++ b/sqlobject/__version__.py @@ -1,8 +1,8 @@ -version = '3.13.1b1' +version = '3.13.1' major = 3 minor = 13 micro = 1 -release_level = 'beta' -serial = 1 +release_level = 'final' +serial = 0 version_info = (major, minor, micro, release_level, serial) From 847875ade0f1af75c95ed9f9f3546a49b23204cd Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 8 Dec 2025 22:25:03 +0300 Subject: [PATCH 509/509] Build: Prepare for the next release [skip ci] --- ANNOUNCE.rst | 33 ++------------------------------- README.rst | 4 ++-- docs/News.rst | 3 +++ setup.cfg | 5 +++++ setup.py | 2 +- 5 files changed, 13 insertions(+), 34 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 7088f66e..b1d6645f 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,6 +1,6 @@ Hello! -I'm pleased to announce version 3.13.1, the first bugfix release of the +I'm pleased to announce version 3.13.2a0, the 2nd bugfix of the branch 3.13 of SQLObject. @@ -9,35 +9,6 @@ What's new in SQLObject The contributors for this release are: -* Igor Yudytskiy. Thanks for PR #194: - fix: connect to old mssql versions via set tds_version uri parameter. - -* Dave Mulligan fixed #195: Minor ``NameError`` in ``pgconnection.py`` - when using ``psycopg`` version 1 with a non-default port. Thanks! - -* Chris Kauffman found a minor bug in ``UuidValidator``. - -* GH user ghaushe-ampere. Thanks for finding an obscure bug! - -Bug fixes ---------- - -* ``UuidValidator.from_python()`` now accepts strings as a valid input. - This fixes #199. - -* Fixed #197: a bug in ``dbconnection.ConnectionURIOpener.registerConnection`` - triggered by non-empty instance's ``name``. The bug was inserted in 2004 so - it seems nobody ever used named instances. Fixed anyway. - -* Fixed #195: Minor ``NameError`` in ``pgconnection.py`` - when using ``psycopg`` version 1 with a non-default port. - -Tests ------ - -* Tested with Python 3.14. - -* Run tests with source-only (non-binary) ``psycopg`` and ``psycopg2``. For a more complete list, please see the news: http://sqlobject.org/News.html @@ -68,7 +39,7 @@ Site: http://sqlobject.org Download: -https://pypi.org/project/SQLObject/3.13.1 +https://pypi.org/project/SQLObject/3.13.2a0.dev20251208/ News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 157519af..cf8a985e 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.13.1 -================ +SQLObject 3.13.2a0 +================== SQLObject is a free and open-source (LGPL) Python object-relational mapper. Your database tables are described as classes, and rows are diff --git a/docs/News.rst b/docs/News.rst index 59cd5963..e01b1376 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,6 +5,9 @@ News .. contents:: Contents: :backlinks: none +SQLObject development (master) +============================== + SQLObject 3.13.1 ================ diff --git a/setup.cfg b/setup.cfg index 43bae0f3..461bc50f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -4,6 +4,11 @@ universal = 1 [easy_install] optimize = 2 +[egg_info] +tag_build = +tag_date = 0 +tag_svn_revision = 0 + [flake8] exclude = .git,.tox,docs/europython/*.py # E305: expected 2 blank lines after class or function definition, found 1 diff --git a/setup.py b/setup.py index 8d37606e..9158ff54 100755 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ """, # noqa: E501 line too long long_description_content_type="text/x-rst", classifiers=[ - "Development Status :: 5 - Production/Stable", + "Development Status :: 3 - Alpha", "Intended Audience :: Developers", "License :: OSI Approved :: " "GNU Library or Lesser General Public License (LGPL)",