diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c5aaf18..f456361 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,7 +7,7 @@ jobs: matrix: python-version: ["3.10.x", "3.11.x"] pg-version: ["14", "15"] - django-version: ["4.1.x", "4.2.x"] + django-version: ["4.1.x", "4.2.x", "5.0.x"] runs-on: ubuntu-latest steps: - name: Checkout code diff --git a/poetry.lock b/poetry.lock index 3e9de7c..e78111b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2,17 +2,17 @@ [[package]] name = "amqp" -version = "5.1.1" +version = "5.2.0" description = "Low-level AMQP client for Python (fork of amqplib)." optional = false python-versions = ">=3.6" files = [ - {file = "amqp-5.1.1-py3-none-any.whl", hash = "sha256:6f0956d2c23d8fa6e7691934d8c3930eadb44972cbbd1a7ae3a520f735d43359"}, - {file = "amqp-5.1.1.tar.gz", hash = "sha256:2c1b13fecc0893e946c65cbd5f36427861cffa4ea2201d8f6fca22e2a373b5e2"}, + {file = "amqp-5.2.0-py3-none-any.whl", hash = "sha256:827cb12fb0baa892aad844fd95258143bce4027fdac4fccddbc43330fd281637"}, + {file = "amqp-5.2.0.tar.gz", hash = "sha256:a1ecff425ad063ad42a486c902807d1482311481c8ad95a72694b2975e75f7fd"}, ] [package.dependencies] -vine = ">=5.0.0" +vine = ">=5.0.0,<6.0.0" [[package]] name = "asgiref" @@ -44,40 +44,40 @@ files = [ [[package]] name = "billiard" -version = "4.1.0" +version = "4.2.0" description = "Python multiprocessing fork with improvements and bugfixes" optional = false python-versions = ">=3.7" files = [ - {file = "billiard-4.1.0-py3-none-any.whl", hash = "sha256:0f50d6be051c6b2b75bfbc8bfd85af195c5739c281d3f5b86a5640c65563614a"}, - {file = "billiard-4.1.0.tar.gz", hash = "sha256:1ad2eeae8e28053d729ba3373d34d9d6e210f6e4d8bf0a9c64f92bd053f1edf5"}, + {file = "billiard-4.2.0-py3-none-any.whl", hash = "sha256:07aa978b308f334ff8282bd4a746e681b3513db5c9a514cbdd810cbbdc19714d"}, + {file = "billiard-4.2.0.tar.gz", hash = "sha256:9a3c3184cb275aa17a732f93f65b20c525d3d9f253722d26a82194803ade5a2c"}, ] [[package]] name = "black" -version = "23.10.1" +version = "23.11.0" description = "The uncompromising code formatter." optional = false python-versions = ">=3.8" files = [ - {file = "black-23.10.1-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:ec3f8e6234c4e46ff9e16d9ae96f4ef69fa328bb4ad08198c8cee45bb1f08c69"}, - {file = "black-23.10.1-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:1b917a2aa020ca600483a7b340c165970b26e9029067f019e3755b56e8dd5916"}, - {file = "black-23.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c74de4c77b849e6359c6f01987e94873c707098322b91490d24296f66d067dc"}, - {file = "black-23.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:7b4d10b0f016616a0d93d24a448100adf1699712fb7a4efd0e2c32bbb219b173"}, - {file = "black-23.10.1-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:b15b75fc53a2fbcac8a87d3e20f69874d161beef13954747e053bca7a1ce53a0"}, - {file = "black-23.10.1-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:e293e4c2f4a992b980032bbd62df07c1bcff82d6964d6c9496f2cd726e246ace"}, - {file = "black-23.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d56124b7a61d092cb52cce34182a5280e160e6aff3137172a68c2c2c4b76bcb"}, - {file = "black-23.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:3f157a8945a7b2d424da3335f7ace89c14a3b0625e6593d21139c2d8214d55ce"}, - {file = "black-23.10.1-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:cfcce6f0a384d0da692119f2d72d79ed07c7159879d0bb1bb32d2e443382bf3a"}, - {file = "black-23.10.1-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:33d40f5b06be80c1bbce17b173cda17994fbad096ce60eb22054da021bf933d1"}, - {file = "black-23.10.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:840015166dbdfbc47992871325799fd2dc0dcf9395e401ada6d88fe11498abad"}, - {file = "black-23.10.1-cp38-cp38-win_amd64.whl", hash = "sha256:037e9b4664cafda5f025a1728c50a9e9aedb99a759c89f760bd83730e76ba884"}, - {file = "black-23.10.1-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:7cb5936e686e782fddb1c73f8aa6f459e1ad38a6a7b0e54b403f1f05a1507ee9"}, - {file = "black-23.10.1-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:7670242e90dc129c539e9ca17665e39a146a761e681805c54fbd86015c7c84f7"}, - {file = "black-23.10.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ed45ac9a613fb52dad3b61c8dea2ec9510bf3108d4db88422bacc7d1ba1243d"}, - {file = "black-23.10.1-cp39-cp39-win_amd64.whl", hash = "sha256:6d23d7822140e3fef190734216cefb262521789367fbdc0b3f22af6744058982"}, - {file = "black-23.10.1-py3-none-any.whl", hash = "sha256:d431e6739f727bb2e0495df64a6c7a5310758e87505f5f8cde9ff6c0f2d7e4fe"}, - {file = "black-23.10.1.tar.gz", hash = "sha256:1f8ce316753428ff68749c65a5f7844631aa18c8679dfd3ca9dc1a289979c258"}, + {file = "black-23.11.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dbea0bb8575c6b6303cc65017b46351dc5953eea5c0a59d7b7e3a2d2f433a911"}, + {file = "black-23.11.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:412f56bab20ac85927f3a959230331de5614aecda1ede14b373083f62ec24e6f"}, + {file = "black-23.11.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d136ef5b418c81660ad847efe0e55c58c8208b77a57a28a503a5f345ccf01394"}, + {file = "black-23.11.0-cp310-cp310-win_amd64.whl", hash = "sha256:6c1cac07e64433f646a9a838cdc00c9768b3c362805afc3fce341af0e6a9ae9f"}, + {file = "black-23.11.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cf57719e581cfd48c4efe28543fea3d139c6b6f1238b3f0102a9c73992cbb479"}, + {file = "black-23.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:698c1e0d5c43354ec5d6f4d914d0d553a9ada56c85415700b81dc90125aac244"}, + {file = "black-23.11.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:760415ccc20f9e8747084169110ef75d545f3b0932ee21368f63ac0fee86b221"}, + {file = "black-23.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:58e5f4d08a205b11800332920e285bd25e1a75c54953e05502052738fe16b3b5"}, + {file = "black-23.11.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:45aa1d4675964946e53ab81aeec7a37613c1cb71647b5394779e6efb79d6d187"}, + {file = "black-23.11.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4c44b7211a3a0570cc097e81135faa5f261264f4dfaa22bd5ee2875a4e773bd6"}, + {file = "black-23.11.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a9acad1451632021ee0d146c8765782a0c3846e0e0ea46659d7c4f89d9b212b"}, + {file = "black-23.11.0-cp38-cp38-win_amd64.whl", hash = "sha256:fc7f6a44d52747e65a02558e1d807c82df1d66ffa80a601862040a43ec2e3142"}, + {file = "black-23.11.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7f622b6822f02bfaf2a5cd31fdb7cd86fcf33dab6ced5185c35f5db98260b055"}, + {file = "black-23.11.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:250d7e60f323fcfc8ea6c800d5eba12f7967400eb6c2d21ae85ad31c204fb1f4"}, + {file = "black-23.11.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5133f5507007ba08d8b7b263c7aa0f931af5ba88a29beacc4b2dc23fcefe9c06"}, + {file = "black-23.11.0-cp39-cp39-win_amd64.whl", hash = "sha256:421f3e44aa67138ab1b9bfbc22ee3780b22fa5b291e4db8ab7eee95200726b07"}, + {file = "black-23.11.0-py3-none-any.whl", hash = "sha256:54caaa703227c6e0c87b76326d0862184729a69b73d3b7305b6288e1d830067e"}, + {file = "black-23.11.0.tar.gz", hash = "sha256:4c68855825ff432d197229846f971bc4d6666ce90492e5b02013bcaca4d9ab05"}, ] [package.dependencies] @@ -97,29 +97,29 @@ uvloop = ["uvloop (>=0.15.2)"] [[package]] name = "celery" -version = "5.3.4" +version = "5.3.6" description = "Distributed Task Queue." optional = false python-versions = ">=3.8" files = [ - {file = "celery-5.3.4-py3-none-any.whl", hash = "sha256:1e6ed40af72695464ce98ca2c201ad0ef8fd192246f6c9eac8bba343b980ad34"}, - {file = "celery-5.3.4.tar.gz", hash = "sha256:9023df6a8962da79eb30c0c84d5f4863d9793a466354cc931d7f72423996de28"}, + {file = "celery-5.3.6-py3-none-any.whl", hash = "sha256:9da4ea0118d232ce97dff5ed4974587fb1c0ff5c10042eb15278487cdd27d1af"}, + {file = "celery-5.3.6.tar.gz", hash = "sha256:870cc71d737c0200c397290d730344cc991d13a057534353d124c9380267aab9"}, ] [package.dependencies] -billiard = ">=4.1.0,<5.0" +billiard = ">=4.2.0,<5.0" click = ">=8.1.2,<9.0" click-didyoumean = ">=0.3.0" click-plugins = ">=1.1.1" click-repl = ">=0.2.0" -kombu = ">=5.3.2,<6.0" +kombu = ">=5.3.4,<6.0" python-dateutil = ">=2.8.2" tzdata = ">=2022.7" -vine = ">=5.0.0,<6.0" +vine = ">=5.1.0,<6.0" [package.extras] arangodb = ["pyArango (>=2.0.2)"] -auth = ["cryptography (==41.0.3)"] +auth = ["cryptography (==41.0.5)"] azureblockblob = ["azure-storage-blob (>=12.15.0)"] brotli = ["brotli (>=1.0.0)", "brotlipy (>=0.7.0)"] cassandra = ["cassandra-driver (>=3.25.0,<4)"] @@ -129,26 +129,26 @@ couchbase = ["couchbase (>=3.0.0)"] couchdb = ["pycouchdb (==1.14.2)"] django = ["Django (>=2.2.28)"] dynamodb = ["boto3 (>=1.26.143)"] -elasticsearch = ["elasticsearch (<8.0)"] +elasticsearch = ["elastic-transport (<=8.10.0)", "elasticsearch (<=8.11.0)"] eventlet = ["eventlet (>=0.32.0)"] gevent = ["gevent (>=1.5.0)"] librabbitmq = ["librabbitmq (>=2.0.0)"] memcache = ["pylibmc (==1.6.3)"] mongodb = ["pymongo[srv] (>=4.0.2)"] -msgpack = ["msgpack (==1.0.5)"] +msgpack = ["msgpack (==1.0.7)"] pymemcache = ["python-memcached (==1.59)"] pyro = ["pyro4 (==4.82)"] pytest = ["pytest-celery (==0.0.0)"] -redis = ["redis (>=4.5.2,!=4.5.5,<5.0.0)"] +redis = ["redis (>=4.5.2,!=4.5.5,<6.0.0)"] s3 = ["boto3 (>=1.26.143)"] slmq = ["softlayer-messaging (>=1.0.3)"] -solar = ["ephem (==4.1.4)"] +solar = ["ephem (==4.1.5)"] sqlalchemy = ["sqlalchemy (>=1.4.48,<2.1)"] sqs = ["boto3 (>=1.26.143)", "kombu[sqs] (>=5.3.0)", "pycurl (>=7.43.0.5)", "urllib3 (>=1.26.16)"] tblib = ["tblib (>=1.3.0)", "tblib (>=1.5.0)"] yaml = ["PyYAML (>=3.10)"] zookeeper = ["kazoo (>=1.3.1)"] -zstd = ["zstandard (==0.21.0)"] +zstd = ["zstandard (==0.22.0)"] [[package]] name = "click" @@ -293,17 +293,17 @@ toml = ["tomli"] [[package]] name = "django" -version = "4.2.7" +version = "5.0" description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" files = [ - {file = "Django-4.2.7-py3-none-any.whl", hash = "sha256:e1d37c51ad26186de355cbcec16613ebdabfa9689bbade9c538835205a8abbe9"}, - {file = "Django-4.2.7.tar.gz", hash = "sha256:8e0f1c2c2786b5c0e39fe1afce24c926040fad47c8ea8ad30aaf1188df29fc41"}, + {file = "Django-5.0-py3-none-any.whl", hash = "sha256:3a9fd52b8dbeae335ddf4a9dfa6c6a0853a1122f1fb071a8d5eca979f73a05c8"}, + {file = "Django-5.0.tar.gz", hash = "sha256:7d29e14dfbc19cb6a95a4bd669edbde11f5d4c6a71fdaa42c2d40b6846e807f7"}, ] [package.dependencies] -asgiref = ">=3.6.0,<4" +asgiref = ">=3.7.0" sqlparse = ">=0.3.1" tzdata = {version = "*", markers = "sys_platform == \"win32\""} @@ -341,13 +341,13 @@ requirements-deprecated-finder = ["pip-api", "pipreqs"] [[package]] name = "kombu" -version = "5.3.2" +version = "5.3.4" description = "Messaging library for Python." optional = false python-versions = ">=3.8" files = [ - {file = "kombu-5.3.2-py3-none-any.whl", hash = "sha256:b753c9cfc9b1e976e637a7cbc1a65d446a22e45546cd996ea28f932082b7dc9e"}, - {file = "kombu-5.3.2.tar.gz", hash = "sha256:0ba213f630a2cb2772728aef56ac6883dc3a2f13435e10048f6e97d48506dbbd"}, + {file = "kombu-5.3.4-py3-none-any.whl", hash = "sha256:63bb093fc9bb80cfb3a0972336a5cec1fa7ac5f9ef7e8237c6bf8dda9469313e"}, + {file = "kombu-5.3.4.tar.gz", hash = "sha256:0bb2e278644d11dea6272c17974a3dbb9688a949f3bb60aeb5b791329c44fadc"}, ] [package.dependencies] @@ -357,14 +357,14 @@ vine = "*" [package.extras] azureservicebus = ["azure-servicebus (>=7.10.0)"] azurestoragequeues = ["azure-identity (>=1.12.0)", "azure-storage-queue (>=12.6.0)"] -confluentkafka = ["confluent-kafka (==2.1.1)"] +confluentkafka = ["confluent-kafka (>=2.2.0)"] consul = ["python-consul2"] librabbitmq = ["librabbitmq (>=2.0.0)"] mongodb = ["pymongo (>=4.1.1)"] msgpack = ["msgpack"] pyro = ["pyro4"] qpid = ["qpid-python (>=0.26)", "qpid-tools (>=0.26)"] -redis = ["redis (>=4.5.2)"] +redis = ["redis (>=4.5.2,!=4.5.5,<6.0.0)"] slmq = ["softlayer-messaging (>=1.0.3)"] sqlalchemy = ["sqlalchemy (>=1.4.48,<2.1)"] sqs = ["boto3 (>=1.26.143)", "pycurl (>=7.43.0.5)", "urllib3 (>=1.26.16)"] @@ -473,13 +473,13 @@ tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "pa [[package]] name = "platformdirs" -version = "3.11.0" +version = "4.1.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "platformdirs-3.11.0-py3-none-any.whl", hash = "sha256:e9d171d00af68be50e9202731309c4e658fd8bc76f55c11c7dd760d023bda68e"}, - {file = "platformdirs-3.11.0.tar.gz", hash = "sha256:cf8ee52a3afdb965072dcc652433e0c7e3e40cf5ea1477cd4b3b1d2eb75495b3"}, + {file = "platformdirs-4.1.0-py3-none-any.whl", hash = "sha256:11c8f37bcca40db96d8144522d925583bdb7a31f7b0e37e3ed4318400a8e2380"}, + {file = "platformdirs-4.1.0.tar.gz", hash = "sha256:906d548203468492d432bcb294d4bc2fff751bf84971fbb2c10918cc206ee420"}, ] [package.extras] @@ -488,13 +488,13 @@ test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-co [[package]] name = "prompt-toolkit" -version = "3.0.39" +version = "3.0.41" description = "Library for building powerful interactive command lines in Python" optional = false python-versions = ">=3.7.0" files = [ - {file = "prompt_toolkit-3.0.39-py3-none-any.whl", hash = "sha256:9dffbe1d8acf91e3de75f3b544e4842382fc06c6babe903ac9acb74dc6e08d88"}, - {file = "prompt_toolkit-3.0.39.tar.gz", hash = "sha256:04505ade687dc26dc4284b1ad19a83be2f2afe83e7a828ace0c72f3a1df72aac"}, + {file = "prompt_toolkit-3.0.41-py3-none-any.whl", hash = "sha256:f36fe301fafb7470e86aaf90f036eef600a3210be4decf461a5b1ca8403d3cb2"}, + {file = "prompt_toolkit-3.0.41.tar.gz", hash = "sha256:941367d97fc815548822aa26c2a269fdc4eb21e9ec05fc5d447cf09bad5d75f0"}, ] [package.dependencies] @@ -595,17 +595,6 @@ files = [ [package.dependencies] six = ">=1.5" -[[package]] -name = "pytz" -version = "2023.3.post1" -description = "World timezone definitions, modern and historical" -optional = false -python-versions = "*" -files = [ - {file = "pytz-2023.3.post1-py2.py3-none-any.whl", hash = "sha256:ce42d816b81b68506614c11e8937d3aa9e41007ceb50bfdcb0749b921bf646c7"}, - {file = "pytz-2023.3.post1.tar.gz", hash = "sha256:7b4fddbeb94a1eba4b557da24f19fdf9db575192544270a9101d8509f9f43d7b"}, -] - [[package]] name = "redis" version = "5.0.1" @@ -712,24 +701,24 @@ files = [ [[package]] name = "vine" -version = "5.0.0" -description = "Promises, promises, promises." +version = "5.1.0" +description = "Python promises." optional = false python-versions = ">=3.6" files = [ - {file = "vine-5.0.0-py2.py3-none-any.whl", hash = "sha256:4c9dceab6f76ed92105027c49c823800dd33cacce13bdedc5b914e3514b7fb30"}, - {file = "vine-5.0.0.tar.gz", hash = "sha256:7d3b1624a953da82ef63462013bbd271d3eb75751489f9807598e8f340bd637e"}, + {file = "vine-5.1.0-py3-none-any.whl", hash = "sha256:40fdf3c48b2cfe1c38a49e9ae2da6fda88e4794c810050a728bd7413811fb1dc"}, + {file = "vine-5.1.0.tar.gz", hash = "sha256:8b62e981d35c41049211cf62a0a1242d8c1ee9bd15bb196ce38aefd6799e61e0"}, ] [[package]] name = "wcwidth" -version = "0.2.9" +version = "0.2.12" description = "Measures the displayed width of unicode strings in a terminal" optional = false python-versions = "*" files = [ - {file = "wcwidth-0.2.9-py2.py3-none-any.whl", hash = "sha256:9a929bd8380f6cd9571a968a9c8f4353ca58d7cd812a4822bba831f8d685b223"}, - {file = "wcwidth-0.2.9.tar.gz", hash = "sha256:a675d1a4a2d24ef67096a04b85b02deeecd8e226f57b5e3a72dbb9ed99d27da8"}, + {file = "wcwidth-0.2.12-py2.py3-none-any.whl", hash = "sha256:f26ec43d96c8cbfed76a5075dac87680124fa84e0855195a6184da9c187f133c"}, + {file = "wcwidth-0.2.12.tar.gz", hash = "sha256:f01c104efdf57971bcb756f054dd58ddec5204dd15fa31d6503ea57947d97c02"}, ] [[package]] @@ -757,4 +746,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "d5730f4966c51ac3e1af03c8e2c5ca4ff31f136d270963a5534b1e35ad782fab" +content-hash = "5f18b47f7c97b894dc914dc139ec746d6e7952aa38cf8294d3e65696342e2450" diff --git a/pyproject.toml b/pyproject.toml index 2985315..7c121c2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,9 +23,8 @@ repository = "http://github.com/nyaruka/smartmin" [tool.poetry.dependencies] python = "^3.10" -Django = ">= 4.0, < 5.0" +Django = ">= 4.0, < 5.1" celery = ">= 5.1" -pytz = "*" redis = ">= 3.5.3" sqlparse = "^0.4.1" xlrd = "^1.2.0" diff --git a/smartmin/csv_imports/tests.py b/smartmin/csv_imports/tests.py index 0f08212..b333b40 100644 --- a/smartmin/csv_imports/tests.py +++ b/smartmin/csv_imports/tests.py @@ -8,16 +8,16 @@ def test_csv_import(self): pass def test_generate_file_path(self): - self.assertEquals(generate_file_path(ImportTask(), "allo.csv"), "csv_imports/allo.csv") - self.assertEquals(generate_file_path(ImportTask(), "allo.xlsx"), "csv_imports/allo.xlsx") - self.assertEquals(generate_file_path(ImportTask(), "allo.foo.bar"), "csv_imports/allo.foo.bar") + self.assertEqual(generate_file_path(ImportTask(), "allo.csv"), "csv_imports/allo.csv") + self.assertEqual(generate_file_path(ImportTask(), "allo.xlsx"), "csv_imports/allo.xlsx") + self.assertEqual(generate_file_path(ImportTask(), "allo.foo.bar"), "csv_imports/allo.foo.bar") long_name = "foo" * 100 test_file_name = "%s.xls.csv" % long_name - self.assertEquals(len(generate_file_path(ImportTask(), test_file_name)), 100) - self.assertEquals(generate_file_path(ImportTask(), test_file_name), "csv_imports/%s.csv" % long_name[:84]) + self.assertEqual(len(generate_file_path(ImportTask(), test_file_name)), 100) + self.assertEqual(generate_file_path(ImportTask(), test_file_name), "csv_imports/%s.csv" % long_name[:84]) test_file_name = "%s.abc.xlsx" % long_name - self.assertEquals(len(generate_file_path(ImportTask(), test_file_name)), 100) - self.assertEquals(generate_file_path(ImportTask(), test_file_name), "csv_imports/%s.xlsx" % long_name[:83]) + self.assertEqual(len(generate_file_path(ImportTask(), test_file_name)), 100) + self.assertEqual(generate_file_path(ImportTask(), test_file_name), "csv_imports/%s.xlsx" % long_name[:83]) diff --git a/smartmin/models.py b/smartmin/models.py index 2289fb5..ed6d295 100644 --- a/smartmin/models.py +++ b/smartmin/models.py @@ -2,7 +2,7 @@ import json import traceback import zoneinfo -from datetime import datetime +from datetime import datetime, timezone as tzone from xlrd import XL_CELL_DATE, XLRDError, open_workbook, xldate_as_tuple @@ -220,9 +220,7 @@ def import_xls(cls, filename, user, import_params, log=None, import_results=None # timezone for date cells can be specified as an import parameter or defaults to UTC # use now to determine a relevant timezone naive_timezone = ( - zoneinfo.ZoneInfo(import_params["timezone"]) - if import_params and "timezone" in import_params - else timezone.utc + zoneinfo.ZoneInfo(import_params["timezone"]) if import_params and "timezone" in import_params else tzone.utc ) tz = timezone.now().astimezone(naive_timezone).tzinfo diff --git a/smartmin/templatetags/smartmin.py b/smartmin/templatetags/smartmin.py index d628718..85c97b5 100644 --- a/smartmin/templatetags/smartmin.py +++ b/smartmin/templatetags/smartmin.py @@ -1,7 +1,7 @@ import json import re import zoneinfo -from datetime import datetime, timedelta +from datetime import datetime, timedelta, timezone as tzone from django import template from django.conf import settings @@ -34,7 +34,7 @@ def format_datetime(time): """ user_time_zone = timezone.get_current_timezone() if time.tzinfo is None: - time = time.replace(tzinfo=timezone.utc) + time = time.replace(tzinfo=tzone.utc) user_time_zone = zoneinfo.ZoneInfo(getattr(settings, "USER_TIME_ZONE", "GMT")) time = time.astimezone(user_time_zone) @@ -164,7 +164,7 @@ def map(string, args): @register.filter def gmail_time(dtime, now=None): if dtime.tzinfo is None: - dtime = dtime.replace(tzinfo=timezone.utc) + dtime = dtime.replace(tzinfo=tzone.utc) user_time_zone = zoneinfo.ZoneInfo(getattr(settings, "USER_TIME_ZONE", "GMT")) dtime = dtime.astimezone(user_time_zone) else: @@ -174,7 +174,7 @@ def gmail_time(dtime, now=None): now = timezone.now() if now.tzinfo is None: - now = now.replace(tzinfo=timezone.utc) + now = now.replace(tzinfo=tzone.utc) twelve_hours_ago = now - timedelta(hours=12) diff --git a/smartmin/tests.py b/smartmin/tests.py index 531b5a1..b2eebd2 100644 --- a/smartmin/tests.py +++ b/smartmin/tests.py @@ -26,14 +26,14 @@ def fetch_protected(self, url, user, post_data=None, failOnFormValidation=True): # but now we can! if not post_data: response = self.client.get(url) - self.assertEquals(200, response.status_code) + self.assertEqual(200, response.status_code) else: response = self.client.post(url, data=post_data) self.assertNotRedirect(response, reverse("users.user_login"), msg="Unexpected redirect to login") if failOnFormValidation: self.assertNoFormErrors(response, post_data) - self.assertEquals(302, response.status_code) + self.assertEqual(302, response.status_code) return response @@ -162,7 +162,7 @@ def testDelete(self): return object = self.getTestObject() self._do_test_view("delete", object, post_data=dict()) - self.assertEquals(0, len(self.getManager().filter(pk=object.pk))) + self.assertEqual(0, len(self.getManager().filter(pk=object.pk))) def testList(self): if "list" not in self.getCRUDL().actions: @@ -222,7 +222,7 @@ def _do_test_view(self, action=None, object=None, post_data=None, query_string=N def assertPageGet(self, action, response): if response.status_code == 302: self.fail("'%s' resulted in an unexpected redirect to: %s" % (action, response.get("Location"))) - self.assertEquals( + self.assertEqual( 200, response.status_code, ) diff --git a/test_runner/blog/tests.py b/test_runner/blog/tests.py index 84f4890..05993f8 100644 --- a/test_runner/blog/tests.py +++ b/test_runner/blog/tests.py @@ -1,8 +1,8 @@ import json -from datetime import datetime, timedelta +from datetime import datetime, timedelta, timezone as tzone from unittest.mock import patch -import pytz +from zoneinfo import ZoneInfo from django.conf import settings from django.contrib.auth.models import Group, User @@ -65,7 +65,7 @@ def assertNoAccess(self, user, url): def assertHasAccess(self, user, url): self.client.login(username=user.username, password=user.username) response = self.client.get(url) - self.assertEquals(200, response.status_code, "User '%s' does not have access to URL: %s" % (user.username, url)) + self.assertEqual(200, response.status_code, "User '%s' does not have access to URL: %s" % (user.username, url)) def assertIsLogin(self, response): self.assertRedirect(response, reverse("users.user_login")) @@ -123,7 +123,7 @@ def test_permissions(self): # even users not logged in can read self.client.logout() response = self.client.get(read_url) - self.assertEquals(200, response.status_code) + self.assertEqual(200, response.status_code) # along with everyone else self.assertHasAccess(self.plain, read_url) @@ -169,11 +169,11 @@ def test_create_and_update(self): # get the last post post = list(Post.objects.all())[-1] - self.assertEquals("New Post", post.title) - self.assertEquals("This is a new post", post.body) - self.assertEquals("post", post.tags) - self.assertEquals(self.author, post.created_by) - self.assertEquals(self.author, post.modified_by) + self.assertEqual("New Post", post.title) + self.assertEqual("This is a new post", post.body) + self.assertEqual("post", post.tags) + self.assertEqual(self.author, post.created_by) + self.assertEqual(self.author, post.modified_by) def test_messaging(self): self.client.login(username="author", password="author") @@ -183,13 +183,13 @@ def test_messaging(self): post = list(Post.objects.all())[-1] - self.assertEquals(200, response.status_code) + self.assertEqual(200, response.status_code) self.assertContains(response, "Your new post has been created.") post_data = dict(title="New Post", body="Updated post content", order=1, tags="post") response = self.client.post(reverse("blog.post_update", args=[post.id]), post_data, follow=True) - self.assertEquals(200, response.status_code) + self.assertEqual(200, response.status_code) self.assertContains(response, "Your blog post has been updated.") def test_message_tags(self): @@ -205,7 +205,7 @@ def test_message_tags(self): def test_template_name(self): self.client.login(username="author", password="author") response = self.client.get(reverse("blog.post_list")) - self.assertEquals(["blog/post_list.html", "smartmin/list.html"], response.template_name) + self.assertEqual(["blog/post_list.html", "smartmin/list.html"], response.template_name) def test_read(self): post = Post.objects.create( @@ -409,7 +409,7 @@ def test_success_url(self): post_data = dict(title="New Post", body="This is a new post", order=1, tags="post") response = self.client.post(reverse("blog.post_create"), post_data, follow=True) - self.assertEquals(reverse("blog.post_list"), response.request["PATH_INFO"]) + self.assertEqual(reverse("blog.post_list"), response.request["PATH_INFO"]) def test_submit_button_name(self): self.client.login(username="author", password="author") @@ -423,12 +423,12 @@ def test_excludes(self): # this view excludes tags with the default form response = self.client.get(reverse("blog.post_exclude", args=[self.post.id])) content = response.content.decode("utf-8") - self.assertEquals(0, content.count("tags")) + self.assertEqual(0, content.count("tags")) # this view excludes tags included in a custom form response = self.client.get(reverse("blog.post_exclude2", args=[self.post.id])) content = response.content.decode("utf-8") - self.assertEquals(0, content.count("tags")) + self.assertEqual(0, content.count("tags")) def test_readonly(self): self.client.login(username="author", password="author") @@ -436,16 +436,16 @@ def test_readonly(self): # this view should have our tags field be readonly response = self.client.get(reverse("blog.post_readonly", args=[self.post.id])) content = response.content.decode("utf-8") - self.assertEquals(1, content.count("testing_tag")) - self.assertEquals(1, content.count("Tags")) - self.assertEquals(0, content.count('input id="id_tags"')) + self.assertEqual(1, content.count("testing_tag")) + self.assertEqual(1, content.count("Tags")) + self.assertEqual(0, content.count('input id="id_tags"')) # this view should also have our tags field be readonly, but it does so on a custom form response = self.client.get(reverse("blog.post_readonly2", args=[self.post.id])) content = response.content.decode("utf-8") - self.assertEquals(1, content.count("testing_tag")) - self.assertEquals(1, content.count("Tags")) - self.assertEquals(0, content.count('input id="id_tags"')) + self.assertEqual(1, content.count("testing_tag")) + self.assertEqual(1, content.count("Tags")) + self.assertEqual(0, content.count('input id="id_tags"')) def test_integrity_error(self): self.client.login(username="author", password="author") @@ -456,10 +456,10 @@ def test_integrity_error(self): response = self.client.post(reverse("blog.category_create"), post_data) # should get a plain 200 - self.assertEquals(200, response.status_code) + self.assertEqual(200, response.status_code) # should have one error (our integrity error) - self.assertEquals(1, len(response.context["form"].errors)) + self.assertEqual(1, len(response.context["form"].errors)) def test_version(self): self.assertTrue(smartmin.__version__ is not None) @@ -476,17 +476,17 @@ def test_management(self): "blog.foo.*", ) - self.assertEquals(18, authors.permissions.all().count()) + self.assertEqual(18, authors.permissions.all().count()) # check that they are reassigned check_role_permissions(authors, permissions, authors.permissions.all()) # removing all category actions should bring us to 10 - self.assertEquals(13, authors.permissions.all().count()) + self.assertEqual(13, authors.permissions.all().count()) def test_smart_model(self): - d1 = datetime(2016, 12, 31, 9, 20, 30, 123456, tzinfo=pytz.timezone("Africa/Kigali")) - d2 = datetime(2017, 1, 10, 10, 20, 30, 123456, tzinfo=pytz.timezone("Africa/Kigali")) + d1 = datetime(2016, 12, 31, 9, 20, 30, 123456, tzinfo=ZoneInfo("Africa/Kigali")) + d2 = datetime(2017, 1, 10, 10, 20, 30, 123456, tzinfo=ZoneInfo("Africa/Kigali")) d3 = timezone.now() p1 = Post.objects.create( @@ -576,7 +576,7 @@ def test_csv_import(self): response = self.client.get(import_url) self.assertTrue(200, response.status_code) - self.assertEquals(response.request["PATH_INFO"], import_url) + self.assertEqual(response.request["PATH_INFO"], import_url) csv_file = open("test_runner/blog/test_files/posts.csv", "rb") post_data = dict(csv_file=csv_file) @@ -660,35 +660,35 @@ def test_login_stripped_spaces(self): login_url = reverse("users.user_login") response = self.client.post(login_url, dict(username=" superuser", password="superuser")) - self.assertEquals(response.status_code, 302) + self.assertEqual(response.status_code, 302) response = self.client.post(login_url, dict(username=" superuser ", password="superuser")) - self.assertEquals(response.status_code, 302) + self.assertEqual(response.status_code, 302) def test_login_case_not_sensitive(self): login_url = reverse("users.user_login") response = self.client.post(login_url, dict(username="superuser", password="superuser")) - self.assertEquals(response.status_code, 302) + self.assertEqual(response.status_code, 302) response = self.client.post(login_url, dict(username="superuser", password="superuser"), follow=True) - self.assertEquals(response.request["PATH_INFO"], settings.LOGIN_REDIRECT_URL) + self.assertEqual(response.request["PATH_INFO"], settings.LOGIN_REDIRECT_URL) response = self.client.post(login_url, dict(username="SUPERuser", password="superuser")) - self.assertEquals(response.status_code, 302) + self.assertEqual(response.status_code, 302) response = self.client.post(login_url, dict(username="SUPERuser", password="superuser"), follow=True) - self.assertEquals(response.request["PATH_INFO"], settings.LOGIN_REDIRECT_URL) + self.assertEqual(response.request["PATH_INFO"], settings.LOGIN_REDIRECT_URL) other_supersuser = User.objects.create_user("withCAPS", "with_caps@group.com", "thePASSWORD") other_supersuser.is_superuser = True other_supersuser.save() response = self.client.post(login_url, dict(username="withcaps", password="thePASSWORD")) - self.assertEquals(response.status_code, 302) + self.assertEqual(response.status_code, 302) response = self.client.post(login_url, dict(username="withcaps", password="thePASSWORD"), follow=True) - self.assertEquals(response.request["PATH_INFO"], settings.LOGIN_REDIRECT_URL) + self.assertEqual(response.request["PATH_INFO"], settings.LOGIN_REDIRECT_URL) # passwords stay case sensitive response = self.client.post(login_url, dict(username="withcaps", password="thepassword"), follow=True) @@ -708,7 +708,7 @@ def test_crudl(self): ) response = self.client.post(reverse("users.user_create"), post_data, follow=True) - self.assertEquals(200, response.status_code) + self.assertEqual(200, response.status_code) # we should have failed due to our password not being long enough self.assertTrue("new_password" in response.context["form"].errors) @@ -716,19 +716,19 @@ def test_crudl(self): # try with a longer password but without our requirements (8 chars) post_data["new_password"] = "password" response = self.client.post(reverse("users.user_create"), post_data, follow=True) - self.assertEquals(200, response.status_code) + self.assertEqual(200, response.status_code) self.assertTrue("new_password" in response.context["form"].errors) # try with one capital letter post_data["new_password"] = "Password" response = self.client.post(reverse("users.user_create"), post_data, follow=True) - self.assertEquals(200, response.status_code) + self.assertEqual(200, response.status_code) self.assertTrue("new_password" in response.context["form"].errors) # ok, finally with a zero and a whitespace in there too, this one should pass post_data["new_password"] = "Passw0rd " response = self.client.post(reverse("users.user_create"), post_data, follow=True) - self.assertEquals(200, response.status_code) + self.assertEqual(200, response.status_code) self.assertTrue("form" not in response.context) # make sure the user was created @@ -750,9 +750,9 @@ def test_crudl(self): users = response.context["user_list"] # results should be sorted by username - self.assertEquals(2, len(users)) - self.assertEquals(steve, users[0]) - self.assertEquals(woz, users[1]) + self.assertEqual(2, len(users)) + self.assertEqual(steve, users[0]) + self.assertEqual(woz, users[1]) # check our content too self.assertContains(response, "woz") @@ -767,14 +767,14 @@ def test_crudl(self): post_data["username"] = "steve" response = self.client.post(reverse("users.user_update", args=[steve.id]), post_data, follow=True) - self.assertEquals(200, response.status_code) + self.assertEqual(200, response.status_code) self.assertTrue("form" not in response.context) # check that steve's group changed steve = User.objects.get(pk=steve.id) groups = steve.groups.all() - self.assertEquals(1, len(groups)) - self.assertEquals(Group.objects.get(name="Editors"), groups[0]) + self.assertEqual(1, len(groups)) + self.assertEqual(Group.objects.get(name="Editors"), groups[0]) # assert steve can login with 'google' now self.assertTrue(self.client.login(username="steve", password=" googleIsNumber1")) @@ -790,20 +790,20 @@ def test_crudl(self): response = self.client.post(reverse("users.user_mimic", args=[steve.id]), follow=True) # check if the logged in user is steve now - self.assertEquals(response.context["user"].username, "steve") - self.assertEquals(response.request["PATH_INFO"], settings.LOGIN_REDIRECT_URL) + self.assertEqual(response.context["user"].username, "steve") + self.assertEqual(response.request["PATH_INFO"], settings.LOGIN_REDIRECT_URL) # now that steve is the one logged in can he mimic woz? response = self.client.get(reverse("users.user_mimic", args=[woz.id]), follow=True) - self.assertEquals(response.request["PATH_INFO"], settings.LOGIN_URL) + self.assertEqual(response.request["PATH_INFO"], settings.LOGIN_URL) # login as super user self.assertTrue(self.client.login(username="superuser", password="superuser")) # check is access his profile response = self.client.get(reverse("users.user_profile", args=[self.superuser.id])) - self.assertEquals(200, response.status_code) - self.assertEquals(reverse("users.user_profile", args=[self.superuser.id]), response.request["PATH_INFO"]) + self.assertEqual(200, response.status_code) + self.assertEqual(reverse("users.user_profile", args=[self.superuser.id]), response.request["PATH_INFO"]) # create just a plain user plain = User.objects.create_user("plain", "plain@nogroups.com", "plain") @@ -813,20 +813,20 @@ def test_crudl(self): # check is access his profile, should not since plain users don't have that permission response = self.client.get(reverse("users.user_profile", args=[plain.id])) - self.assertEquals(302, response.status_code) + self.assertEqual(302, response.status_code) # log in as an editor instead self.assertTrue(self.client.login(username="steve", password=" googleIsNumber1")) response = self.client.get(reverse("users.user_profile", args=[steve.id])) - self.assertEquals(reverse("users.user_profile", args=[steve.id]), response.request["PATH_INFO"]) + self.assertEqual(reverse("users.user_profile", args=[steve.id]), response.request["PATH_INFO"]) # check if we are at the right form - self.assertEquals("UserProfileForm", type(response.context["form"]).__name__) + self.assertEqual("UserProfileForm", type(response.context["form"]).__name__) response = self.client.post(reverse("users.user_profile", args=[steve.id]), {}, follow=True) # check which field he have access to - self.assertEquals(6, len(response.context["form"].visible_fields())) + self.assertEqual(6, len(response.context["form"].visible_fields())) # doesn't include readonly fields on post self.assertNotIn("username", response.context["form"].fields) @@ -891,9 +891,9 @@ def test_token(self): response = self.client.post(forget_url, post_data, follow=True) # no email sent - self.assertEquals(0, len(mail.outbox)) + self.assertEqual(0, len(mail.outbox)) # email form submitted successfully - self.assertEquals(200, response.status_code) + self.assertEqual(200, response.status_code) # email with valid user forget_url = reverse("users.user_forget") @@ -908,8 +908,8 @@ def test_token(self): response = self.client.post(forget_url, post_data, follow=True) # email form submitted successfully - self.assertEquals(200, response.status_code) - self.assertEquals(1, len(mail.outbox)) + self.assertEqual(200, response.status_code) + self.assertEqual(1, len(mail.outbox)) sent_email = mail.outbox[0] self.assertEqual(len(sent_email.to), 1) self.assertEqual(sent_email.to[0], "user1@user1.com") @@ -930,8 +930,8 @@ def test_token(self): response = self.client.post(forget_url, post_data, follow=True) # email form submitted successfully - self.assertEquals(200, response.status_code) - self.assertEquals(2, len(mail.outbox)) + self.assertEqual(200, response.status_code) + self.assertEqual(2, len(mail.outbox)) sent_email = mail.outbox[1] self.assertEqual(len(sent_email.to), 1) self.assertEqual(sent_email.to[0], "user1@user1.com") @@ -951,7 +951,7 @@ def test_token(self): # email are case insensitive response = self.client.post(forget_url, dict(email="USer1@user1.com"), follow=True) # email form submitted successfully - self.assertEquals(200, response.status_code) + self.assertEqual(200, response.status_code) # now there is a token generated recovery_token = RecoveryToken.objects.get(user=user1) @@ -963,7 +963,7 @@ def test_token(self): response = self.client.post(forget_url, post_data, follow=True) # email form submitted successfully - self.assertEquals(200, response.status_code) + self.assertEqual(200, response.status_code) # now there is a token generated recovery_token = RecoveryToken.objects.get(user=user1) @@ -979,7 +979,7 @@ def test_token(self): recover_url = reverse("users.user_recover", args=[recovery_token.token]) response = self.client.get(recover_url) - self.assertEquals(200, response.status_code) + self.assertEqual(200, response.status_code) self.assertTrue(response.context["form"]) self.assertEqual(response.context["view"].template_name, "smartmin/users/user_recover.html") self.assertTrue("new_password" in response.context["form"].fields) @@ -995,7 +995,7 @@ def test_token(self): recover_url = reverse("users.user_recover", args=[recovery_token.token]) response = self.client.get(recover_url) - self.assertEquals(200, response.status_code) + self.assertEqual(200, response.status_code) self.assertTrue(response.context["form"]) self.assertTrue("new_password" in response.context["form"].fields) self.assertTrue("confirm_new_password" in response.context["form"].fields) @@ -1016,10 +1016,10 @@ def test_token(self): recover_url = reverse("users.user_recover", args=[recovery_token.token]) response = self.client.get(recover_url) - self.assertEquals(302, response.status_code) + self.assertEqual(302, response.status_code) response = self.client.get(recover_url, follow=True) - self.assertEquals(response.request["PATH_INFO"], forget_url) + self.assertEqual(response.request["PATH_INFO"], forget_url) self.assertTrue(response.context["form"]) self.assertFalse("new_password" in response.context["form"].fields) self.assertFalse("confirm_new_password" in response.context["form"].fields) @@ -1035,7 +1035,7 @@ def test_token(self): recover_url = reverse("users.user_recover", args=[recovery_token.token]) response = self.client.get(recover_url) - self.assertEquals(200, response.status_code) + self.assertEqual(200, response.status_code) self.assertTrue(response.context["form"]) self.assertTrue("new_password" in response.context["form"].fields) self.assertTrue("confirm_new_password" in response.context["form"].fields) @@ -1046,7 +1046,7 @@ def test_token(self): response = self.client.post(recover_url, post_data, follow=True) # form submitted successfull - self.assertEquals(200, response.status_code) + self.assertEqual(200, response.status_code) # now the user cannot login with the old password but can login with the new one self.assertFalse(self.client.login(username="user1", password="user1")) @@ -1059,7 +1059,7 @@ def test_token(self): recover_url = reverse("users.user_recover", args=[recovery_token.token]) response = self.client.get(recover_url) - self.assertEquals(302, response.status_code) + self.assertEqual(302, response.status_code) response = self.client.get(recover_url, follow=True) self.assertTrue(response.request["PATH_INFO"], forget_url) @@ -1075,7 +1075,7 @@ def test_token(self): response = self.client.post(recover_url, post_data, follow=True) # form submitted successfull - self.assertEquals(200, response.status_code) + self.assertEqual(200, response.status_code) # password must not change self.assertFalse(self.client.login(username="user1", password="user1_newpasswd_2")) @@ -1104,7 +1104,7 @@ def test_lockout(self): # on the fifth failed login we get redirected response = self.client.post(login_url, post_data) - self.assertEquals(302, response.status_code) + self.assertEqual(302, response.status_code) class UserTestCase(TestCase): @@ -1112,7 +1112,7 @@ def test_reverse(self): # the reverse tag here should be blog.user_list, not auth.user_list, since the # CRUDL objects is defined in the blog app response = self.client.get(reverse("blog.user_list")) - self.assertEquals(200, response.status_code) + self.assertEqual(200, response.status_code) # also make sure the proper template is used (should be /blog/user_list.html) self.assertContains(response, "Custom Pre-Content") @@ -1140,9 +1140,9 @@ def setUp(self): def test_value_from_view(self): context = dict(view=self.read_view, object=self.post) - self.assertEquals(self.post.title, get_value_from_view(context, "title")) - local_created = self.post.created_on.replace(tzinfo=pytz.utc).astimezone(pytz.timezone("Africa/Kigali")) - self.assertEquals(local_created.strftime("%b %d, %Y %H:%M"), get_value_from_view(context, "created_on")) + self.assertEqual(self.post.title, get_value_from_view(context, "title")) + local_created = self.post.created_on.replace(tzinfo=tzone.utc).astimezone(ZoneInfo("Africa/Kigali")) + self.assertEqual(local_created.strftime("%b %d, %Y %H:%M"), get_value_from_view(context, "created_on")) def test_view_as_json(self): self.list_view.object_list = Post.objects.all() @@ -1150,67 +1150,65 @@ def test_view_as_json(self): view_as_json(context) json_data = json.loads(view_as_json(context)) - self.assertEquals(1, len(json_data)) - self.assertEquals(self.post.title, json_data[0]["title"]) + self.assertEqual(1, len(json_data)) + self.assertEqual(self.post.title, json_data[0]["title"]) def test_get(self): test_dict = dict(key="value") - self.assertEquals("value", get(test_dict, "key")) - self.assertEquals("", get(test_dict, "not_there")) + self.assertEqual("value", get(test_dict, "key")) + self.assertEqual("", get(test_dict, "not_there")) def test_map(self): from smartmin.templatetags.smartmin import map kwargs = {"title": self.post.title, "id": self.post.pk} - self.assertEquals("title: {title} id: {id}".format(**kwargs), map("title: %(title)s id: %(id)d", self.post)) + self.assertEqual("title: {title} id: {id}".format(**kwargs), map("title: %(title)s id: %(id)d", self.post)) def test_gmail_time(self): - import pytz - from smartmin.templatetags.smartmin import gmail_time # given the time as now, should display "Hour:Minutes AM|PM" eg. "5:05 pm" now = timezone.now() modified_now = now.replace(hour=17, minute=5) - self.assertEquals("7:05 pm", gmail_time(modified_now)) + self.assertEqual("7:05 pm", gmail_time(modified_now)) # given the time beyond 12 hours ago within the same month, should display "MonthName DayOfMonth" eg. "Jan 2" now = now.replace(day=3, month=3, hour=10) test_date = now.replace(day=2) - self.assertEquals(test_date.strftime("%b") + " 2", gmail_time(test_date, now)) + self.assertEqual(test_date.strftime("%b") + " 2", gmail_time(test_date, now)) # last month should still be pretty test_date = test_date.replace(month=2) - self.assertEquals(test_date.strftime("%b") + " 2", gmail_time(test_date, now)) + self.assertEqual(test_date.strftime("%b") + " 2", gmail_time(test_date, now)) # but a different year is different - jan_2 = datetime(2012, 1, 2, 17, 5, 0, 0).replace(tzinfo=pytz.utc) - self.assertEquals("2/1/12", gmail_time(jan_2, now)) + jan_2 = datetime(2012, 1, 2, 17, 5, 0, 0).replace(tzinfo=tzone.utc) + self.assertEqual("2/1/12", gmail_time(jan_2, now)) def test_user_as_string(self): # plain user have both first and last names self.plain.first_name = "Mr" self.plain.last_name = "Chips" self.plain.save() - self.assertEquals("Mr Chips", user_as_string(self.plain)) + self.assertEqual("Mr Chips", user_as_string(self.plain)) # change this user to have firstname as an empty string self.plain.first_name = "" self.plain.save() - self.assertEquals("Chips", user_as_string(self.plain)) + self.assertEqual("Chips", user_as_string(self.plain)) # change this user to have lastname as an empty string self.plain.last_name = "" self.plain.first_name = "Mr" self.plain.save() - self.assertEquals("Mr", user_as_string(self.plain)) + self.assertEqual("Mr", user_as_string(self.plain)) # change this user to have both first and last being empty strings self.plain.last_name = "" self.plain.first_name = "" self.plain.save() - self.assertEquals("plain", user_as_string(self.plain)) + self.assertEqual("plain", user_as_string(self.plain)) class UserLockoutTestCase(TestCase): @@ -1225,7 +1223,7 @@ def testBadLogin(self): post_data = dict(email="foo", password="blah") response = self.client.post(reverse("users.user_login"), post_data) - self.assertEquals(200, response.status_code) + self.assertEqual(200, response.status_code) self.assertTrue("username" in response.context["form"].errors) def doLockout(self): @@ -1413,11 +1411,11 @@ def test_expiration(self): response = self.client.post(reverse("users.user_newpassword", args=[0]), post_data) # should be redirected to the normal redirect page - self.assertEquals(302, response.status_code) + self.assertEqual(302, response.status_code) self.assertIn(reverse("blog.post_list"), response["location"]) # should now have two password histories - self.assertEquals(2, PasswordHistory.objects.filter(user=self.plain).count()) + self.assertEqual(2, PasswordHistory.objects.filter(user=self.plain).count()) # should be able to log in normally self.client.logout() @@ -1425,7 +1423,7 @@ def test_expiration(self): post_data = dict(username="plain", password=" Password2") response = self.client.post(reverse("users.user_login"), post_data) - self.assertEquals(302, response.status_code) + self.assertEqual(302, response.status_code) self.assertIn(reverse("blog.post_list"), response["location"])