diff -Nru python-hypothesis-3.44.1/appveyor.yml python-hypothesis-3.71.11/appveyor.yml --- python-hypothesis-3.44.1/appveyor.yml 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/appveyor.yml 2018-09-24 10:46:59.000000000 +0000 @@ -3,25 +3,41 @@ # 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 interpreter # See: http://stackoverflow.com/a/13751649/163740 - CMD_IN_ENV: "cmd /E:ON /V:ON /C .\\scripts\\run_with_env.cmd" + CMD_IN_ENV: "cmd /E:ON /V:ON /C ..\\scripts\\run_with_env.cmd" TWINE_USERNAME: DRMacIver TWINE_PASSWORD: secure: TpmpMHwgS4xxcbbzROle2xyb3i+VPP8cT5ZL4dF/UrA= matrix: + - PYTHON: "C:\\Python27" + PYTHON_VERSION: "2.7.14" + PYTHON_ARCH: "32" + - PYTHON: "C:\\Python27-x64" - PYTHON_VERSION: "2.7.13" + PYTHON_VERSION: "2.7.14" PYTHON_ARCH: "64" - - PYTHON: "C:\\Python35-x64" - PYTHON_VERSION: "3.5.3" - PYTHON_ARCH: "64" + - PYTHON: "C:\\Python36" + PYTHON_VERSION: "3.6.5" + PYTHON_ARCH: "32" - PYTHON: "C:\\Python36-x64" - PYTHON_VERSION: "3.6.1" + PYTHON_VERSION: "3.6.5" PYTHON_ARCH: "64" +cache: + - "C:\\Python27" + - "C:\\Python27-x64" + - "C:\\Python36" + - "C:\\Python36-x64" + - "%LOCALAPPDATA%\\pip\\Cache" + +# Appveyor "helpfully" ignores skip directives in the commit message body +# https://www.appveyor.com/docs/how-to/filtering-commits/#commit-message +skip_commits: + message: /^Bump version to \d+\.\d+\.\d+ and update changelog/ + # This matches both branches and tags (no, I don't know why either). # We need a match both for pushes to master, and our release tags which # trigger wheel builds. @@ -53,13 +69,14 @@ # Check that we have the expected version and architecture for Python - "python --version" - "python -c \"import struct; print(struct.calcsize('P') * 8)\"" + - "cd hypothesis-python" - "%CMD_IN_ENV% python -m pip.__main__ install --upgrade setuptools pip wheel twine" - - "%CMD_IN_ENV% python -m pip.__main__ install setuptools -rrequirements/test.txt" + - "%CMD_IN_ENV% python -m pip.__main__ install setuptools -r../requirements/test.txt" - "%CMD_IN_ENV% python -m pip.__main__ install .[all]" - "%CMD_IN_ENV% python setup.py bdist_wheel --dist-dir dist" deploy_script: - - ps: "if ($env:APPVEYOR_REPO_TAG -eq $TRUE) { python -m twine upload dist/* }" + - ps: 'if (($env:APPVEYOR_REPO_TAG -eq $TRUE) -and ($env:PYTHON_ARCH -eq "32")) { python -m twine upload dist/* }' build: false # Not a C# project, build stuff at the test step instead. diff -Nru python-hypothesis-3.44.1/benchmark-data/arrays10-valid=always-interesting=always python-hypothesis-3.71.11/benchmark-data/arrays10-valid=always-interesting=always --- python-hypothesis-3.44.1/benchmark-data/arrays10-valid=always-interesting=always 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/arrays10-valid=always-interesting=always 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for arrays10 [arrays(dtype='int8', shape=10)], with the validity -# condition "always" and the interestingness condition "always". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 402 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 6.00 bytes, standard deviation: 0.00 bytes -# -# Additional interesting statistics: -# -# * Ranging from 6 [1000 times] to 6 [1000 times] bytes. -# * Median size: 6 -# * 99% of examples had at least 6 bytes -# * 99% of examples had at most 6 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 96: STARTPCOKWVRKZ2WEULKWWJJIQNWTKEMELI3ICSG2EUJURJDNCKA2IWRWQFANNIKKXI5AKSOJVGQCNTAZWGAY2UBAAR2KANAA====END diff -Nru python-hypothesis-3.44.1/benchmark-data/arrays10-valid=always-interesting=array_average python-hypothesis-3.71.11/benchmark-data/arrays10-valid=always-interesting=array_average --- python-hypothesis-3.44.1/benchmark-data/arrays10-valid=always-interesting=array_average 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/arrays10-valid=always-interesting=array_average 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for arrays10 [arrays(dtype='int8', shape=10)], with the validity -# condition "always" and the interestingness condition "array_average". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 416 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 718.32 bytes, standard deviation: 529.53 bytes -# -# Additional interesting statistics: -# -# * Ranging from 6 [6 times] to 3226 [once] bytes. -# * Median size: 824 -# * 99% of examples had at least 42 bytes -# * 99% of examples had at most 1723 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 3240: STARTPCOELGB3SISDODCEV7JDC5Q3AT75ZKZI4RUQZWPDNFR66LXGJOZNVGEK5ZUX5ACEEIA5J35PT57776767H5PL6RLKZ537IXGX2PTTV75JRC47PQ7FPG72KPG2CZ6YZ4O7R7NKGPPK7XUWS7XV2XP2KPWWMCQWWNDX5K5THPUZP7B5BNLKLKUCWO3OPRLWPXZBJ6ZUPG37ZX5K4TNR5OPPM7IRYUFHFQW7W36SUNQRNK3E66JXBKTCLXW67E4PNX5TBWMY3L7Z5U56UJSC5K5N42TMDMF4WSSMOURNJEULG3J6ZO2RN6ZNTE5HK4RM7WWKVIXYQB2KYEMDXD5WKLAH4OA7JUZ65MLF2IWK4TWRZ6WIB5WGT2WHDBBVAEVABRL2BMPUT3AOQJGQBNEIKLW5K43UCNBOSQ3DAK5G5MU6EORZRHGZTTAAMSOVYMBMWR4S3GRA7X36TJLFQGW4GBD24BWI2OO6WMQ62SJGAQIKPNT6ZIZTL2STOXP335ZP36AFMM3AFFCVDALYFAS7AA6ATO6AHLMEVFYIPWEGXQAKTUXA3K7WQEALGBVYOXPQDRAYXC4U77XH5LMCRGFEIH53C3VEUITCWAZSATTUYECITLENELNEUY3FGP3R3QIFTIOWBOG5ISSGU4DUILFTAZY54KJPSIITBECJTVUISO3IQCIO4YNDWBESCQ676WPGJAHDYN6UJULGENRGK4ESRL7RUYXGHZ7TYZSVPFK4JIALMNJA3G5ZTDOOFNW3N2EQUDDN5QIDWKW6O6E4V2QJLU5E2FOXBDYMKOCMLQND2KAXHG5MNQZCNB6TW5EFDIBJT6IOM6N7B3KSM7FMM5MOOU3YJVQKKGILG2VGJLJNISZDPISZD2GIUDQFCKAEQ6WBBRYQLVBKKYH5RF34RTGO2CJD5GRWHMWUCPTVKIUHVEUDVHBXGKNSI526KWRIJYFVZ6GD2DTAKE5IWHUZRB6WMN2M4R4FSHGC3KSBLFIUOMO2ANP7BODS2BPU4NYLGPURB3NJJKXUZCJZSCNBHNQ6EEG2XNFHSALLKEXTEQGNDYQY4VKAMJKRNHFMF3BXFIBBRABPGPSYSTQEHIDSUEIKHCLZ5DIIBJBTSMNPXRBAJTOH4KG2QIFZ6RJGTBYRLZKAPZ2VLACBMQJ4YTE4KX2BF5ZITSSTBWGJ4NGVR6NG4ADESGQERTCI5HATX5DF2MK7LZCZYTZQVKJIFMZXDJYFN5EWODLN6RXJOEWDRLULTCEAXRPXAXSJNICQFVELNKQ4U6VXCTSJK3NH6EZ3AIFMY5DWEKKJRO25B634VAK6EL6QFK3ZKAIZCIJZFBHDUZJSGMKW6VWNEKNURARLE3TSFFDLF2KAVPB52YDBKFQMOC3SCW33BXIRIJRTQIIRGCSBTLIUCQCVRPVYLTFCIB6CWRZX43MUXHFBVNXV6RAPIUW3K5JVEELEXCEFKI7TOE3RLVGAQ6EK2KYMC3IN6YOS7AE7FQOKPJX2QTVP3RODEKZ6F5RQNJCLMQMOQBLLT455J2TODLWDTTCQGWLO3DSO6VU6VOIXIQSWQFKOBKW4WNL3PQ25GIWCZLBFOKICMLLYDLSBZCRBMVNT5FOTZWHXWMFHZOUGKKYJZUK4M6BZ54UVXW4XBIHCCR3KS6GNWFSRK6QCQHM7MXQKRC3OAOAKGH7BZOZD5GK372J3PYJJDDU4I24VKHIIV36OSXC3YBHEDKYJNTGPZFCHU24YZQMARYMAGR76EOIB532UQPTTTSOF4MUQB2LWZHRVI4CQMZKAJMCQQ725HSKRKWFK3GHGXK2HY26HN62IKMPV3HKA46RR2GMZUQKXJYZH6FYVRMODTJDRBKVZEKR7JONN3PYRYF4K7TASJRERNJ3NS3V7N7NRWR5LTRP255LEWKWXOQ2EQ6VAHUPIGGE2DVEMBPDTDQXU2ZIITO2TQTU7LDHMOQG7FDLXMIYAB6AQZOSVU62SSSHIXC5JRPFWRA7RT5KRLWHULBA4OOP5OQKEIUE3CWWJ7Z7A5AX3CFUGYEZHR33QMVTRV5UKH3C2HVDLSCBRTJ3JPDPUGCBJYMJIZICTZUZKSVYAUAJEQHONJ6XXIE6KXD22QIHKSQ6JXNETTXJN3VBS6JYAVJFNBLVQAQPURY33FHNS5AXR77FSELFUENWOZVBP2AZ5ZIJPYQX6SI4E723ZTQPKSP5CA2IROVGL5MMYOB5JJCZDTDVUKWGJYHA5BVKANSV7VCJFWROE25F3QPENZFUGXMYFOGWZGA2SYLDQYNTV65QJ4T2OU2FTKPTSZCZSXJI2LJNYADCETQDXDDIC7ZI73AEOGK3J6L6MZTGP6TALWP7QYIQ44NHNJGB3XHORFLQRXLHEWLZE6NKC3OZBGY5O6HZOHXIP6B2S2S6FFD5HAGO3ONE2U6AMKXZZJS5OD7BU6DK7OIYK6T2RTWXOPTMBRH4RRLVQZTGRZBTNMCZDEDJD4PZEC3LXJTFQCJ4CYKVOQSZ5RVEJN5GV7VQ5JYDX2QJUZ5IOWB6CPQ2J5EFP5IZVMN3I5UE37YCKVYWUUZISE55SVVS6QK3RRAGJCB3ANCYC67J4YUWOZWIDAD65E7UGTVIHSMLJCNJ5TDS5Y4D23EACQ25OGJEM226DUGN4NMC5VY6SRGMAMEWYDFB2KBUYZ54NM75ZQRT5CJZCMZZOWYZASGMCM45W4P725A2D3NLUY63YCD4DB7XDLXOHYUMJMH4F6SOOVNIGHSJRP6N4QNGY3WQ73Y3QX3W2QRIFTFDLQR6NZ5HPZNPHDTLULM6UEFOSDWXCVAPUYGK6KEOQNQROY5P52P64YBGZR3YNVB6GUQYRTHBYDAJ7TZACRSL5YUKTAEC6LXZVI3WASDBLFZ7JOLTWPYOT2KFOJC4HU2PLZ6DLUC5TA3HON76YVYG3GWSIJ4GU55ALGU4OM3NE5ADOYS6A5EV3WKUKXVVJ4TPEGVB22DQ7VXQI2XWLIFEOUKNIJL62TU5CQAI44R2TRLVM3MIDTLG3HGXWEI6XJL554K2M3KXYXQRMTTGAGR3DJO5OMG5THO7H5VHV4E5O3HB4GJEL6ZQFZA6N2LDWG75ZUNKXFT7P2ACZRF7URANQBIJFT7G6LGBWEYFWW43MQNHUBENBBNYA3L5XJWD27Z5FR65TZUXGGRWPDWRDH2K67GERDB3Q2JI42KY3L3IR4HX7P27L4757XH5OL4R47H77HVLZCNA====END diff -Nru python-hypothesis-3.44.1/benchmark-data/arrays10-valid=always-interesting=lower_bound python-hypothesis-3.71.11/benchmark-data/arrays10-valid=always-interesting=lower_bound --- python-hypothesis-3.44.1/benchmark-data/arrays10-valid=always-interesting=lower_bound 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/arrays10-valid=always-interesting=lower_bound 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for arrays10 [arrays(dtype='int8', shape=10)], with the validity -# condition "always" and the interestingness condition "lower_bound". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 404 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 269.65 bytes, standard deviation: 101.83 bytes -# -# Additional interesting statistics: -# -# * Ranging from 29 [3 times] to 727 [once] bytes. -# * Median size: 267 -# * 99% of examples had at least 47 bytes -# * 99% of examples had at most 551 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 2848: STARTPCOFLGBZWISDODCEV7ZGH3DPCQEXBU2VCTZDJBXM6GSNBXKV7EALAQ2OI4WSYECLEIJ6Y7367T5OX347X57PZ5XVPM57X65L5XT7XKZP777PFNW6VN454Z5H5PTX2YNOM76NRUFNPZ5NH3P3NV76M6635S65V34PH7XWONTVHP25N5LWXTH5YTO7NIRXHPOVZ6Z7IBPW32V4GMXNQML55NKWS3WP22TPVUNHVKLFLXLJ5V2PSPNZGC6ZD3X5LYDF24DFWNUW7TBOXJ3WGZ45HZKX35DVP34GO2LCE7QD6P4ZUOSTZ4K36WLNRVGSLIJ7XP3D63BBQ52WLDYS2OKVJF7B5VFK6TBJORXXVCZLJVXY62OHKVYQ5LF4F74GADD5UAWR4OOQWYOOXGIJHUNEUX6E3HXTMKUM5HJU4EPWZIVSOADLLKT4F2GWRSSJFN7XJLC7N7KJVRLEZQWWBK43LSXCVEKPEXQYAI2PMPAVT5GPIJP3Q5FHXBTL627HA625TVFJLIVFX2CDWCKX3O44WU3BVNHW2OHUXWZNOQAP3YFQRVT3S2FG3QDLW6WLZG3KUMKU2VMOB5EDZEFINANFQXHVCIH7WHSV5LS6KBBJYRRX3O4E3G7CRK4WFAPS56DAXVV67JVQI5F5OTIFRK2PTLVVFIV44BT64WHSXPLEVSUTPZCYUSMFFM6XFGKNCQSNLPMNG46XXZNCM6YADR4322YFQ2KCWI6CIPVLLDAID55PMZETTL5KB3OKOCTT6TZBTVWBA2RUEPAJXVPER2D6A2H6V7Z6QCCFBXXPWTDII5OPFJBJ5NR2VVQYDEKSNTONRZVJIOJT7PLOJJJ2UOIZDPVLFPLKSOS4ECMEYRQN5DCWDRJUZ7EMAOT5USVEOOEAWBBRVJ5YKLH4AFAVQLS3VCZ7UPKUOESJL5CX7MKR4CE53ZAVFCKPPPPRIV22QQ5MQ6CFNEZVLLFVRZ6JHCGRV24FH53DXZKJHIMQ4XHEQGW6UMWYPKOGJXGAHOKBLOAQ7LCBMAUUT7FS4PIZX4CUKPXJM62DM2AFKFSF4URQYK4G5SPNX244AHTQKXYHBDCDCIR7XSYFLZFEUOERY3PBHUEUWQIVRVEL5CNJQI53RIC7BF2EEQVL3KVBAPSKCLS3DHJNN2EUPK7ECV5UQCZDWEBGSKRXNJ4DCRBQ7EWDPXSYXAGJX7RA7TRZS43ICMDEVBWQLXBRLILJWSQOHV32ALKLRX4J63G6MADORHDQ5DSSRQSOHDMLG4T7B7DWMNI6TSBU3XLCRY7LMXWPT5I7UEY2P7XPOXJWGP6RAIUERZZ24GR2BUM3XLUCMMX7MDSWQM64Q7MU73SDHSEAYSHBQPDGRUGLD573QOPLMXW5J53OJJYNKLWCKNOIUZQBHBJZ2UYVFMJWFZ5WXGMD77K2XBPBB7INSLQHA2443XARU3L3E5LSHIYMMGLEEREPFURQ7BBZSEIEUYQJYA57AR3S5DZRLLWUW75RVM3LILB5BKQJEBDPGJWKR5CIRHBIF4IDMDIJRPFUEDKBVKLA4ULJENYKQOTWIMHIS2VK6IW6N2ZRI72VJJBIWDVV47C2K2QECZPSAYIE62UZSCPBYM7QIOQGXVK5SAVSDVJPFC6AR7VNE4W2UN4XKVNQCVCSNUYQFHIAQVVQZRFVIJG6LKKTN5AIDTAIQIYLDHPRUAS2UWFCIQU2RQITDVNMJRHIYO3YZLCHL3UI3KFA4YRRRHKWECZNSZSSTFAH72X46GEYE5N2SKOACYANVWOANCQDHC4NL3TMSKPVYAPGCMOCPJGSRI2SCVVLD2I5OWOBBZ6ALY7EMVT2JZSDCQ4RYL2SCBOL5J5IYREWQNCJIXLT3HHPDEFNCBMJJLNJSFDMZAJ5LWSRNY2O66VRJSR72PYX4SVBH2RKQXPMSNTYRTLOHOQSJJGENMDKJHUAF3CNE3WFT3XRU32PZVALEFHITZSZQQVACOZIISZQQ5I2KVK5X5V4RWJVOHAXPULQVMDHNRB6HDQCT7XAVMLJUNALQW6T4C5O5RK3SFWYHP44FQBXWKCXNKGXQIJ22GGL2ZSZYUMSA73KBC3INLFAMKPOEKCJRRCIIVGPOTZGVKIXOK66R2CAU3C6DIM2BDXT2ZE7NAKFIM4EICW3VO4WTPBYQJ4QUOAVXNDY43ERSETIH3EDQGP4V656IMA3PMYYWFCYG47FEXGXA3D7F2GHVJUWVICDYW7OAMKKYIKFIUZ4GS3JUFDKB3NC7MLBYUTCDSTQR4QRBEAFAKONSE727OM6MMDQGDBMWXX3CGR5NRGJGFZYHDGNI6JOUWU3EHHGWCCKAOAMFSAC4JCIBBYPE7UH6IDBVA3YRIASJF3Y6LKESLWYOROJ4DWNMAVHYMSZYLH7Y5G5ZEASAIBV57A2PDE5DKABT7SDN6EY76OV5YGEVEOQ4BOWQRWUBS6CEC6QFEKWDWC5GWHYMAN7M5QUBSZ2GUFTWMT2YRQWRZ4KOBYX6OWTRLOPVPGNOH4Y7IIWETDHCIUH4UPIPQKWSXR5T5XCAKMC2ZXESJEON3B4TRVIB4JURZSMGAQR462GEBR4K2KUPK57GCND5Y5MMTZZ4CYF3DIAJBR42KUMUMCPQ52DYONIGCUGN24OAQEN3IB35LVNOX75FRSAUTUOH4BTQU5MCSBC5VIZESA6JRGRM2SV7AG34KXZVHKZHMSQL43W2A6AL7AYK22TKIYAE66HMRJZJZ4CKWEBNKFEBK4BDDRYOMBLKYAKXXUOP5IWIMSOIM55GH2CDRZVFAIDVS2PBCMATHHNQ4H76H67LY6XZ6PX77XYJVCPZ337IP3YCCA=END diff -Nru python-hypothesis-3.44.1/benchmark-data/arrays10-valid=always-interesting=never python-hypothesis-3.71.11/benchmark-data/arrays10-valid=always-interesting=never --- python-hypothesis-3.44.1/benchmark-data/arrays10-valid=always-interesting=never 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/arrays10-valid=always-interesting=never 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for arrays10 [arrays(dtype='int8', shape=10)], with the validity -# condition "always" and the interestingness condition "never". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 401 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 1195.67 bytes, standard deviation: 221.57 bytes -# -# Additional interesting statistics: -# -# * Ranging from 694 [once] to 2424 [once] bytes. -# * Median size: 1178 -# * 99% of examples had at least 786 bytes -# * 99% of examples had at most 1936 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 3288: STARTPCOF3GBZVYSDSESEV7ZFC4QJ3SL34SVDWUXGDZGSMYYHP37U64MIZD2WAKE4QIHJRO43SOP767R7O7767PV7PDZ7X37MZKPXT5PTTD6PONXX5FQZZ4KM6NCKHTLYQN5L7X6FU3L5XZV7DX3IHHPON5DZSZLOGO667PGJWNJZ23L7K6POXLR6O3XRRRW7PCEVFHC6XUXDOWX7YOJ77OXLKYVZI7GPRHJGP6TNRNVFQZMRZV7D5BLEPWEFCUR6YHE7NXLWM34W2SDD3PHZ5TBMFBKBV4L2TOBB362BMNSHIB5OHNA5P6LNY6OGTPLNHM3U4FZSTMKXVIZUZQP6TJM47NRJP23YZCJTK33NIOIUAMFIP5XSDC6MHAJ5GC5MMXV5CBFNFEQ3L6XVQWNQ2FCLKQMMR3NQ3EZYXPQGVZV5C3SEYYRWWGFTOZLA6ETNMJ4Q57HAKT3KMH7QRUFOV5UUFKEMZIQ62RRYDOZAEQWC3BO5Q4L7H3OF2I6NI4CXD4K5FNCG7XZFTCKXQGV4KI4LTR66RM2TLRP3D2EFXM4DB5ZRLC2WFVHVFZZMTTLG7WHSEAACONM7P4T3CS3YLPAFOZP5A6CHCBHZJFETH6TDYYPBYN7XBV4ON56ZLUIEO3JN6O56VTK6LLQ4ASE4IGQM5WN6EGSLSG2A6LM3K2N6RZ2OAHVBULMDEQFP4H5Y4IW2TPK2KRTQY3GQ2JPY3GNGYFKBHUXCIFTZNW4F5OQGAFMSAJAICNICTZCOATKIS4KE2NZM3W7AME5DLVV2QHODOYSNOYIU6UISTMCBPUCXRFMKOVGTSKGKEMHVERQLERBSZDHQAJDPJQRBC5NRBNCV5TFNMCE6PNXIRK4CGVXRUKPYVORFLUNLQL5S2Z4CGQ3IWOST5ZJ6BLGQIS2M6NS3SNXLDO6SBBMS4KUH2PUP27G3JNDWBMTUDCWWMKEQY33IMMTPCS2BMYBVNH2EP4LO2WYXU7ECGYQD63GVCBQFNQK2HENN6HYTFBVAFWA7UTIVK4UKCFMBRKLZC4YTGFYDF453RI3VBGHEEBJFXLGJIHOEDCG5IZBDW7KC72GEZYDV3PZWCAHJRGZNQRSHRDDBPK43AFNQNO2S7K5FFJ7FQNN6LTOSQ3FPC24DUGGIXPOJORZHXPSAG4BY2UFXCZTJQHRKUJSXWHUVMWQVF66SM2NPUGFUNF2IDP25UAEAJCVADB2VEWGYPC2XEY6XRUQOLWCAOQTRDBL5EC343C443IJUC2WGM2NKMWIDD6KEQLUWZ2N5GRSOTN2UNKBI2GSF33NNUUWB4OYZ25KYWH4IW6ANYJGK3XTILUJZXEMSAXASWWWY2CRUYNTBDXVIXU6SB7DMDH6KTKPJDPGZY7UYUKRRAKS2I7N62VSEIJTWQ4DKIBPRMW5X3F7BESXKB4JQKVL6CM3RMWIJZZOZMKXETSCDQDQTBDBLY3IU2S2X3HYOCHVTNQSGFIBHKQOEU6NA35SAJJQMJVHVN5IFFIMFNWQKOSR3XSAJ5VBA3EULFNNN3BWJF5QZAHO5C4RMIGNXQV2NVBUY46BDZZJWVR6N7JJLRNESJSHIZMT4SJPHW7HMAO7Z4BTOBGYHFZDXO6NXSCQHOYR5QVCMGYJ2ENFQWOAUKT5WFOBQKCUG4ESBN7IFZXY7VMBGOWTAPZDVQQOVGWLZUIDIAQBTRXHJVF4HVWA2MJRZCLXQVWXDV2NYGAW4HD6VWJPWBLFLKJIR2CDKDMG545HYQLV6KDTFUHNEEFGVZRG5MZCAEISL2E27GBLBGURLCCG7SRMNSRUBN4N2XOTZUWCTKQJMM4JV2CXNFEFWSWIVGLZVG2JHGHVN6ZCJNAVGKVH4AYVISGEZXOQQYNC74NKTJ2XKGTFVHHV63F7ARAXKKW7JWY4GJUV5QZBJGRW4OCVQ4CEHL2T73RUNOVE6H5HUREXFWHZAK4ACIARRZXMHK54BMOKNEWWQFPEUJG6RW2MPVDVGXZQRSWJZAANUIXHHDTRZFW3J6SSVYMI6WYOHORLKE4XNABGYUU4RI2PCNFDM6NENTGSR3VZFVPIS6WJX6S3E3URKQIFXIEE34PRKQ63H4BOPSG7GOHTE34KALNKPUHXIWANJXOLPZBD6SFKGK6CSVSJBCJ5MERU6R2X266UGCXJ5NUDGXZR4ESYWBVYNRUMQVH4ABJXJPNGQWUV2VQV2KNNJHJQJVEWNKE773GN3I6F7ARZSFNTNZFFEPMHSBZXVWI2VVV2KLTXH2WTHPJRUYJH2F6XYGZLSIR26HMNP2NPHM43IN7THVTM7WRKMHVVGPX7M3EP34VMNAOORUWNZQCT43ITWIQRFVDEKLP2WN3ORSAHVRJ7UPNT34T4EHF2BRADX7ILHJQYEVQ57SLQFJN54LO4CUHSX3SZHUKZ3VYUHNTAST5QMZTWVTVPD5UAUEAMWVGHICRJKTX3V6WFABCXC4NYBCJ2N3FE4LFVKHGDWTJYGTJ634PCNKGMAEEATL5SRJTUZ2HIFXUWRUBAKWVNLS73Q2QPM6BKB6VR2OFD4VTIVK5T7V4Z5JL7KLSHM7FVSNIT5NLGYMTI4IGMQ5EBQPFHVAXUGCDGMHYLTRFURKOWQ4AQ77IMPJPXIIDU3LY2MOEO6TU47DMLAN46TN2SCVLY4SLCH6JQQMQHVWSNOIPVFAV65G33JJGOXIBBEKPFOPXGVBMAN33KCVBMUTONDZX4OLPHFLBBOKE7PHANVZKVEZ6CN3C5NLPCB6BE3DNNAALJWMZTEKOTCTKH2MO7IC2QP5KLSGQSST2GWWVCL362O4HBX4HGVCESFCKTCRR4SR3JUAHHMXRT6EBHYI2Z5KUX5D2YBYW45NER6C4ZJVC762MPTVWOOOZWIQGEPPXQZFB3MTIKIFBLVCLU3EWJUNEZ7CCKGVHL4NP3CZFHT5RPV2OBRFW3FOVY6XVUY3J7UTCXHK6ZCMX4M4FSHL25SHARVV6H3ID7TSYR4ZZ2GYZ5Y35TKFY5ILZFKRI2STZM3ZZX554E5P74W2GM7HMCMPYFQM2JIP2IO35XCISZJC4XET7A2CUNY3NZZMXOXQNBPD4SXJ5TUZRLNLDPR42XSSJNSTFRWPUPMBWJWSSCPDOIPUZLRNLDQXISU5IGVY53IMQTXW6HANEVWC5FDPMIQLTF4QBYVYUFQTUFSVBGPPYSSHOBPRYX44X3H4KAZHXV3S5ZAMBYVTJR3NAWWTO5PJMDS52XUZW2SESPJP5GXZ6XR7P377X5PXRY7L4W6L777AO2DEMFKEND diff -Nru python-hypothesis-3.44.1/benchmark-data/arrays10-valid=always-interesting=size_lower_bound python-hypothesis-3.71.11/benchmark-data/arrays10-valid=always-interesting=size_lower_bound --- python-hypothesis-3.44.1/benchmark-data/arrays10-valid=always-interesting=size_lower_bound 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/arrays10-valid=always-interesting=size_lower_bound 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for arrays10 [arrays(dtype='int8', shape=10)], with the validity -# condition "always" and the interestingness condition "size_lower_bound". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 405 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 17180.64 bytes, standard deviation: 19739.17 bytes -# -# Additional interesting statistics: -# -# * Ranging from 6 [56 times] to 128851 [once] bytes. -# * Median size: 9886 -# * 99% of examples had at least 6 bytes -# * 99% of examples had at most 84297 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 4328: STARTPCOE3GJRSIS3SDKEV4ZDD5Q2AQEYFZC6IUQU626ILZHQVXK5TEHTKKZZ3U676V4RECIMQTDQ7367HT3773VY6P37737OG3YRW7TG6P7WDG7726H6FP33RP75TB5Y5UR7Y3LM6WBX6TGYYUNJL42Z47W5CND67DK4J6P6KCR5PBBX73356TZ6ICH5TVNS7LSZVHSSGXVEC54OG6ELVTZOFN4W72QY75FL6JW32FJVXVP65UF7OLLNI473QZ3X6DWYNOKVPHX37GCRL6J2GJ73HLZDXLV6UIZ5XKPKHCR5FMOMV4OHWHB37NSC4EMR35TJ7ORWPPOMKZ4LL7FTJ5YRZ36O4UEH32WQGLN36FUHB673XRSYPL3HSBPPLL27IXO66F5APJPA6CWKGWR676N4HIMPDPHPVVDT24XUOXIXEP2IMF27TTR6IOVMSM5HR4OXLVTXXXZ4Z3P7NKOWDYFGW2TF45V7P6JP46P67LLUGL4KTWBOL7DDTVHZOGWOO45OZEVNVZZZ5WXZEB6K3E4I44S5P673JPTL3OI6LSGSK5X7535UZ3B7K3RZ7GSYHOFKWGKD3H7LBXCR3QUPWO2445LWJZ5M66IWEGXXF4VUVGFSE4AOUB4JZI3BXA6WO75NOCQW4AVGOSMOWGFOFMHPXDJTQ3ATJSSH4SVVAGM4ORTS4FFTP7OUDOSL2AYA5IYABWCUQFZWKR76P6HN5PWC5Q3PZ42NMYW65W6I6RNXMTBXXJ4BHL3XK7PLXFLMSELKAKKDQHMCRMW6I6XX4XLBHFQXCDZ3C23PNLQYMW33SEY76VDDHFH2ZKSPKJDTWRJFMI5WQNJHUGDTO72FKZ2SMJ5STPF4SML2UYF2757XV6KZ3V5Y5QKKVLKL57IG5BKLTHBART6U2X5OU7I74U7O6H6T2W5F5SE3VI2556J72JEFOKMOWF2NKPRE26VQXC43CVHYMXY3WNUMQ2MQ2US4MU45EJR4FFHQJQR7X6LZ2XJ4LCLQJOAWK5K6SGKTEDZN56PGGBGUCDDOOJGLEMNKV5PRBFUTMGYM4CMQVRC7SLT3VRDUG5KHLDMQHPU35MY5QSIGDASYODEL3P62L3E7KWTLQGS7WEMPK32XT5VEJ3BQZJCWOIK44BV56MJIZXXCYPV7R2RYPVVMZ2JENBZZOUDN4XG3K4ATSNRVJ6MPLHEPXCAPNDIXXIG5NFKAVK7LAONPVKUILLHUHPR2L2JB4J2O7U7ZVTIT52D2A2U7MYXPOQE2SYCZVWP4KMPUCFJMXQQIBWN5G6HDXTMV6ZTSE3MHNCYL4QDRRQDCO6QLL42BEW6CEDBWAPP3LCNKBTJNAIMDBPYBFAHE3CQJJHIXAMI4K5TPUAOB3PIJN4DY46YV3J3FZDVQIZW7TJG5OYQHTL6BZITO3GFPJGJTWLN4ECPB3ATPECEEZ7VNTEE24AQAY2PRQAPVRLBVNHCBGLXNXSX6DCAWBCQYMUEJDCW2I33O2CF6RGNOALW5VCGEISJHU5NUOHOQWFODBEDWTENSHVZIC2WW3WSN4TZPZPXZ3COQG6WTRNXTGHG2G2VTLGD6MWAAGHO2NIRB27XON3X4YC522LEQRLH6GUHKYEHYIETPWDNATQYMMVIDWZJX3QDVW4PFGGWSA6IDHSGYK7AJSGTZSCNCXOTASTQ3U4CXETHXNZXMQTZM6NEKSW7CDJKMWIK4OQS7NQZFTRCGJESGPI2L37ZGCUDRV2RGCL63WJ2KOB3GKTUAUEIQ3ERJ4H54WZUIGKR7KPHBH3NL4SK5BQ7NAL2YCWPWFA7BHK7F72PB3VYHI4Q3OPNU7UL3VMNFYLWPNFEQAWJSEVPRMRETWTLD3N2NTGJXTQ7UXQG3Y6LJE5VAPRNOY4JEVNNXLDGWFWM4CTXE6DX3G2SOYKU6AV2E4NHXFHCDV3RJ2UG4AIAFHCVYDQXZSQHRSH45VBWTRGNO3JHULOIH2Q7JRDCYWSWKROAJIN24M4NCRIBC3UUAKGSPDXTRIWCPO2T7GBEMZBNI5WYJMQXTKFV6CJ2ES63CGBYOSPZ7RXGYTYFT2REFOFDPVUY4LL2O6C4OPW5ZGQP5HWWRETXZRZ3I2RKJDSO5HXGO3BG2LQ7MG2JHW4WS5NVESYW77PKSQZ4P62M3GWYAWUYWI2YYEAVMIAVB5X47VHIY6D3YGCXKILLJ3YVXKHJUY3G7HRUB6QDYOPJEUIDMZNWCKGXCVQ7JIJHLOPXZIHYJDMMEGHOOD4SZIXBNCMJ4QBD4UZLREIOAZP57GMQR574OXDCJSEFC7LUFTQBTSC7SGSMS3VEOTDVPPC2RNEETEUXT5MRUZA6EYMCLJ4HHWLMQMTTCKKCLTDICEWWPI3U3Q6GT6VLD2FTNTXDXCHSEUHEYLDB4SFAU4MVRLCKQUEYY5L2ZMPBTTS5NFWYRVWD2WR76CTRGFQU4RYKPZNSC42BZMP54CUHRLFOFNRVEGK5CIFHVE2E75LFX3JQ3I5JBGU2LRKBPHO5DV2NGLGLQTY3YOMYRJWIYVOIZSYDMIAKQHX5VAEW5DZ5O55CRQACCH7W2ZVTGUAELF2MQ6ISGMDSHQNGVR5QR6ZM4JIFSGI5DCDG2PRAB2TB2ZLU4IDPWJEYMGBLGMS7YZXMWKDLIYB53PPC5N6LFEJO2P4CTNEBLKO4BQ33YANJR2QNS24OWKIYXVIUBEPZYGVBLBYC475RFUOR4CNQKP7PGSO3H542MOAUDWN4CG77VLJAX2YXYH3O3RH22XXLOU6NRPUNGLGLRLOWJSOIWOZR4HBLW2UCV6LVGAPL75YLSNWG67AM6A7LBSP44CPPGNAUR2D4XW5NWPO2QHXWMH64OXDEBNU73XGPXZ3LE3F2XL3WTGX2CTLU2YYDDCRNWX7BSXL4CM3G4HAC233OEEYZHBSVIXTHZW7TZX44GQOMYNKEPDRXNDOAI7RA6MSE7KO5YCPI6VIA4VDIGCMUZGSTXQHSTAGSCMY53U6BK65QQZLBB5C3GTXU6RKMMZMAZZKSYV6OQ7OD6FB5H37JPXBG4YN2YJEF2UWUW2GLBOTHTOYXMPJEPKIWYME4QX4DBHA3EHANO3LVMGMVDM4ULBJIPIK5O6SQWCLBKB6AKTQ7LGOCO57L2DCYZUBCMH5NMSAUTBNQUBVFXTXC62KPTEMFESM22NK3ZNM252B3BXSIR2E6FEFHHOBWEPCSURINZGIEY5LVMGUT4DR6DTBLGZDRFNROJHJOHT5FICU7P3PUMHJJEE3EOPDIMGJHTQ3GDL7IW3RZ6QZ4CCNJJ3MZZLQP3NIXBJV6DJVFZBUNXGRK4I3JARXETLKN5WFEATM67DTWG6YTGGD23NAKPUDELSPMMFOGQPB7J4UA3PCY4F2U6Z3ITH5DU3DLZEHHNMQGTDNMQDF6TEJJGNZIKXGDKVYDFTKARXFLXUOIAAPSKCWWB3BCI5E33R44XVEKLU7X4LCBVH4UKBS6VFJ7NVS2I44LWLQMQBIZ66IYOWEK3GWT3Y3KRJXTZO67F5F7FOI3I3ZQDTLS6LRGOD2TMBCLD3R4AIKGMZSFXDA3UXCINRAEG6LBOIZ5XI6CJBVE4JQYASRX272V66JB6SMYXSULOWB5CA4JBOZHT7BL6VBIBRT4BW7DCGFTOA6WKSBK6DMDR6ABEX3B2JQ54E2USCJQ3KGM3PV3OMH2GKEREE7PTEOZTETWVQ5ZWZFVA65XBGQIWUMKKOMP5QUYXBXNSHBXJDX2WJKVQEGV4CIYDUFRSEX64Z6WPMFUNI2GWG7IPHJXL7VVXO2Z3HTN5ZJRUBKWODPOMJZKMBIZUM2DSEHQPSGCMZXWJVHV72AJL4PXSQ562LUQZ2URMZEBTP4YQHKMVMNCJMF264HBEL3Z5XKMAWKLOENXGZ3AJKYUVKCR2XYETNWWU7MY645BHNRRZBUUBWTV3YTBZVPSZY5RK7CYJWQPTQMUUELQY4MGWFKZNX3F6YVTBRQXHDHTLH3NDUF3UQYV4BOTIUBWCGJGH7L44CQD3SMKULQ353X23RPA2NC34AQXP5JK2ZQ5D5EJG64G6NGF7T2LWL5XPIGNEBZYE55QFDWJXGMJGA5LODYAYJYZ7ZPD5I44K3FZSGCALO7PJ5I4UAUZQQL3JD6WIS34OQCPP4KCKT3EYBTPF3ZMEMEQJ6OMZJQ2HUH5KO26ZLJACP24YYZWM42FXSR66CN53HP7LQW3AKSIQ3QW23A4VSL3UQ6UDV3Q6FQ2GPF6DZTNNTMGKKL2UPJ4HZFAGPWCGMJQGKUGVO7775XD46P777DRR6P37677QD7HHX7XDNAY7END diff -Nru python-hypothesis-3.44.1/benchmark-data/arrays10-valid=always-interesting=usually python-hypothesis-3.71.11/benchmark-data/arrays10-valid=always-interesting=usually --- python-hypothesis-3.44.1/benchmark-data/arrays10-valid=always-interesting=usually 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/arrays10-valid=always-interesting=usually 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for arrays10 [arrays(dtype='int8', shape=10)], with the validity -# condition "always" and the interestingness condition "usually". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 403 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 12.25 bytes, standard deviation: 23.06 bytes -# -# Additional interesting statistics: -# -# * Ranging from 6 [905 times] to 183 [once] bytes. -# * Median size: 6 -# * 99% of examples had at least 6 bytes -# * 99% of examples had at most 123 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 560: STARTPCONKV6LN3BSAEH4CXF6OHDWMGE2DP2S6VLB66XWVVI77PNAXAEWNAIFHOEVI2NEJCAPPROM3C4YZS6X666IY36D7P4TJFFAGG3UU7SVMV3TE4EN44FEA3NPX5UHVH2E76SLDURRINWGTGQ2YIJR7QDUZ5G6SIBB5UBJKZQBDSW2OIDJAXCDNDUDYSN5EYJOA7X3G6C3EADDN3NJ2WJ2VXGMVOCSKFNYTBABSMTUZQXC7UYEXLHCD3NZ464MM3FLZZ3ROD55YKXI227CJXVEITDJI4CG2OJXIWRXURHPQGTEZ3HHBZZY3ULFCGUPEDLQGOGGDYSSRNCSEXDXRLPIWKAVY4UUCZW5NILYUAZZKUGXYQTS6KGITKTEU2AY6IMQOTETO62ZB5JIOTV2VXU5SKX7R5APIY44RYMPGX44HUHGGS4JQNUTZIFKFYCAUZTSMIYJ2DEP3UHHORHAUQ2XCHBUSUYRNRLUS4WMELM2KXAUSWQMWPGYSX3TDOZPXBAT3NXULFA3YD2QLWHT2L4TQDPDGLHZ77XPAOA756IF4IHRWYY=END diff -Nru python-hypothesis-3.44.1/benchmark-data/arrays10-valid=usually-interesting=array_average python-hypothesis-3.71.11/benchmark-data/arrays10-valid=usually-interesting=array_average --- python-hypothesis-3.44.1/benchmark-data/arrays10-valid=usually-interesting=array_average 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/arrays10-valid=usually-interesting=array_average 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for arrays10 [arrays(dtype='int8', shape=10)], with the validity -# condition "usually" and the interestingness condition "array_average". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 418 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 795.10 bytes, standard deviation: 578.38 bytes -# -# Additional interesting statistics: -# -# * Ranging from 6 [4 times] to 2684 [once] bytes. -# * Median size: 997 -# * 99% of examples had at least 27 bytes -# * 99% of examples had at most 1920 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 3248: STARTPCOE3GB3SIRTOECEV7BBRGYGQDBHPL5CSCTTCZEPE6C64LXEJOQLSBQZMR32GUE7VSWEJ7736XZ7OP67H5P36XT7YR5L64RK7O57L4L6YWEP3PYNLXGWW76PWR7ZLGO7V7PPPTZW64Z5C5NNS33WX6GXX2QXLEMK7Y3BNV5WX5RU5GMXRXIB4ZPNE7TF4VDL22R3DNY4PKYPL7LALNKQ7LT5UHKOUB5HJTLLFH5LAOZ7RB2XNUDF44VZ6NJ3XZNU27F6CEX3ZNXOBZWYRNFNCFS574J56OLPEMS63H5LNFPZXSFST734LIS7MVGEPHTFGHLZYCMKBDYEICPIHA5XQSG6ZJSHRN7N4HJANOMSDYM4H26QXI6LBID3SGTD3FZHHEGW2MEUWAUROKYR5Y5S3HX4C2N6Z5O2YG24AYRHOLS34P376PYCU3XRLWKN7RUKEBLO2U5UUM3HAPBO5ARF43K6JKOHECADHO5QEDS6KW6KYAIOSQQOFVUHZQ2TW3KLLQQUWSQQS3JITAPQ3EQATH3TBAIBIRUQBDO4DJ5E5TQCHSFJ4RGQ6TUCYWGR5N5AIVMFU4QWHRXUALAZAPQEWBKUAUE3KGPUVJNQU7ARCSFBFQX7UYCJBUBCDSLTMDQI6Z7WOXJJN7F3SVIFOFH3RSANTA2TSMAVATMY3YEBIVY7MX2FVQH52GMKSLRLQULLXJYNYCKQQQADXY3IEF2SKX5ANVWMIA5XRAT67NNQGUSXBV2N2JGXWJIVVAVNLA25PAQGP2GBDXNG6YUDPNC7RIMCTF7HLL535OBNZVBHBZ3IAZIGDWKDGWICD2XPQ6BQKBFDV52CXW7OYSCRHOWHKIKWLOTZOMFTK4G3ETBCEYMYPKJIJHDZOBJXNTF4WECTZEVDQU4OTPWCZKRYWSS6BIRG6EL44JUFX3QL4CUS6JQ2E7QZKHEKUYEJEL2ACETFLX37DF6SUXBG6POUHMN5GRIE27KMXHK7UIIUDDSP4KJMAGWAUOBGR44WKIB6U2RGM2A4L2IQYAY4RNULXYA3AMECGHIG62LKQEVC6RAKSWTNABJAWXRRRPRMFDCEYXZJFEK4QYEHXRTFUZ6HB6NWASCZU3F7EAWC4LWDBQYLMLC6AUXLCRVDDVKBMY5RLMRKMPJ2BJWVLUDLKZEQT7JNHNMVCXGLTD2L3JNZIJD6YVWFXNYITEXAAUJFJQPQIJ7XBSFOETRFLJXQ22UDYLS6JXFTDHWVBL6H3OUDF2PRZLQJDA4LWEMXOBERSGDDWVKZRXHZIKG2BRVRGZYSKUL7DO5C6XMFTDOWUPJXDRQYT7HPK7R2HRHXND6SDPIDMFYF3F6PXWAMEZMAHHLFENKI4FOFYNJUIYZWE5OB4EB3CWGLPLEN6R6JLUJFMYXKUENZACTZVMMDY7FGIR3CE7Z6D6KL2IMRGTEAIKHFNB4LLEEBWGLMCR65FMWNYUJHKQC4WBPGPJBWOP5PBKD2D53NFIEUJNQ74GOXDFH2XJG3IWUYNYATDZLKAVTJ7EQH7HOKFM5OVZ3ZKXUR6D4VYQQDEE2XNC5CHKLEOXFGOVZ7D5Q4L7TYA5TIUAYWKJMNW4RZPWNCTHKBSZG26TAB5MWNZWHTGBHE2YP7BK2JTK6LFTCNBEQ57ZJZ7I3SYIEK4MWIJ4MRRJQSFXJIESK7TGYYTOEZIU2ZRFXVDC5AR6EAI62VEVMQQEVUTUKUK7CEITM3SC6O4TUQCUQQ67K24E6A7GDAWZ5UIXWNAXKHM65W64ZYAAGQTW74KU42QYHPHGPVQ4CRMCDHM3WXREUAOHS5DBTYKNGPQJ3A3EIUJR4AMMMFZ5GAUARAZU45FPFCBB2UKTL5Q6CGW3YUL64RLKHYR3RR5YJFK5ABOTQ24NZWPDBNUSUMYAEFGYIYYZXCCAHMTJLFLE2WBXLOGB74YVKI36FUMOBXDVKWXU4UDT5NKGGMR5OJSW2YAS4LEXUFBJMPIK7E237THJJHI7YNZOKHNOYOOE3JSUA5PJ3COQKBJZKPMFCCA7SHIPNKCY3FVWFNQIO2YRMGOITCE5M2TL2YM2O5Q4OWRVHSJ27FRYUQXKVMPFV6BIUETOCCDDEYKMWZYDJ5B6DQ5JHZDZWTTALHDJ5PTEPP2UFGWJC5GHE5R73IM6E2LEOPZSEPWD3GW2UZ4EBJHFGWVAUDZXB5ZYWYVWON4MNZU4N53UGO2I7H5LARTKNFYI7AUKHE5ELIE46L4O5VGEECGNB33D5HCZMSXEA6RWWPAP5M65CDRH6DIIW55VXAYU3ADN2H7VL6IDPRCMN732YJMEYW5EM23VGWBAHLAO655RZJNB3FGFJAYXKZY7ACRGVSZYHQKAD232JKLBPLPW4RZFPFRGZ4XCZKFGOWQBSIGMQPB4BXGA6KKL2MPEMDC3T3VQKBYTO2OLELWJ5TNOQ5U55VRASD3QFSZGGVIBS23G6KOIASPNO2NQLK4FPLPRFKOZNNMYOKOS7LLWWH3ZCBHFFMAVXIFAV4M6JKMKBLOOJJFXGBR2HC6ICUG5BUZZ2DAOFIVZXHCVOG52E6O6HPOTKMWX25XZKEHEDTQXSZLDZUM5TAS3DCDBAAAMLMIY346PEH7YMIYH7XQFS7MHP6S2NT36O4RR572KMMMUVVVIZZADVV36QWKHXIZUMES3Q656D6B3ET4X75O2WPDUHMHY5DEX74S3BUBBWBHUPO7O4FSWIOEPRRUAFYDZ34LZEQRPWNDTI23ZBVWAIFAPTBXBP4ADPKBKKJXAEP7BHZMMPUJ7ZUXFSAE433JM3AM6GWDNWTEPZHO6JQTVZZCCGK464XIXY57GMGYFXDDDIEIAGVXCJZH3LENQMMRHHVQG7ZUYCYRY2G7ZVWQ6JNM43KWSWFTTBI7LPFIK57HQBJZJ5K4AW3BULADRKNEBMKL5PXIBBKVZNPLIJEV5VCVP3LWD5IRJZ42BBFOYHP7TZLUZU6CODJGZR43VJYTVNZRNQS24AEOXIPRVIT3DC3CXXSJEAH6XDMTJTPR5MP7F53Q7O7Z4IRU3XJ3JDDWVBXKP7RJRNPSCQOGDY57LKKOLVBWLZWRVYHCX3T3THH4WLU7INA3RZ4CE46UQ3ZLM3VX4ZVSB27JUFXQGLTUYIEVL5I7YSDX6BL54RZX4WSHUEKIVAOOYMP5VUG6UHIT2UXRVKC5L63VEE3RYKNNFDSJORTYKRKZ7XZPZ6727D77727K22XNP7POP4TRLMOS===END diff -Nru python-hypothesis-3.44.1/benchmark-data/arrays10-valid=usually-interesting=size_lower_bound python-hypothesis-3.71.11/benchmark-data/arrays10-valid=usually-interesting=size_lower_bound --- python-hypothesis-3.44.1/benchmark-data/arrays10-valid=usually-interesting=size_lower_bound 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/arrays10-valid=usually-interesting=size_lower_bound 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for arrays10 [arrays(dtype='int8', shape=10)], with the validity -# condition "usually" and the interestingness condition "size_lower_bound". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 406 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 18011.85 bytes, standard deviation: 22290.09 bytes -# -# Additional interesting statistics: -# -# * Ranging from 6 [44 times] to 168836 [once] bytes. -# * Median size: 8860 -# * 99% of examples had at least 6 bytes -# * 99% of examples had at most 98792 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 4312: STARTPCOELGB5SIWLSDMEV7ZGF3LH6ADQICK5IUQU626ILZHQVXK5TEPWUQSOZ52FOFMLAAJJSCP646H377XV547776XDN6774PWPH337PLZV37XV662O7V37P4PXJL6TZT5J7D66XXR523XV6J3L5DNVYR7X5VMKTX7GVDQZ75VN3677ELJPOD6ORC7QQW4VGN6PRDULOTBNKBV2PPXM5VL7VLRV57JEW44WC7I63KO5ZTFY7J4GT4EV4M7WP26G5FRPYXY24T5GD2VVVYMV23RXH5CCPPWOOG4H56X2XH4OEOOZWPZPR6P3YLEZ7KWDZORPB23ZHEZT53IJ6O553EUALMJLSIWJJAVN44323CD5X4LXVANF2T4IX552XSQ2ZZJXFFMH33VVTXDHP5NR64MLUKPGOQK2NE5NTPJBPNQXEAIXWTZ75Q5TF5HTKNDFGC7KW25YHN4GO55LY2R6K7YZ53IMU6V2EVK4VEGP37WG6D7I4V4PHWPP5XEK4OZK32YEYY5CPPNBLDPEATVHZSY27Z53ULHPKASOSG7A2R2357LFO5Z7VEFBSRQCJN45L6K4SZWRBZHQDPTDQSLQKXS6RXXV533HNARSVZQRFV5BZQN6IZUV6OMGSVEFJJ5TX3CDYL3UWQDYLBY3DR552LQY3YLNHVVHTBVXGEAZM2VGM4PPQS4W6TVDKXPZGW6PSQ7MPYXPEGLDNM7WGR33GCOJNL5IIEGIHHO3FDOY3A2TZ2UOB2KGCDDAZ46F5XFEVOETQYPVEKSZSTNM24FQVO3FOODX6LQCDYXFKVVNCBVONKKUXO4K65JAQLKQ5YQL3V6XJEYF2OATJDIHXIBI3YDL36M674UB5BZ5TTNGG4F7M56ABMUXAGECOLPHDLGDFPSDWV2L22N36UAEETLHISMS76WWK5TMGIX5ZONQSXHOUNF4BNZTDEQNBKLRFTRRRFLOKYX6E5S45IRTOBGPGV3ANSJSJRM5AG42MPY2W34NOSDAIZJHKUAIHSZKEEQ3USF3E2DHHYIJNDXRVAKCLMITVSJ72MYZ4Q3G2TLMMWHYTUC4G6OVO5MM5T66DTLXOAYP2FJ3ZL4GCNJHE6OAYIOO6UTT6HEQJU7AK4MHIMQGD6DQU6RLELJ2FPO4BWZ6X5TNIWWMRPTAAQS4YWL4N4NSRT6PRBEEBZZYIX7NEL6I5MRIVMA43F5O5SYARDTVFBKLR6FKXSPDQJ6GHU56BZZC7ADY57WY4ENPNSZQE2CYZUKASP7HEDVII7VFFRKH2GZIQKHJH6EKGYET66PBXECSO2G32ECKUOQTZRYZMRKRAOFA66DMCGP7GNFXL65MMM2HE4YF7N32PO4WDDMOGPR52ZSF5X4BDJ4ABOFN76Z2MSX2F2NMGMRCHV5ZOLYATOKOWI6JNW2EKIJABMEMPMZHV2OAGNUPAGETJ2EAPO67277UHXJUM7INGFYZCN6L3B7US7TVWRNBRUHPESVBLUTAC5F37OOVU5HEHWCOJGHXK7PAJJAI2GB3VRAGFWDHJF4XKOZG6E5FYOLA5OI2JKVVHIJ3BYVG62FOPHIC5RHELEKHG4QPJCRYG6E55LCFWH255Y4JNYHPBTI26F7VPCVWX5KIIOMI656SAGV2UVO5QCM3P7CHRS3NSQO2QJEMSXM3XQAZ2CPES2REH7EXS7HY43727KTOU2Q4QAPJ77FD6I34VSFZEYG4ODFXJ55AIHRTTB2Q3MUG6KREYGCS4DM2E7RGN4CREUTSO6XJVQNJCENA54XOI2QDHZZUEHEEJ3IPS5LZW3LYHH5JX4PBDTRFA625KZFTICSI3VXCDIR2S2JZBDRYWZOY5JR66ECILQURLHWHS63LW532TT734QZZABJVQNCOV2S3I27XYN2LJIQ6CM66EKILXOG6T2JA2LMJVSGBL24CMLZ6FYKNINCGOAPANGZWAO2GDPQRQB76MHABDZQMC5CFTQRSJ2UGAGTA4JOIRJTV5TO6DYTMAQ75BFFTXSUNU3TDFYBPST745B7JG5JMLMFMFGNCM4TJN2RU5UWNUE4T7FUGJEJNKK63C6XOMC3B5TI2C5LSXPPQPOGG5HBBHCI6GIYPGGIQY23T6QG7QHMY6JVTQUQOKCLDD7BWTQK5QH3PFY7B54VH3XCGPS4AT34UUXWARF5LWM7PEUCHYISPIAYBNV555GG4ISDBYHZFVPXNBZPQSGNSNQWXAWPS7Z2MHBPSTLJB6ZT7TGNGJF7JKC26D7SEO5JMMJUCNBVQ6QY7QRTWQTMI7RCYOTKT5XAY6WR2X7KBI5X7XKVQIUTIVYGCCVO5MDIZPBKN43W6QFVG4LQV4ZBIPXHZV3O4XQP2IBBDHK5565Z3H2PMOBWIFNLLWAOXIBWI5CK3LCB6ECJUL4IV6PDCAJOD6D3JVBEZDHZTZSRTF6UJUFSPZEMAN7MODACOURZX47RHXLJ6RWL6P3AMG6EFZCGTJXPGUEYKRVHYZA6QMJY5K3G3NC4IWFEA3ZC4DSC3FTFFTWWEMR7VCADOUGNNNTE33R75WV4ACCZVWLQXZXFSFIQN3KRE42HZ6NTZQ7FSHNWABHBNCCJTHUEHVYQHMFXEXBTD7ETJ3CZLPDYNKHGRUX3ZUGQADDVMENNYEYZISE75WH47MGAXGK7AVYHV3PS3YQVNTEHUGXI3JUIA6POHYWWQPTJ7ZAJ4GU43SFTEAH43Q2KRO6HE5MBP72QRUGINHRZTE6U2CSJMJD7MENSJ5J7MMAHMZQ7D6L2D2ABOPV44ZEO5TCL5ND7D2QH3MELOAG44RJZ2CMUY5TSE5ELHPBSBQKAHGOXZEBWUTH2LWP3OQCBKES7RWK7NQMY42YEO2W6MVPGBSJTBPOCORKVRM4CRATD3RGWEK5EOEDQWKSELLO62DA3MCICMRWAQF3MU2TC6VONJVYTCTRGDXUL4ZO7MGG2UR6MOMNS6OSMJXVIKWDISQXYQ355JXVMJUS64BXGWBTIPE3ESRBXJX7XTDCRRMI3BHGHWVR2ARBI5IHWNULM4HITFKSRBG4XH2BSPN2ICWISXWR5PZVVKHYB4ZFHDQAEOGUXMELSY4JATM2CA5JP6C5TPKPVOZ7WQMAMN6P6TSWI22AHIQ2QXIYWBZQOBGDFLYGAWNWZA6B7DT53C7RD6JBBRCNCF4PFLGKE5HPJAYRYMG6BT4WNRCKAI7Q3HC43L2T4KTG7GTM3O4DCIZZPRNZCWXCXPCWLYHBWEFM2MCV65A4H2FBRAEWYESCPF6PTWOEQWBCUYRTS7G7CGA4VOQ6IXMOWX4BTV54OWINUZZ3XIMJOSIQTJK4JXCTDQ4GWMXUUD36UIPNSTW3EUNYYQMSQQB6YPMFKSUXLY6ZSL26XVVB7B5JL6743KDKZJU67QMGGL3X6MVRWY6BVD57APVSOVGKTBBPFMHRMFSB66TTOWATCUWKEIDQT6JNUTY4CWZZDBTFKHMIMP2ACPOBGBB5HPV3BNUMWHDOUCOGKUCVL5AYEQP66Z5JO3PT3MDXH65HWRKHE27C6EH7N4P72EJBTLGRUJR2FDQ5AQSIAULIUONBBIWMDUJZWDTYJ4JYML7G5SXDW5L6OOWJJ4PKYUCPW4NC7TZWABVYLHAXIEX5E7XDUHAR2JNVHG5UQH2PLGY62RQGYHO4YFETRUO7Q2JSOG5JPEMCHFRJQUXJQOWWI4HTZ6RORY6OPECHZWB3MKPXQOZ5B7GA5FBULKLPPBIFLHKMFU4XGESTP6QSNSM43W37X7VBICKQWWY5OD7FSKQDXRHSXXZWWD3LJHGDOJZI64DZWDZEHVHHCGIFFWC3ELSFEO24YQ4WJVI2SXLWT6GB43JP7F3RFWTZ3MW2W3NATL2VHA2C35WD5DSS2FAYAGIBD222DYP22BQQOON3W3OLCHLDTFOWMQCQ2FY72DNIJ6SOIMYGVTDRJ6ZQV6JC3CDVKZDQLYCGEG7LMTX6P44JVE4HOVKYXDQGC3PW6DM2BS4HQXZTJTLRHHK547SRZM5AOPHWVRTE4Y6EOSECWEMBSXX2NMTYKK3B6WUJF2MNIXDEXKPDYOD5XACLPE6TDIPGGUYESHJ33XULSFTJAPYPLLOKPC3QGHLYQOB2C4QE6DW7OSAXNRDBLM5JHBTVW4J6BRXRUIBAG5OKGR7GWAIPGYLG2WSSODQQL3HE5UBTR6SWQN3PPCMT2ACLSZ4XME5EFIH3MGKGHWUZVH34F5SMJGROHJFLBON364H2PWNOHJUNTFZJEIYJX5GQXVR7P377XY5PHT777ZY7PVZIH77YH5DIL6XQ======END diff -Nru python-hypothesis-3.44.1/benchmark-data/arraysvar-valid=always-interesting=always python-hypothesis-3.71.11/benchmark-data/arraysvar-valid=always-interesting=always --- python-hypothesis-3.44.1/benchmark-data/arraysvar-valid=always-interesting=always 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/arraysvar-valid=always-interesting=always 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for arraysvar [arrays(dtype='int8', shape=integers(min_value=0, max_value=10))], with the validity -# condition "always" and the interestingness condition "always". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 408 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 2.00 bytes, standard deviation: 0.00 bytes -# -# Additional interesting statistics: -# -# * Ranging from 2 [1000 times] to 2 [1000 times] bytes. -# * Median size: 2 -# * 99% of examples had at least 2 bytes -# * 99% of examples had at most 2 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 96: STARTPCOKWVRKZ2WEULKWWJJIQNWSKEMELI3ICSG2EUJURJDNCKA2IWRWQFANNIKKXI5AKSOJVGQCNTAZWGCY2QBABUOT6OLQ====END diff -Nru python-hypothesis-3.44.1/benchmark-data/arraysvar-valid=always-interesting=array_average python-hypothesis-3.71.11/benchmark-data/arraysvar-valid=always-interesting=array_average --- python-hypothesis-3.44.1/benchmark-data/arraysvar-valid=always-interesting=array_average 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/arraysvar-valid=always-interesting=array_average 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for arraysvar [arrays(dtype='int8', shape=integers(min_value=0, max_value=10))], with the validity -# condition "always" and the interestingness condition "array_average". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 417 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 553.41 bytes, standard deviation: 372.98 bytes -# -# Additional interesting statistics: -# -# * Ranging from 23 [once] to 2354 [once] bytes. -# * Median size: 661 -# * 99% of examples had at least 65 bytes -# * 99% of examples had at most 1271 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 3136: STARTPCOELGB3SKODODEEV6ZKKWAB34AHIFMXGMVXBLGMF3P533AP4AUNRLMZ75AQFDKGUM4767X36X3T6P37PX57D5KH57V7WV3P327X7WJY67P3476HX574LOGXW7PU6PXNPZO7VXSGXP7U7XDHSY7K3642Q5LDR54ZGHXI2PXPRUO7G7UN7PZB452BX6LWFXSLLVN3AXXH7L6TXZ66HSQSP5DJZS5WJ36247MN3UUPQLJMHZTXAHX7PBWNUNTZVNVUPMYTMUO5J5NCD3G6DVN4X2ENPW5DM4KFU2S5VUT2RJNTWRN376LO5DXARW52KCIDB7W3C5H3MZ6564N3D7DTUWUMCAC4UGF2MYQEQBWKKH57O7PPIQL2VBCE5LNL4K4QYEN72PTSS33FFIQBPBB6T2HWCD7KJYXN32MEOWAI3LPPI7IQLBBKOYSNLXV4AIUIN7ECVAECLASHZOFYJ7KZLYQJASZGMB63L3C4WTHHCY5EW27LSOJYFPTONJ7K73JN7RZSLSVFO4KYGQDUUFRPXPRQE6ES2YJI2BOOTWOKH5LW5IWWKGWYMIHBPENYUBTGBXQDA7O7MSQ43YEQCYMI2DK3AVV2DAFVNNTEYAPOUPT4NOUEZQQMHKII4GHRF2NKR4PYVIW4EHABIPBH7A5LLCWWKMK3UXUOAUDZJGKWGBWUJCYY2UL2BULOZBJY3YBN5NDG2V4VACPDOWCGBZB5DANVFGDMS7W25IIJFKQME5U45LMQQROXMJAUKAYA5MI53A3I3XLX6UKEZJYFLQUA6JZ2SGMJ2ACDCF3FUULVKBLU3AJ5SPYMUARQS4LLRQVBBWQTRNKRBRNHJCC4I5FY2JTQ3MUWTAO34K7YSOI3FRU5DIMVI6T33VIOULPSDX4A2CR2QEFKDXFQ76FOWQG2LUN3S652WOWBAFKIE4ZANFVFZUONUQ5FCLPIIW5ED3NSSP276CHKVGOJZPQQTB5VXSIVXQRP6VBBUP5UIISAC72XZILZVKDEUOV5KRWH5WG324CELQIWTE23FBYMTL4BKARWUC2J4NJ2B4KB37KSQQU2KYXXJZSUDJNU3NM5LE4LNZLS2QVJ2GWDNHQGA5CWPHMGHLJVKUVE3GJRRBDZKKWVC4KYENVA4SRD6CD5222TMEC2AUJJIEJYFZKIHU3MXKK3EC6XU6JCXSFFNZNFNIQWQJVKVCOF2OHMM3CVAJ2YURL6RH2MIUCBG237O62G2NFEYR4RHJM2NJICGPJAEFD4LMXSKRIZSB4C5DK5Y5Q6HX6ULJDSXBB5RSGJIYQV3IUXBXKLGMJBRJSAYRARPI2NM2LMZPE5A45AFJ5YLXGXPFRL4SEN6XKEKAXJYR6EVABGRNKNJVNTGQFEA5J3WO3MVIJ5KTOITMWE4PJJIRTGKUMY37VKITS2D63QFNEAGEKR74OLAHSPYWJ4FUU43E7YHMU7272W6FRJCKZFGIIAQ4YUWBKXR3ZE6VMVBCO4A3ETOCYRYLASJSUPYUHGEHAU5IWRBYU72T6JEOIAIRGVD7VRDJASROUPT2PR6YIMIM63LMYOEGK4HCG7GGHOWQAU4SHVTEHJ57TUTU6RXXOMHKNCG2QWRLH37LQKVTSL4FOJQIVA6WQA5NAULQBETOGKLFETWUOHUPO5SPBAVGNRBAALYD2DGBO7CU32PHU2GLGZDQJDGWKV2GBXPURTAYIEYLTGCMKVG37DDMRJRZ4C3XFN5ICYPXHWZFMEI3N6AODQK4ZZXDXW2A4FNI3MMMFKXPHUUYIZHUDCSSSG7AJ47V24BZORPLJ3NLJX3T3GANHN5L56IJ24ITSMLXXIR52DTR3H7E3IXJ4FQRDNGPUV3XKULGAYINDZAK2GZL3HFG7YCEON2WRJLQZ4OSVJQSIYQI6BZ7MWFVTYNW77RVEP6PJT4WQTWYJ5E3KMDRUZI3QF4YEYKEKTM7FX5QPHJJEBR6AEVBEA4FOCBJ5REUURCFRZJ6MAOY4UJCVCPUBTZHTMPKMUTQQKSSEDKOSILFY42R4O2X6QIW5BQJTAUGR5ROM3HMSECP35XYQ5DVJO5RVIKHCJIDHY2FJQHHXNW6EZDO47SYOAYEZSFSOYPUOKVCPXBQBTMOQW4NTIZWUXNRY44FRGQCKEZ3HNW3PFHDTLIQDD4RQ2MV7YGNVSDSFBEGSGMIADLSXCKAOB6NQFYG3XED4ZZM546ZIZSNQIFDXUHVZDQLEERDW4HRVPLYTTT42PKOYZUACCZQGQOL2DU2STY4YGFLVRAOVYAGRZ7EWESCPZHISTA2EJHUAQBDQMWAQPXKJDQLOMDOSJHUTC5B4SQOFN5GMYMT2J5N7F52UAYDJQG7GNXVL3HUD6KQAWPXL3T2XWXK4N4W7BSCFIFU2FJUM7MPNNFAXZMNOPSK5JKTXE5QLRL6EU2MMAOSBLQLGSQZ4BO5Y3RVZ6YG24YXCCJVTWBKIOCVW23YHNWROMGYXGBFHY7MZELFRHD2C7DIDQYGA6TSRRJDNFKH6ZB67MHLGKBPRWH7LGZYXTCTT747KXMIWELXXASTGN2JOVTTIAF6LCZ3LFIKQZRG7EUDKSZBLI3TXU3GF7UMS5GCBXQHHGM45EJZMPLCBRIPYMET7TSDNXAI7I6FC2HJKZT4ZTOMTZ3XG4V6BRRAX4DORY5ZBJNHEBIRU2AGI423TVJRNARNESBMHDI2BGEQSTMVC55WJS5OSORUZT2NSHBRRGHOFFLFEQCPJFX4EGBZ2UWOPKA44A4TAMCYJFH3QLOMWENAB4U3CF4YTVFJNK54CEDHY5XJNYLYXADOOOSB33EDPF5MYHDNSP2HJM6GOGKK5MP2CITFYYAJZN4CJM63T4RACYQ7LYNFQTYU72AIE57TJAA6ZCTYMRLIUGEKGVDL7AW44GAQ7MZYAQUL357AQQGL4JOCSWX7OEZTUWQPJ5K3YKWRN5Q3AHFWXEQRCNWNHWIWWORKWJR4G33ODF6UJ4KKXLR2PUSQYY2U6E7XTA7N42FQIIONVE575UWTIIEWYRDIGS2GAGJWC7LURIL5MV26BGGYUEOICML7NUVSMT5GIJBX22SL6VICHPRM7GNLC6LEYJG7P67H66XW5PT47776XW4PXGL775B6H4XFXHEND diff -Nru python-hypothesis-3.44.1/benchmark-data/arraysvar-valid=always-interesting=lower_bound python-hypothesis-3.71.11/benchmark-data/arraysvar-valid=always-interesting=lower_bound --- python-hypothesis-3.44.1/benchmark-data/arraysvar-valid=always-interesting=lower_bound 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/arraysvar-valid=always-interesting=lower_bound 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for arraysvar [arrays(dtype='int8', shape=integers(min_value=0, max_value=10))], with the validity -# condition "always" and the interestingness condition "lower_bound". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 410 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 845.64 bytes, standard deviation: 247.26 bytes -# -# Additional interesting statistics: -# -# * Ranging from 2 [5 times] to 2546 [once] bytes. -# * Median size: 852 -# * 99% of examples had at least 32 bytes -# * 99% of examples had at most 1482 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 3120: STARTPCOELGB3SLWTMDCEW4ZDL4IE4IL4JW4KZOMSO4H4GK53Y55TB4AE3IV2K4JES7A2RWDP57P47X3T7X57H57X37BR7LLYPH7T6VQT45FZP7NTH56XY5U6WXXW7VXXM75Z7PL4PWTW546VH3ZMV3Z5DNLLSNMNVW55W2XLLJVF6743NO7UTSQVXWXY2GXX333VO3J2X47I27LNE5VUZVXFU54PHBOYXB7WX636YLAZVGOR7V63WLKLP3C3LUXZXFUZTYWB3VKH3LVQ7XTRJSJXHXGTQGHW43S77JUTUQVPY7I7ZFMHU3DS4S5XR3UQ6S3U4BOBLLZ53BGXXOXDIN7XJEG6DI5HFTRXACTN3SRKZYPMUAAH6DDJFNO23MYWJH6MQI64VBYTJ4XHE5OIUOTHOWWHFDS4BFWWFAY6OIJR5PPPINXKRGJTRQ5FXOJUPJGKUVBXAW6DEO42CEDPYHCKOLCYOK5Q34TQOKG3WLG7KOTLVYVBAOT3NMDS6UWDFBJFFNO5E5QCQMUW2J36FHSGYBBQZ7HBH57BUJRYRF4SPADDNS2GTXCTDLLRPX2BEWOTRFT2Y5HTY3RK5WPA4A6MFD7A3PSUO7YSH745O7ZQV26OZOO7PUC4EM4I2PICMR7WG3SWGTJ5TKM4CI5A5I6AGKSCRE33TICAN2ZDQKRUTE4YKBU3WCIKU6DW53KON5HUZKNRMC7HHZABJRQACMMWWSW4LZMLY6YB2KOQVETVTWFVEJNAT5HLK2JBKVHETTU6QERYOJUMXFPN4SYHW3MFLJQ4YIXIGTAXO5OAFIRLPV34ERXCUK5CVQOXXO5ZC4XCXOIME64UV4FUPG57RKXJDRWTFKANVZLOECF3KQ4AG3QACHXADBUEDVWYBR3JCRYDLDFFPCRBLTUJQIIXDPERGPSOM4IVSVTKLOXVFARD3NMLZLXQHNY6DJB6RMHNVU5KOAXJRVQLKJHIKH7AXA6ZE2EOLY75IUDEQKQPB4UTRGY74ZSMCZTKTNQHBYMOTVRRFTLLNVRT5HL7PWT45FRFCAAKR6FA4FRYVXUETXTIEXQYNHMCIF5SCOPCHQZ5QZAEIQSUCQDDZKPYTT4TRXHEWKXAPY7ULEH5US4R4NUCR7BND5NNU5WUPCFDWYLB4BSNZEOFHVLNIKWBFO3UXCJCNIS7QW3TJERRSNUK4LPQFSEV3IZKNLV2FP2OEIN24UP6BOFZ7IEG3LKLJSEUD4NT25Z6RMDDBKXFZEHLV3DJ2E2X6EBSTTUFGXR2SP5I3NVWRNQZVHSEIUDORTZKVIRYR52XGHNBNYFPOW2FZ4QP5U6YTLLIPRRRM7KSQUXC4O3WGKBROUJ2URDROH2ZD5KPGUOADW7IFZPAPVNOE6JB4JWJC3CLSOZSZZJI4AAI5MSDZAK2IPLDJXSEJB7DB4YYKMB4MBIK2FCRCBXSW4BYIIMGSCZ7RR327I7QAMI6CZEQSP4ONIBBTYACZGTHE72K6MPWV3DQ4KX5KGJYFKSDKXUH325QPPP5SRCAPXEIBFNGXPUCWRAAPND2T3ZM426WXZ6LE72AQLK6MRVHPDVZS5MUIBWBTK5IOPMWGSHWV2GZPE53ODIKQT4DVFCHJ6POS6PUEEX24RFLYCILAUUQGYI2K3EIBBSYMAZ4UE3ZYBYKHIUMSXV5NO6OF3XADZX37YIGIKVKCE2CIB24XBV3KQRQVAMTGZ2OAGC4KWFWISERI7JW3LIE32SVWT2VMXFLIR3RTT6ZNCHPC6LHBHLQXDUXPRBCPKMVFRTDZI4KIUUWGB27HKUV2FP4L2Z5EWDCX6QUGDKEXFGWFEMXD4BUMDRG6Y6ECUQD44DIAQ63IET4HCELIWEWFSCSPAMUI2AOTTP5Q5YOSCVTTIEJ5EFXKTF2QDPRAVWY4JQB74BAJVPWLWV4LDUKKPHFAODITWTNRETUYPDMQKCYLQKQBGARXK26AYBQFUTHM4P7DZSJEOGANVPON5NC3CUNAH4G56QWPHU6NTJ5NK7BRGGZHLFI3O7F4NHYHLMUHGJSFQDJYJ3B4IYTNTCUBJDBKW7JYFWD66YU2QPBQDEQ4MN7R2XACOFIMDYPCRC4XWSJVHI2VYNBSTPV45ARDTB6SEHLMY7OSNNJYTCEBV7IDPWWRGPMTNO53XNERVMAYJG4FIHKJNIGPJCQC2AT2QASCWB5MENIK3GV73UAQYG4MKFCD22P6L4PIZGJIPRQBCOMJIENNF6VYEAOIQDHXNM2CJ5DXMUXRUOX2CXIXEJECR72XWGKGFTSEQOYHUFPHRVFLUFDQWEXL3BKBSS7URVEYRSMUMLOALRWGGVOW2JV4UCZRXHKZABS753ID7CYEOGBDANTFSNTUIWMNZ2WQ2D7LUNHMQPZVEMZNRM6VZ4YC36TS6NRCATDE2U6D6M4M6HBGV26CARZRWYXMF5NMMOZVAA2AVLP33FCM7Q4JIU2PNFJT4CAQ3PPNDCUQN6VNEKNNIZZILKRMKTZXPCZHC535UM5DGIWQQMAM6CBFHZP7BLXNEYT7VAHS5S2YEXATAWE2M64E7YC54272BD5MIUMIYLPI645J6BSEZTHLJRKERDPIYPQVI65XJENGRFX4Q6SYW3QRVCR5MM4TXXQFT4LLUWC4C6VGPENAI6QLSQHAOCABXIJKEXKN2JEMPJICUD6RBNC77UKUH4TRMYG25DWLXKHPZIIR2KWNCEACHZRSV5CC6OAFQVDU2GDWKGVGTH6SY6WVTRQ4MKPZYTLAPKR5QGH3EQJ56G7L3FJG522RSBI6YRO6V4VW3NPQ3BJPGCQZFLB27EOTTL2EBSCAVDXPG6VR3UP7PAZGUIJ6LM6FSCB7ZVHOZAMGXPWCT6OGGYD3GXW6N6EEDDBZ6VPFJSMI55HTVBASY2RWEY6M6AN3Q3THM7KGIDLIDMKPLGH3O2GT3QEGJCFRSLK32EVG24CKDX3ZJHQI7AR6KJCZ65FUDYV5ZTZH4FNAASJMDEMAAGGCNPUOGGFFBRARVMP45L2EGCHPLIC7TAXBX6722SGXGB4OVQDCVG4JA7WWUW36YTIEW2WYHVTBW6652X7H67T4PT7P57775PZ5NR3NZ5774AU2JF3IM======END diff -Nru python-hypothesis-3.44.1/benchmark-data/arraysvar-valid=always-interesting=never python-hypothesis-3.71.11/benchmark-data/arraysvar-valid=always-interesting=never --- python-hypothesis-3.44.1/benchmark-data/arraysvar-valid=always-interesting=never 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/arraysvar-valid=always-interesting=never 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for arraysvar [arrays(dtype='int8', shape=integers(min_value=0, max_value=10))], with the validity -# condition "always" and the interestingness condition "never". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 407 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 894.57 bytes, standard deviation: 162.49 bytes -# -# Additional interesting statistics: -# -# * Ranging from 568 [once] to 2325 [once] bytes. -# * Median size: 870 -# * 99% of examples had at least 619 bytes -# * 99% of examples had at most 1405 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 3096: STARTPCOFLGBZSISTODCEV7JNC5Q3LSFAJINLFDSGSDGZ4NE2DO4LPAEVI244D67RM3UJIQRFD734736OX3Y7H47X767Y7X4PH5OR3PZK7D7TZSXQ63ZTV2W4L5N55GRX67OYXQXZTX33C2H23R4DX3XIXPJT7Q47CO7O5U665DLDGGEOTNW5PNZ5Y72P3SFQPR3XJR2IPHB54PS7QZ7XHV346S43WGLMPS7LXZ6PVSM56Q3HPLWNEKT57KOPNDY2I4LNGETGNDAFVTC3JXFTE73XAPAG544OBCBDRQPJXCBDGHMV5RRSQKAUO54QT4K4HY5QMPDOYMMTW4OS7RJIHP7C47T7NTCDWPOWACYMA36HCQL2UXS3R4PY6M7WOHRJA46XSJ6U5L7FT23GEPWPJH3Y4SYDN5TU74L6R7SS2DXCGP3NAAUVADE5SSCEKP7SFTW3I4GGD5QGJLTT4XZHGALCYAG5HR7DOHEIRFLQB2FROAD57OAG7HJ5S4UDHWRVNB2RUPRKMEYTL4EHFQAMK3C3JEYV4NUJWQZIX2Y7JDHDHIIMI7QXA54GF5DAKXQGUC2QIZXJAQMJOTYNGBYLBU4BVIAESN36PGXA62AD6VXXTDPIQ3LMXBPRIMUOWZ4H3TO4W5DZQCMZJU3AXWE6SAMEGGA4CD2ACWCTKGZUVANAWYMQPNEM247JAYATTPMLDELA64YDDKGVWF5RBADU3EII6HIFDMC6YJQ7RD7SDCV4WQ6KCUCCNBQGANBCUW2CJGOUQNB55WDNCDIQ5PEGLWY64E7POM4GP5QYX5E2BB7BDS4QKH2OSDWAJPH5HSYPPLVXG2JZA2Z53HMQOHBVZBFSBJBIJ5FM5GP4QBRMXTJIA7RQIBSLXVRHGJVRTIR5OJQ2C5KKIK5SWN4ULTBNYMX4UKJTELKCQB7CVCUD5RBFZ3VWBP5NSIKTQDQMT2IDOZHTMYSJIZUCLDHBMRD5T2FDMOXGDSNN3MFSEI5DEEPNKQNPBT2AK4BDCAVEEOWUNYY2ZHBAWB72YYSP3VPS5XQGFKNUA3WRLQWYPVIIO3PZ3GEQVQXLESE3EIGWGXPI56A5CQEQSE52YGISWKRPCZKAHTPO6YFHPY3HUUGIQOXX2FJRCRQOJFFEGR75RXFGQPLXW3HUZKTNERRCXELHBI5KIRFPWM4KYZEJMRWEEWPKROJHEF7PFUENIH5CD7L25KTGWFSSM7QUOPUPAQWQ3FY4A7IY34QZEVEZYDD56E33USPIVFRXI5NAEZKMRUKC4JEHZIZUJD4IHKBD6ZVNUK6Z46CXAXJIWGSSZD7FITUBCODVJUKQMGB6Z4OYZDG5KSY7IXMCQBKE2R5B24LLY2JULVBGIMROPT5LCYLKONUS5VUVSTRP3NETCFOJSNCVERK66U6V4F7BDAMFZEOMGIS3ERHFS6IFVSRZKELU5PS2KV5MA34RGYXOKIICMKLNO4JSAIEALQKNOW6SOGTTVTNMIYITBLOKU2X6XRPAKS7USCSZQGGSXMVJBBBDAU6BNWVHKLPAV6X5SCZD2CZG6LCWBJMWCWKU2SOFO35I5ULI3JOBSAFWQNULFPTMTSWZMBEWN3XZ4J4Q6YWQF7FECBELDCMOISABBLMRSHQPRCFNFGGEX6O22PTVZ2HMBXPVGCSNUQCAHAEEA3FLNFBEOAHJH52Y5EQCZ3SR3IEZRKTFA7TDMMQZZC5VX7LW33OBJIABK3AZTPN7JMWHQYJ2EMH4I4OOJGESAQADKNEALELFQBMVILT4SU7ZNUT4AJFIW5JXVGOOL2LVA6ZXZ3LG4LPOX5MUC3JIG2RXX2L6YWIQTXZUAXNK5BU6LHWJG5DKBRQIBYKNDZKM63O3RHD4DOCJAK5ZQDPMN2YF7J3TVTUX5PHJZMD6XZMTM4YXWDWFFL5HXNKMFKBYJOULBEJWQCUOQLO5HXS4ZUKFNKJ5WSXMKYYHON7WLJJOYRZJJRAXUSSJFDJ333FNBJFKYDGQYTZCV3WMNGHRI4JGSEGXUIGDRCQ4W3BRFW7NXCH2HRCYBANRY2U4XJ5ONIJVZ2WJKE4FI27JCQEQR5KWHEVUSOKVSRG3MXYSWZFZRBQEPVNVM4J2EF4W4NEOA2ENIRJKTFU5GCVNKI2PTEHTXL4GZX5YA3O7HWSPZLO2NWVAHTSJPUKYLFIRE5YYFZQZ334ONPTAZWA7HIRXIL6FADA5ANC6EWMIZ5G6FP3DZ2PKK7EFQ6SBF7NXSTSFZXIAUGSN7RSRI7PRDCQ56FCIV5JAORXWJKGIUOS2YTN3FHNTVQ66QQI23AFFBUJIMREZJUB7NHDDHPASCK2EUOMA32LTBHPRC36ENAZGMM2MUFJAKYVNIJ2RI6ILJNRI55SX3JFCEZRWOMQZSBTMZJFLKSCBMTUAFNLXWVQMS7ZZROYYNPSR4UT6XDTJRPL2ZARRPT4M7TELU73X54R2XL5MYZJ7L64GDH5VURP7FJ2FKGLUIFNQG5T5LKQKLZEH6CU7JRCEPNKIDFJHHAFINFK66WY4WETOVWGGVIJQ5NWYVYIO32YZOS7QA62Z2GMMASHTZ3E4AO2VCZXQPWRPLKTK6K7WJQEWOZ6LPDWULF4VX6CGNWZFQ25DNORDV7UK5QDX7BGAERJYAQQME7UVZLJJXLXKUFX5EWHLRBZ2Z42PBVFPVN3OXDPBJTDMWYFABW2IU2ZFGVGL2724OI7MYMS5GONMETOINSEE3747LTWCZ7JEVKU5ZLTCLAYPMEROMKZ5VC3GVAODFBJS2LE4C6B3N75SJHKGOLESNWSKSSCFBDFXKZWEXS2CS6CN4XWIFWO2UUQV3XV7LQJFSNTUAKJVBE57TG3JGGVW4HIZAXMUKPBF4M35C6CFLGPRQCDZP7TMWAMEOWHZIEYZEF6UW2SUJL6NXFTKLCLAK6SSPXJHRM7Y5JRPKET46ZILP3HE3QUJOQETZN3ZIQYY7QLZAWT55FJDHDDKZPSFRRSVAW77P4QUKQNLYZ47HBCZVQS6D7F3FSIEAMEYRPUEWEQXRAQ34SN5P7VFKDUYXHQ2HA7X67D5PT7PZ4PDZ7H56PU6M3774B5CBXDM4===END diff -Nru python-hypothesis-3.44.1/benchmark-data/arraysvar-valid=always-interesting=size_lower_bound python-hypothesis-3.71.11/benchmark-data/arraysvar-valid=always-interesting=size_lower_bound --- python-hypothesis-3.44.1/benchmark-data/arraysvar-valid=always-interesting=size_lower_bound 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/arraysvar-valid=always-interesting=size_lower_bound 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for arraysvar [arrays(dtype='int8', shape=integers(min_value=0, max_value=10))], with the validity -# condition "always" and the interestingness condition "size_lower_bound". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 411 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 12079.59 bytes, standard deviation: 17201.65 bytes -# -# Additional interesting statistics: -# -# * Ranging from 2 [20 times] to 181025 [once] bytes. -# * Median size: 5220 -# * 99% of examples had at least 2 bytes -# * 99% of examples had at most 78262 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 4112: STARTPCOD3GBR2IS3ODMEV6ZLL4IGAQARBJFO4JZOMDI4FOZ4W5ZX7LBURKWS7P333GJBIGQLXUMY777PZ46777473Z6PH57PZQ3NTVPT63A7LO7X4HG757LQ756K73W257PLY73LLLP7XSJX3WNOV2XNOV7XGYV74RD7ZPW55V5DH46PNVPVWKS6XK4XVX7K2P7VWON7G27IS6UGGXGYXXXLMKR527PWPA6QM5D2PZKLIHMDTPKYLZWWEK25MFMWQ4ZN7FLEPGCR2FP45RH3OLU7FDP6GTZZXCTXWGD533OEPW67PNR4V327WI3MJU2PN6SOPMFOFHBMFVPL25DEP5SK6RUIXWYOWNULEIM2L7EEELYSFTSQTC3PGXFFEH5RJJLHJZ75Z7SPVGUFZ3FH5ATIZUQ6HO3B5CVXCT37G7XU6THS6TELFM4H3NO6JSTUWX6KSAWS3MFSRS2HJDDRCZAV3DXNXJQIWXHN5I224UW2AXJZ24MUTQNXOUZBYVUC6VKTOMZHRMWRMFCVRKNT7B6VVL3LFWGBZHOVLH3C3O2PAVPPU5VYXJKLNLNDSWYNMJJKFW32RS2ZJP327UTNSZNM7X3WIXZEEUPJT7TT2VPBNT6ZYXTEX2CLZRUHRJVENLVUL5OEDI6TUNGU4J24NH3VJMSAS4I3SO4QU2LDUZ6XLPYVEEKKJZCRPCCTW3LVF7CWU2CJ3JLYTIQ2VGWKPIXBA3WKBBEMXWFTIKK63UBCQUXFOXRWKHC5G4225FXLNPIK5HPKPDMBUXFHIU3X5RL3B3D4YXLC43C7YMT5OXT3FGY3NAOCKLKHTKMYRMGVKV6V2XRKAY3R4J4CAVCJ5SB6QNXR7FOPDNSPV6OUVC44FW4J2J3QTRNHHOYK5WIEUKIMHPA6DXSTSSNSI5OKFGPZMODTOQR3Z6B6XIJJIDSCAO63GRLEEWRSKQDBFSK2FN6WWUVAOIHCS34HGS7F4QILW72GYRCJD4FFH4N6AS6JFZDRDSTWYNJPR53HKIME6EN62G2HL4D2QUPPFLMTVBNZ5A6U424IRHOCMPU7OQIVEE76FTE4NTWA7YYFGI3ASBRZ66QKBAANGVV5DU4BR3SMH3QSZIZSK5RNSQDJO32ASYJDP4254QSHJNAWXHATI4SDXBBFUAN3S3KJYY3QBWSGY5DPTFFHCPN7NDJPTPMTUA23K4EZCAMAXXG7U2EB4WAEVCT6ZNSEBYYJL3GSBYWSAOUFHMRKMOS7KMBLZ5MDNCCDQ53UABQYS4YT7KJIJ66Y7SJPEQA5GZROXDY43AMQLV7RRCZVHAH2OVQRYHIGEEOGIXPQQQVDY5CHHE6R77X5R2XJLQWKA4T3OZENHAGSU5ZTHRSEDKGIGMSS5RMDFZP5GOK6NQO6Y7NNI5DVF4K3POKKFNIHMEO43UCDKJ5DTPUPEKVND3W4DQCQIKGEPUKUJZ42H2QRGDBJORX2XIPKDTFHOPGUQHXPS2FTZJDCXNZEK72QQU5YGUNKAVFUYTVZTBVXHAXBI5LHQ3N5BLN3UCUNXADABESVLWDIH6ILJ35EEMWO2XDIGL6WZZCC5MTLEGB2J6IMQKHJEXG5Q2UDVID27DPO3KRK6P5N4UOHR6SL2IR6ECQRM6NO2OEDKWANTBBC4JCDJH3WXBUGJ47B4FMCQX26YRM2DN54YEWHV6MCIJ7YCAT2RSDBLLCD54WWRLFKHEAWRQPJ2MT4JY4SIL4TSFGKSHYYMCZBI7SHRC4QET3QSJB5E4YFCL2YMKV3BXIYG2QN7CLG5OJF3IAL6D5EJJGYYFY4WEKJLX23SFXJ3QBO2Z4EI6TABUNG42LEDF66DCKW5OGTQ625MHRRFSJRQTZT3563MACVZJILQDWS5ICFEZZT6EKJSPIYGCLKDYSSOF4L3RY2NCM644QPASEDANBXEUOJCX5Q2WEBTR3J6VAHSCOWQHTPKUIP4TPNV6IJ63C5HCEPKOWA4ULM2W2ZQRFUD3PY6KLWB667ZDSF5CCCWUJZQKBNQH224H7MVO4RKPF2CU62452LYXHEB24GINL26LIHESZIO56IYGSXWT47JMEX4NQD22EHR6BWGYR2X5HUOERU3LJKCOA44KLMRVM4D473X2EWMO6QLNGEOCV3OSDURRSOKM22NDFLWCFPN6FWOQBTYYD3ME6RZ45CVRNUCATUU22E7VC525SLDNO2LN3QUJBM52LTDQ6XBLEAYPLXINFCUUEO2IZRK6EPXI5ZE24ZBEAUWZ46CAOHTKRJLF5NGZUUYRULV23BE5MVGIHRVXHY5CDXCCRFVEVUJR6HPK3IB2Q4NWTMO3JYA6ZCCEEC6MHLFYTILUJYCQUMG5VBJALXUVBSQ3NPE3SQRNCRWJHO7WZDQQCXFIQDYHXNADQPKCUTCCJYSA3DROXM3BFMD5KK5ZPNDRC7EFQFOK7DEAJ7HNURYQDZGOTNNJ7AVMRJEFQJYKJVAZ3LIB3ZU7HTPUUK4LSDJC3XSHPL22NHOUYQ3CIDWXUUW7KFR46GNEGWUYOI6NB4XEUA3DNX4HVV7AJPHX2IHEQXY5BS4KAPYOQWVDRZUIYRUG6OTVNNRD4EXNVS5KKJSS5GPQBTBMWWMTGQ3EIBFUIAM264PMLIVTWUVAFYILMDJ2YWKEFK37YRIY2H2J2AHYGFLS5QKV2CDB6TWWUOTHJZKCY7QYZQYTLDCBQF5YLLHBP2OTP2PAJ5A2CHJDB27SAC2PRD2SO2CE5BUKRQIY4TYVTMQDKBWO6354GTJBQKBVDZ3NJOCD46KNW2SXGOHQ4FH4LUV7YYLISL3ADYASBBL4ZUMH4DCTIGJWTX2MIMNNRQ7W2MRK2AJUP2MMKHR3BGOTVD5KCW42L6A6IDHLJCGUZ7Q6FOJ5254AUZRAF5MLQIE62XOEXSG57KAGD5II2ZQUET5DZDF3X3TA4D3G2EL7RVMNTSGRVJ3PBJSA2AHWWE47IMUXKQFFQQ3BFURLRPVDFZJP6JSCLQZRO2B6EYQ7FPX6MDTYVZSSUNFGVDX5Q5KMG3PWVIMIZIZM2OR6AYBBPIJBSNWWJQ3LCEZ43PB6VPJZZ66WRVXU24HBWTFLZY42CMCCYB6GIZCHJTPROLVDEOUB7XVTXUVAZT7UXYTCI7PX5WW26D572IEPEYWOJPFVYJ3VJW3BRWI26LNGPTDDTBNIZ5CZ7SQDAMBIV3WW5DPUXUPAJ3GLRUVBUX62F6PYCZED3NVEY7VVEG72IIXOM6K4FYDOUGRR7SOYOR24STHKWMDKUZWHG47TNRLGRIS5MLWJUVDZW764KB6WMTTCUXKEN7NNDWNTDBMXUJBRS77MSXZFFR2OI5FQ6LBR5JF3KP6UXDBMGMN5HAG2ORDALOG7XRPGGSJAF2NAXPGP3LI3MBEMCI5B6B64O7UZWYRTCIMDBQWEJZLTPLD2NEC5GDQ4TVWSL4IT3GYTCCMGVVLINEQWCMP4TJAV4H6NNWU3CNBDEE2P3TW6U5FDHEOKG4TCMMORVDC7O7TYFF2GO7OUHIFQMDYTNGBMHFTJ4PYNLGA5GHMGFPZSKU2UZILPBZVUCBNRN4LKNDOKLBGGLMKYCFEWBYGSCBX6ZJDGMHKU5TYNM4WMURNQULD6SO7LRTUXFQ7JAH2WPXCFEM6ODOJTJIHVJQAJASEXDJT4CWFDR6AIEYYXYQIB2FOZ3V5ORQS3KEMJV66FZWGVVCUEO57LDRJU2SG24XG2SSWZZM73QGLK6OPLVUD6TUZO6IASNMQLGZJTV23WQ4MIGTAIXW2ZV2Q2ZNPM7D3DUUOVZMC3WKSJ3HH3PV65W2ZGQMVPE6YL6FY5Q2NOBSHDKBWYOZBVRDAHFGH2B2SZ4DRP6ZF5KPZBUAUSSEAWBSKTHRWBFAHLZ5OWPDDI342C77IAPBGHZWV5IO6UTGGAZWPT6U4XZQ3Z42XTBIJBE3S7BP4BTOURVB2TA4SHGFXZVOZED2XA3HS3HDUYZXVIY66TGXDA53DYWA2QPOELQOSH3ZVAEMCH6M5FBV6TCHN56MJZRTYMIDMLJKRAIBIYO7TBLHDMDSL4WOUCY7D7JTHTS7XZ5PD47777H57NPT772QZP7N77YBEODVPGQ=END diff -Nru python-hypothesis-3.44.1/benchmark-data/arraysvar-valid=always-interesting=usually python-hypothesis-3.71.11/benchmark-data/arraysvar-valid=always-interesting=usually --- python-hypothesis-3.44.1/benchmark-data/arraysvar-valid=always-interesting=usually 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/arraysvar-valid=always-interesting=usually 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for arraysvar [arrays(dtype='int8', shape=integers(min_value=0, max_value=10))], with the validity -# condition "always" and the interestingness condition "usually". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 409 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 7.44 bytes, standard deviation: 18.30 bytes -# -# Additional interesting statistics: -# -# * Ranging from 2 [900 times] to 138 [once] bytes. -# * Median size: 2 -# * 99% of examples had at least 2 bytes -# * 99% of examples had at most 100 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 576: STARTPCOLKV2JN3CCAEH4BLZNSB625T4UUNFX7CILG34J6L3RRYJQFRW5G6EIKSJBCSZPIV3QS72P3PT5POSNN7WB3AGPNSMRSLHBDMQOLX6IRJ6Y3O3ERUBCTYWIZRGHJHINKBAN4KSMDTMTVEXH4JQ5REANT5A67WPJ2J3RTFDY3FGUNB4OT2XZR4F3TJ32KVL2ATOX5MBWQAVSJFNLTNKYHHAEYDAPR5IVV72GE3NDNHFVBOSR2VGAESGCYGAKZLQ3KXL2MLT43R7VIUZPVQT7AXRAWJLJOJMVZLA6BWFMIJT47AHIEH26JDKGQTGN2MHNYBU37E5PJRBQFX2FIS52U2EAXQ57JICECFDDTBKECEKEGEMNNLXA3BZ2GJMTSBLHPB3YR3DZ4A62E2JLWQNUJILJWBCEFW3PANL4XHPXMKFTX2LYGDOIN27KXYTBIKXE7WX22AXWOUTA44RFKH4JDR4OV2BVBDKGUGTY2EZXAQTSEX24XS6E5RLLD7YGQSIWDV2YQ6FJFKSZC6VZJ762SSGJGSYX75MTRDD4ZJTNLU77N7YFZHO46LZ2QYFPQ===END diff -Nru python-hypothesis-3.44.1/benchmark-data/arraysvar-valid=usually-interesting=array_average python-hypothesis-3.71.11/benchmark-data/arraysvar-valid=usually-interesting=array_average --- python-hypothesis-3.44.1/benchmark-data/arraysvar-valid=usually-interesting=array_average 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/arraysvar-valid=usually-interesting=array_average 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for arraysvar [arrays(dtype='int8', shape=integers(min_value=0, max_value=10))], with the validity -# condition "usually" and the interestingness condition "array_average". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 419 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 593.62 bytes, standard deviation: 408.75 bytes -# -# Additional interesting statistics: -# -# * Ranging from 25 [once] to 1786 [once] bytes. -# * Median size: 639 -# * 99% of examples had at least 55 bytes -# * 99% of examples had at most 1410 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 3176: STARTPCOD3GBZWIS3WDKEW7JND5RTJBYAF72WCTZNJBXM55E2DPMLPGJCZI3PKS76FABBSFENI737776677747H57OX577ZIWP6PZKVD776MVNPUCTT2PZH4PTNOG7L45LWTZWOZZ3H7TV7LNBH5UMPLLHI47S5VZ7H5I6P6K3HYXPNXK223HMG2K3PL2XXHVCOVTJ3OVDJ6663ZZG3GWDXRZYF7LNTEHNDTKKV35IY2LUZHNP6WU23JFE544T7M27NLNJZGNMXXZKHFZV3YR47VD4Z7POIPLWLVIIVXWVV7DYYAV2IYPOVSAY7HFV2VBLZ5MVW7VLXOPUVCVXI3I3VY2XLWFDUC6XTU2TBZLM2MLDRV3UOHFD3762W3BFCFG3F2ZJE6M4Q6IWERMW253F2X45PO2IDGBLMP5YWOGX4FHMDRVEJFRIXTC4OL5ILA263SPPQPVUKR3NIT5CMPE66Y3FM2Q24GDSOPFPTTS5DBIISJOHWQYZ5TOOOWLBPLFITDUIXO7W6MZLKUORLFRWVMVSL6K35KDBZBJH72UKERAZCBSJ5GRCRBNSLYAMZKYUQWAYRU6LRCYBGCTTGW52U63EGXPQ5B2PWGFAPUJNX2TEGXYIEHIAKSJBTKLR2TQEP3UYMPA6NRBEM3NKILDCM4IZ34ECNHZZJ32ASCXA2A4IE42ZJER3MSASASRSDNQCEQKBYAOQUFJUTRLEFD3KCYZLJM47M5BTHPMQFK5KSPDEJQXAK3CZJATQJLSLZDW2ZY5UAVWBKZ77O3C4AMECWOBTUKJV3M6INHLKUIFD2SEYEF733CFRH3APIWNIZBLHJ4TYKQV6QVIB4ORZIME465BCTTQJQZFOEZNAC3KLYW5ZKMQFIHEQVYLEQNB6KPX3XOETT5TTWQMKLFCWX45LOB5AVPSFZNQGUWTMXCZCCABSMVQWSZXME6VOTLKHVEZ7TSUATCTHEGUFEGK2DU6LUXTENXVTDFAAKI5KS3VYJSFILEYMGAJBUCSMCXO6OORFYWJARJEKSCJ4F4ZXWC4XURE5PK7SAAVLHQQBUQU6CAGJJIJAT2MEBMR32X5FPPLEYZQZ3EK6KUQG4EE2F3W7W35WCTHNHOOEUA5KJE2TGTXYYJ26MCRWGRCKCDFVU5MBYQ2Q4ZG4UUCHLX7FAQ6KO2HYNZIL2X53G7EDZ4TUT2KKDANRZLCVIIWJATUUKRJZQMEUXZCW42G3HTOWUHBYKRFWNHERIAIJVONN6WBXNKOLZKEKSKFAQKK32QDPQ7D3FGUKNZVYNDPL44PCVSPCE7FVTWL27INWEUSANXIBCX3K6J6HENYXNW2KE4IQENILU5A7VFXSRFBKL6TE2K4XQ2OPBYWLHR2GAV2FBUJOG2TLV4QUWMU7SBFBZ5NJB4AGF4AQZLBTWP3QIZUJWPOVKW36WSYV5XBWTOVQBJC2QFYRWTYNN3SJ4IYATEWZRMYV5H2O3QEPJ4FJQ4KAXVI4SAJ6ZAYMTLAYCTRATQCNI6UOMRXJSY5DTWMBCTIBNPG23IDFGSJL5MHML3OL27I6UZBATLNGUBAAVVAMBVEMF2NKLOVCPQ3LPZKG7FEKPPFQNTZTO2CKTEFRHTYK5SVMROGQQNG5GSL3XKIQEONASX3JZ26L2QSJBYSHIIDTHG7KUK6DWQZPMR5VKV4QCUO4MUYSZ55V63RWNX4W7VBG27542WBKO5NI5JSNLZG2QBAWCQCXU6P2VFPOSB6NRVNPDIKWXBMSEQ3JZSOBBMQLLMCBBYGYIONGJFGCPHXRWFVKVYRYKF5FESRYSYOPUYGE55PE4C45YRPEW6QGREHY2UBLOU2QVHOVSOAIEV3IVKZLDTQYESXSTBXUJJ4VKSVDWLPU5KOXIXD3TURAUFUBCPT3UP7T23NWLQD4UBWK4VZTPZKOIL42Q4X3QEOU6EIUJHJWO37LG3SK3S2C343AGARWBISYAK3LN4UEJ5DHX5F7ZGTJHCXZWOY5CYIJMRIJZNTKQB7H2HOSUUKBGKYG3UCBUFUVPK5F56IL6MXWZSX7V6PSMJQV7OKVO5LOCIVYAUNBLKZEXDWWRAFVIAATH3OMVVFS6IZYYIW56MIUQEBHUZUIADFAVM33S66DISBJCSEUVBZOVF4Y6R3TBGXNM26J47FULZ2X2TFXM6TFOFAURAUALL3U3GO54DAQ2BST6YA5ITDOJI5ZQWK4FKRS65XYC54Q4PGQVQ3X2L3QXDXQZKAEFIERHANIGDWYT2IJROYSTGGFAIPLKVMUCLZAWGOD7MAM6UW6YLEL7LKYK2ORFLDGC4LTIBYK7R7EG4FK7O5IOKEOZ5QFAACXZXKAVENFNAKZKJOJ4TZVJVMFMJ33GSGAR7QZUQJREQOTYSNJ7RQ3ESL5W5NL27FOYOESE452NYJST4VSL3PIPGBULSWSWADCGVNKCC4W5EZRKZ5NBA3JJAA6VSLKAYFRU32PTOXSJHZZKWLUQ33UUS63LILFLUTUY5UMWHC2DZZP7Q6NYHOKG3LMF7VSOKIAAOAWU5BVSSIVASS3FLG54YO5XHNYJQBFJN6FTKAFZSIHV3GLHJL64NVGJ6FBQMWESGBN43RUNTU7E435B3VR4CT3VMM2UK3H227V4N2Y4V7JZT4DFCIUX6V6NKTP6WIURWRSVDPEZO345TSXBPS5ZQ5R7MK6J2SYYEBLJD3ACXPMJTTFIMUDJJUPMMGCQDD22JI7HX4ONPM3EYUJVIJX3NC2PBIOEUHV2U56TUL6F2EC2GKK4BGRQSXC3DO46ESQ4EKDKERD5C5ZWYFNBTL4W5NUNPRDVYEQXLL5GL3GMJ5ZSLEXXXOITPGGM7C7ZA5KNG7FDAOIGT3PGTGYKN577DVKDF2JDUGP3BQCRIGDVPMLZAJTQHTMQOG3Z3ZBLSUO645TIMWNGLEDUH4PTNL34UN4CUWLBTRKZRMPBCYUA6WPR2NTOXR32356LYOOEQJUVSYZUCNBXRXTUMFP3DIY7SRZKNE7QZTW7IZ6PAJ65LTYDQPD5BTYAYQNWYIB5FFQTPHZZOB33JTUX47JCVL7SBYJTSZKBMT4O3JR3MP6W3366ARFVH3NCGQILRXV2RD7SG6K7KMXCBG6XFO6JL2L2GPATDOIYPRJPI256WPT5P377766PTV7P77SKA776Z7JF7KVII=END diff -Nru python-hypothesis-3.44.1/benchmark-data/arraysvar-valid=usually-interesting=size_lower_bound python-hypothesis-3.71.11/benchmark-data/arraysvar-valid=usually-interesting=size_lower_bound --- python-hypothesis-3.44.1/benchmark-data/arraysvar-valid=usually-interesting=size_lower_bound 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/arraysvar-valid=usually-interesting=size_lower_bound 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for arraysvar [arrays(dtype='int8', shape=integers(min_value=0, max_value=10))], with the validity -# condition "usually" and the interestingness condition "size_lower_bound". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 412 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 14057.69 bytes, standard deviation: 19622.91 bytes -# -# Additional interesting statistics: -# -# * Ranging from 2 [14 times] to 138211 [once] bytes. -# * Median size: 5749 -# * 99% of examples had at least 2 bytes -# * 99% of examples had at most 89609 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 4200: STARTPCOELGBROKSLWDMEV6RNUWABAGJCB6NO4J5JSN3QXSMV3PV3XM74ZLQVJCRZS72ICBUHIN7YT4P377XV56P367X46X2Y6HBT2335PDP272VJTX276O6RK6V547575CTTR774Y6H2PRLO37P5OX6NNXBT6U5N4KT5CLR6JVV366LL4O3T5KRVU636P5SV272D77TYRVH2PHX5CW4ZOOHO7LZVT57EOTL7ZXV53YLAVZBAVVV72PN2PX4YO55I6GNRWTHJ3U272EZ3PTRZLLYQYR2QFS7I6FT4Y6QZ33KTTXZHE23PH44VS63JDU73AMV42R6Q455FP6H6KDJTYPD332PA5Z6T4RAOFUYNP5H2M44MYOXP7AQDVHVWP7BU64LOIWZ46GR635ET6M7DQYPSDCFVS475T53JSERLUTE7MOHO3HLC5L2XTV4LJQD6H5O6JW7TYRL6C35WTM7HGQ6EPNF5RMLM64N5YYUC75JYOT5LA24ES2U7IAST2HUYHUEPO6WUXOMKM6EWOJUZLHLWTV22W7ELQE37LVNZLDJVD74PDW3HSFEQPHMOEOOMBYHF2JIQ2II7674G3H5PKT77OKKUY32RPFSBILMLCB3LVB2CBVCPD2D6ETNO5M2M6IGZY3IF3DROYNEVKKI524PAJLDVCTHQLVX3SDNOW45JAADP2CDHG33PF4LOBWPSFDKZ5IBBYQ5B53ZFHK4OG43TVXTYQMWPV25ZU2LVIH5YDUVN2TVKEAVZPX224VZAWDIGZHNJ2CND7HWUX2YZFVMZWPFYEMKWJORQDNMPU22GIG6NT72SIBA4KR2LOA7O64UCNGKTK55FT57BI5POER3Q3DLQR3HLY3XSIFQ5QITIMQ25Z4ABYB2K4DLAJGW5O5FR2N4TYQCQKHV7PHS64YMQV445OREQ4Z5LODEG73MOHC6MSMWHWCCA524XY3RX45FNVPVJKBVEUFJLVRSLQAMC45JYU42BANI4MEMKJFRSADPKKRAOK6N7VLLQ4PSXEFNHPM3NIXCG3EMG4XJVJ65BYLVUKMMH5RODZLHGG44D3RQFES54R3LAWRWCF7SRF3PKSI77VUCZ6ORD5BVRSB53WJMVKDLULPERWBV3FR3TFEVLMN4HAF3G5LY4M4LDB5DZAQISONPHPCHHGNVRDAKCVGIXKWUK4KGQP6TAVNNNMF3JIHOD3CIUFCG6CAPL4BVPL7A4LYVFZ253VUBZC255BDIU3XMYFOHPJFJVDGQZOTNE2RB6SGYTGOXFV5JSPZHS6FZAF7DEOUIDBGRD32QPGPKKX6LFX6TOENR333JOCP7TOFYAQGQF3ZVIJ7UE2DXK3ZY4DLI7ERP3TQKG6YTMXME34GZNKMPSQMHOLOIJHK6TIFCK6ACWXUOHGMNCWA5MV5VZEEUDDADWEOA7BCEAULWOYADHMSSPILG75ZJ4DYTVBO2A5FS2ZT4JF3XGW6ITCNB5GSFLDZZXNV4AUPDXA66HBYT7RJD3UVDLPDGXVTQ7PJ2IPSATMSDYIDM6XIYMS4DHQFHXUK3QFD57ASK5M5S7S6MLYDC73DGVI2O6HEHP2TJEYRIGUNE2N4H22K3F6N3IMWNWRQEO57PHDFJHL2USZ2BUJRSHGSIOMQHGYXCESQ5Z2JXY3SJ7F3V323JCTT2KB3PSHFCNTD36F4YR4EDRW34OUQEUWAPUNQYSRIENQROAJMSKUXF466IPKAU6N7I4RUHOYJ2GRRMJLBNVZLUVKPP3VQD5ULT6ATVLDPWNTUSWQODHB7AS5D2OSFWSRHHIJVWCFCQLUE5WZVTZ5VMCKZAGH6QOE7Z62ZUEIUG5YAQFOWE3ULL35D4LC5SWECA2VADXXCV2DXVKPHIYHZFZRRXFWI7KTHGKIBMGWOVQ6LAKOF6QDLO6AEEPI2GBROZV2AAETUC7A4KLMWICXKKAAF5FUOGDWNURRQYEG26Q2QITZOSEBK2QY3LIOYDFYHNQJJLKNTYOHRBVIDLXDCNP3XTGK7LBMM3KR3SH4OXXFBZTPTHNMHWQU6N3QRIQXFB7ZID5FEMNIBEFJ2NDDXZEJURJPQVYXFZYLOSNHKVSSPF2R2DYZNUKICGROSL2GD54AGFW6EK5AA5LMA6YJQRXDD4ZQG2RXDJS2UBU4FFAY7A6ZATGAPXVC6VODT2VSNBRFE4DZBQQFGPDFIVFXHKWD6UBWUBBIQN2D6GUY5GY5JRKPUTLPYAEQBQG7FBDRIFERB5QGWRVDADOFZVNPNFVWFF4GSG4QBPVS665OD4XT24RMZS257MNLFKFDEGGCFW4YW4P47QE6GB3BWQLZ6H6KZ4HI2MKHPQXNH5HSYVTH54CNQK4J3W4XMD4774NL7RDMT5H7R6YNA3OATVWEU4GON3HMG5WA7XTZFFIWEKG2VYOSQYREKVP2VHFGX5F7MDUWPQOWYEFNGBBMQUBIK3KGKVNGJHEOUF5ISL2ZTL66MMOSDSMAAYGUPKN36KRO2KPPILLANGT73J747ARGAEGQE235LPT4VZHX4PXLKLDU4IPJP5OVUEE4QET3Q6TXZVEOWIUOIYEUSGOTLMQY3Z2KH6DRULDWJYDOTXUSK7XXUAT43B75A4PBK732TURSNFSVGMMARR3HS36XWI2WRJPATZFOZ7Q5GAH6YJAKKT5DDABAE2FB47THKXQ65X74NHCPTTGUJLJ6PCKMYB4PZPADFE443U3QKJHNM7M7UUQU42X634IXK7L7EZC6I7CVALAWA2ZAKDZW2IXELLNUFEHNZUWMRKAC3KC6APBHDKRHYGCGJIXXCHWAQPNOB7JCF4OHYK4EAU3TQYYHVFVTGBGOMCHUIESIU5CAHL4YQXMO4IGFCNMYPC3WJ3H4W7SYXAHMMBZ6KYI2AFSSS3TGKK2GQSMRNKGLYMADQEIUTQCJ6MN6WM7XI7H5F2TUVG4YI7AJMTOPNRX7ZPWJBPA34H3GFYYCZQZLHHC3ZSTUMQM47O2JMLZHHSCQAS4OZHAWQ6YUFOVSOHES47DWFUKZDNADKHBRCMDBNVQWP7RHLREE4BDS334SRNVWTJIOPTQ43EQ5QP4HEKVJNNJALPHQHW3K4GHQWYBLDK2FPJY6ZQRVLF4T44TZYGSPIPSO5Z7IKUQGMAGPY3GHTDMI463CWEOPD2DYV7Y27K73YXMWRRWDZWOX2P5R5L3ELK7562TI34FXPIIZILIUJ2PAUERN7Q3TGLE7WIIE7BL27I6FIXSAQICTAL26OO32YIYPTHMY6NPIROD6ODNL47ZAUVPCYHAT24OGN27BIXED352ENF3JDFPIB45ZLLSN5MAYUQWN4GIBTYEEDJOZRTSVJSNYMAXKS63QM7QCQYBQPR7KMMLBPD5SFYGS4AXHCQS64TWOZ5XBYEJMHCBUMC3RO43TTPSQTJJALZ2VBGSAVCFX7ROY63ES6BXFUHK3ZUPQ4H56DT2CFWT6MTVSXGU5AVU5CQ2MYASLY24GBCSUNSDAGAGW67C7DF6YKDLYBMIYWOCSBEDEH5XLGEDWNMUL7AXML3OH35DU2LQKNBVOM7J6TUO63SH6SMDFZDY3L6AFKN5SCL6VG4VQVMIT34NGCZVDNAREBG4374PVUHQHFETOIYZK7MLE24QDJTH6V2V5II3RREHE6FDU4YHQYNWNBPMMKU442KBHPM7RJZ5LNZ2HUAH2NHML2X4A5GUC5LKXCPZW4BUOBIGW5I5YYPM66T6SP7OTZUVZAFEOHU5G6VNVRO7VTKYOXLMMAO6HMU5RPO4EJTPGE5D47ATOL52OYY5MB2JYDLIX5YYTMKD6LIMFDYTJDE3PUIXIAWG2A7T34ZTE3ADQD2G4YNDFW7LLKGJZBG37YGPKVXJVCTSSZHGNN24COG6JZ2UGAA5UYCWOG2JWNHJ7VA4IGAPPQ36ROEM43PDHDG22FFKCVFL7KIQWNBA6IBKTW223R3MBWE2PGIX73F4OE3U7LTDTLFJJDU7OTO646RHAG2DGVD46EKAIIZQ6PUDVO2JIBVWKK67MUHAVL6T3PNLTEPRPBBOBQ2JS2YLMULPNXL56O2GQUIN4MA66M2BJ2DBJOBMDFFLV7NQ6BWVEDZVILAK3MHTGMWUG4FTHUWHPNQ5FGZ3X7BZQ6QH7KL6ZA7SGDG45QNCF5L2474PX67LY6XZ6P777HRS7D55776R623UM4KQ====END diff -Nru python-hypothesis-3.44.1/benchmark-data/intlists-valid=always-interesting=always python-hypothesis-3.71.11/benchmark-data/intlists-valid=always-interesting=always --- python-hypothesis-3.44.1/benchmark-data/intlists-valid=always-interesting=always 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/intlists-valid=always-interesting=always 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for intlists [lists(elements=integers())], with the validity -# condition "always" and the interestingness condition "always". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 378 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 2.00 bytes, standard deviation: 0.00 bytes -# -# Additional interesting statistics: -# -# * Ranging from 2 [1000 times] to 2 [1000 times] bytes. -# * Median size: 2 -# * 99% of examples had at least 2 bytes -# * 99% of examples had at most 2 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 96: STARTPCOKWVRKZ2WEULKWWJJIQNWSKEMELI3ICSG2EUJURJDNCKA2IWRWQFANNIKKXI5AKSOJVGQCNTARXG232QBABUPE6OOQ====END diff -Nru python-hypothesis-3.44.1/benchmark-data/intlists-valid=always-interesting=has_duplicates python-hypothesis-3.71.11/benchmark-data/intlists-valid=always-interesting=has_duplicates --- python-hypothesis-3.44.1/benchmark-data/intlists-valid=always-interesting=has_duplicates 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/intlists-valid=always-interesting=has_duplicates 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for intlists [lists(elements=integers())], with the validity -# condition "always" and the interestingness condition "has_duplicates". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 414 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 2946.87 bytes, standard deviation: 1606.30 bytes -# -# Additional interesting statistics: -# -# * Ranging from 526 [once] to 14321 [once] bytes. -# * Median size: 2554 -# * 99% of examples had at least 786 bytes -# * 99% of examples had at most 8342 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 3968: STARTPCOD3GB3SISDODCEV4ZLD5QYYSD37PMKIKPNNEF5TYKLVO4QB5K625DUKSZVSBEQTFEPBXY7X7775Z6X54PT7P766AZ4754XLXZ66L57EPV7XMKR37BW47NOLXHXHWNO467NP52XDSX6PNSWVX2BD6T67HGK274NKPVWH2C76MOD3WOJ6O2FUMZN6SCDLMNPKZDO3GLR6TVRSQ77DJNGH57ILWTLO3FPE63PPVQJWVB65E22XGT7M5GWN7JT4UOPYO6Z5O27IW2JP7TFUH65PVVP7QV5PUX6OHTHWEULPG23GVT2HCP2W5U6UZHY6DE5OYXO3PBYQMP62332K6CVVP2OTXM4NVFJQYH32JNVP2NHNS6FNGHTEOMM77PDVT46PLRZ5ZGHVBBIZ5PGFKHSVEUZKQTXRO4RHV645HMT7QIJ2PTHV3F44OWJX3KOF4G6UGUGHH3XA5HWK2NGNN7XE22TOHM536XUUW5FBR25I5KAKVMXWVB7TDFLL6LSE5IDE5SN4YYS5FYNM23FQIS37HBK46F2LLUOVVBYZO3DHFSETMOH5KJQWD2KKLAVAINGL25QRKDSHIEXC22LEAYFY72NUUZZMQHNA4QFZETEHJNGDGTE5DEJHZ3WR3FD5L36HVFHGP7RYLZ7OV37LX5FHRNM56TWHU4P3E6CCX66LC72CLMXLZKYAVA6R77FKZZ2EBKWQ626VO6HX2XYAVHGL3MIKEY2PAZHGB3ZL4JZVEGWYOORDCBJ6QSYNQ6Z7CZ5V4MGRNXUHSCKOGMNE7YJ3KMVQOOSPCLU2VXYMMQ6ZZN7ZTHX5WLDB7CODAC35SMD7ESD2STWSVSSXKOKRFO6URZMPFTXY5Q3IJZVBLSCFWMFAXAVRORINK2VSA5PGAINYVSLEJFEHYMR5CTL3JSAOGD6KWXFUTVZRQUHIQUEFBA4TEKCCQT7NC3UHMYOG3CAELCPSAVB7S7XAAJ4YQYGGTJJCOVCH6FNMQPVG3KKBCSIQN4UNNLV3C6SVCQBQVV75I2BWZSMOSIWUQO5UKY3MXAKFIN64Q7SSR5WUCKZUTHGT42TZFRKKKTDQL4EERKLM5VM2XVDWUF6RK6OK6JANZA3BGSVNKBKTJ2VZO4HMIVE4ER5YA3RIYIGVANWBSOQMUYH7UO43CWWQSXLQCEKBPMQBR5PL2ILHVBAWKT22UXBIT5G2ZLS4NZEKP4AKRHNIBXJNE6F2V56U6IKHEKZLPS7SKJZGGQGZKS3ZLRUWIYIISMHGUHNVF2QKEFH4XWVFOPMGRHU5MVJWBKJMFURE5PIRV44B5XQZYKSYGFIDM4XDMJG7TBHCMJ25BGKKZNIDCP2SGSMKCLHJQKKVL7HLVOPNB3A6ZIRWSRA4QDMJDU3BZWZAVATAJD5SXWAWOJIDLDZYQAKSGYOQ5SMRM4QWGVRZ5IYRFI5UQEPUPXQTVSBAVVDDIOQSG4XCIR2CQZZBVQ2LZCCGEWMKCMQJKZIGGAU4CALNA3X2CXCY2OYMEWSGCFXSF3DL5NAAEPZAOAE75GAFPEXBKP7KPUPVPOFOHIQNNKWG35RVMSCZYNN2BSKIKHIXHUF6MKZRFBCGJ7UT7MBHGT4XTLOM7HMANYE6YA5EH5NO4QDIZWIGPJRQEKX3DQ4DUKB2TRYOG5GZUHZBKA7IY3CLMLRYNW6LIKYJDKKXVHD6E66FHNNTDTHVCCNWDBVOJZNDPKAA44SJZZIOPYVRJSALSNBYKWMAPQW5MSISVB2HQGIHUIAMM5V6F4Q62GR5HWV6LZSI67NUJQ5MR5Q5AVYWQF3VLZDGJNQMJXWEAGVJWEUDBBTJ7KC35XCGKCRUWKFMA4CO3LUBIQSNPCKONS3FEUYDMNXAWK7P4OXMQLKLKDFKBXKZIDDAUGWUDQKGJT4WCJNCTIVV7ELUY3X2ADFETPGBX4RZGUUF4O6QE4XTBG6SFMXIWV3EU5F37GHM6UFYJ7QA4VVW6AO3BD6EB5NKKSUWJF2EW3PUCYASFI2ZPCBX4B2AFHPXXOUFIOALGEAPAW2RJYYBUVY5ADNBIDJSW2PPL2Q7JQTO6LOCYFA7ZMONE763BZYM7N5JDL2DCDDAWADL5F4YHAL2PVSLHCLU3APOQDHZC6GCFY3OUDYIIBI3XARZJE53WGEZ7CHWOOOGL744YTESJHY5EYY27TZ4SZNUPKJUADUYEUJZC2TDW6DL3DBPFZI7BAMPAD4ML3PN7FEVWIKIISTVABIKPQNL7U3AEOHSMAWH3JRQ6OBBWE6YQWTKYCRJDCK5MAIRWGLO25G5FZZN35ZV5EBPL7UHF426AO3VU32MMMLAA2KPADFELHLWMSR3IBAEXQNS7EZIUBKZUNORQRMSLLJ4LD2JJBR3H7TJDFLFQOODJP62IZP72GHZYRDSZNEUCMAADXGHPUOUP6BMJDO4HXJSTBLAMQ6TRSSY43UBBCTTI6W6YLICRR3C6T6MYZDUTQJM3QDQ2IY5U55O6IVOPTO5OXHA7TAA7ZBYVG7D2VAROUNSB4XJSNWTVKYHWXGBFISBOI53FAFSMFXUQTNOENC57XAJUMECBWKQ7C2Z4FVS6O3MKPZ3JM4OQG4YGJB4NJAGY7LCPAZM44TJEGJMTS5JB3ZR5E2SZU36YDKUMAT25UYOMCA3RRNNPPNWLYELOEF6LGHIOHQOUPU6IXHQ5LV2CMOZBMQN35CZWLZPVUTGHXJXY5WCESSQVEJCSGWJEG5KLDZENUO4J2BRPADQ23NWUXUEBY6SLMMF2E443IKDWNTCBULLL2OTLN35J4E7R536WWM2BBQNEOKKHGIGX7KHY664BXXO57N3TGEMHVIYWRTW4WHRMGX72VYZNBMMJZXYG2OR7O6JNEI5GRALQAQOCXKPAHSU42UTH53Y7GRTXUJ7DAGCGGE7QF3WUG3IGIDJT3VRYYCYAPKXR6LDEAUU4G2YL3KRA7K563PA6B2VXMYU77B42TUWC2R5HSFVIYG463PVCAUUIAIYHKEMZFWIAU72ERR35YUYFMNDD46LON6YOKB7EFPJI26RY2K2NVGJAA4E2EIQDRQ4HDDWVGWITD4KSHXHDTFFGHLIENDJMR6M5A3UNL5Q3WWWREJ53XBLAS2ZHGAKK7L232PNCYUNY2UYLFKXIYERONQ4WXJW354FM63MHGMJWSGLM4Y5TENRFPW4MI2QYSG5DWW4Y3NHMEJNGCQSJMYGIJD6X5FIPK3Q64KKZGTIGCL2EBFA4YQJJ4ZX62YOCEUYFNWJOGQDXW5MJ47X3WJR5KKSB2OHRSI5A72KDENX52WQIPL5LV4I6VROUVBUBVSRBZM2YBSV6C3HAFINSO36XTHZCVTQYR44QJPYDONU2BQOMBUIL5O5ZB6PROOUAWIC3NJ73KXO4XW7WM55MOKFM7NSKM7RII6BFTBGZA446L3I72WE2FCGUJSWWQH5FPANZEEH7GG2MDE6TSGGNE4XYSCTQOMC7ST2DGUMB2RANAG53NSBH7PEBLAGDTGQH3NRQ3X373UZWQIMJV2P6YCS5VQJELI77B53WPO6ZYI3A4S6VSQKPLBZVXOGLPVZVUSZSOFHVJSPY2SWKTG7PPFSAVMPB3B4AG3DK4R4YZIJUQUGYLY46CTU64WCVLGL3LOPR4TTW7D4C64MHBM527HDWOCVTN2XJQ7JWCYE6563SJIBCRUIX5KHJBXPNBF5HVSYZ3CZ7UHUILR7OIQFUSKLM6H2MIB3GM5KH2ZIOHRH7JKXNCHOYJ4DXRNW6TOOYNIOCVABUCSV6GYSC7BYRHO3OH24YAG5D3NJ6J74N6PVUTNLXQ4RTAGXG5L757FZXVFSCFZHN6VC4C62KKQCYLAU5CXM3RRGUKSDNUUJPGJ4EIDAZRHYEQK45WU7TYVGCDDDTTDKSYWTEVAYRQD5I7MJ2XPROG6YUBJOJIYP57H77PY7XV5OXZ7P2FA3775B6AOOWE4END diff -Nru python-hypothesis-3.44.1/benchmark-data/intlists-valid=always-interesting=lower_bound python-hypothesis-3.71.11/benchmark-data/intlists-valid=always-interesting=lower_bound --- python-hypothesis-3.44.1/benchmark-data/intlists-valid=always-interesting=lower_bound 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/intlists-valid=always-interesting=lower_bound 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for intlists [lists(elements=integers())], with the validity -# condition "always" and the interestingness condition "lower_bound". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 380 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 771.53 bytes, standard deviation: 922.53 bytes -# -# Additional interesting statistics: -# -# * Ranging from 2 [6 times] to 8880 [once] bytes. -# * Median size: 529 -# * 99% of examples had at least 10 bytes -# * 99% of examples had at most 6150 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 3208: STARTPCOF3GB5WISLSDMEV4ZPD3BRJAIPZW5LFDSO2GDLR63RXOV3TAPYA7QKHEK5LXKVESIEQJES7XH5P357737PL67LR4P772TD7DHR63X3LX3LWG3LX3N35XWFVS63W47GXO3P3PQYN3XXM5G5RWPT7VR257XL5D655X6WF3JOFX2S5O277X2B4GVGRNLLN4I6H55HZH5FD7PLUU73JTLNDNVOAXWLZD5W47NXYNHNNV3PLUF3LXDRLQGQS6XJ7OV65WXG6VT7EEWL76X4C24PPPLP6M6X7GT6DXX5OPPV425AURQB7PLMNOT3LG7MPF6NV2LRJWHJ3JJ3C6ZDP662UJNX2I7VWG56V5OACD7LTHAAHJZHJ27LIYYXNTWW2OEV5YMUWQJLQCU7RR6V3ZFU6OQBFBANWSTE5PNNWVB6LXLQAUU35S7PFDSFACWW73NZWXJBSIHZLU2323PGHXYSJA2X4CRRQK7QVHOBZOCH2PHFXOOPWW2J4IQVC4ABCPCYYOKNPXMUJCCZSVYFK3OVYW6CVEWUJJ2XQHTTYWVVVMVOZJNHZGRM7JLVAWWDB5KNKARYXNF2BLPRJBDPVUW74UO5NHNFI5DT2HWZBXCQBHL5KF3OQXZRNELX25CXXL2FXVCEKI7DGFHHCVUPL5YRMLFNNWCZMSEO2FNN5OSAPPKVCDVX5DVU2KNKYS7BWXKBJBOWDL7IDV635YBLMZXZCYRPCV5J5EJBF3O4DCNZIRL6CRTOHMJBZRNQUWTY6WDH3QU7HJFCKGMFGNLS5VRSABKJJUQR7UPGAT5VSU3ZNVA3GSK557IAMJWMABZ2WNCL5NHFLKU3ZI4SCIKLXY6U2L2ZAJBIHOILPUNQLPBXUA6FTSVBGW5WUQKSPUE4JMLYIXWFKLFMCMJNJNODNA5TSNZHXUXEBRMTPPEJZ7BPYJDK7OJFUFWQTDY3DMEXMC2SRBRIRC6WUSGNB7AKJW4ENUHUZTXIUT57J2RZS3YKUPJROMCRJJDS6U635AMEUIBJIFPSR2CSJAWEBBYHU2Z6PR2AS6BMMZ3UMSYPLVNNZWKX2TNLBUIUL4LXX7UBNNM36VZQP2CAPPAEAUJBOTBHNSZ2JZE2TI5HIKP64ITUPLHUFJBKFRNWVXCOXO6ME6ASDTK5QQGCSJSGTJNMLMI5C5VUQREUAIP7OJWXMEF7EMMK7KX4CRJVT3UZ4MCQ2WQHDWFSN5Y2ANIIYBTWFJX2SL5JEBM4SHKC5RC47PIDFSXKENWCBW3LCYKHVZXD7WLRO7UFCSCCZMCZDDV2A5CQUEJ7FKV2UQIFTC2GYP6QXUDXX2LCJL5EPZRB2BQZMCJYO4X5YBPQLWPSMJ4OTHVDQCRDCV2Q7UBFRNHFOSS3GQFS7QPQUAEE2PWRO2II7UWGMTYZTW2CVNQOCZSESPWS32QZ4J6QEWMX6TXKZ3EENLG2TJAE2VFF7MYXIIN3LTVJJEQBS6GZPAFHLJ7DR32XVXGPZZ6WT7FHTJFVQ75GTCKWN5KVWMAQHQWAZ2XNFVKFVUYRARCPOFBU45XVCDBYTCOU6LEUXCJULST7BHLDKTKEHT3M43QBVGL5O7YWUQ6JGGZ7QXOVIH26M2CJBUAN3YFL42QSW2MKKPFPMCBIDZMXBRET3KQBA3NICREG4MMG6NVYUO2ET5B6CYTYLP7HUPVTPQY4KEBEZALELCFOUAA3JMTVHL2OJ5AOVKBN7SRBP7ABS66XKYA2RMNEORPSCRPDIALI25UNKIITY6UKT2GJSKWZEYI6JIRXKGCMEPRJMCYJBWZJV42W45TY5AM4AMQACFLOWNNM6ZOVL46IRPZM5U2S6DYSYRZPH2SMLXFJQ3MWCOZRMSTSYSJUDVJ6MKF2527AW5FRQJXHQU4TZ653ZXF6DIF5ABUFTQGW7NAL4LYHD4GNYUCGVCKLDQFGFKJC4HWRN5UK7G6NDLPBMUFVDRSB6UXI3C7DNBU23Q3UB3NE7TF2JQYKWGIFDCN67TWIAXUEBPY7567FMSA6WO4PKTCAAMR4LL54ZXCFBD3KVKHAXADA7D4WO3BNTH6PI2PFJMPKMF7R5EVHI7ALQU5HGRHZVVI5F7T5YQ4JJNGTRYLSHA7FMNBJYJAQTJ3Y2IPOZFSDVAVJO444RKB4ZS754YCSY66OAPSXPLQRAQ2M2ESDH3DEE76QNWPBR4UYZPU4QGV2FKZNVARF475EPOXKNHXHPNJQ4QGC6WRMLXOLCEYZ6FHH4FWZKZSUISQRLPMOGXW4HCNU2HZPH7P72VWVPCRP2AHQNH3JIO37ZD3JINRTRN7VTYZMQ6DALKZAZTWMMWA3CPV4WFA4MWVW4RQ3JTTEZDAB3P3IHW5ZVHJYDQ5DIXQIKP4TBRX7BVAZ2SICBZ2PPFTZULPHAYS2ZWRIXNEEI5LZIIT2PANV3NUX4GRRE4MG4DWGQOI3YKSHTOJMJQUTDJXV2TVJQKGMGEIVQVV4YOYOB6ARTOHX3DGJUASYELC2XIHIH6BP4BCK4DXNXRT2TBJTRKMK7O5VFRYLOWNHMAVQWOWLKDCOSUQUXC3XZDCKXDTPYECHFM675TXCEPRD2SWY7KOJNCC2CDEGDUXWIKA54XVDUKTFLIV7K6T4J5CDTTXIZI6JFHIUOZB2Y5MLZJQKOU4YJBFJDTUT7V5UWQFZ36OPPML6P5PRHVQ2KOOV5DSSRK2DNMQYVIG4OZJZWORKCMBXLXHKNVO65LXZPZU6UOG6GMF7S7YBEWEMGZIJDEYKYVUNQNMEGTU6ROZVJD6ZKHZ4OPRHZIW4O4VV734QYXDPUXKEMYJRY4ABXPT63X5GPAYTBBSOBZEMD3J2RSAD44N3VBXOBJPNBGVYCIF44IL5DANIMP37AQYYSASDVA4O5SLDFLFILN4PTKNCMYJUZUXINTEPJWUWOWIFUZ7BXK7YNZ775JGAMHBKR34TWV4B7FUFOR36U4MIIUH74VXZOJ423R2BZCRW6C2KJ3KU62B7QOO5HUFD75FJLDBG2NDTZ4546HL4QCE3GLR66EMRDWZY3GL5A4II42JLXIRRZGLYFIM3UH6M6H5LHYPLTF2PYE4GHFS25RSMKO4CXZHMGMTVUSXLKPFZDWA5VQOXVM7L344KYMH7JUWEHZD37WV7KPAPPI7QXGUWCLYP3D6BXVMNI7P77XZ4PV7PL67757H2INFPTH77AII4NMOLEND diff -Nru python-hypothesis-3.44.1/benchmark-data/intlists-valid=always-interesting=minsum python-hypothesis-3.71.11/benchmark-data/intlists-valid=always-interesting=minsum --- python-hypothesis-3.44.1/benchmark-data/intlists-valid=always-interesting=minsum 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/intlists-valid=always-interesting=minsum 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for intlists [lists(elements=integers())], with the validity -# condition "always" and the interestingness condition "minsum". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 413 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 1357.65 bytes, standard deviation: 694.08 bytes -# -# Additional interesting statistics: -# -# * Ranging from 721 [once] to 10775 [once] bytes. -# * Median size: 1156 -# * 99% of examples had at least 775 bytes -# * 99% of examples had at most 4018 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 3328: STARTPCOE3GB3CLS3UDKEW4ZDL4IEETAO7W4KZOMSO4H4GK53Y5YDU5EWUEUVVYXELYWTNA2PJX47P777WP57777PTV4PP7KFV7GXR7NGVDLL64JFO23ZH75PR5LDRW6PLNT77WYF4ZS4ZPFOKY7FXUL4W745VPCZGWSWR5V626LNGOPK6HMPO7HTWTTIFX77EEQ323WTKH7HP4RTNXJ3D63JD67QUDHNFYUU5UFXGMFN46NMVOJW4P263MO7LI223KP35S2FVGF6K4XCVHUGZ3E722AYPLGQVJ3TZ5JHFH3UGE6C62LNL3VEQA327ZK7DKLAK6XK3JNXONJLZUOO7HPPFKLWVM6S3XZNBWX3SJ26QYAWTYJKYQQU3RGXRZMTLQ25O7FSO5PHSKAT6GC2ZUE65SAE4RLDXY57CSGOS36ZEKWM2OJW5SMLXX2TMR73L6ZUKKMMCXJDNXWLR2HZULJFIMTDWF23WC2X6VGELF3Z6HHJZGKYE6RIHRNY34TGDWWE43CDWQ2BRTMYRRM6PYXJYNJWLLMAKEQ5L4Z7E6FFZMRNPGJZADKDEPP4RZINXAY4AGXIHZ4V3V6AY5V3ZPSXXHPVPJNNGJM5JTVPI5C3J4LTGNR6OODWD7OBTOACV7MOGUTDWY5VZEHD2VR2HAVZ4AC7AKVF3TUVETHZ3J5VO65LEWO6APQ5P4W4M2Z3A2Z7AGOJG7LWA2EPPXAG523VPJ55SIHGLFUAGRJN3HQ7UR3WLRNY7HHHZ5DTG3QSPWKYFGTXNO2FPPUYH722AK7JLOUIBFFUBGUB7D5CU3DFUWZ3WKJ7LW27JIP4MQJGYV4HIMLGAUXRKDNHWPGMVQJOPGBFAJSTTAMQYOVL67FPTEMCMGIMR5XKDZNZ2YOFWKMTIFKVALHBJCC7NMFKIJZKLHDIFSVB7URMXF4IGWTM4TMKRCLHZWBD5DLFBX3MZQUYTTQ6GIRPPRUI7HWGBU6WZJEHIAAUUWQ7JIRNT3OG4JZELP4WBLZHG7OFLXAKEAEMCGSJO3CTM6EWJRN3MRY7D4GUO734PHREI7F2ZXIMWFLGSZ7JAP53V6FYIHGHAT2AVKFAOWABAE6F7D3XMFDRD7G4KRAYNVBK7GADX2QAPQ6YC6CCGDWV25ZN243XCTV4G6JRWF6VNV4Q3ZHQLKZMIJD4HONUIRGIV4MYKKVODNCBREOA6OLGAD7X3OW6LM2SJVC324VMOO5S3D44F7MWC46J2PU3PDNAIK6MWKEV3JPNQSIT542KPYBKJXIQULVN7SXTYCZK6V3K5YYSVX5ODMFP3HMCNAPDCFLB7NH4OHEEQTRYOULK7WDJMM5ROREV26DQZAR6QUHREPMUTUSKEQ5NWADIBWFMFCFHQWJXRNDPXH33TTFWDG2CK4OOWUJDZJA3FJGDCEVQCFS5SFZKHTKCI2VCNFLQU7XCXUHS2PJ7EJIXFKOQET42R7ZLIW5EIIXKYHS64EHVDG7VWZPLHDCPDAXGVICZDB7EEUVFDTSRHEEYMCLPNHZGZYUS4HEHOQB5H7IGZTKCDMPQKAMBT4FKK3TB7VC2X5OTLIWP6FCEOUVM4XBGQO2PAXC3725QOZAGWXO2HFW4UF2LESBRFJ3YP3NKLULIOPC2NNDLXMUHKLGBQ3W272NDBNGKX5T26XLR7HSXKG2MBXQU3GW5X26FU6KNDYHEIFXMNFUGUJU43BZB2VQ7D4OIIZ4DIMRHCLUKYJ372KN6EQL3HSUNNV6VYKEUJ532CWOND64XRXJ3SZA3MVYDVOW2D4IDBFCLQTJW7BZMMIR2E3HC6D7GSZNEZFGVAG4PMSFFUU5GN5UD2NHBJ2527ZA7NNCDE5J4WW7IWDADXAM2FUHJCS632DRQ3JKR3IJSZEVFL66VLU5ZELVL2FP6STVQ26SYDU5SHCSD47BYVVJXKIA2QCPEYYFPOUOVUEPDBTSI5SQFQZVR6GIBR2A2HIVOHIXCU5NLZTZ2AOXCMZUTLGI7TV3VAPSPAUNUANPHJXSZEUAYJJUH6KUMEEDQT3KSUIBJYQCG5T6SKW35VHKPCIBOLYWZOGSBRJXI3NBUHTWFBOY5PU4W64I7QGGMNXE7QY2RKKYMW65D3VCJXUAB2ZQWNHMVQ6D3QWDJVRRRBBJXKZ7FBQMSTK2VBVJGMV3SIT6MXLJOFVMGODWDYWRE4DUXG2VEMYS7QRHKCPPJEOUUJKAIRUKWQ2RO4TWLUJDRIIX6WQFMYRI6W57AVGTWOM5FVVH42E5LR2JLN7I43R3URM4VIFLTBABN3C4PESOKD7ODBKNITRGEEHIMRVZJCKSOQYBRY7YVFJBYZD5XVHMBS5QTFE5DVJ4WE7OTIC5DWPEJYFSQAN7GNX3REUFVW7HK5SHCTSEU23XPDEKQSJ7TUI7GIOUZ6BUJPBPPCJR3XX6SCW3ADXNMRGOLUQUMJMLZD6QHXHBG36UELTMEPP6ACNO7Q5I2GA4UC5PBLQGECKY7XVGJGTFCUGN333BD7JRRWX2TT7J2IWQXQGP5SSOMVEYKBHF35LW2ER4SJYZZG7WRCEUQC2ANING4VEZSD5HVYFBE3WU76YMC65KCNVUFKP657Z6HD2EPVMMMVVZDDCG57X64OM5MNNQ3VFUP2DYXNLBNLX4MEVOVBSST5HRU36DH6A2Y3FZQSO3ROOGES5H7IPRHYZ6MV2I27LQA6SSNZWWBHKPKO4BLCOU7H2JQNA67ECMNHIE26QPLCVFXGOSLV4PBAF2KUOQT42QTD7EWQQNDM4GVHSGWG7SLJUR4L4PIFCDTI5EO7O26HEBF2OT4TCBUPFIK2YSJAUC6Y5TFOBAD73LLX6N5VUKHE7VMR6X6CTJSJ6KNRXUBXHI4FRWY3EHCKW5U3VHLQVKRKO2JGH27KTIRVPPYRY7UMQ35OBGHGQ3M45ASQFDF2WF3EUL5VYGNXM5I6FVBGPFNIDFADKOIO25IFTGQR25J4MV27VX5MQDA2IKTV6PJIZFIT4RERNPHLWCNX324MRFYQJO65Q7ZCB7NKPV6FYEOCOJXTMW5HE6YFV7PAG2IHAB2XWT7LZ4JXYFHA3MGSSJGAHDIZTLORQHDYYRVMPEVVIGFX2MPJWSKBEYF3XKY4FOOQSO3WBV26RZ6XK2MGKGXIJI77TCAOWZN73554BX272OKYEK2IYZUNW6AG4A4YG3G5GVMGKLQY25JHNFUQQIYX44BIQRJL6PPOVER6BNJJGYHZPMN7ZKKN6UCULXUF7OJN6UVHZC4FPTZWFFCONO42FGT2KNZQ3P56PLY7H37777P3L47P76YQWH5577Z6MQZ3E======END diff -Nru python-hypothesis-3.44.1/benchmark-data/intlists-valid=always-interesting=never python-hypothesis-3.71.11/benchmark-data/intlists-valid=always-interesting=never --- python-hypothesis-3.44.1/benchmark-data/intlists-valid=always-interesting=never 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/intlists-valid=always-interesting=never 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for intlists [lists(elements=integers())], with the validity -# condition "always" and the interestingness condition "never". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 377 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 8729.52 bytes, standard deviation: 1998.71 bytes -# -# Additional interesting statistics: -# -# * Ranging from 5148 [once] to 22379 [once] bytes. -# * Median size: 8354 -# * 99% of examples had at least 5762 bytes -# * 99% of examples had at most 15022 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 4136: STARTPCOE3GF32JOMSDMDL5C2KWCBL5E7NPUKZOMTO4F4TFOX45YTD5TGIJ5DL4Z6P5EFARAJB7767HLT777V45PT777Y6G3VQOL67WEJH56XR4OLP7464OGK277WLC7X4VGF2LXXD6LK6YBVS37KKM76OXGVT64V77Z4MOSN7VZLCW6UV3UI7ZVM757UWDLH7Y6V672TSYXW57KQ753752NFU4U4P23M7VM7GXT5CU2TQ7GOIEDLT7PL5TWTK5NZ73443Y3VOHT5V3PPNXOZPO6NZXDHOCIXSOK4UQHB6T2XPTV7IP3VB6T46PPVAAX5LUGGKF23J7GUKOYXX562XJBGKEMOXF4KGFFPH2OH5GKH265HW43ZXUMEG537JOPVKHHCR2S2P5WVQVPB7NU7XV5DC6HDNZO3OD2E2BFGPPCPA7HFPWTDFGTDLF2OTDOC3AWAVXKMTNKQCKSLPFRWXC5HFZGRLP47V4YS55OIG3Z6NMVGBZ3RNOSTCHNIHX2O4VI452NSJJQI7HIFWOYU6JGCFE523IPFWIN3VOL65ZYJMVWTMWF2NM6BBIXEPL73QEZA5SR2G3T6L4RXLSTUBZ2I4OLLS6ZB4ICIEGESBIVDPBHQC7PZXG2BAMAXQ6NKSDC4EHXAUH5V6YTXLRCTGGOCO5GC7ZD4S2MUSHKATCCD2DEKXQBWCSKZMTVB53OMRVAPYZAZUMDZPCGLWN2J6TOSMPZTR4BDQGZPALWWHBK4EYLFYII6YGX2TEZVYWAPIBIBTMACUAFPST54PPRRQXKLYWYIADYDK24BCJ6XHBVOHPEOKVEM34INPZS27KVEDLILBTQ62Q7I3CFFKAEKEVSHNNGJYYA5TYHQUVJNUG6DXBFQMNQSOCZHIEMB547KJIODUYRSTFNNFR5N4WUS4J776WO7CWNOX237ZSNQUXBDSF2OPZQAQQSBZZLVBHSXQCXWXLPFMCZXAI4TVCVSEHNHYBIDAXLHTHS65G5WVYZJCTTYAN3TA4NGNFIY37H3RQDXRMYU24WFVPXCNBBTRUPJ3EOLGY5LKUJ2F6YAEGCUFJVRO6N5IWHJ45OINL2656CGMEHHQWUIOBTVR5Z2B52AQBLP3RQLORDFQSBMK6XDLXKEO7ZPTWUDTJS7SMABWWKJEJN7YUFFPLFNDPK7PL32FEC4YB72TQ6HAWRDDWI6KYK3THS2VZCWOWHODUMUJVAMLSI2ITPLHWUWGRY3KENBONJP6SIAIJAKQF2JJRFHOVNJCCPTV6MXGYHREPIERVBCHRJW7ZCFYAKNYZHH73OJB32TWQWEEPEKQ27QDZYOS5LJMWQICEFYLJDPBCTZDXJVKCEF42ODG5HLGPV2EWFLYDJWKNBFPRF2BLGJ2A3JLS4CIVFRBOIOXYCJSFVPVQXOPSXEKWXCTVBH2TECMU4ZYAP6CXULPLGHVKYUKILOOZODB3FCFQI2WQWDIYGGVZETDC3SYWLTKNREUMJRE4PYAKSAQQIPMST2OR3E4HL4DUUSNR3DV4YEOUAQN7KRKVDHPOKGZSUWGY3SOB4WAKSRRZX72VPK43SNJH6R3EAEKVXWKRO3EBL4LNJENEGR65B7CJRKZEGOCZQYLZYSYZDBLNLLYAMMV2BUVTI3XMOT7542IS2JFAXDNPASYV7W3Z4OXWLT4HZJX6EUFLGFIY3AVA773WURR5IWUTVYAU63UMKIZ2YOS4I25OOMSSFQUQU3A2QX5D2LDUBEKUITHC4EADIJTOFXADL3WAEZBKJEEPHBBCNBMPMLNTMJRQQRSFBWAMSKGPRH4EGMPEQXRBIAU425F5MQNURUZVGROQMWFPDMDHZMDRGWFRAIOVPQPVZWYZASYC6B3VRERCYBTA4YOEUMZFARFKHFN6RVWIIZNKGZ2OBB5J2OBZWK6VAYROPYQWXMXVGSXWISM6HXPB5VFWAPZ3GCKBTJGID3X2GOV5RWX5AXE2GFH2C2NFJYAK3MOG4FYAL5W2AUIWTOMAYSYLMURTLHAQ7BSGDIL5I3RJ3B6FJNEPTGSFQ7UBYMUVXE7CTC54QU7QCFZJD5KJ7MMZODI7QAYQ7IO5COWVWOBUOQRWO2NGJUR6MHEJRTT6SJWWT75T3BJ4EJXDRLZP4GUYAXSNU7IBSSE5U2VBIIJ652JDKPSNUHILHUZH2QUSBUR44Q55LYKOVAUZ7WEHFKHIFUNPBLV3TFPOEBUU7QV2PYFGDCVHCUYV3PTFDBZHRLVAHHP4CAQGVBVUHTQ3OT2BOGQJLQQDGKT24KHMVGB7WFCH36PSZ5LZQRC2PGWZ5XIEASYHEYDJXNKPMQEB7ONJ2AC7M4M7RPJB3VBKZOOL2BCNRISORVZF7ZXHYOP3TSG2PHDWX35YX7V67IRD2XL2A6EVTOM32KO7OXM2OA4W74BMYOPPOYTVBCDF6TSQ2SVQWHYUI37FHUHZS2Z4DIOYV72GWT4KTFQYZILPWEIUEJOOZHVYPTILO5HYIDAOYJCQRYSRYHZRNJZFG4ANTF2JTNJ6IXM4RVJXSAD5KV723CLI3IFMBA4APKQCH6ZFPOLP3HLF2ABNJNVK6Q3H6NAFPNQONUT3F2BMYDVQHIYKC3OZ24DBCNUIJSHM75KGSFHDOHMYXUMBGFCCMC22WPOLTK2WPPQRFMCFEOZG5T4CO3NJ7ZDMCG6EP7CYHDPLVPVTAG4KVJYESCXXHPNVGPOUTC3MMG5KQP6DCCOJDF5ZJ4DBVW54XGA4YULLWGHCYFVRVZGMME7NWBOBFWQPOE72U4PDCXJ7LWG7T7UO2QX3QLFDKSQUSCCH3WUCZWDT7FS2MU5AZ2CBPWXDCASDQ7JW472ZK3C73INBT54LU3WYRYT3UG7CXSNEJITLEOL3Q3OM4LDTKFR7JAY7V7ZNUWACF3UWREPMWZMD23Q5EPJBNXUWFAHN2463PQHVIDP3L4F7S5ONTLOI2JULOKCVPLQBII6GSBEP5MYYOU4DSWGR2NN5Q5F2PEQPFEFNGKX66MGGIWDJQG6EY475D4J3Q5XSAT7L6OEIFHHD43P2LY5K5GC7CWA2ZPJOPDOT5WBEFT4K2WWW7OJ7OWLOIPC7LJ5SZUKJJIB5BZ5WU6BOCRXGLRVZJCRZTBM7POXMPAGPEMGOPR4NQE3LP62C7SK72EB6A2DKAT5CQ3FTHWVUHAMOE34TU2JOIRMDG27RSOVU4LH4FKAJ2PRLCDE54GHIMA6QDCPMCMCZFI7APIP6GGU7HNERIMKJ2B3EXL6EI54BDLWNIP6Z5THDWH7Y6LYRLIL7B76ME5F54637TCZ2LYCJTDPDOL2XXX257IM4IU6W2USDLQEU3IUQCYMU26UCFAKPOTPUQ3DITRTBMJDNAML2XMERBKDSGGJYHVGC3NPYUMQHBJQ6QQK3LXNUHTEFHRMHWLBXHVNMCUZGYGXMWPDLZ6GMJWBMZMDGXYDODSZMABNS5F3CIWCJFASPIFVZEOFQ232I7ALU4U73KVSN2J3QCRZH4VDGDF3HR3E55I7T7UQXIQEA5SULVKUOXCUQPULDFRMFJXM75346DBV5LDPH2OAQIODQ5IZAS2TYXHIJA6FYFBO763Z7I7QMRCWG53YWBEFMHN2RIA7KXCKTAF5HLBBZLODNWANENLOSUTCGJD5N34PUDVT2PWZORHADQG5SOMWJQUQJ5V5735CCCGRJILHUMY6SMIZRFY4XE7HPLFHMROJYDA3ZQG4UM5AVDEMP6AC5P5LGSBVY6DRQGW6WKQRVPUJSIZZOB37J5DWBVM2D7TFBZ25ZU5243OSX3NRHQH572MBN56GOUOOYI642S6QI6LDVT5VJQBSYYNI4OST7E55J7BMUXJRQ6RIJHKAYQGNBO3JSHB7ZUSLGYCPT2DVMMQVWMNBURT5JRHU7MCZHBLLC62ZO6SGCKMW6Q7GN5I4LB4G5Z4T6QTOZRI5G2M5TIJUGGU2Z2CREGI6BSBZP3NQBA3PFGE372AF72LBPOMD7N3QM7PIS4WTK6DGO6DQHUFLW5EAMHEHKCKC66MMVL2WGGWTCRGRXZWGZ3BOYYQJDAIIMO5KXQRXEBDLKXXV3UIMFHXBJCPD7EXVL3P673V6P367326PH777D44PD457GP76AUV42J72===END diff -Nru python-hypothesis-3.44.1/benchmark-data/intlists-valid=always-interesting=size_lower_bound python-hypothesis-3.71.11/benchmark-data/intlists-valid=always-interesting=size_lower_bound --- python-hypothesis-3.44.1/benchmark-data/intlists-valid=always-interesting=size_lower_bound 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/intlists-valid=always-interesting=size_lower_bound 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for intlists [lists(elements=integers())], with the validity -# condition "always" and the interestingness condition "size_lower_bound". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 381 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 859.48 bytes, standard deviation: 578.94 bytes -# -# Additional interesting statistics: -# -# * Ranging from 2 [28 times] to 3870 [once] bytes. -# * Median size: 750 -# * 99% of examples had at least 2 bytes -# * 99% of examples had at most 2469 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 3200: STARTPCOE3GB3SJS3SEKDW5JNC5QZMTZD6W2RZBJRXMW32PCOYXOEAHEVPTUN67XIOTBCSFAJE7777LZ5777573Z6XL5PP7G5VPV7OLCNZV2S233VOG72XFDN3VZ67P35PPR3X27XVX7P2W277D54D7KURX27WPX7O6ZO7J2O375ZR36WN3BR7K7OJRVANXXN7M7JIZHPWRVU3AR3LWE7V22X6DINZQQDL5XIKFRY6MOTXZMWNUITYU3SH37HIOZZOPL3FN53NUGAHGK2ZUN2QZPYUJDJVLIAW7PI2NJBGC24DKTDCDNXWWUNN5TASFMHDTZM4CDJT46UIQJVZKWWKTNV2ZZM3UGQLHWXXOSD5XT7AGM7HCBT53EJ3QPXWOK7JVW4G6L4M3T5I62IV3WFJD37XPEEJZRD4EBHVSTAQG7DOXOW32J4FJK5GVINIWNFMAWSZRCEILPE3JMCOOOCKKM6KVZOJVM6DOTBRINQHT323JZRJTLBLISFALHT4RQ7737XVNE7RI3LWBGEBPG4STHKQ6V3NMEHENCETRCWFGCGCPHDSLQPCSW4HWTTRWZ5ZYB3ZCVIL36EU4B6IWOG4HODV6KZXJ5ZPW7V6JNPKTQYJE7SXCMOW3HBJAHHWAFWTUV3WAYEPWOXCLV55HNCDUWFWDIITRYVDQCA4QGMWP5AK27FLAPEEJGDF6OIXEVLZ3WU7TAD7CXIKFCUQ4FDUSDANJMSHLMAU7MSN6DCJVUWZGEXTJDMQAUZG5ITSIMGUTVX4K6WF2FNTMST3CUTS7SNUORTE4ROZOQJ22BQUMJ3BIC2YL43GQRDWKQXU7R5D3KQQZIYXNTOHVIKIEKF36TUKIWTKGAZC3QSLHMDBV2THFR5M7ADKW67BMRDEBFZKJEAVSVGOHMVTID63JTUAW6NLKFD3X6IXJKR7MBSPGCVF6MZYTIY2VNM7VFDSSB7GUUMLWKADHN65YZLES3A33DUL4TCSSQQANE3F4O73COLTKSEW6V424YE6BDIMUXXCR3PM2URMMCQGZOSEZKFZQZPVOXKIRGZW7BN37ZGSWJIJNS7HKFPFIZCJ3A7MEV4EN2PBUQEJKST3PETLYBAKQRO3GQXSKQS7INPWEZ6HKPB5ALJK4KWZV4JHXCGX4BNLFN7IU4NHGVIVIFESJHSBS73NZGUTPIWYQMH7TI3TLIZVJVB5OTV3AMUQCYUBVVLRT3WFPOVUTN4RYQ3OW667O2XVQZ5FKRI7J7QTBEBVDAZIIMSCPWQD7NYD2GSL5GZ53WCW7P4NEILRBITAMMMC3GCM2ABOHFNP6WMBRFQNU457JNJOREYBM2Z2MM3TQZEU5CKV3FJP26NWJSS23FB6WVMWMPWBT6E3QJ3ECKMCL23OQACRMTFAAKEAHU2QSZYBQRMOAQS4GQHASOFFGKPPSNXEX7SOOM2CNM3WGGECAIXBARCXGUCZXRJ5SHMWEDAYAKXWZ6PRCSSDOXNV34MDWZSTHUH7Q75KWMIIJK4RLNHLM2KYKA6HZIHY7CMJ432W4WYIC7WXFM542RFWKO3SOJKVIULATAMXK336W2CBGAVRGVCQBATQKVJP244XX3VOMFJLSBV7T7AMGEG3TC2BQEZXRVGCLBOVHK7OIGUSPSV3ML2VIGHZMVEG32YJBRIRGKYKDKEMX6BW5RHRVDD5KYDPSXN4C4CYS7PXT5BWET5GB3NZ2PI2Z5D4TCU3B2LDYYK32XJTXMZSEV4KV63SUV2IEJ3VZYKCVB5KZTHDEMS26O5TEBMLPEDQEV5C6L66VYMJ4DBSD64JDYOSU4OXXI5YIGSNYOPW3M7GCTJG7DXK22JX5LGS2FB5MCCSDG4EEQXZWGHX2SLBZS43DPVWBONCQ4PE6LMZAC6OQC55BABMVBMZRO5JGUBDRVVOY3IKPBCSIALMIPPMYHJS3TU5AKZPIHCLWE4FLJLFEZ3SLHGVWY2LYTAGE6IVO2JYDKI7S4GHN5K3FKGM5OA7NFBHPD3TTWLLTDYMBEKE3JRBIG6APHJK7DF7EFJY3KXGLTSMJKIERGUJP3ZYCA2P6WA73U7P2IOENM55BGGBRV5TDJRB2G5BIC55XWQAFSXDAWLUUG3JFCABM3XFQLJY7AH34WICZSOIF6X3EWBBZWR2DEMFUR56WVXM5MORFMRAUIZHZFLBK35UTI4NMUCLVPMWRAAF7WRVZJK6SGXX7M65ODLEQ7FIIGKFHILYHSL3WAEDKEEKUXEQ7B5PFBBTVADI4PBBPOQCGWSGOBTPNRZRLWGXKE5YMO5D2E5PYVG423KCH5OCNOXWYVYAGRQPONZOV3TD3AOPLKUEGUKVXTKPWDLPUDBRN2VOGXXTPXKG6PLBLYUYKU7K5SB5EEDW6UV2LFSR7BZV2H4DMYXUZHTYSWQXXUXYPTFS5TJOQY37CUZ6H65IXOGE4ZG7BKTAFMF4GOOGAJWUNOSJN6XMDPXVWWY6F3HVDOA5FUBQ6XVIOHXA26JKBXCL6XNCSB74AWKA2NUFJ55SRHY5WCMDRJUIM27Z5GNZGEQSXO7EINUQYHQXVE6JUK2VR6IDUYYP6HEZW2VH3VOOFEUDFCFHISO7OGT7KMUTRVBSTGJSHQ7RZOPWHVOZO56D5HBIE523SPYVGSLS2PKUCL5P2YLOJYMFABBXEG6W4PE4XJPQR5LMC3JK25WU6PBOKUV5YFCPGK6Z6LJCREWJAX3IKDDCRNWMNJIY3XA4EEGEI6ITFV6A3HPOTTCTSF2Z6MAYGMNSDZHASBMCPWMDHSQC5IOLMYE7OALUOOKL5NUTU3GTT7MJV7HUSZ5P3F5NBR4PJY3MUIU2INWC2G44IWBNZLSUGK2B6ZZPO4IJJRWVNPD7HI53TNB3R4T3P2MZQP3IIP3LJD36KKNSZ3H6TAC2UMKZP7U2RFY33OFTRRZJSEFXM5HLS6QTAUTHZLFQ3DT2TMR5HFBFYGQXYKVRAIG73PBAOBOSTIIQ27PVXPYODQEKUODMTONF5NFSDO4K662ULHAC4Z245MOYZAKUM3BEUDEMZGOZFDZN7J5QS6GHWJBTXSZ3FSL2XA7AO45W347GOJPIOIYQKING5XQTL2Q626XEX3DTYBJG4OWOH2YYT7T5XQBKH4GJUAHLB4PS7F3P23NTLEPJRIWOUXGP57X77P26P57O7367W25PHH77E7R3YWUYI======END diff -Nru python-hypothesis-3.44.1/benchmark-data/intlists-valid=always-interesting=usually python-hypothesis-3.71.11/benchmark-data/intlists-valid=always-interesting=usually --- python-hypothesis-3.44.1/benchmark-data/intlists-valid=always-interesting=usually 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/intlists-valid=always-interesting=usually 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for intlists [lists(elements=integers())], with the validity -# condition "always" and the interestingness condition "usually". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 379 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 34.57 bytes, standard deviation: 151.52 bytes -# -# Additional interesting statistics: -# -# * Ranging from 2 [898 times] to 2029 [once] bytes. -# * Median size: 2 -# * 99% of examples had at least 2 bytes -# * 99% of examples had at most 731 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 632: STARTPCOMKV53OLCCADH4CWH6WKYQBACPTFKMXK4ER3JOTH6HWTGOG3DIQVZ4O6M5TAXBWAIKXVPDX3DPTY3TTLDZPYKV32DBIIG4WZCHHWBHRHOPCAUMJK3JB3T3VCLYXFGY552PVZEEUT6V5YTMAPOK64FC4CBO25FYBYYPSH5B4TFADLXN3C7QBVPDNQB6UJ57Y3A7VKC6CZJKKK7DXQQ522LJ7M4DL2CYLHTWAZITYO73TC7QDR7IDLIHLXVI4IQDWKIFYKJIDQDUYMY5WDFVUZAZR5Q5NAL2N7JFR4EL5AJXCZH4IQAJKMSKLFLJUVIO5OSQNW4V3J5BJHELXIBX7CAJIUM63ASRSHRAZJO4AEV73OQSNKXSVMKH5GOWNFIHZLPMVM2DBOZ35KBJ6OXQBMF5CQAXTN5IEXDECVS2FRFRIIIK6YMJBVVWTGBZ6ACKGZEOJAQAPQ32PXRZ44RJIOBJJDNYZO4NNJBMZUORSTVNNJQE6CE4LOZJV4GDRW4UZG2OAB6BIQK2XNLLVDJCJSGTVTSYTRF7O6UEA5XIFZOMHK6VGVJLWS5A7W2LJUJOPQINDHA4JZBEWYME25ETS7V3BXRTYTPPZM7Q2RPO7MD3LCIWPA======END diff -Nru python-hypothesis-3.44.1/benchmark-data/intlists-valid=has_duplicates-interesting=minsum python-hypothesis-3.71.11/benchmark-data/intlists-valid=has_duplicates-interesting=minsum --- python-hypothesis-3.44.1/benchmark-data/intlists-valid=has_duplicates-interesting=minsum 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/intlists-valid=has_duplicates-interesting=minsum 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for intlists [lists(elements=integers())], with the validity -# condition "has_duplicates" and the interestingness condition "minsum". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 415 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 7914.53 bytes, standard deviation: 3847.96 bytes -# -# Additional interesting statistics: -# -# * Ranging from 2836 [once] to 29591 [once] bytes. -# * Median size: 6846 -# * 99% of examples had at least 3461 bytes -# * 99% of examples had at most 21917 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 4304: STARTPCOELGB5SITLSDKEV7JDD5QY7QAQQ4VPUJME626ILZHQVXK5TEHV7N44T2PK4KQSAQJJSCP647L5777265PX77724PVR727FT2736XV57X56X3FTPZ7WKXD6L727W267HN7H7VM57L52TUGPS4TX676N7PROUP7BS7XCQ7KQOX2OUHHFA5Y33UUJU7P3LNF6RDZEW4M7L3FLT5HXTH5YKXU2PYYJOIWRQLDU7YWU6GB2HH3ZDTPVY67IYF4VHH7P447532MNZZ432XP25HIHVMOTQHD5LTY4JN74SO5UKCYMDOS3X7VSIWTHRUM46257UFQBKRXK2FKFQPTSBR627DI4ZBQN2W36JPPXXKZV7RSWZDVWPXZFY7S6PEK5WZVP2SMZ3BGF7FTLB6WK44XRY5MO4GKMZRMDPO2USDOHWDTHXZNXLQEP25EB33V7IOPZLPHZ3RN5PW4DTPMIAM47OOBFNMWX6RQ5R232WSQ7MA4JAN443PEO35C4P6SYFOUUAUHENZ3AN56XNFZTCF33RLTXQR3UX35AANH6HQJ7MOCOHDVDU43S64DQRXTZZYNMHTT6N2DUJYLWO7HF4TDTWZNYTQOEBRD7HIXHRVL4IZLKNFZN77SB2ILKCPNOJHYRKTOIPTG45OTSIE4ITSOPYZ3OD56HTLOIOI6NOB34E6OF7BPIZLOPFO4K2EU2TRUT5O7DW3JVDJWU5ZBQSJ2G4H47MPTDVPNL6NZBW2HF5JUATH3PU735RDZSLTRWZU2G7M4JUWSEUBGBDGUDXIVTUL3OXRJS4TJ4A54K4APU2LO2F4E5SEG4VZRGQLAX4OTQWG5HCW7XCG76CUAUH6FS2HSPW5ZRPTU5YICPI25RMABLK6N7SGZZ7VZOLLWQE5TB3WG7VHS7KWPU4F5DTSIJVXXUSBQOLTFZTMI6NDZZYYBPWXSMD5PDUK6BBD2OELWLXIDOBXUOMTLQNSOG2ZGKQSFZNJ3AFJ4CUM5WYX3YYTNWXY7BXBOP5HMGNSOEORW4MXVEQR2A2RTXRCZY5YXLDDXTOL6VHQG46QTJCD5SACM5Y5FQ54XCAWMQ3VWD4ATMILU2MZBMMK5LVZPN5LITTQZAHRR7GNK3YB2U2RPXPGPWJVJTHG56RVXJODIU6AHT7UUCDZIWVZ6PFY75APGFMLS6OX5HP46EQGMPGDCSPJO7WN657BXVLUYMRNWBE53BQSKRY6Z3VC4ZPWZWTP64H7CQSFWEXQ65UCVOSHQTPNGD5JY7HO74I5W5BRZWZN6PJOX7PJWPVI5FSTNGJM3QOJFGZYPVBPJ3HTFK2IKG3NIKW7YPARTDLYKUJQCMNPIUE2RIOHWENBG2D36DRMV3ZY62IJMVCLJPNY3XNK3R5DADXSAEHBHG7IG4XHTIAQM2QDBK2JEDQXZJSIIENEPVLNDQXOGZ3ECVO56VHF7KQP3HSRNBASMDOAQW3OJOPXFESOSQFZQVGMO2R6WBNYC2EHP7AGEPHI55PZZUZ5GMVDXRVVDUST4QQP4AZ56QJZDSNH3QCVQXJSOE3UPG6FCGZGXACANZ32QRLSDXQ2JUJD4QC6USFPQLUPU4MZQRSIQNS7GWORI5SQ3YU7DGH4DPKD3UDOZIUMJZB2COOA4KEKO3KMCIYXWY4YWAFLH67X6FBLNVTDRGH6MQHAEFEYSA3GR6VUNBVNVHBCZRTFMWAA6QSMZGPIRU43AP4O766BTFAAIHFYKOJ5FZWEZALF3ERT7SVNNAPDMLCSZ6P5T2XHAP2GO5PMBRRKPZXU6JAUZLJTHOET6GQ3TAOGS2JXT6M2GRX7UXPPGGA6OG7DMUZ3IFLDJIDJPV5Q45FNPH42G5I4F6SG6EG6QRKPPQTEIYWMZI7HY57ZZLQPTW4J2G57NMWZEDS6VJ4CZRMQGFRTCVS7K4GEOJ3IOCRBJNRMHJXVR3ZFSJSZOQ7M5INQRDQGBB3HLQ3FSEDVJ6QOENJINMQCJV6QFRVPGRKQOKGALDQ5YOBBMMCA2GCPCFEPM3SFQKC5NBFUPURVB5LIOLXDL7HSGIF57JKRSJOSKSCEQNIO6CGYI65XG3JHCWGLMZBLRSKF5JY5ZRJGVNC2QTSEMRHCYJO72XL6QFFJCOTQ2DBV3QR7ZSHNFBJHIG7DUOMMQGLFYID7TCBDNHINLQKBFFBY3EUC6VXFADME45TB4PTZ2MD6KKW5PAILKO6HBU2WSXXAIHHPWPV4BTA4QZVG2M3AFAHT4E33PG2I53GGOPZ3JBUIL6WVNLWBM22EZY7QGYTPXV2HTYSDZJXQ3GSD4D5ISSIOBNXBXRDSQFA5BN5ZSBWV6ALKKZIBXWMIYQW377B3TIYDSADFLU55M4A7JZI5FAWM6EOFROIAIOLQHOTANB4MGL73P2ZCX6B5JB3WLRH6WIDYUHZXRTYGI4SNJRKPROEQLHDNMRQK4R276VSSCTAP6IZDGBKLRAES5UECAOHGXRRU2QOTXH7OAJUNMML36K6EXPGTFI3UZ3JFQ6R7ZT3KRTBF7BN6CRM7ZBJ3AEWNVKOQAJ6Y24DAPMMFXHA4B4HJPZY23UUHES67AJT4TKPNYWUMRX7A5X2NN6QVEYITNTXF7WXYD4B4MUTWZZRM245HQJRKU6RNHTXPIOUGQFFH2RZFSBRLIVV4GV2IQDFLBWRDMEORBRUBQIVZL6U7MQM4YDNKPTJ3ZIUD4HABZOI5BJFB7RJGUOYQMC6FFWTIKQMX4N7GHT3MZMWYTMTQWCFWKRB7VFY3J3JDK2KGMFNIVHRYCVAQ2YSLPQB7A6RWH2VCQRBDKZLBDWKEWIGBZS5P5FNLWO7OKWZYF7MGQMMVTRBGZ7CCWNWIJ4Z3USUZ4XQNLRLGRT7XUYPYNFQRUCM22ADYHE2NLZRW2AJQCER32XZGADXIRGDWML4SFTOQKYKJLUEAUS2JHE4CWF43R6Z576BT7IBTY6QCXHACZ4FS3JUYT4J4N5TAVBQWNLULEWBHF2GRA3WMQUNAYVLSXQO27KEF3RLCEDNLNTJVJQQO4T2LLCENI7ONV5GOY5UBYNN6GPFFAKW6FZZNVCTU5NPBNG54IVPZQH7WGX5PUYL4HKYHA7JBXIZV2BG4IN45STLBRWKBERPZEJGAJLHLZDCAMLY2SYC53KEXDRK4XDWGMYBX3MLWB4W4HTYJZU7CPTTMMNJDQEYZ6UBERQOEY3Q6YMOTD2XPV6DTMNYNJM6SDXSRQKWG7P3DLGEJVOX2W52Z3JA4VPGN2JT326J6UYHTBRDPDW2OJ7JW7C5S2FYEFV3NDRQF3XUPLMPUZGTNSIFCGMSRKOSIYRVV7ZBQSEUMDA2DEYNB63DVRN3QH52FPKOL2VGSOMHO2MYDXY4H6GRGHT37VYLKBTQ3T7GHEM6YJO5U4T6W3D42HWDX24OVURA3IHRLOYNZ33QYGQJ3JRB3F4PNML3UGFJSFR2HA33GCLWUTDYMO3J5LQ7OOKJ56576K43DSECFCV4PTSUTL5NXFIKR5EGVODTNGPYYVSXLJYS6G4PQTLD2Z6ZKMGAZ3W653P7QXANERRJ6KQGGIMIITZVR32IYDWHD5RMEZ6FY37IFRTEEBGQOSAZV3WRL5BFZETOM7FRXCO5XVMC2LQBE2NXJLD3N5KMXVISFVOTDTFLIESA4EZRHKEXVPV6WD6P7II5KNB7F4CGYKSKUAH6XQMZTO45XU2J6R2CGXPREH7APMEVD6T6BZR3SM4QD7KQFPASKLFD5BZTABNL3CQDB3SRE7E5S7IAWI3LTRG6JWXPT6B4XFJVEYXC7W4RJS5EEWKHAQEKX4DUZV24GAY3CK62I5YEIVENIWXK4BYTXTR7HJ5PEKFGGFJSTHEQKZF4V7SOIAZRIZPGCO23NP3QKTBSTA6ZNQPULBWVPZQ3FIEDHIJYMQR6OCSPBWVDYRY7C3VDFEBHRYVQDZSBOVCJFXFWN4XPSZBNUMMNSDOAUSU6TAYR2KQJ4NUPUIYVP353YXIQF56CONQZ72THK2EL4BS7XCPTWVO62PA4L7RXMOFUQ3U3CAGFYRDPAAGV7XNHDXN7XP5QHQIUJZPNDHH5XRLJMZYBSPUKDUTTOEPOPKRL3XF2BFR4LVAYC64GP3NQWCMU5MZVRLNTENTV6U2DF75UM4OBK3LQECFRR3L7Y7ASOAD7LSFSMSK525M55M3U3S7FRBTAE4KZSH3IQF4EA4RTUS6ZPWFUPIPAS3H6MYC5TH2ZWZ2LNYA36L33R7BE7TALHDGU3J347H56X57737OXL37735MHSP3577QAUW3R5DQ====END diff -Nru python-hypothesis-3.44.1/benchmark-data/intlists-valid=usually-interesting=size_lower_bound python-hypothesis-3.71.11/benchmark-data/intlists-valid=usually-interesting=size_lower_bound --- python-hypothesis-3.44.1/benchmark-data/intlists-valid=usually-interesting=size_lower_bound 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/intlists-valid=usually-interesting=size_lower_bound 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for intlists [lists(elements=integers())], with the validity -# condition "usually" and the interestingness condition "size_lower_bound". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 382 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 959.35 bytes, standard deviation: 668.30 bytes -# -# Additional interesting statistics: -# -# * Ranging from 2 [17 times] to 5024 [once] bytes. -# * Median size: 817 -# * 99% of examples had at least 2 bytes -# * 99% of examples had at most 2788 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 3376: STARTPCOELGF3SIS3SDKEP6SWH3BWJCIOAY37IUQU6Y6IDZHRX67PMKPCI3Z3G65KX6AACKEQIUD7775PHX777X7PH25PV577LGG7L6V6535PTI537P5ST6PTV2XX27WPD7IVPWOPPNNO6N2I44P6FRT6SXHHV5O3U5XSNSXPGG7ZWZLB5RZ2A7WDRK5SSXX26VWOTMGG3LZ2GN2OMOKZJ7L5TP3UJBNWO6O53IOWPT4445TY3TPJPLJYU3S23K2HKU3K2PXE3FU43NLD726HHQVWHSE3WP7FZVM272OOPFGROVENLIWWOVCORZG5MTWJZT73S3TXD2ZBE4T64Y3QAZPM4CYCA7LN5TTPKS66UU3GB54RR674V6ZWKREUPRUPJSH3WJ3E4K5L3QZ3XYAZCVHXIRMXC76B6UMF5HTD5XMRGY55PNNEFFDNYXTDXQMEIELWPZFGBZOOAQSMCO22OCE6YVC4LPTXIXK2JMMHBXM2DXMBUQONZ4GW3JTQH7D6VMHNG4ZFXJSFGGPRI5KCRPNVQUNHMKYUUYX2PJNXOTVBVBNXUAVQAIYXQNZWOY2NRM364BMA2T5X52UNQKZIXOBBXXL6MDVNMZLT5PY7CTH3267MZKQJHRRTZKEB6PRN7PKAEDLUNKBBJ5VQFW4I4J2RCRIVTOAMUXME2OZVV5B366R4DIKV3ZVRYFMSBRVIR57H6FIK4LFQB3Y4FMDLDG4XGARAG2OJJEIBM5U4HUBWCXWZID3TIELYKNU24BMIFEPMRZHDIFFNFG5REZZGKGXYUUI5QLCZNTLSZ3M5UUHLMXWIEHO2VC2D7EGBFNSWXG4EZVCOGVDZ3OF6FGFSZWXYJS2JTFDDUXJBHC7C3VRLVS636BBYBGVL24V4JNELMBEAXRFG33OJQUUE7CRCKEC3E4C6RIPTC25QC6Y2UT5WB2KQJPSO5M4NJZCLRISQXGNTR3A33WQLFRAM5JS4ZTKGCAIHMTVEDGEDFVBQITO6ZQ7EI4HBDRMLRHNG6ODGPGA3LXOCOWUFKP5JGABE5CCNATBNH6FCZJ4ARPWO44D6ILGIUIOZ3LFSZWCZMTVJIF4O6JPPATPW45GW2HPELR3WJYPTKJARQRPGLEDAYLHPSQJRAS22AYYVSA557O57TKFBQRPTWMUNZO7FIPBHIA5ZTAV6YZTL7LR3X5JZY53NPCHFMUB6UVCWSJMDB55VALRLOUTZX2R3QONGLBUK5HHEHC2BRCVSDS5SOGCUZG766OJFTGAQGMZDOJXSMOC24AY4FU6PUU4453BWT7RYT4K37WYTHQYWC2QNKQ3AK3LWWT3RAOMNDBHSUZYSUVZIXJXBVBX7XFURIOGHD7WAVCW3XYOSLTEPTOSKPHJI3DJ2ZCZF3EB6NJUEPI7B3HQTAGI2D4MJZXRXZEU5GFIMMEHTIP4MNA3XOTUIIRPD2XKULILWAUEHJCLHIJ4U2ECDPNCIOUCO3SSB4237FEHCM4WWZV5KEBCQC3PU6X6KVZQVLFEADMLCG54FMNUVTZSL2ZLLLQITS6PH3LHUTZPVB3LCU5DAUMNRINCXT4XDJXN3WSTHHBGGCSGZNYTJ5FVESIASWLUU4U5BZGJCW57RXGUKXOZYQW5N74S42GMJAX2TKHOPWU2M5DJYMMKRDWM45E5AIIAEU32ISOKCQGQ5KTPY62Z5FHF3APLPFDTYXQOJ73YSJKS2T26JLW2SGZTVXVZOXKPC2YVA24YKZ33VPFBPCWUL72BHJIQ55C5336AWTMCLWMXPQPOIRH3KRF6ZBHATGY5JWRQNRDL62QH7FM4ZKGQTS5JKOWI5XA4S5J5IZAHE444FEAXXVQ34DCBCULHCD6PSFH3SOKHHYSKKVO4S5MXSKCFEGG4F5GXPDTUWE27VDSYNALAO7I6H2O5TTLB2MBIR4CWDDYHPUJPFX6CA7X27Z5U3V75UUKS357UACUUS2NQLQUHK25FYURK4LEYMOXVAQLPENXI4PTLZGOIT45VWR4ZBMHVKOMSWTKG65ZOUI44YITI2EV3K4PY3UVIFGNGDJJB4PXINKEQROJP7VK4RGF26S32XOOZ3BH3HSOEYALFHQKOZBIMBYBDHKG5X25PE4IIUQXHGTTSPCVYV2QXYJC36KSSPBNG36F3PUVKZUMS7UTTSINDX3DZXJQ2OY3U2J3NFV44TSD7TC272KKGSNDCE2ZKEPPX7C46NPTLRZM5AAP23JCI2KSBLUP2MOI45FKUVN6FDDXNM4K3QLKR7NWOD3JZX5IEA2J42TSFZXR5L3FNSODHSJYAVSUUBVU6G5SGXDX6TBLWUJ4VVAEPGMPM6WSBHIMKEEUQZGAWCDYQ4AMLVHBSHBW3UYCO55G5GCRDARNJKMYILQOGHAXDSVMWQ6BBIBHJCOAADHS2BZQTBWED2OO3SQIPKGA25MFTWJMJ6THA6UZXGDPCFBDXD6GTTZEUNO4SGMGCSCBSR4MTRFOEKHV7JTZIUHYAAVJDKGNC7JL74ZCTHGTI2DOXJRCLHJQ5NQXOK3H6646S4C6S5NNEFIB7NGVKGEOSBAVEW4XHXZCNTFXYVVMHY6BSPYIWQTFMSHGA2TORHARNSAGGLAXL6FYYCSB35MOLCAYUKQLHYAGO2OWMEHXEKVQSEYLTGFMSDMCH75Y7TKFQ6IEZRR5524VXAEJHLMQJ3XWPR4TV2YZZ4KQ4HS3HZDICTUTG6BJABXLP3OQ3QGV3QFRWDO2442QNDEGFTKFEVTYCSGVDSYJ7K6TZ375TCLY7YTF4J3VDUUY7GQICQNDGZSUOLNUSF5CV2C5RWF4JAQCMXA6Z43ZKWUB3L7PHUIRPNAXZP36JICE3XE6PFS5PCCGWTOTTXXDPHTY2CQSLJ2VHVEA6GYPCEH54W4WTOF5RXDN2M6E2VMKPASE46IMMIKP5W2DH3VE6QCEPHCPOCEL5NQQ3SF2IZ6KM65LVDNX2AFT36HUSDR4HIYW6NENEDFSWFXCUYQI34MDYBOEIKWQNUGBRYZ5XOQ6L5DXF626S764UX4J62K5XETZEH5IIAY5X5BHNHJ4XVOV2Z2QSY64WWTCG4OG2L4BXPOT7ON6DLJEHUKPRE6K2P76MGKQKIZIPENWVMKIHHUQOHBPV3PLWPFBQ7IAM66KYPO4HVLFNI5XTZXXGKBPLHFP5Y34DQCFANNWRT3MLVSRQOWROBYYVDDOY5FPGYDVINWZ4JVFMYJHSYPK2NMPVBW7FSUCZCFVUD7BCL6WKJC7PHIET5V27ZFDKPUPBLPHSYT6IWVMU6F6K23RA5IYVVHOLLJN6UGQUEQ6CEFBIQZX4IANQWQN25E7OXP57X77P26P57O7367V2UBDT77YH5ZB666E======END diff -Nru python-hypothesis-3.44.1/benchmark-data/ints-valid=always-interesting=always python-hypothesis-3.71.11/benchmark-data/ints-valid=always-interesting=always --- python-hypothesis-3.44.1/benchmark-data/ints-valid=always-interesting=always 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/ints-valid=always-interesting=always 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for ints [integers()], with the validity -# condition "always" and the interestingness condition "always". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 372 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 32.00 bytes, standard deviation: 0.00 bytes -# -# Additional interesting statistics: -# -# * Ranging from 32 [1000 times] to 32 [1000 times] bytes. -# * Median size: 32 -# * 99% of examples had at least 32 bytes -# * 99% of examples had at most 32 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 104: STARTPCOO3V5BBUACADAAYFKZU2QUCUSKYQTQKSQOWIHMBZNWAXW4CC3TLZXS2AVM24QSAAAAAAAA6BJU7IXBH3PNJLPEOMAQKEF23Y======END diff -Nru python-hypothesis-3.44.1/benchmark-data/ints-valid=always-interesting=lower_bound python-hypothesis-3.71.11/benchmark-data/ints-valid=always-interesting=lower_bound --- python-hypothesis-3.44.1/benchmark-data/ints-valid=always-interesting=lower_bound 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/ints-valid=always-interesting=lower_bound 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for ints [integers()], with the validity -# condition "always" and the interestingness condition "lower_bound". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 374 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 5697.52 bytes, standard deviation: 241.36 bytes -# -# Additional interesting statistics: -# -# * Ranging from 4768 [once] to 6640 [once] bytes. -# * Median size: 5712 -# * 99% of examples had at least 5136 bytes -# * 99% of examples had at most 6256 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 2520: STARTPCOGLGB5SLWDMDEEV6ZLL4IL7AX6UXOF4XGBWOG6ZQXN7XJDPQ6UFT3MUJJHCNBA3BUDIAH67P4735Z7L7PZ7PZ772MKXLS7D7Z5ZY7RHTNH4PHHXKPOXDHVCLVSHHWHWUZON5PMWXO57LDRPV7ZZV6KDDSVV2OX7MXNP6WZV2KRD35M5PLSGLNQN6FXOLHUWB3IMJ33Y6ZV2PWULBU3XJDP4HEYY57W3LQSCPVPCL7KZ6FVU633ZVZYGUEPADNHYABB54TM6EVSPUSJ4MN7MXPBZ5WHS5W6YODYOC3RUI4OHYBMS6O5LYVE3DKO5K64U4UC37S3COJZ3X5PL3RFPEAPARDOAA3C5TBBS6PKK7HHXGXH6EPARL3RLFNQLLDGPPBZB2EDCXLEBCJIJSYCLPX3H255BM2TNPP3SM3WPIPBSHP6UXEJUZLRMYT45DQ35OK66YLGVQICSMEUK7QQ6OYW4MNXX5NQA3P7BAMTCZ4HL7P2QI6HYABRXSBJ6YHFTTA464NUWRR4Y5GM7FPFSFTWQTMHVTZPROQPESB3DKL44H2ZGMWDPRPTO3T4F2RLVUE4T4ABYRAAGC6KGW4G2DCEIPBP6VKMEU4CS5W2YWVVK246IXNLFETPSFD7URVRGBXIBJDHF2UNNQ7MVTGB2MCUMSHZWV5LYVFPQI4UO3DPVCJN6ZNWFCYFFFDETXQKZGJP7RKPMWGWOPIMNHEUS6HIZIR5KIROCGXWNXGD3M7JEG3T3Y7IYEZ6UDE2PKM4OGRR7N6WVVVN6S7NZVTSYS7LFSF5TXKZ4724FMX6WF4WEAQ7RBI3ARJ4MFDWK3SJ7WD3PLLGUZIC7FCTEO4S36ZFEPXFTT2ZUSCGIRBA3R5CVADLEMYUEVOM3IVD244THIRD5VHERFREDPXMHMRV4OCAUYUJVZUDK5N6ZRHOVPGZWM5KB3RCJONWSPZ5GMSRXEGKUIA4POAT6OOLBI5VV3DUKKIMOE7CAKVHYT5VNIS46IU4K5RD5LP66LGWTPWJLLYDA5WUXZJDZ2XYJATJAHNQ25M2CCQSLYUQPQLK35YZOPQEM7DGSPAX4ZLK3BSVAF4WQ6SOGRK5SSZCRQH43XVFGZKKRFIVD6HHLK7ALDBT4PCUITHHNVY5FEMLTVQSCPM6ZWMJAU7MU27HT2WJ3WJBUCCNDKZ4WGZOVIA2K7PJKNQY7CRLPUWPVQTM63QEB2X5I6JRQTNNPXV3H3PMLB3NDSYO4BKG4GQ3EJTCYQXMIXM22YZHPBHNXLR2EPESN3WNIKGLIR2XCIHMXVV3HCEAPQ2VKPBMTJJHK2U4OWBWCU45YDHN4AFUT45LHLDGLFX6GWWXVV5QOVLFAHOYF5J4YNHHUWQPVRJZZGJ3FCPOVZWO7ZGZ3RTR5PJDGT5P75FAOXVSXO7PXIG6OLOFTJRKXTW37KRVKEOYRY4CT76WN4RYFSN3ZWYRSJLKHJIPVESLEQZ6PI3ULXEDUXSMQA46VSZ4FBC2LSJY2A5VDRMQPJNOGPKWYWZ5RUMCT3VOGDBHAZFP5CKWRWRJXTROQXFGTGXJYWAGQFQ5VCFV2MRKRWWU3ZLXYBRBU3JN5HX5DBOQVGJCHRDWVO6PE2WLG65TP2PJV3TTTR52E32W4L7XHATQUVJI5DDXGS3NOL47G57XJYBPSNO427FHRZYFF4FEPN2JKFW2I7HALCT6OJQA3KYCZLLOXP3DA4DUU777V4V3ZYSCQ443FVWANU2NT6YQTUCW5B5OZZ5E6Z3CXBKWUVCXLGUXY5Z5TGMSSKZZ7TGOEHZ5EQODXLMPKJSE7K5NEOZUMUNQHZPZLJNEQ2EFDB6FZZVDDO4INHKIW2I56WHWS53EX4WTJCGLWA7M3GNAV222P76TXKOW3U4QGOPWPM22U37HAZQNAIVVLKERPCVGPNTKUJ5GIU4YMJKJHE7MBCJN37HUXOLWK5ZPMSPW4OKKPLV5KFWN2SW4XNHJE27K6VRPOTJZF5KIJKXBZN2ZJHHXV42THZEGD2BRPQBDKJPRDHAWOK3VYL2BQPQ52TSI6VZ5YV5GM34ME5QO552X7DPYVHJCE4BPCCTL6LZUZ5GEL252TUC45SNEHVNIU3YMNNBTE4KHD5L454KZ6DHMG5LV6VFXPPPJLLEAMSM5O2ZJYY3CMU7XM7HAL2X5PJLCXO2FPGGH3KMTTIWGYFXTU75KEI3HFPLDL26ZPWKPVK4R3WFRBNXIX72KW5GC6G67U3OPXD4FE464TE25C2X5OMVBTWOBBLHZ3PPIBPVUY3PM5ZBMV3CKFAHEZ25URUHT52JIL3LIT6PNKAZTW7B7BUA36AMQSJ4E5FMMJC37XNDFW4RNE3KT24L5NLOUFDY23WBUBJN2QTLW3PTHOEJ3E6QOPHMP6XVH54YDRPVLISOENKRON3U5M7KHV5X4J6HFSTIU3NTWMN6P4WKT367QM523N6ZXZUBCKJ4OXCT42G5NH57X27D6P56735PZ7ORR7Y5774ASNGTJ4Y======END diff -Nru python-hypothesis-3.44.1/benchmark-data/ints-valid=always-interesting=never python-hypothesis-3.71.11/benchmark-data/ints-valid=always-interesting=never --- python-hypothesis-3.44.1/benchmark-data/ints-valid=always-interesting=never 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/ints-valid=always-interesting=never 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for ints [integers()], with the validity -# condition "always" and the interestingness condition "never". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 371 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 1600.00 bytes, standard deviation: 0.00 bytes -# -# Additional interesting statistics: -# -# * Ranging from 1600 [1000 times] to 1600 [1000 times] bytes. -# * Median size: 1600 -# * 99% of examples had at least 1600 bytes -# * 99% of examples had at most 1600 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 112: STARTPCOO3RFRBGADAEAAYBKZ5L2TEQEAUWKF5RGGDHKOOF3XPMF6FPXMS6O5MNTI7PNNWWLLA3O3WZW5XNTN3P7T6SXEDTR4YHWL23PA7D6RHHFQ====END diff -Nru python-hypothesis-3.44.1/benchmark-data/ints-valid=always-interesting=size_lower_bound python-hypothesis-3.71.11/benchmark-data/ints-valid=always-interesting=size_lower_bound --- python-hypothesis-3.44.1/benchmark-data/ints-valid=always-interesting=size_lower_bound 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/ints-valid=always-interesting=size_lower_bound 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for ints [integers()], with the validity -# condition "always" and the interestingness condition "size_lower_bound". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 375 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 1063.74 bytes, standard deviation: 743.83 bytes -# -# Additional interesting statistics: -# -# * Ranging from 32 [342 times] to 1600 [658 times] bytes. -# * Median size: 1600 -# * 99% of examples had at least 32 bytes -# * 99% of examples had at most 1600 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 528: STARTPCOLKVN3B3BDADH4SUUHHB2CAVEP2FOEI2D45XKA7Q5WEQCAJHWLW4Z2GQBFCB73L27OOZN6JVFR5U3Z3B36T5PMRZ676PR737L377E77QNVMBLWTN34H5YT5GZFJXYGVPZLW5QPDRTGKHEQ6O3UXLQW5OFUGOGKTA3HGWKDBINPLOUYCPKA4VD4UN65LEVGR24KMKKUDW3JGEOW7SXNKNGSLCGSRNGWGXDX3W3N4BYRZ53FRVIVIQZNDXFH3MVVYYY2H3NU7CXNN7R5T3ARUQV6YN2TMFDV7P55GSQ6YZ3RVU4YO3KHSYYJQA55TSQGMRNUKUZCGLLRNN4VGWCW4SYULHOES4JNOLHCU33UY3Q3YNQQMQIZYW7VYPP452GCMYO47ONI33ID46BP5JOKC3XCWXXOLHFCROMAX7I2PXR2RWUIXFAETMNWTOKZXAW5NW4JVPMEIX4PG7OLJ7F2QTOTXE62DLTAZY4TMYQIBNN7VWHGPF6V5OUUS5U3VZRRBWT4HYYJZ2NLNVA=END diff -Nru python-hypothesis-3.44.1/benchmark-data/ints-valid=always-interesting=usually python-hypothesis-3.71.11/benchmark-data/ints-valid=always-interesting=usually --- python-hypothesis-3.44.1/benchmark-data/ints-valid=always-interesting=usually 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/ints-valid=always-interesting=usually 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for ints [integers()], with the validity -# condition "always" and the interestingness condition "usually". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 373 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 35.44 bytes, standard deviation: 12.91 bytes -# -# Additional interesting statistics: -# -# * Ranging from 32 [910 times] to 208 [once] bytes. -# * Median size: 32 -# * 99% of examples had at least 32 bytes -# * 99% of examples had at most 80 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 352: STARTPCOKWVRKZ2WEULKWWJJIQNRW2JIYAYJTCMCJWEEGVHC2NBY4ONENKR5MTH2MB5FUN6UIMEJZOZNBRYGWI6XPWDKNJRIDKGYZLBIM7RME2QHUJKET4JXFZ3RDI2OJIWBCG3L5GKV4ZA2ZOGD56THKD6GCOKYKIN2C52AOK5DCZQMYR5ACOOR2DGIBOUWKIZVVQ6OHTKMRABEC2BAGEIRGQZPWIDDSXNJKDRNIMP5BJQ4BYMBF7GEJFMAB5GSWL6RGY5PYHLISDZGG4JBVX4HZLZR3HXZTPOCJRZWDDNK3M74MZJDG36BJAXJIDYS55MSYDUC2LYWU2QKGA5653DOLQFQAQW2L3AI=END diff -Nru python-hypothesis-3.44.1/benchmark-data/ints-valid=usually-interesting=size_lower_bound python-hypothesis-3.71.11/benchmark-data/ints-valid=usually-interesting=size_lower_bound --- python-hypothesis-3.44.1/benchmark-data/ints-valid=usually-interesting=size_lower_bound 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/ints-valid=usually-interesting=size_lower_bound 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for ints [integers()], with the validity -# condition "usually" and the interestingness condition "size_lower_bound". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 376 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 1227.23 bytes, standard deviation: 810.66 bytes -# -# Additional interesting statistics: -# -# * Ranging from 32 [280 times] to 1984 [once] bytes. -# * Median size: 1744 -# * 99% of examples had at least 32 bytes -# * 99% of examples had at most 1888 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 1672: STARTPCOHLGFRSLNTADCEP7C6GOUFITJRI5N7SJEZOK2SL6LUZ7R5WFEAE32BXI4I3DUSIBQACLEW7ZZ776XV7PZ6X7TR7O7B6OL7XPWUPWK626R7Q7NKV7V6X2JD7W72WW7NO7623V5V3DJWI56H6XHHTXPHNXMOQVWLLFUG73GV33MM3EXPYY73LV74HOJXQ5PN337M6ZVH3PSC5FY7IV3CVZXFYPPGBVBHXR5RND6AHWYDWYUA46HCRX5YT2O5K7N3V3WYWCM5FNFD425ZWAWF3KYFHNMDZ7P3M3F37WTLGWCNU5ZJF53GRSDXGSH2KJ7QCWUJSZYNZ7UE6XZ5PWC3T2V3U3WOWF4GDX73ZIJWQBV4TU6TTYVUMT37F7N53F7WZ3UZDGNFKEBU7K7BRLVBU6GEHV3255K5O5MDXET6Y4PDWBODQKFA5NMHZTCB5ZLTEJ44FB6X2OBNLFXTM4QZNCF34PRPCAND32RWOWWUWDKRN4LJLXI7ZNOKF5KTDZ4O46LGLL7LLXLKHXVROPDJ43J5XH7WAE6HHNMHHHYMBFKB5YRAD7SUL7ZJLOABXUBDMOSW5EUZL2U5L4RRPC24J3QIKESMPGRMBITHHL6SQHCBCKTNA63HLKQ4A22454HYCCEKXMGTKNMQJ2ARDQBD2E35XD7BXTOIWHBJNXA5PFKEF34FAJZYDS43FGXTTME5GIOFSKGN2WHC7SVGUG7ODUU65O6GBEJTLBSA66MSWTDNNU6UPHC6OLSZQHJYOHUCE7AAAY27SYHPX53JVTCM54GMUBKEUS7NGM4QMKPYIMHSKMRQ7E6CWFZ4YHMQFLY5N7PS2MRUMLWLX3RJ3JP7GITHGCMJBKCLRWFDKKAFM7XRE4LQL5TM4DZVCRVAXXRWL5FFI2BSIWDRMHCVKA6Z5DSKZN44V33KCGJUTWOV6XEDIE5SJ7W2MSMMPBDMLTHTSPZYW4KESKBFEFJ5DRKBQ5HPGNGOY5YZL4UTN3M3ELPZLLPKBNWBLGHU4DPQ2MAJSKB74MGIGQU47IVOMNEHN4F4YC3IT42ZCAOLWEFCEVEE5MHXJTCQU6BMAQTUF5LHXSBQCCCEKKG3NY5E6KTYOXKXEOBAREY4DGZUNMSVRUNAOA3YJ7MZ4RFKMPSEXQJJPIU6ZYREUPDZ7ACFT643CWG5TJFHBRVMOTJMV65NGBOQXVMY25YFZU6R5DKEFLZZDBA2Z7I34YUWREGFKAMUOHQKHUTYKMGEPA4FIJOUT74BDRMPLI7HA5JU5O4N3JYVV4EI3ESHDGW33GL22CNU46S5T2WA7ZQNM467YR6EVK6UPFBYYLOV73IJZEUPKHCQOGQTWM6WVIFG2QFNMSY6Z2RZ2DBQUB3CSBZPRXVNCYNU4S5GQLYBI4NU7SMULJH6YRJKG3RJYCAKA6YTPYZJTY22DTJEZ6EGLGBNTQFTYHS6P6PQKGEMGMUVXFK2H2D67WU2J3PPT4XDLQRAZQWO3GFUVKWG5AGUCACEHLCQHQNVXCLMMKXNQZKHZCG2FNJTXGXGLKC2HSLOR2HBVV4LSCIKLQIG5JCRL7DRBEPDTOATB7OS4TS7WDX57G3SLHQGLS2LZ54AAQ4A6XJNFSEKB3QV6RLFBSHLOOHSVLM4P56LXXN7HY7X7XR7N2H2H7H5A6GK7XHIEND diff -Nru python-hypothesis-3.44.1/benchmark-data/sizedintlists-valid=always-interesting=always python-hypothesis-3.71.11/benchmark-data/sizedintlists-valid=always-interesting=always --- python-hypothesis-3.44.1/benchmark-data/sizedintlists-valid=always-interesting=always 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/sizedintlists-valid=always-interesting=always 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for sizedintlists [integers(min_value=0, max_value=10).flatmap(lambda n: st.lists(st.integers(), min_size=n, max_size=n))], with the validity -# condition "always" and the interestingness condition "always". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 384 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 2.00 bytes, standard deviation: 0.00 bytes -# -# Additional interesting statistics: -# -# * Ranging from 2 [1000 times] to 2 [1000 times] bytes. -# * Median size: 2 -# * 99% of examples had at least 2 bytes -# * 99% of examples had at most 2 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 96: STARTPCOKWVRKZ2WEULKWWJJIQNWSKEMELI3ICSG2EUJURJDNCKA2IWRWQFANNIKKXI5AKSOJVGQCNTARWW4Y2QBABUO76ONA====END diff -Nru python-hypothesis-3.44.1/benchmark-data/sizedintlists-valid=always-interesting=lower_bound python-hypothesis-3.71.11/benchmark-data/sizedintlists-valid=always-interesting=lower_bound --- python-hypothesis-3.44.1/benchmark-data/sizedintlists-valid=always-interesting=lower_bound 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/sizedintlists-valid=always-interesting=lower_bound 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for sizedintlists [integers(min_value=0, max_value=10).flatmap(lambda n: st.lists(st.integers(), min_size=n, max_size=n))], with the validity -# condition "always" and the interestingness condition "lower_bound". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 386 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 6083.48 bytes, standard deviation: 2640.32 bytes -# -# Additional interesting statistics: -# -# * Ranging from 2 [2 times] to 62752 [once] bytes. -# * Median size: 6097 -# * 99% of examples had at least 385 bytes -# * 99% of examples had at most 9697 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 3944: STARTPCOE3GF3SISTODSEP6SWH3BW7DAIHVFPFDSGSDGZ4PW4N7X3EIH2V3WIXHIVCXKFQJACEM6B777PR5OPP57P56XRY7LZ6MPNPZ74LDHZ7W2SZP57ZYO6P66L2KRR532VR7B4PUVP257WGHNP36I6H66LGPVVHN2ZZ463NXXXKO76447LZWUF7O5MGB3232J33BVGTNLDWWHMLUB3X225UCP5LJUP3HFB765P5HQ5ZETKUTJ4JPHU3T3T36WURJRJVKWXR3V4YRPW7WTS5U2XILS7PIZVZEOHDSXDO6ISXEKAHMJNGPRNO2RXKLHXS77MPI74PUXJKIE4W7PU43FD5C76B36Z4GOEUCQAMOPCXVFQNN566R2O3ZEXNRNL3KHNINUZ3LSUU3UWK555O2LI52TLFFIFG4VT5LZSTSKKHU77Y53I7O2DKFHUERICPRCOTEC4LKZHO2KPGTHWE4FJX6TIPCPVVOJ5HJ27VKKPONM73PLTFDVKG3LTI66PL5LDI5P23JCSZL6LSOWQWH46FR4XCBKYC25VJHEAHDAFCWP6Y2BA4FWI5HXLVWBF6ZJIV7LPJPLLS5524IQBT7M3TPCH5NWKVHCB4TBGVPOPTKBYU67NLCFYCAJBYSD7MOVOOTTAFQZGBT55DKNLQL2WJKZKWXYNJC2GPICKWCB5FHEPAX2BVSJKJZ2D2CXJAKMWZIYW5LJY26SGI5EC6H5JRPBYQJPOEDFAOB2BYOSJLTPLCJEPAAVOQLWQK2SXPEVEWTSV42RPG2XDRFPMUHCMYANMPRY2ESSWTUUJIN5HY6XT25KM4C3KTOBSDF5DGJ3ZLOFXRR5EIOKT3MC4OXKDVNX26D23WXDHRW6K4LRA2LK6OUGOWNMWE2W72P4HCBL5UYAH4ARMAXICN43WDVXFDND3O6RGTCZA3JFWZ5AAQRIVTIXYADT2R6E3GD62V3D6STCKFCXT62ANHHEWORKDNKAJH4UBEB3SIKZRW6T7RKFHFK4LHS5JYFBPIV2QK3PHPWVKB7YWBJUS6PNJSLVTORLSAZ7CUTQIAPFCSVRAFK6R7A65G4ISVQOXKS5DHVB2QUIH2G2Q3LO6WXO7MLJJU4J67PHCGMC5GVXKIGWOQKTBINE4JYFWAERTAG2SRIUOVAABOHDX5BT3QIENT7QJYUHCUKI27SHWKTWRLU6K65WELBSJOHD2PUMCVX3KD2NI2DKN77JECJTIF6MK24JWVVLKNFKEKGDRSRSJF4AZFCEYFCQNY654F4O6ODIHLXJHWRDIBUGYWAOSIWCIQQIODDYBJ4KET27X6C7P523UVFP3UJZYK2SUPBMYPR23XWIBADZBT5ABLGVTNIDDWJSRK5MCTE5BT7BXLIS4ZGW4RWCEDTITCCVB45WRZQOHYSYPFUYUECM3BI6XLXQZDVT7HKF6IS47RLKTDEGIY4SRXB66D5UFBKEVPZ4G2URRAFUVUBAMNGPHU65W2NNB5QHRWXHU3WAKYU5M5KXUT37L54C5IFVMX3C5KFJFMA4KQA2AL4BM7PVL7HZJCHGSJHNU6KDUVJPUWDLBGUO2MECWN63O5JFAP4B72QSBBJTM3MS24Y2AEHDZUQJAOTUDWIJWTLOX4GLPW2TKEVGIWDNI6ZPJFJEUDS4CETGHFKXJAMKZURT674O2COB3443FIMKFG4GOBNBCODN6XOQOVXEJG3DVFUIWMQYKDGNLYYWWNCKXFFFEM2DCHZWSI3U5HEOQECHB4KBJOYSVUNZSDCOJW7QHIKILDMRIYNM27XQ7OQEPZFKKRWLWKOLTPPJFFDJ6D3SQ36KPIT2ZSQJW62IMHUUCBYNRLLLUD6QADGHNWQIB5OE6GNQ47UACXDPF2FUWR2SVWLD2DD633ZIPVBNC3MCAB3N25AAIG5BPPDNNV7KY4MADWNGR3HXDAPC4TFKUYGPO4HUQD6T6QAJMOYME2BZXNW5EYP56YCGTSQ4WSJ4EJ46TQTQU2HQIBDL3GBLIHYHHIYOCMFLZXQTLSDME5AEAFCJCPLZTBLRIYBY3GVDWB4X3DROZANZEJGQ2UQJ46PM3MQO5TAKAN5VWJO6NO3YITWYW5Y3RLCKN42N7HKC2GFCREFOMARRQO7CO5GTJ4VGGEELEUBBFOXIRFG355CLFV6FXIV7YYVQPBN333IHWUHCDQZX3TR3P3B3FCDMZQH5WITKIUFLRBXNNBOYNOFZQKWSQYVLYRTEEDOTRSG22WOS6H5OO5M4AUE4EQAHZVXKFVAAAEXMHDYX2MEZ3M42HF5TEMOQCP7RV7XINIGNAPQSTUOXJWQTBB7G7XCDWCJH3MPNL3TI5GMDYTONHU4MUK6ZAHZDYTLS6J55MBWWQL524FRHUC5JVAHFGUVV6XVPVEKXA67MVEYXPYPVLBG2XHUVFQZVGBDJKGPW64HL7EAXLQWE5CVQBIZDMEH54B2YHENKGMGBGK2G5MRTBGAYN5J5AVPN7WV32PYJ6M3TSY65MAZIGDIXG4CAZG5DBT3CR4GCXLO22EJUOX4LIW7AYA5JQQIDAGJITMIOVNYYU5LNZQPMLYORDO6AZNOVYXIQ4DLKVTDDK7BRSUTZ3BPKEE64XESBUD6HNGI2TTY6VPLTB7QZE3XP7NDNYANPDVFG4G62YUZQDXD5NC2KGWYGRELYTGVXHQPIKE4HGPX6D4RMN4APWU3HBRW7W64SQKYCWTE7NRLHCO2TAZNEAJGUQNZCGW77MW6HIMC6AIHIRYNYQIWDIFUMPJU2KXJYGFKGRUCK3ZA7N3WGKWLLRQYBTEBDQ4546TQA7UO5ODKABGXUETQTDIXDEYF2BLV5RNFIRVYIXXMN32CDQD3NO5LU65MNE3QTFJSWR7ZTPW5Q3RXUGOCR3WARPHHWFHMILI7ZMAMPDAZ5LGDWEEZNNU4KDV4VZBVI4YZZEJJDW5LJNYNRY557LVCFKKD5GDNDO3AIFMDTXTBN5M2KZ55KJE6WTE6REY6PMNZRSYQMW7GYQN5HZ4TAUXCGUBDW2VKZ6NIK5B5SFCRBWNDQEWQ5REP6HYRH7GUXACZZ4HGWVXAZJYMVYKWRNNYFL6FVD5F5EBY6SAOATEAG3ENQWTBF7ARKISB247LVLIUK6HUOUCALO7EMQT64CYSSDEB6IKRWPSOY6VZP5VKMAPBT7Z2M3VJSGMHKG6P3K3FPVNUF2TYUIPCUYJNOKAZYCHJOWTZOQ6APMGYOZFF3MSBZTKUD5UPC5VENGJDFRRQ63WV2QH3R675BWTHJ32ZTUATLMIDAZXWMO626D2FR44PKX3LKOCEW3XH2WAUNPZIQTMTWS52UKMUP3RB7SBXW3QGJKSETKDYPUDVIRRQYKBXXND52LRAGE5FQ3ROCXINGZC5ARTTLYOC4E3UX55X6RRILM2HR34IJ34XWZVCMTVOMWEXOMB7XPQYCOQ3RDTDUEL3IIZJCEVJM5VEUZFMTYSRXWNRO2JJHSJZGAWR6MTZBGGN5VEKDGJGABF2UI4WYXL45RNJFBKOSWVUTPPXJLNBMOCL3RKVNRC5ZB23MPIFPBXSDOLM5CDFP7HTMYAUWME2RJWMYZQ5YDB6FJ5AVRQNUZSS5BGNRZ3TQK4Y3USFQ4UY7LKVMWHFEOOZTUNARPYN6AGAM76RGLZLKL5XLRMRJQJTCVHLXM7EV6TDI6325YT5VL64E4BHNZUGOE243HZ7E6WLLAIANHAZSCJ56SWNKWL4VOR6BLLL2GPYY3UR3L7YQZXGFXYBTW3N6YXAWF4T3KZ3IKINXB2FZ3YGAB6YECUH4MZZUAIUFNWM4KQJF6UMIYYLFACYL5XNJHK2QUHKTA54TNSRRRPG5SXGYQT3DSWUGCXEZE3DL3ZL4N7MPKML323PTGSR7GTS7H6CEIRXJTHSTGDO2B2735P767R5PT47PT77XY3IT75537VSYWGUI=END diff -Nru python-hypothesis-3.44.1/benchmark-data/sizedintlists-valid=always-interesting=never python-hypothesis-3.71.11/benchmark-data/sizedintlists-valid=always-interesting=never --- python-hypothesis-3.44.1/benchmark-data/sizedintlists-valid=always-interesting=never 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/sizedintlists-valid=always-interesting=never 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for sizedintlists [integers(min_value=0, max_value=10).flatmap(lambda n: st.lists(st.integers(), min_size=n, max_size=n))], with the validity -# condition "always" and the interestingness condition "never". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 383 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 6323.27 bytes, standard deviation: 1171.34 bytes -# -# Additional interesting statistics: -# -# * Ranging from 3554 [once] to 15672 [once] bytes. -# * Median size: 6224 -# * 99% of examples had at least 4224 bytes -# * 99% of examples had at most 9688 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 3912: STARTPCOE3GB52I2LSDMDV7ZNLRQ35CDREKK7YXS4YGZY33GC5X65YSBZS545ORG7K5FLFEJAIQH5463T777V547757HNN6775HXTT3PX7XJ5XBLPN5PF5JVZ54P3V5LVHP7HVO7N5XP7T257U5443X3U7TGZK7PMVIP347G2G73VZVFH5R6QTJ6OL3O367T6X27NQX5PSOT5RVKUWK7E2ZLZ5L2PFOD25GN2LZOZ7YZ4TNTY5YQJV2SQQ44HKZ53H3YU6HKBTCV7OZUBPPCVLMV5JVHPOHMALXZ22FIUKLGFTS6PL5H3IT2ZHGN4CX3SVHRVWRJXNVG35DVXFHBHCQZZSWKT3GUDX5MVVPWO3IZPJ2W5NX2SPY3DXLKSPYDFSCTW5IWA37O3D7KAUV7ZHGR3JTTY3LXVGDC5WX7PPTNLGXPSQ2VBJSTOVEQVPJ7FDNI5VQZZ6YWIJFC7I3VSY642SHIVPGVHXPTRVFQBBIOWFF3D2UQIDH24RYJFVPFNKOO22GNYV2RGHMNKT6FVZ3MZHKXJLN47ZFVKOPT6LN3SSVOTNZMETVPHEUWKLDKNDP3VSSM5ECQV6GZ44W4KE7LQLMIRPKZPJTCQGWP2GPLLCPQSGG32M2IJHJP44QIX5KUEZG6EFV2ZUU5J4BPKQSV75LNIKLULU25RAIO3DF3WG5ANOFUW5ZLO2ORTAV7MRWAL7KBDXF4VKXSXRZDHNCTRTKSFF35O4CSX7VOULPQ6L7OGBI4MDEIHLVDXUCSWH3W52VKY36UGK2NWA6YR77LDUWPDWHBCI3ZAWD4PPUDXZJ47SGP2XXTOO6PNEUHCRUSXN2BK47M5RWBACFBHPXLUWKVLMPISSSLXFDNHH2MFS72JOOZXZQPNZZ7XLSJYUJG4IKLQTJN5EFSYAJ43ACULFPW6BRRTJKS3W57POHTBFI5PCCBZXHCSO6PJAL5DODTMWPE4YIY3OMGCUAXS2MECCJ6TZQAD4QJDKVELVT4Y5GOW5MA2ZKPCU6476CJUTL3N6JYCP7NYZR2YPTHHC6V6PATKOMNDSP7PKHJYIVOUPWYW5QRT6AT5OU3EL3GNGF25PX7WTBJOSFRDWYUGNC4IA7HFME4A7F6MJT4IUKU7EE6MOBS54KIFZYE4XU3UFVAXJGP4ECKNXL34XJJH2ABCGP7BJEZPGZJTOZ6S4TALEY34QZ5VMOLIBHISYY56Z5G4AFJ7DVUDBWJL33FE4JSH5K3KKHAR3MKB27RMCS5ASHXQNFO5OAOXCNUG3HU2CW6VJUWWL3YHQHTIV226CZ56IXWE63AKOOVOSFE4MQGCMPL2DHAUJTKTXLPPJYHUZWGYUMJ3K4VDSSXVA4JQ2YBCQBCGKGXW23GAT7BEMV6WHRYL6XE5A47DDVYN7CMWRO5NOV62ZMDZFOSB3B22H6INSKSWFBR3DJT2FW27OJTVWKT3OMWS7X7OA4FKLFSA7JPTO4L5STTKWGUALXVA67SXLXVXTONLWAXN2M5IW6AKLWBZ66YFOD5WAQVKQA3DKAWBX67NEDXEPV43XOLRFDHQT2VMQ3YPNEYKWTFBWG3576CZR2RNPIJRN2W7IL2RQP422VHQM2VCGVL3UB2RHJ5AJFLPRUMDQCRQUB6RL7VET5GLETIPKKIUJUPQDA4UD7VCNIS5YJSRLXRWCT52B5C2ACTXKO5UGH25KBCELCR4LBARFDTNQTJTLLB754H36NOECKDNY6E67WB6OFS5WHD7UC7T4SSDPJ4Y4G2PYMHNUNJTMTHYYBEZVWYX3JFP7PXTVXTNPJK4ST35HILQAUHBAZKMTD6KEYVO7PCVSONKMZU7BAEKTUHYXIQU6IPALN3U3Y3NLUI5LTINTVRV6Y5ZNO7PF5TXFQEPPHWFYMBMCTCUHZNHO3OYCKHTVGO35THY6J7662YKJNVX2VLY3POYDUVOGLMKAXVJ34H543RTQJNUBKONNEQLHAZFJ2ONWAPNZ7VSQJ5VZHAHBDIOBJEA7ZRAG3S3SJIOK4GE4JROCGSN2ZHFWPQGC6REXQHOVE6WKZ6FJQK2J6GPIJRO7WEFL5Q5UAC5O6TBBT5P3IGL53OJYZOP634DVPIJVPR62G254LPDIV4AS2CHWD74N4TMCBJF6HHSM6RNPIHYKRYUB7JHKMMOEQSS7BUSP4RWN7AYBZNQPWWDYVXJPDSIIM5IXNU7QCXSQWB55RWPSGJWM3ID7FYZDGYP2FPAZJDNM5RZF6W4XWFQCZUUE2EHQUFBALAIDXB5UYWAGPNYGB2WKXZNAL3ZNCQ4TWMLBVJ7D3RDSW3DEF2DZQAHM2EJITJC5NR3RHA4E4ZQLBZ7QY3QLDA73PLZXKJW5M4SD4VLZLHERGV7F5DDHRHNQK5JERPGNKCW4V2YUGUWE4MAVZRPB3ZRYALN2CAUG33LJAQXDXDWKJ3O4FBVZTRNGEZEJHDY7NDTQRX7I35NREV2IMEJB55PKMZPC3362MLDBLR52456INKJJZ4ZTHWDXXG7TY3EB54AU475GGHO7DBG3TFGY5VJ73V7NXIOR26HP3DS4UX56TEY6AMU6CFJ7OLYONOHY47H7XESV7G2O2Q673AD7MDAUM7BRRRO6G7VUPRQ6WXRZB3BGNFAYFWTC3NXSB54FW7YCHZQJ2RBZADNSPU6CHHUKZYAZUB5BQ3TIDSLPKMSJRTJU7MZPMBMY3HYMMWOXNTXQG75AW654X32XRW5KPJBNK6K76ORB5CGIHOWCNWFRGHU36YVZWGLN37S52MNFYGC3I4HCVSDUVHXRUUCBPYRI3LRRALG6RKUT64XHYPYYIZTCHPRW3RUCT6UPB2ROE34UCIBOX7MYZ7HMUTENFJ6LAEG2BBZ6K7Q2ZS663KD6O5XFYGLCKGALHG2CXI4I2KVUQPR6DVC2GRF3E4ZID4T6LTD4H7ORBO2HZJTD32CEI4NHFXWQWNFCFZGVIBCDMFMJGQ72PQ2BDZO2PL5HYI6R6MDYU6W7INUHUJQQ2OMRM6URQAJXRN5PZYT4P347JGSJSBAFWGRFCJHF7BPHVQ7AFUTKOEUBO255SZ2RFD3GM6O3YLZF5HMP3UYTU7NRCNJHLYUDPJGPYSEBCHHE6P65KDHYOPKLWGLQ5AFDNU42Z7RZOXHD3W2KWJFMBCTVHP4LM6KA5J3SSRB7W6FYBXUZNHGWEA4NIHPWSX5TFQKM3CJRY5LTGOXTRJ4MHI2IW3RDTDF5QAGYGMUUCZBRRNNMVP2CQKR3H5TC25MBXCSZS4OIYPBKUBRDMWS3JOUNWDROBXIPH3STRA2ODB3O6VTPKDGPKUMGHKP3OOKNJH5N5GLXYELHBI4D3JTSWF2IMMP4I5H2FVY2PBLNP5Z6W7YPGPJOJTNGAZNIFGKYHPWUZWYGTOLEYU4QFNSATCXYCDIGISM426ZUBWGVCOEQJXI4O7OWSET34P53X3AGKUHLYYWSF7F35HYT2YW6WISNEQJDVQOHW4B2I3LMZY4LYORORQJ5KHCBIKAPHFLGHAODZNYAGI4HS6GZLDAWHNMCRTSLQDOCPQMNVYJA6D5UTANCUBSSJP4XMB5JBGB7RDB3MDFPDVBWZC5IRYHRFP6B4AK4IXANXQGULE64Z3YWRUFT6D52DIY6M3QFWHY2JSWR7SAWOWAQUQRKS27B6HF6PXEJA4Q6YTTHZBRTLJYHANHVSG6AAIBZLD52ZE4XAAPTLMPK6ZGPIOBBWGAUYCKH5CLW4SWWESP6MPC3B5TAO4JOA44J4DBYYKN5AZD2OWZ4IMJV5MTSM4X2OBD5O7CZCSQTPS57QWJCDQ2H2OA5B6FY2RO3PX7QHVBGSCSDSNURUHTHL3NBIGXSOCGYA6PTEFQZGFSNB5YGPVR7P777LW46P767DTW6773WVV775374ROGVCI=END diff -Nru python-hypothesis-3.44.1/benchmark-data/sizedintlists-valid=always-interesting=size_lower_bound python-hypothesis-3.71.11/benchmark-data/sizedintlists-valid=always-interesting=size_lower_bound --- python-hypothesis-3.44.1/benchmark-data/sizedintlists-valid=always-interesting=size_lower_bound 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/sizedintlists-valid=always-interesting=size_lower_bound 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for sizedintlists [integers(min_value=0, max_value=10).flatmap(lambda n: st.lists(st.integers(), min_size=n, max_size=n))], with the validity -# condition "always" and the interestingness condition "size_lower_bound". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 387 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 1285.08 bytes, standard deviation: 1151.25 bytes -# -# Additional interesting statistics: -# -# * Ranging from 2 [17 times] to 5662 [once] bytes. -# * Median size: 878 -# * 99% of examples had at least 2 bytes -# * 99% of examples had at most 5322 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 3448: STARTPCOE3GBZSJSDSDSEV6JFM4QKYTBK3L6S2ZNJPUDSNEZTM5Y77IBRTVKCUZC7ZYBHWE4BYDX667D267766PZ5PDZ7X37MYHG7L5TDHPV7PLF7HT7N7RP627EP2337OVYO777PF3LHLFNP77U24M6HI7KZ6MWLI5J6GZXXUJ5VKPJYGPH7PKZO53D532ZMRKITW3LJ3J3LT4BXZGAWVTICWAZ3HI5WXIYWM6W3T7UHXGO46O6OR6RS6PK6HJAHW4FK64GJ3GXWC2WM5YO567M5NY74TNOY7USCPPF6TDFO26TVNN7THVRMRJR6U7PGRT5DYT6NDZ63WXFX553VZ2FL5T7D2BXD3CCD3TMJSK5CKMX2IPFX2BHWNWHJV3JZM26BGF3OVLHIUZS35W65YGD3ZSM5ITQSY44TMXLMMJAWPKJK5BBI7DLOKWHWYZVGYXLFSSX6TT3UTUPCINBWOFKUZDH74Q3FVRKR7ZGKLCW7KM4Z4U7ABCRKO3DQ2RKHMXBZWMUXPOSMH27S7AFAYRQINRJOSDE24OMWRTUFVXPZVY6JX7BWHYXOKQTIOAC45E7IZBIXZ2CE26DD2F4VYDO63RVZN43CMQ43GAVVYBNOIURILTYTVVARBR4D36IC3XUE3FCU5FK6TOW6FLWP32PUSU76XMQJ4XOL3QUBCDSJPTVIMNZAU6G7G6JXFJEWPLGKSGFEPJY5O62ZDAVHMCXLKKJNWDBEFQESEOYTO3UQMIUUOPR2TEBF6UMIH4KSI22N6UNEXBSZCM2CN6A3XHPJ5NWLBXVD7NU634YFCDFSWKB4TIJXXPBORVS6QKWE43LF5Z4IA55ZR6ZQJME3LVIOZ6NJWM2R4PEDKKS2ZAL4R6LWLI76BD76ITAWJX635I4BC645GBPQAO6Y2QP3UYTAQFSOQJ4IKOPT4NCSQBXH276T42RZ4EU4FG7SF7A232PLNQQGGX73BZWYQTPCLHNBPNCHA3CQY6HPNMV3R7AEYBBQQPLEARASSZUCT3HWML63LKPRO3ZKEWD2RKVKKOXB2QV4SAM6ZLLXDIGCMDSQ7F4AOWVGJVQROMVFCITBTLS7BEEMCLWGD4OBRFZLBY57MVYX33EGB6KMWSZXFUBOZZQMINQVVR3C2SUZ5BPDYOUITO4BYSRO3JE5DSHBMN4RXWS74QKLJEXDFS6A6UB34SX2UD5AOI3JVLZGTTRN7ZBKECD7NYPGFIXK2WX5SMRO2PXJJ3E5FWQF6ASZJOBREXA7RXE7VKGCDFRMHKWN3ZFMTZGR27UA6OMDLG4S5C37HJOCCF2LYIXKIMPGP7NIZ2RB6F7QUKIGBSYIHIS4B3OUNAIVEEN7KLKCTSSZIUGC6CSVOPAYMGAH6V2HTMUMTYUPVSIBIEIQC2F6PJKVADDEYQKJE5B5D7ZTMMX55U3F4KCH3GSTEWZ2W2BSE7FHHCFAWJSWPSNOVMBCFO6Z6HZSWWZHQKYIOITITCKRFBHA34H3RJYW2PKIAAK2RDRGWSGNUYN56QTO3JSJJKONFFENQUXAC7IXFFHEQ5CWUPEUOJ5AXIMEI6ARRMS3QA3QJECQLCCOUKWDMAG44UMRSA2DZAK5UYMRP4GGQX4O66AWE6NKFGYP7QFG2EGGA2F4ACN23JAJIVID266KYDBBWFB3NBCNVDV6RQ66KYFYTA3OMR5EIAPZGFIL7KMQLJCL2M54I6L2M5SGDBYE4RBXA5HVR5JRDZ65NUHRCVDJWTYYTTUQVPF7OZIP4XH5REEIIHDGXLS3QGHLRID7IP6PY7C2U5NC5O3ZVGEXMMJILHA5XLXQQQCYNN2PDUNCFKM2INEY34IIM4DH2ZR4Q2TSBLFUD7QTDEKX2CSZWOWN5HYXEAWW466TFJUEK6IQDEBNMB5LCAL2UY7SYQH6QGBPAVQ42KPUYKCTPHLJ4DV3E5AAI3NCL4OB2BTNPCSRU34TCCU3AN3VKLIIPYKX63TX6FIZPET2NMPEMNJKA4KJJC3EDGKVLJW4DWLUHK2TVRBSXUBGU4CUDJ5GGYIOPBBC5UOYB6FRPDO3EMFFBA2GIJ4WN433KRGB6L32BBR54JBMM2P5VXBIAMCF736ICIMBF5BECIJMLJ3MBTKXRJZYZH4MSPRKHBUMM5CN2DKNELU4QRW6NDJIZZIXXSX6UQDQNFNSK6UVKMDDCQDOQPFFS3EDWYQUQ4U44U5TVRR4B6GMERTRQIMGWOVE5ABPMGUZFXOSU3U6GCKUHQ4QJOGRSHWSLC46LE4CFVUHBSETKSDH2LVL36W25VD3JYG7PI5OX4FKLPVGPWV6RQCWG3DZHQ7QHQSTQYPWUDPRDWMD27MK2FGDVJSUS2YFRIBOGUHTNUJZBCYKGAU6TBNMYFU4DJUPRWFFQFKW3WNO3KCJGK7FKVPGQEIIPD5IPNGPMN5LFSQV2ZAMUM4YTQCKZG7XCMIHWJYMGJW73DKURZTDCJRL5CQQEPGVWRVGAM2IEPKNFB3CGNQ7JHCIN2YZ3O3EBQEZ4FPO62TJ7M33PMRSYRRIR4TUTEHYP2OX5PK6GMCT4KTVO2YK22DIGPTJJIKPI533CI5SUOQS2N4BWGHRIYUONE27NSNS5XUFZTPHEXJ4K5AOSHNUM3VUG7DUJZBVS6XQZEZFNSLFNLU2JLU34WOMXEM47KVIVNVBLF7VBD77MH3YE7Y32XLZLXTXKPKERMKK4TE3YBMFKURV6WWSAO72BGLKMQPVPQ4SIJDHUZ7LNF4CURSOACLGS2VGT65A5KIPHOCUKPBTOYLTKXSW5D4LJ5UMI7ZSP6WLYU4Z26AAO3LELZHEWBFQCUEC5MTLJJPBAGCDRFRJMEGDQD55VPEBBQTNLKR23KCTH4YSTAVPA2XXWTRZGW3VEDU6V3UPMDHABN5PXIUY2B6BSYFKPPHASH224Y3QOFOBTKNWH2PBZLAJYVV3RL2ZVZO7QMDOBCEUOY37SQ37HR7JPYCTVMJFAPFYNNY3VV4T4CQ2YDG2QH2ABFGUYFKG6XTYRG6CCLMLGLQYDCM5XBKIOBV6EXCMLFGTC5GLFNUFNELGX2NRAQU2KDSBVQFOCDN24YIVKFIEWY7P3BE4X4GBJSAGVBG2KGZB5WCW4N6H5ZGNWL6RC47ZPNQC6FSI5YH4VB75XHK6BSTJBKVMYASVOYZW7RF3H2G4SIF2P7PWIMICEATY3R3MTKUF5P32RIWY3QNSXIM3YR4N7HXXWK3UTSQZKWSWJ6R4TDWPGGAZTG4KAINKH7OLBZHGGNURRXOC2LGEUIZTQNOUYMWGTR55YMUCKU3XH4VJWBICTAQBGCGDGFLY3V7VEHMGVJMVKATFCLGRFZCJYSYU6O4PO3WVH4LROYM7ZO3ZV6XIBNMMF4GH4WB2HP3WZWROWXQCZYRETLRBIG67PP56X57PZ6XZ6PXR675IMP76777BKXR6M===END diff -Nru python-hypothesis-3.44.1/benchmark-data/sizedintlists-valid=always-interesting=usually python-hypothesis-3.71.11/benchmark-data/sizedintlists-valid=always-interesting=usually --- python-hypothesis-3.44.1/benchmark-data/sizedintlists-valid=always-interesting=usually 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/sizedintlists-valid=always-interesting=usually 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for sizedintlists [integers(min_value=0, max_value=10).flatmap(lambda n: st.lists(st.integers(), min_size=n, max_size=n))], with the validity -# condition "always" and the interestingness condition "usually". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 385 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 80.91 bytes, standard deviation: 339.19 bytes -# -# Additional interesting statistics: -# -# * Ranging from 2 [904 times] to 3362 [once] bytes. -# * Median size: 2 -# * 99% of examples had at least 2 bytes -# * 99% of examples had at most 1989 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 648: STARTPCOL2V2BOLBSADH4JLDOOHAQSIIPIK453SNEHT56WXJ36N6UYSHLCMHAU2O5TGJEATEWE5ZFSLHWC7H7XCHMHS7J2WPE6EISU3LTEKHMPTU4TV7CW4ABAWNPWDU424IYQAGE2NLOS7MDZEQFCZK65RGSCIQ235AQHV6GFLHN44P55JPX6C6HUTAGELMQMZEVMBCW63657WW3GB5MUEBTZV7WEA47KG3N3XL7SBORYUW665YUDHKIXSDAEYISJW2MZ2UKTK3H37UHRADDEH26CLIIG3COFDYFV5VDB644G7MOBHYBEFFA6467CSGQLVB4BFTDNJDFJY2VLOOT6TFSN2DT7Q6WU35CVCQFAVIRPBUSJYOZTC4HOE7V4KQ5XBA3PUSUNELEWUKFATOFPGX2OA2B2UKFQ5ABULPHEYJ6C4CO4ME5GL6SP6CKLMLEWD5XNYAEPWIBED4CSH3DEUPEZ3ECERL3PTYS6PKVD72H4BTZU5MGOAZFE5AOQBZDONBVPPNGVTCWOOHU256YBRVVZNGI4HN2GKETHRFTSJ57FQXKFFECRN2PW7HC34DGY3ZDQGZVCYKTCCKYXPZXCBNFJBGQY6GCJPZUETPXCYN2NEXOPUZQL2XW7NZ7EPUPT2Y3OXJR3UA=END diff -Nru python-hypothesis-3.44.1/benchmark-data/sizedintlists-valid=usually-interesting=size_lower_bound python-hypothesis-3.71.11/benchmark-data/sizedintlists-valid=usually-interesting=size_lower_bound --- python-hypothesis-3.44.1/benchmark-data/sizedintlists-valid=usually-interesting=size_lower_bound 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/sizedintlists-valid=usually-interesting=size_lower_bound 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for sizedintlists [integers(min_value=0, max_value=10).flatmap(lambda n: st.lists(st.integers(), min_size=n, max_size=n))], with the validity -# condition "usually" and the interestingness condition "size_lower_bound". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 388 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 1393.57 bytes, standard deviation: 1259.92 bytes -# -# Additional interesting statistics: -# -# * Ranging from 2 [18 times] to 6429 [once] bytes. -# * Median size: 1016 -# * 99% of examples had at least 2 bytes -# * 99% of examples had at most 5411 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 3520: STARTPCOELGF3RYSTODCEP5S3B4IEEKU2O76FODTA2HDPM3B763WWUF2A2LHO6Z2KWJJ6RLCWF77T4PLV67777T26HN5P37L3F35P2HL7PFZV3PPV7HX7RZD746L4PR74KODZY56LL35P4W47JLFN6XDLE7D66JA2Y7F5Z66BOLPUJ3JZ5OUKSMHY557PV66WOXQ247UO43W2PVM252RLG6NGG2URRYPZNPZ5W3LG73OSOP6ZROOJ5G44Q6WL34YWJBQMRYRWXW6M5PKXJESOL75DCW32GNZKTW4QFFOT4WMUFW45NZWYXIQ3H6WOK65HPLMOEAVHTYWRBMWZ6D7HGK2HM6K2XC2XSN6ZTHX4VBW2M5HJNZINT47BLE46GGZD243ZTCHHMX62DI36LW2SCB5272HH77NFOBUY4M44SUE263QDTRU2BSOLE2ATFDCWT4YS23PGZGGSUZL3XAVQSUO5X6JYUYZODVRQL343BLN5DRXU5E6BV3OTS3P2HPBGM55MHTZHF2PIEFPTFZLSJMNQ2IT2P544OWJWQUR7TUQ3I4V3UVQGAAWFWCSQEJGZ4HDZ4JO675AVAQXHJIF5DTDNQXKQEFUEXWFRIOYJIFB3PKEEOPU3CIM4UFZXLV54JLRX4TTWQB4PMSNFGBKHIBNZL76QKNGFKVXWCJYNVEKBXXF3OWZ6G5FSMEDS2XWG5YFGMI5PEGNHABACEWT3AO7KGEYK2PCGD2PGG36K6PPFWQIT4P5TRTWF4F2ZFOZGQRZ2WKT7EPX2GN3GD3BMNCVVVBFXVHJUFB6ZUBLMWPFNO5J4FN5KNE363XOPINCABDTJ3CXWPNWYMILTNNLEVB2LP6YFOLZIETUPMP3WBX6UKB7SCEDXFSOTKNYVJBZFVFOU7CQK74SYNFL5NN2TJJRCH4VVKVTATAXVOAGQ5B6IYEZNKWXVGKREG533XBMMVTMSOV4YM5R6ILP3NMRCF2IHAZPXXBXYMYQLKFS5YCZVKNATM6GH3KAYEBB2QIQYNS7CSIKTFKF37A2ZCIKYFYA4EHFCQUKWWNIARJK3PZJ4MXRYMHKBKJRN4QUOUZO6DK32DG6AYOFIQEBAXWNLZUQCZOOFVVCK2ARPI22VAUQDXL2FNVFVMG4PC2G73UHXNC3VWWGWUQ7JKN6KOIWWJXKDQAV4AYKDFRPZQRXQA5LP6EVEGKILA4JFJ4TO2D3VIMBJVSAEJBHIIMNIGE5IG3EBEYHZA6N3AK7Q5J3MWY47RIDTXA466FQVQFYQC3UJTOU353VBUBQ7ZKR46KRBXHQUV5QQAF4ROCJODHLQLQUYXOQCYE3A7OMDJO3ZIMPKPQWBWITPGERUYVP2OYDCJUQIRJJ4YTJDUX32GYKWLXXLMMIAFGM4PP4HW32WMD2MNBAYUI4PQU5QJGWAURLI5M24UAV3GAEHTGXFQQTVZTWXKU4MPALD3R6ELU4RWQHQONSUIIDAHHSVIK6HVKDVXN5VKWKVCWZSY2ARWSHIZ2HCGQEALG6OVNRUG2Q4KVERQLMRNLTNFFUSWIGA6AKPOGNDQKSVQRPHDAQAGA3M62GBDDPGRZ3APR6YAWH3DLNCL2GTIIVF22DSHJSNBKYXIJ3SNW35SVMDUVJR6D2JKJOETG3RASGDRD6ODV7J3UZHJQ2ONP4SXRDE4JVOSSANE6MEBLSNZJWL4JSRZ4VHH4TLDIOIRWDS5AE4NWJPVFV2YT7GKVHRK5PLETKNMC3FLIV5AHT3QFA52KLAYJ4RPQT367NVLLR3MY2FXRNOTCND4YYVEYPBDNXOV7AKWVT5KQYT7AQBOAICUIVQUQBM2EM2UXYXVKJDJLQJA77Q2Z2DQXNHDAFVUR3QSVYQTPL5EWJZGXUUVKKQQIER6SJCHVC4QBAJ2RZJ5EJ7KWXVECNZAQD3PS5HEBJELJE6I6KFFKS53C4QSSFYEEA3LCD3YRUJHTUDD45ZD2YWNM4VVJVNAUV7ULWWBPGSHGIWQ3MXVBBHZ6TVDHEY3PLUMNRHDWUN5WQD2IJZMZE3XA7ADKK6VCOBIETZRSR2EAYCRMX4YT3CYIT23YQVITAIZDZHKJ4BJQXJEDXAYVR5UGKWPSKQZN6AFGMCVBGENXXHWMQGVAACNRCMPZICFFDO2F7VVAPY6QJNLTA5DC7G5TCXFMOBA3UYAJ4YRWSBDA4IEOXVKORXDUXLSEHKFGFJLTIXC3WWQKPHWRLBJIIUR3E47POKT4N6QDSED45W3NPPOJGURUTDBLTCVD36SH45OYVQB2FUJH62AWD3BUODACCVLTJEIKNB5I3ELBPKE5XO4VVNZJXQJEVCCRHPLBF5KBBGUV736HPFLR4YVDK2WMMDVWLWEVF426WAOJ6AFWWE2ECD3HSKD7D74VTYP5GZ7RIJTQNXWBA3MO4YTQ3ILUAPWJSJUICBCRVA2XCS33CXOBNG3RDWY7TIH2CCLGR53IVJZQ7GBLPGZL745FRAZCOQ7A7KJFBJVEAUSCVDVCXS2KQBWFB42ICGMFEFVHCOU277KVNSJ5A5RSDUYZDRUZBBMUK2MZLFH6GEAB5UGIZ26R262VXWROIR4OR3EQJUGBBWAICMVLI2AJMS7Y2I7ICUI3IASSPAMZZCU2HL56A26TEAWO67ETZGIS3DE6FASJJVQMIVYVWSZFKWFAML4PGVETBW5BBBINMATVJX6TQIB5U2KAECFXIWERCGKEG3RZ5NEUSBGD4EYB7IAP4UXZJG75KQZZ2VPWATMLWFOQECUURLAF4JQQKISXCDXYWGXXKGV5N47GJFSI3KPWQYBVUZVI6KVNJBV5RT4PAZFU5BO25A2CFKGTOHPY2R2BM6FCC3GIHGOEKWBGK7AKB5SHVKVS7HM5QN5V4EYZE2TBTVTQKLB3B5XO6CG7QSVCXR7RPQ37MO6HANCOOYH6RUYYOKIE6RWZROFD5YVL27FH5JJZAUO4BVPPDM47JBYTDNPW7KOOLNUPN4M7ASN2QYVPB6C4EE2662CWKVSWTSJKGOP5CPZKAU6GUYW4KTMDHCZ5KOUUHCFY2JM4UTZQDW3C4YV2UH4XIZMIJPBAWUPKMRIBJRMDIQQ24YVTRAHWW27MJ3UTHPUI4N4FAPBV5KWD2UOJXWQT5G55WMIXU7DAXEHIC6VKXNG5P2RX3YW5FMXVPUXYT5BKUQDI7W6VJNL5LVRHU3VJHQMYKNNM7TU3TGUOSEBDDEUHKMPJ2O5ZQ3AICRYQYIEBRAIYVCD3UMPRRHE27JYMB3UZDCKNBUA2N6RXDR53KLWYZ7POWUM36YJK46UA7FLZJ3ZXHIWKDXTJB6OTWJU6UTHTTZKAQBEVSAF6WDKF6Y2MB6YOQUWCXQ3EA2RKVCHJ5C7BWRPTG67GFEKAZNZ4SZMBIUMNOM2J5AZJWK5P3ONUEBAYYOMHBW4LFUQAYBIU5QRCX2CYYF4RZP6LSJHYIASN6AFYATEF4OEUKHW6KHVKSYT724P56XR5PT67767HRTPVP3X77QCEAG5D3A====END diff -Nru python-hypothesis-3.44.1/benchmark-data/text5-valid=always-interesting=always python-hypothesis-3.71.11/benchmark-data/text5-valid=always-interesting=always --- python-hypothesis-3.44.1/benchmark-data/text5-valid=always-interesting=always 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/text5-valid=always-interesting=always 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for text5 [text(min_size=5)], with the validity -# condition "always" and the interestingness condition "always". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 421 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 296.00 bytes, standard deviation: 0.00 bytes -# -# Additional interesting statistics: -# -# * Ranging from 296 [1000 times] to 296 [1000 times] bytes. -# * Median size: 296 -# * 99% of examples had at least 296 bytes -# * 99% of examples had at most 296 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 104: STARTPCOO3RFBBWADAEAAYBKT5L3LNAEASXMF4CUEBV4VWA5VHYHOYQ6TT3WZI63DR2V6SWICISMSEREZF5DDM6ERZPK73FRK3S73AHUZLJKIEND diff -Nru python-hypothesis-3.44.1/benchmark-data/text5-valid=always-interesting=lower_bound python-hypothesis-3.71.11/benchmark-data/text5-valid=always-interesting=lower_bound --- python-hypothesis-3.44.1/benchmark-data/text5-valid=always-interesting=lower_bound 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/text5-valid=always-interesting=lower_bound 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for text5 [text(min_size=5)], with the validity -# condition "always" and the interestingness condition "lower_bound". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 398 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 5284.78 bytes, standard deviation: 917.40 bytes -# -# Additional interesting statistics: -# -# * Ranging from 392 [4 times] to 11932 [once] bytes. -# * Median size: 5137 -# * 99% of examples had at least 3847 bytes -# * 99% of examples had at most 8235 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 3800: STARTPCOE3GB32IODODEEV6RFFLEAB46EQX6F4XGAUHBLWPFXON7Q6XWPYTVWWZTGOSIQNB2DP6GP65PX77P56PL7PX567XXHXLY737GON7HRZXOW47OPKOPTCV6U44MLXHSEM36TVTXOO7LKQJ7X227XFT36T3T7A7VPGDTOTVN432GBZ7L55K72Z3FTHZZUZKZHGOOTK67XXT6WNXD647YGWLKKET6XSTXWR2WJNI76CV3IQ2TXHQRXU7LDWU67W4455D27WXE6HP5L7UIRF2PCYP755PJL72TT377K5GB5K37RVN37TXCONO57N7RDS57WNKFKPX5R3RCLKOZHNEO5LWXE2B5J3RNP25D27KJ46POVQJ5X6VMUNLITPY5PFW7ZWQOWITZRV5NG2H7LDBXK73DT63UU4GBLCMWRTS7IDDLCKESONLEXTSMS7MS4HHINM7S5ZTXX7Z27DZQY7XHDK2VBXJH5M3B4XCG554IESETXT2EM2UJ6VO5JNFTX4NZUORUDWHL6IGWF653ACKSGUDH5JJUL23MMH2RML2SN3Q5BYETP2HD7ESLI23PXHZJGQWOZRGA3TAIA4KOJQZDMZW6PI477DYPVNOOD4SRFXBRVWBRI7BXQAPNHNCBEBEWOIFRKYAKV3DVH63O6W7BUCB6Q5MMJJPCKCXPU2JNCTDAHSJVLRUXNU2XQPLZP5WNUK6LSWRQILTWM5PV3EN2DLRFGWDPPXVU3CSVFXUGXUKGA37DKTJ7JGSAKSFSAHOHFELNM4QE5MUJ3TWURRKYAWTMTMRWOP2HVQNJQY4QYUYTF5ADR6CSKWME3GBZKWCP2ZVMKCBSKIDLRSXXBAAWT762W7NJKHTXQOHVLEGQPWWLQCZHS2D7XED22WPPS7QQAIXO2Y5S4KXXFGF6INKCU324MVO3OQU64A3U4TJAFPNGU72VV7O75KWFURMM5K57W5WZ2RUITJSHEKTMNXSAQ2IJZXOG2U72AAJEHMPVJXDC2CCQDALVZRQZDLAAXFBIIK4RSC3VDXXQE6C4OZ3B6Z3VIT3XXODQY6OHDGTWTOBSRQYRYWS5RAQT7XF263LHR4NT5AKN5K5ZCEV4XQEP2P64KU5APWVIX6S7NDFATTTIUGCBBYPT5FAZ2GXUKECZKZ6GZYCNJVT5SKDQOJ2DAQ3ALN5PTIH25SHME2G7VXJUEHHKSNOPNDJZIYT3ESD6IHSO77GDEUC4AWWQCWF2EJEQTL5KODMQXXUHX47A7EKDQO3VPLSSJFRGW34SXCIRNDNKO2QJVVBMPJLHKTMWVMDQGHQSFNTUJ5AXU5OUUM7IPFMG4LAP5NKSPGKMS7WP3B2VN7GIJZHFU32W3PP4WDNJZCCUI4OJHOGJP6ORDIISJDAPGEWWYQ4FJBBUCPQ3HSODT42MJGBZN3HCQTMUHWXPRAGNUTNHTFBHOIDR4PBR6BSOPAHK6BRYWWUAJHRNFMRX45DYYC36ZHVMFEQ5LS2RGW6A2Q4QWAPTZDHOV2K4YJZIGWFYRMWDLSGG6QFOOIJWNLSYDV3AJQVFHENGTB42EGXIA5J4DRKGOHA4ERKCB4NBKRB6RR4F4EHIRM2ABJQ7LXPU332WDF5R3G7EVRM4ENWPEJV7L4FYPEI7OFJSPNZ2GSDHQCFJGRQG5QJWJFWRE2NZBYILOI6IK7HKJ3PAZ3RPD2HQ7AYF6EELTKYGHAVHXJZ2ZB4MOBQNOMQSZEVX2P4Y7DPKTXLQVPK2QHCVGUHBLES5QSZ275A7OPN4O7AQ7OBPF2I45JLLMIUA45FBL675QGMBQZEFFZKZ4GS35S2RD6TRK2ZOVQS7QINKBPLKHXOFTQYNNR2W3ALMW5N6G45SJ5WCRMWHHFUYVTDYBOSYCC2YDP3VKJLZLGBY34SY7D4DWEL46YX7UHXMNWJGNSUSWL26G7WBCJRJ5LC37AXXILSQ2HF33BZ6JL2G7SCDYGKNTHC6D7NONUEMLLK5TX7ILB5IJDPOEOX55G7P36Z7YWDJGSWK4LG3PJVHY5F6HB3GKZPOQWIIEPOMMM6VOH4BH7UCLGJULKRKEJY4KJL53RANB7AIFLB2THI5F6KQSFXSQDPEXTFAUELLIHQHPRPRNFMR7BEBFRVZCLIPTFVCZDBD4E5BI2QNYJW6QTEFLUWAO3FPFUFCVI5UKCYBCZ3RZVZCP4S3YW6U334RFU6KRFVMGFLCH7GBLIR5ZEJUHYKFZMMC4JWM4LHXDSUOYIVDNFJFVF3UNEYIBS3EAUAZON7TE5SI5ZBOMDJRDRNJ6AU2ESLQUBCWBESVO6KVJRHHLAEKBASZKEU4FYGIBRCDZVCTAAZZ4RJAFEGPDUO6WQPZTEY2UR4E45HGFTHJSB34JMCVB3BZKIUWS4AGH3IMHKLGJLUXR42CT4VM3RKUSAJ7USANSWO5VCQTG75VG4AIVELFUH5JHOPF2LVWMSYHYKQGJ4WEZKMMATSBDTRVT3MRMDT4RKGJLLZFEGU3GEAI6IPA3TIEEOVS5NCHEJIROMBYP4V5ISR53IPW7HKKF7T4BRIWRKUVQAYVIEHOYXFLGZCUJNYTULCAMDTDZDAHBJA7VHLKUBDDOQO3LD7N23THRZZA2UM2QLZAHFDETIYOGMYL7BQODOKYOET2TNLCERGTOFYXDU65WOLGRP56RFSPOIC72MLF72SOK3U4BHA4HA4D4BV6VASFVNBQUCMVMDNKOS4VZHN7H3AH7HI24WTJ6DDDG7PSXZPUXRQAA5ZQ57EFPDNWJ76VVI6BTY3OEUK6ACLLR2TMOHIIULCSXY7R7CS42VU2HWMW2N3GYSQA7Z7ZXBZXAKJCG2P6JWATAXUMZBMLEHJBAX4A4763ZBGFQCOXQZ4PMYWMTTJZOKEHCO36HHFKCS4LGQMPNO42STCFGUEMF2VFEFKHEHYZSUDUOBYTYL4FFGM4UN3RPJIFBZVPITW27PQ76I2XI7PKNYRE6UV2HRD3LN5F5RVP2UL4LCXW5DEN7PKCLUCRZSFZKQRREJJQQJVCH5KMPYS6IGLOOA66K2BKJKBSV3EK4ORTWAESN64IZISZSBMSBLCADDSJQKYAEBGGFEMECTPUWMZH3Q6FRIAX67CQXSOSBCNCWRMRSHJQ6BEFWFA3PHKZLVAIO363MRAJZED5LJXSPY5DFCTIPSYASSPXRJ3OZI5NDPU2CB2TCHV4FSXTDO2QAFFLLLTRLPJN3ITLVEW4XG22HAQLMIGAV2I5UH4YYAIMPFJRAPY6G7YXWQZ7SFV2FTHEU764Q57DQON43USTEIWBGIT77MTBPWAAOE5WJ3D7S7EMYJG3KMDTC2Z6Y3S4PLYSPV4M2Z6WQC3S6FYPWCB67R6L7VICZ4JH47Y2WEU7PW754FHPZHT3MU3ER7JDSAUT7PPFZZPIK3TOW6RBJ45ODALXYR35KV7QEOUHOU25Q7ZQBNZKZBX2P73SVSVJVTYZ7GJ3SK6ZIGRISYDES2U35XXEZVDOMCDSJL3I5GIZEJWGMDC5P6YVSFUSDAY7ISK3GCXSIXZX25OG7VHGGAGOIQAXDHROUV37NIDGMLZQOTAH7TVJBCXILGOM4QGE2HS5K4B5RJYYEROBM4GRAL5ZL5THTY4C5O4OLV7PZXLHZVGQNOTBYLCQYPSTXWIUDD63WMWQZHLZKMPR26DX5EDI5TKSLS2BK6OMCBTOYM5EKXSBHLGNNY26AMLK5PICFC6WUIK3GSDMRCKUWU2BC3PYOANHE2ZMY2MNR7ZGLT2KOZHR7PZ6PX7XL47HT7P77K2WHH7X5B7MA6ZJDEND diff -Nru python-hypothesis-3.44.1/benchmark-data/text5-valid=always-interesting=never python-hypothesis-3.71.11/benchmark-data/text5-valid=always-interesting=never --- python-hypothesis-3.44.1/benchmark-data/text5-valid=always-interesting=never 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/text5-valid=always-interesting=never 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for text5 [text(min_size=5)], with the validity -# condition "always" and the interestingness condition "never". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 395 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 5361.16 bytes, standard deviation: 975.56 bytes -# -# Additional interesting statistics: -# -# * Ranging from 3494 [once] to 13144 [once] bytes. -# * Median size: 5186 -# * 99% of examples had at least 3950 bytes -# * 99% of examples had at most 9406 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 3832: STARTPCOE3GF3SISLWDKEP5SWF3JRJDRED4X6RLRHUWSD6Z5FF2G7AWOKZ2UR2NIVDTPCANEGIJXYT5PX77XV57PX67X56X2Y6GBHX67XZD757WK5GTZ5T6Z6VV6N5LG337PPTX7P2FJ6J7764UN7FNVLZB6XTA6SG6SM2TENYWO7MZ5I7COR573TFZVMG67HZ5VXK2ZWLLGLFKL7T255U72VVEJ5OL3PYML3K57G7TIT2ZV5K3EL3XLFO4N5T7W7NM7VZD5LIR7SV6TTHJ7X7O6XXRLJPW5DRM47UO7TVJ6G27AF4MLTGJ7Z75HMTZT7JHWTPK3IZSJ6J5DWT5P37KLR3LR6UMT6P4W6P53DYI5DX7O4Y7D3Q62S4MPJLCC57XWP3I6XFXJ6YW6B3WZVPKD5TUPW5SJZ5WSWI6H7HDV5HCF45S3YUJ5G5364N7X4OOEXZVPOKRUPDHCHYZGPLFB37P7MMQYH7TK4ZHUWRWFR33N6DDC3VP3RX2YVHVMTO5OS7YVMN2H53NRLP7NMN6JTSKZ3PVJGG36R5PDF3TEZTXGR2PNTI7HXYVUNWHNWRSJRDJX5DP5VK2P6QGV3NJKMJHWM3QZ5IEBSYJNNGFF5IV6PUX3PORKRZ3ENPRGL44XXYYVAQGJAZLE5OHPV5W7LHR44BNLAOSBDEOZ2GUJRC4ZHWFPL3T4QMIOPJAF7E25MGV5JL44JJGOMLCTDSL3R5OP2LQK6DDUPGG7R2KQLQTTVYVATE4RFMC3MHMZQIWE23HRVHVLUZFKBETZD56FQVXNAXVRVFVLUVCLY5G2QBIBIHCUI3N4KQVPMYVTVKYR7N6ROOIGBHPLYLK2LAZVYMOKVV24Q2WBIGSBCTR5ABCRQ6U2D7JPWAV4HEQCEZGUDDGOOKOZUVGYBUUEDJKXPGZXVBTNQLKJFMLNG6EOWGQGZCCJ5ZUTKYAVCCMHNFRRKC5VAXEOCLHXWD5RB2CZ4XIDWIVUKBMGTEGXIF335R2DGGFODEXUBIZEDUMLGC34AOXVXIR5FAL4FI6FEP52VTVU7VS55SM73X7MQICSJ7GPNBKAIKHVV4JM6KM4FABXCBOVM2A2ZBPRB3JJURDR3FVUTJ3RP6EBUCCX2G7WG3S2V6EFEAVCSWSUCOZD3B763QADEYOMIJ42CQ42KCIJIAWUPW6QUZ5KXIS4AFSMKILBG5ISZ22SU5DRKGKWEE7TXC5GAFUGKX267WDBT6I4CA6SOJUM7RAKYAP4EEGNC3WCKUCV56EJGXFMQ23VHLFYEVTRVSBIT5TMT7AVXUAMKC5AFSHWIYJAEKSWEFDRWU4FUM5SRHEIXAENRU7EMLCISUVBJCUZDSGN72Q42TNJBZUB2TEW4SNBI7M3OMG6VQVPNNIXYAMCN47STJI6T6IVBWMWNMDKWIGFGUAWOJBWBHBE7BGDBDPBL5IQZWRSGW3DFBJ6TP7UMGW3COM2BUM5J2DM3STWHGQUL7O2XWQV4Y57NNR5SEYFP4RLQMO7SI4ZNHKFOIBBI4TWWEBLMT4FGCI32WL7I55INCAZECCVS2QS7JY3GHPCITZRSJHTC4BFDUQHJ2ILPZBJVZAFEMEAHZMT4BOUXQJDZSE2XSKWVUW2EW2A3ROMYCWLQCZ2PRAGA6US3YE24QEYBRO6CEGRHODGMARVF75YT4WZP3LVFJ6KGVPXXSV5PKQSYPBZYT2SPMWP4KENXYECKAJCZN2T6HSNK7C5OIIUHS4AHCQ7VI25YTCNGNPNLXBEC3UHZYFMSMIDTJAYEZKSFVECHVCAOUCPXDWP7QIONDSNCMAKPE4J5FIMOEQZB5WGWPAMOF7IRRKENFXKKNS56NRCJPRDGE64IYUS2JAOKVGVMFNNJPLYMBIZMO7BJ5QWOBDTDCJYTZYF3CTGPD6AQ2Z2OTHV7UVNVVB23YGQUBIESRXADWOH3WQFQJLJBNNDZB3O5UZ2D4BSQYY26AXCSN3UIBFRRKSLJBHJ44PADLYYXW36LQ2ARN44FYVEI7OZY7BEUA5SC3CHAZT5SDL6EWN5XZ4HP624JX6KKKQQYI4XKTDKMADPKAYKEZ4MLRSQCPLJ3HHF4FZIN4WKJTBMHBGGUVNHMEISOIMNGLQVC4AYKG2OIRXHF5DFCUFODFMGVMANRHM7MKX3OCRAQ3DJHX7EPMRIGZTHQPK54VHT7GSTP6EERJLHZEWXJGGEOPTV24AVGV4DNDFXPIMVHFPMI2XM2WURES3GIMBAOTASJYWST2XZQN6W6IL5QC66BK4U56LJEJQ6CYPIBCROIORVIER5TENGEM7JJDZGTJOG3PRXX5CUGNUSLBUER4BGKBYVZXIC2XWLYX4PWLMOS5NQJ4I4SOGOHOYSAYEYIZ7WF2FPWHDIZLW5NG7TSBAITBZMWESBMR2E5T2GPPTHLOP2ITR7L2RQIYV4KAF7ECQ2UFZKHDCRVOUEXABR4G36FSM65XFJ4BBXREP3CJZXVDVEFBWRIFKEXISGCXPLQGLZISCSEEKRCANUXXIM3EM4IZQKMFVL75CSOYRCZYDDIL4RO4H3UGTXR4PUMWHFGU2HWMSR6MUSRBWP3KW3CXXNG4U2DLGYG3HEQXJ4M67JSQAIRJJI6KHODH5UVHA2MCMQ37EFE3E4UBUQ2JDB6K2VLJAUERZQUFEHVVTT3JE3GSCAJTZNG7VS2QLFRIBPTA3DQOKK77EOZOX2QWNYLLVT5IWV4VAYC42JGDSOVSJTBOTKDD62D6CVOAJNCPKQZZK4EAUQKWQNFEYVFOZUXKYLMXFKIS3SQMYIUQJSO2MSTMEQ63TRFAOIRD54T3GVYQAZMUL37PKNIICXHSTJAV2NB2YAEMGMN7JKDXM3BKDRWAC362JXYFU4QA4Q6QK2JCUQAQ2J3TQNBW67D3RFGZ6ZI2I6EEYTP52Y6QVG3USVK56FJ5PK5JV7J53R6AZLAHOR4WLLDR76VMJ4PKMEFQMZRXIMLTV3A4OSA5KJCDRST5445VUMJJLYAGQ2V3WM7RV6SPE4JF6P5QGF2STKPLQZ5BIP5OJYQ7ORLI4MWBYKZPDH6OQU6OEJJPIKZOQOCGBIDDBCDEEXPKICYLQDNAYZ4S5DLDZJ344VR7MSDQVPWINZFNL7JGBVEIRP22LJ3UGVSHGT3FQA2O44RYCS2HQ3ZE5TOTQJY2W74PY7VIEUP2GDUTJDQIQQVEKHAKLBK5RDRU2R35JK6QHDCXSRFHGGNC4XMMVON3N75FY2RA5SWZ3AFRWTWYGFJYKOYO3GGIKEGPKFP2ACQZPZOOP4H6PN4VF3QFYUK3ZKU7EXP3FP7WZZYPNE3B6SSNA42R2MVXLSMBAERIH2XQALE5H2BFJRMAESSGHP7ZUCVQYFBSNVZ5YQSFQP3NE7LJHC6V2NVESU47RK3RCYQB565F5GF2V4PILKEIBHVCWTSQNEOS6NYGC5HVW6IWC6ZP7KUW7XY4NZE2OCTC5RVQJWMEE6ZRK2XGSYQQC4HRHAM6T2J5CB2DDUC5ODYCBTP25WSPYKQSFSL5IJJJOAPN46VLFEATTFUKWUQTDCYCGEDYN4HXJ4RGQDVNUZ2L3V25HW4IT435YP6ZKD2JRDOS4DJ3CY56QWKIRIUEJSFCWGCU4ARE2JCZXISJXUQUMSRDJWYR7SORUCVPIV2RQPE75YKM3A7LQJSBRSQBPXG5ZEK3A7LUJJ7IGHXXR2XSFXVHWUFO5POKMGSEXJQ5ISX4565HDMVKNPIXJYHYVQMLGBVIS7UNEHAVOBS3KJTWHBJNNRGT45F3GVABFES2CDVA77C57X26X37P3775Z5PX4NM5775D5Z4EZ2CEND diff -Nru python-hypothesis-3.44.1/benchmark-data/text5-valid=always-interesting=size_lower_bound python-hypothesis-3.71.11/benchmark-data/text5-valid=always-interesting=size_lower_bound --- python-hypothesis-3.44.1/benchmark-data/text5-valid=always-interesting=size_lower_bound 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/text5-valid=always-interesting=size_lower_bound 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for text5 [text(min_size=5)], with the validity -# condition "always" and the interestingness condition "size_lower_bound". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 399 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 6396.64 bytes, standard deviation: 8280.42 bytes -# -# Additional interesting statistics: -# -# * Ranging from 392 [333 times] to 66330 [once] bytes. -# * Median size: 2974 -# * 99% of examples had at least 392 bytes -# * 99% of examples had at most 38237 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 3432: STARTPCOH2WF5S3S3YDL3SU4VWTZB5KDZJPSXZFEZOLKSN6LZZPD3ADEKNRXDJG3LQ66H26LEIEQAIH77XV47P77OX547L57X37GNUKG47D26YM7T7TC2LOPR63OV5NR7VMFPP7V2GTU7XC3VV2NP37HIPFOZ7X5D5LAVLQMS2GX6TPV3CRY36XPKHVRSPZMK5WHQ675L2FH6G3PQOPA7PWGMDGYYIVWT5OCF4VIZMHWWHLXCKPR7UJ3EJU4DGFM6W53EXZ4NRVMCS555ZF3LDN4MMIUMMFK6P4KCLEUV5OKO55F3WTDOGOGH6ND6V5I2OIS256AFVK2YWRNK7Y52WTTJUPYHKZLQZVTLAY3W3BJHVCFWTMV6KTE3SGF64WEYPNQ7NXVLW56635Z3SNS5HHS3SAVJ7W5NO2S4FNIE6XDIXVUUGZVRO3CVUO4OHVLV2XFHLPOPDDFQSZQOQBEDSUX6KCROGGBKXIRIXBZSC6O7FJGFAVTHLIGM6KULXUYUSTKBKYQWOFE6VFHXXQYRJPYFJJJQLPJRFXFVGXXGWMI3YMEQKMXKIRZPM543YWKKRFSQIL6MUXK66EPDHMZLQRK6FQOHKQTGNP5DI6IPZ3ECKJCFDLILF62XMZ32RRQKU62TBG2ZHIEHOIFDCO74XVMSDOBK2LHLBFLE7TIXI47TM76NLHAH5PTYVGYO3FOTA5MG56QVLTO7UCWKLDJ3ZAKSFEDZXOX7R2WMVNBLU3Q7UKYRBM6TW2NM5N5DLNGO2SCNWERGFVNR3YSMM3J52PV2FG4ZTDQSLL4XBXFOBT26AXVMF4ZCSQ6JESQYEHQCCHGFIQEIDNTZRRC6YLEPDO532HQYY5QCZAD4RC7FKFHFGKWRIUMKIFQZGO3CWD7C57DS4OXF2WFLZG3A5WRGBPLF4Q44LXZQTYJRA6KYSZ4ZQWSBZJ56UD4SE3G2LMNFWY2BFLBBTL67SZXS2VEW3J4FNXAYIRP4IVJVDORADPT3VQQ44ELDWFTHTLMKY2Y7RUBIETHTIEQD7ONYVTQ4XAF6UKGRSBEPF3FALXUI7DOLQOFNGIDKLH276NMZVPBD344JZUFHOY5RKY7XZL76JCC7SVQTKCJIKX46PPNZFWSMJIUQUWNEEH4WYEZRFXJYNMGZMDIBR2V5GSBM5A2JNXG7XEKEX6RQDH2NTWS4II4WSHQADTYSUCW2SSJ35EFESU3PVHXTFTG55CTJKB47BSEJPLRHFE6MJU5Z5O5DXISABJJFAAZN5ZJ5IJNSKDAH7TX6RCTULMBSXACDIIDSWPBY2OMGS3ZXQLIEJVXH2C3MY2GX6WDLKXLGJBBEV3EHNDCGPCHMTH3N6R4OJQUWWBLESTZIMC3BZOYKWJMCD55UDVIIWN2R7IL7SKMUSA2SLE3DNXIEUOL3VYI6XKDHEXXF2XIJQDQ7MFTF7TIMTRLJGS2N22WY5OVJLXD7HVZ5I2T3IZM2IHJYAPY3TW2WH5VF3ROITNC67TPRCQPZ7WQRJMJV7Q3VMSBBIKMRBI2CVY3QREAVA47MIS536AUPHMLBO7TYZMKIU66JKZMQKAK343WI6JUPGWJXJXTZA34COKIO3HROH2IDBUDTILOAES3WYAG5ORFKI2W6PUIYYLHSI7ETICARP7C2C3S42UWRQ5N6KF4OC3SQOMQYOTZCXGO5NV46HXFVYVNPOVEPHKAKOCKPNOFH644GAP6N42JAMRUPSOZLK62T2KTXR6INTTMGQMVXZRAZLB2C2LVV32QNQZ63O3TMEOETW2RCMJBVMXIV43KKJOPS3C66KSWTGNOYPQA5CBQGT67ESYIOU57SWCJLVMMUD3UOI7MRTFDA7T6EXHH3PY7Y6YIYWKANGVMXAX5WOOXHRZTVW27EL4SBCDAJ4SPKGLIQAB5RANJ7M6EUIYZDD3KFJWWJM3OXXKHNWXGTAFC44WXKBQSEMDNUVF6TONN25CMXV2AM3EICEF3EE7CNONXXGBBKFS54EEMUL3KKPWTMYKMJERGECRLOBC3SNI463IBKHGKHTBH5LCZFAZNKPYGAGSTS6MD6AWIXLFBDQ3PMQRXE4OQQ3BVBE2S332AQZYW4HFFHKJZXFAJV2DZSC55CUCVG5BJAKDRYW3GERBWHAYYPFPOYP3D2S6GLHLQYFAU7AMIU4Y2Q5WQT6WSWU7URINAYYW3525EOWNJCTPNTYPLVSZ46G6MKPQDBL3M2E33KZFEGBNTGJK3ODIWPJ7PDOSTPM3IHABF22B4C6CG4L7O3KDWNELIYSKTGSOVUBLMYA3T4I6EKROVJZGJLZS6ZH5T2I22YEIKANPX3PYGIRGRBHLD2HLSRVQK6EOTAE6E4224WH5WXOECZVOWQOYC44YMTUJFJ6OSDXCTRN7G7E2OWR6IC5LLHOANR7OQ5IQRA5RUZ54YLYHIHGDSZWZGQWUKKYZ3KCZTPIXDWXLDILEOCBFXCS44SVZARPBFWWVSKOQZNNFYXSIQZJ2GOTKHV3HVWVFQYUYYLTA3BI6J46EPRFHBYEPGI46R63DKMLZSD5QBZBL5SFKXMKLP52KYA66T2BV3SKR4WRBSDYH2RZPGA77UDWX46O2L6ASKTKDIMG77BW7C6D4NUDR6LWJTINCOFQOHNEH34XW4WCS6SWKGMPGCDI3UVULPO3T3WQXENQUC5ZUJHBJ23OB2RGJJHHI6XKNDGDXR5M6A6L6B6YOVPQC7C5O5WLAKJ2XTD6KWEFURY334SFWIPTEZDKHJIFSRWW6Y6RMWPEMDSMNDLWYGP46O2O4F5XHAKA7HGGR7TW2H45SHSHV5NHPBDQ7B7WPDJTWXXNQRFH7T4MUDA42WESHE4JVFI2FHWGG5EGVGZGHYH3SVYMIIIFNQTIU3TODKBYQXXVEXG2R6T2CWUXIIULGSTQHBSNIS57V3U3WN7DQQIZPCNTXF2IS55C5WH5F56J6PBUXKA4SJPCFNGKMLCUZWG3FZTNPVBEHA4FNYL3YKYAQK4IPA3LD3XZMJV7OLZONP35UJLOGGUTOW2FB2FXO3TE42TVUEZM32GOZTEYA5H2OUTZOH4O3Z432AH475OF6PVW3W5ECGXSQQZDUV3H5UKWSQ4CLNHFWO74RZ53YSVJXX4EVAM2MEI7R5EBF237R2ZE7QKCZS3DC3AWPWXIJOKFO3UUHWZ5335JFZOLDZRHPERIC2A3B25Z7P44L7PUAOCTNFRMJW3SOOPNYHVH2JKS5JPK7HLJDOWSS5FW4TJJTDRJ756M7FSGPE2LCXJXO3UGG4BJCRNSWVWSPCRGZJ3WEOBETOPB6T2AMYLSKEMJMNPV7MCUC4675IYKSJU3ZGLMMXDRVBESHXS6PJD3P65JXA2E5A7XLNHLZYWHPVMDLVG364AJOXP77XZ6HV47367774PKF76LL77SL45CZFGE===END diff -Nru python-hypothesis-3.44.1/benchmark-data/text5-valid=always-interesting=usually python-hypothesis-3.71.11/benchmark-data/text5-valid=always-interesting=usually --- python-hypothesis-3.44.1/benchmark-data/text5-valid=always-interesting=usually 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/text5-valid=always-interesting=usually 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for text5 [text(min_size=5)], with the validity -# condition "always" and the interestingness condition "usually". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 397 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 532.32 bytes, standard deviation: 428.93 bytes -# -# Additional interesting statistics: -# -# * Ranging from 392 [895 times] to 3275 [once] bytes. -# * Median size: 392 -# * 99% of examples had at least 392 bytes -# * 99% of examples had at most 2290 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 808: STARTPCON2V53N3BTADH4SUQHGBQ7IXVJCXZJXI2UHZ3MFX5O7JMC2SUGUPLMZNYYWLSCRREHYHCPI7VP26D5PW5VZD7HYOJQS5B26QWAQGESN5V5NWLB6J6ZD5FHMKWNHVMR3HCFRMCLR7ELASI2NTTW2JECNMNLGQYBBU6YZW77ZWZEC3CIJYNDH5ILX25VXCW2NRMHZT3B6G7URTCGNQEFZ6WHFVAJHDA3NJXMEUDDBNMBFIRIMIETC2FQG65FBE3S67WTZRHN5RX37Q74GS3FTCDG3ZCQAEVTIUATWBC7VDHH6WOA7AVA7LH53PEYETMN4NMSMSGUXHGQGCK4WMFBHO5B63CEYPDQ2LUZWZUKFRCONOOSZ22RJVRVWWVV4SOYKEDOC3IUB6JCTRCE4HYZC7QHY3LKI2YFN3YO3JV5OIQ4WJIRONDKCJGHJNXTOAPTQYUYRS6MARJO2SC5QVYSHGNUE425WC4EMXOM5BMJI6F32J5X2ZTE5PRTJIK7ZHKUL2DYUTVNZOJNEY4LU4DA2GL5PEGAYG5WKUYOOLS2KWTONGAVLGFKTUWIGUKQF3BRXIULKLI55U4VVYSFTADD76QQS6NEXXZUHI2JJUFBWQL4HRKJKXNU7JEHBE2UYCN526YJZGRBJ2772TSE3U7JGXN36XHMTMM7CJCF6WK32QFDVY2FVHHTZND7522KCKNR3KDTWBMTJRTNBUOGLN5LR4QO6NSDSXLPTI2YASJFLGX7HAV2YFTUVX555CNXKWRGCXCW7AJ5T4HMP27F6JZDZ24X7P4AJXCBVVIA====END diff -Nru python-hypothesis-3.44.1/benchmark-data/text5-valid=usually-interesting=size_lower_bound python-hypothesis-3.71.11/benchmark-data/text5-valid=usually-interesting=size_lower_bound --- python-hypothesis-3.44.1/benchmark-data/text5-valid=usually-interesting=size_lower_bound 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/text5-valid=usually-interesting=size_lower_bound 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for text5 [text(min_size=5)], with the validity -# condition "usually" and the interestingness condition "size_lower_bound". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 400 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 7619.13 bytes, standard deviation: 10345.12 bytes -# -# Additional interesting statistics: -# -# * Ranging from 392 [303 times] to 117219 [once] bytes. -# * Median size: 3603 -# * 99% of examples had at least 392 bytes -# * 99% of examples had at most 46515 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 3592: STARTPCOHKWF3OYSLWDP4CWOY2FIQEBAIF52XPRXOMDI4N5TB7753VOFNG3FVIZHENIY6G2EWOVMB7747LZ27777P3Z6XL4P772GLH477VKXIT4P65XR6H7GHXTOPR7WDH4FIHJ7PONMLVPYHL5NS25LX3WDKPCZVX47R7EI4X6AZQVDTM6RF7ZSFLO26OCXLKWSY2RN4GPRYFLZPVVLS6JAGWWB7A5HZ6YKBQNTLWFSZL6TF3AZHPG2PNVMYTBCTWY6QYQ3OEYLIV5XNVTAW74GDHOLXNXQJ2INYB3Q3D2OHKVV3NTLN3DP4YJX55DEV67HBKG3GHYO6FQDVMVGM7326T54P52J4P5EJO7O7Z7ZMLNDEW3JM7IZRVX7R3356AL2TX5GOLRLJLJXXIEWBFMWM4WGX7E7EF5XXZMRW647R2MKYZZV674MY7EGVKARBG25GGOUNTOX4DSXDIY7VGTXKHZJT27WW5HGQEHYKZKUYVPIY5YTOS3EVF4BZPGBLPRFOKUJ25DOBKLZRK5GQC4JTDKSPKUCHPT5YJRCOBBW6VIP6FFXWFAGKYUS6KP2XOCTSI3JKMGPDGI6HXI3Z3VK7X3L5NNSJNELNQPHEOMQBTZG3XNBWL6FUMBDXKEJL5PB25QCMRVXCJOM47LE3FHFV5Y544QWZI7JZQCFIEM5OUSCX5GDFM5HXSM3DYXEXD4VLVIYFVKX4SW2L27AU5OTNLU6JLJONNYBBLPZAJJVDO34KA5DIH525LQTFKIX5LVDACEHGGZVMJ4DIJHNWLCPSUX7P5L65W2HXHTT3X43I63NITEQ2ZVFYAYRY5PCKSVDAVCDLHNTXXK7336WSHWG75THIL4IGJR542MVNWXODLWEDZNBNAQYM23Q7I7LI5SMYE53HS7UGLFW3OCKNBLJVVOELM6VRRDZUTI732PN35PS74XIS2YRZIV62QF344D4IDLZTQU2N43VPNOESHRLL6AUIVY4V6I7LGJ3FN7DQGDZPNABMAMZJMIHO3PBJU3AJK752E7FYNOWKXZZTY72RK4D74URKNKZD5SWEH65TKXVO5EP5DATKXIECVEO4KWWMMFC6ZXHW25REZV33EMXEBIJA5ZAUOYAYWIEBUWFYS2XMFSLRXVPXOWBODA6FXT6IW5JQB5J4PO4DNWWYKUPKODSQSTVMLSPGYIRNNKYPCYNWRFDZBRM7EZKXTMDZIGWZBXG7BTCONTUJZYVX3X6WANFCX2IRHFZXYXJVTJVV2FZKYU7UQYBU22ZX4ELCC6T4U5WPYDYADKWM34IAJIKPGUXEFI35HWIJZ4GRJQB6WWEB7JABUWP3A3TD7OHFRMTSMMEFGZX6ADK6R6K5A53TKDUCE72MDIQKCHCQCXLIJXYMSLD2WOOGJUKHD2NMTTIPX2N5R27JSVW7EUK5Z3A2BIX6PWLTLO5WD4LMWVKKRDI3TCTHOLIOELWQBVXIPBWRT6GBG7BFYVUBWERQYR2D3MOF5A5ZCTM2EHU2ZPIEAQFJ37IFJGJVYZ2TCKU4IS7ZJCHAGFAYQ6KQV75QQNUS7WXIXPP2PYDCZGS4MPCCGMEZBJNZOYFDWRKFBECCW4564UC3NZO5GTG54FUUGQQQRASAG5RX5M5UWEECATPOVX5VGDEB3PUR3ADSI5N7YNXMURWCM2YXK2SNUWMSOS3LXBRF2E3OCQAFCJWJ3FQAFOLQVAZRLB3GWOS7Q5J62C5R655JO2DIPITWPOMHZA4K6HZCCSXRNSWCMK7BVT6Z6VQMFISUT7QP24I43URODGKLZA65SY4NRQFAMEPLVQXIMCV7L2DFYSURAELZLSBKSW2JOPKLVU3JU5DAVQ3VOOTEEPK2KIWEOCOVEVJTQKRW2M2PJKNZKPCKFFVST3ZWCSXT2F2IBZDNTUMQ4HL5POMVSBIU5Q6CM44NPQMJEFLHHBIIMV6NSO26SDMSIAL5JCNUHCRRML62PYW42AW5MTW3IKGENV5XNZ2YKB62R6HYOFDHRDCKSJM27JDEGDXE3ZKRARQBEAGH62FXOBMQGIV2JYAP6HFSVUUUB5IT3TAYGV4WJLY2BHQLRDIYX3HRSCWIMXARUZW3S7U2BBEN7NYIMB46OIL3NKIKCP5EIWWYPLX6IJNSOVRIO6U2CW3UICDZWOWKXDUXJJI4GD5F4NEYD2XLYLXREOSJDH2J4NSURKKMTL7QADK7YJTLDFJAVHDPW65LJUTXDIUOTN5ONDSUVLD2BTEX3CCZHBS4V5O7FKU2JAM6L4YKJ4UJU676RQ4HIPRBAQKPAGZQUGNIIK2TJON4TFZFZZB4SE3L5YMEARNUC6Z7FHIYJ7G65GRVZDAUJTOOXRWW2ETKZNXDOFYNJ2EVAFAMPE7VRFT6O5SVOJLUSNOLLHYEJE2SURU4FE7FDSKNREC7F4IVMC2NMO6VK327PB5POBUC5LDHFVAMCPEFIMFGCKDMV2NAEOR5UUC7B5FEOZFIG2OQYMT3LTQUY4Q7R3PIIJ27YSYZTVQ4HF3NWGQ6VENWAK5NDY7KL4TKHVZVYVZWNRLQFJQEWJQTUJJ3BKTGDCQYCR6KRDIMLOJFU5UEINYGX34XRXRFBXJOQ3NTDG2RMGY6TUQCWZJW3JIGYTIBQCWIVCWEE5B5G23WNHTFJVAQDA2T6L2F6Y64ECZY7MKQBFZOLHVSQWSU3SRWHQCLO62JVUAFWOQNQRWIS6INORAEJUCIBOEDZZO7EGUEJ3RVF4WACZ7QKQSKX3FI7GHDMACUF5IMNOHFJQKN4JTNVWSAO32D2VAUEO4PQFXUWYTGYLPNTPTL7NGLHW5GB3GWDS4CPLV2Q4L6RVXHXVHGZD4CMBTOVTFVSUX3RGB52I2GFRSS42F4SRVU36AWSSMVKRXUOFPMUHMMMUF6RIGV5WYJJCECXVVB3GKSH646BTCYSPPNCEQYZKU3ERC762YXVPCBYME3ZXJU454BN7N7KLUUI2OWGNCLBSQSZZX63RCELG2G3FG5ZDATUZ6C2MRBKZX3T75ZHFVZ4IW2ZFD5E32QL243S7KKS7UD4TIDLNN3UXYYOJ33MIYA2EJ2YHFE667DVGKKKHJYIBM6KURUAAG5SDJFYA77OM7AHYNSM2QMIKJ7JMHNOOWKCBECRRNVRYTTBA74LZWQXFHWPEDCJF364XZJTX5OVV2M3AYWHX3G6INYU6USSGIVGIHRUTB46ARNUOQEGFCQYGHOES4YIAUYX5BVOOY2NX373A2UD3FGOK54BVKDT7OJOONJMHQIP3H6H3LQBGDVLXJSPCUHY2LKNKLOXKXLWEI577GWYC6Q5STDAJSSWTO3W6R3UX7RK7N5OQLRV56XHNHSA53JQ44XQBXODWW2CJL7ANQYVJOMFSAQESD2SBUZVS44WVMXOGKFVJW66PVUNU2T4IHZG47KV3RIAXIX6JEEJQ3DIHJMQK2QVHV37F4SGF7TH5QLTRQNUSIS3YIO3EISNK3G3KKQ4XKIM44MS2ZKHGAQZERXGWQEUY65PQDT36I6V7RL62S2OEAZMONPJJW3EON2RIFWIX757HY7X77PZ7X5Z5PX64JA7HX76AERLJM2C===END diff -Nru python-hypothesis-3.44.1/benchmark-data/text-valid=always-interesting=always python-hypothesis-3.71.11/benchmark-data/text-valid=always-interesting=always --- python-hypothesis-3.44.1/benchmark-data/text-valid=always-interesting=always 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/text-valid=always-interesting=always 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for text [text()], with the validity -# condition "always" and the interestingness condition "always". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 390 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 2.00 bytes, standard deviation: 0.00 bytes -# -# Additional interesting statistics: -# -# * Ranging from 2 [1000 times] to 2 [1000 times] bytes. -# * Median size: 2 -# * 99% of examples had at least 2 bytes -# * 99% of examples had at most 2 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 96: STARTPCOKWVRKZ2WEULKWWJJIQNWSKEMELI3ICSG2EUJURJDNCKA2IWRWQFANNIKKXI5AKSOJVGQCNTARWWY22QBABUO26OLQ====END diff -Nru python-hypothesis-3.44.1/benchmark-data/text-valid=always-interesting=lower_bound python-hypothesis-3.71.11/benchmark-data/text-valid=always-interesting=lower_bound --- python-hypothesis-3.44.1/benchmark-data/text-valid=always-interesting=lower_bound 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/text-valid=always-interesting=lower_bound 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for text [text()], with the validity -# condition "always" and the interestingness condition "lower_bound". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 392 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 211.02 bytes, standard deviation: 172.69 bytes -# -# Additional interesting statistics: -# -# * Ranging from 2 [3 times] to 1741 [once] bytes. -# * Median size: 164 -# * 99% of examples had at least 11 bytes -# * 99% of examples had at most 815 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 2848: STARTPCOFLGB3OITDODEEV6RFFLEAAT4PIVK4Z26IDY6N5TZN2PP5AEMK2A2N7XB6CA3IGQNKB7XZ7T45PXZ7PZ7P55XRPNP6323D6TY7KYPLPZ67J654Z3TU3Q35H4RW4NNKZ7TXTMZ5GSWAT6XIPV7X3HB6GV7WT3XT6B6Z4X25R723YXT7P2YE67Y6VXVTBTNX44Y7P47RBZG5OY7IST4YYW37U3UZWD5NWSRV7T6IZV2X327BHWT7PINT5WMTVGBST2KXW2Y33FU7VWCOZX26PI3JY5XFWB3LW4Q2WZFRDRNVM63LQL3WOOOHNGP5SZE5L3S43OFTHQOTFUIKV3XM6B6XD3PF7L636PQ4UKQQAFI3TKA7DLXKN2LS2OCXC53CQOZRV44CPRUS7QHWLXXMQYMXNGJZ25HQ5FS3FDTMFOITWI2OTQLBAAIMOZZRJC3ELHLRZLMCBPACEYQ4MKS42RWLYUJSZRIDZRLDIRJGQ5LDRLVQBYOTUNDVISUFPEWKT4PSNODCC3HIS2Z5Z6MOBZ4JT4GYLZGITTQJKXXVKWUA63PBJVCOT4OXA7HMWERZXM5OYEZ2XD7IZBY33JMVXGJIRZW54OE3EMKXEBNH5NEIOC6CPLAJC5UTENJ7A4V2SKQOXBDTWVZEKMCM3BMZPVOHANHDMJFJQBEUWJ7B2A5NC4ESQDZK6X365WCDVMWAIZNLNNGPHKKWZT6U4NEUKI4NUC73QBNZEN5SZ7PIP2JQX3FAD5RIPX4ZJEYWJHRWWSBXKTI3IJPXQI7EOFM2CGQIIK4AKXFHMA2WLTGCSBQIBNXRETIZRMCF2ECGTJPSIVZZ5EMZDEKLYJWHWD3KMFYWMRISBFAXKN7PM37V2BASMZZO5SJ2KG57OFYFMCSHNAOKTUPELFGBOPBE2APASCCES7JBQFUNZTIX4RE45EKTEXGXJGZELVGDJHZTPEHT6VRGL7XCB545CLGJSXCAIFL7ZW4WLXJEFZ5ORVZ5HEB4JJZ456223RGYIURVAARP6EDLKJHRCUQAKMVIFGDI6JBKQELTW5QN5DWHQ7HLGWUQV4JUCU7JXFAVY2RMLABK3PH4WIKP6DQDXDHOONK4EIKMEEJ4UEF75FYERIWC4TA2VDAQ3SCIPJAW7SLZFEODRSF3EYMFUWXLSUTJVU3XDKAWWCBFYRTPMSK6AMYRBIFKBBRDQNUFQDEGPIGQVRERCTIV2ZFDG26NMTVSUYSS4NURP2OQOYZB7IOCSYV6OYTM5QCRCFECQY5EERDC6KSCSTQOAB4ESLAWIWBPRVAD7RTLE4FTH2XW4Y6OJCSXBLIWDIIAHQS5V6BBZA6OE4WTVSWUP2HNHU4RMNMP5YAE4ILYXUIJLK72Q3P32EVVCKJ2UYLCJQIKBMTKFAWJEMR75BBEO5BIRDIYFCCRCQGGQNOGV4UYY3FBFLZ7KBKZAKOZG2OHJSQXWS53EHMADWHKOLELSXIVTTVCTSICGEC5O5MCKJHG3T6U3JZ7GU3HFDZG2JOL5FSZJOOBEUWRYVNVUNDUDX4EI7UKAUZYK6YORPT5SSBL53NNL6LLSSLBIMO5DOSONOTCAMBUVLMUCON5FI5UVQXLUCKIS2GINQ2BMER266RBKWRFXIVONJAOOAAGOMIW36DGL54HRR3KIQWRTNFNTANKT2SDC5NVUMUPE5DA3Z6QLTZKODIQ3YLLZ7YKDTBNRANZ6KBITZE6Z4EMRB5PK5TM2PKTQLNPGYWRI2CXIOFWFVZZSFXJEVUL5ZWKOWBDPK7ALHVYRUSIR3AKDZ7UFCBKGCJEYJFID3HBA3JFAK6QXXXIXNN6SNEVMRCFCSY7NC66APDJ63FFJKARIUNQVXNCNKCH2JZ6WRIZAHPY5FIWKRSU2RVKMZ3IWMLLNWR3TKHJCM4IB6IYVGUHWIVF5N5OC7SKBP65ODF5MJ6YF5QCPY24C5EAMVA2IIVPWFSN5VGZ3FZ5CQ3LES5IKLVQEC72K7M2UXLF27KBSNBIQF4M7XT46XFELKMTCAFANCBJZDJFZGLX36CSLXFTFL4RCDJE2IVB2LB2J6BAMNGF2BTCTBBTLIJKWUETLDJZEFRBYKNDOFHGL5RLUZQAWGYBKWBG3WIREUHLOUGKLVXILCILWVR5FRU2BQDSOGNBJBAQHV2FLRZPHKDMYBYLOUWUEZ732VBNWKCP4ZXVBLI2M4JRODYQYSOSXC5QY66URHVKBWFHRLW4FDFVODZJ2DQUHGG6NLKUYPEYJFIOJNM2ECENU2J6HVMABX2ZQVFXIK5XVKJLJX5DVIIFCT5IXABUK53E2WIZSTFAZWFWYQD2VW5KZ6JWTDI3HNRKGY2IDK5WYQTYUE4K3JIAMTX5RJDKYWPG5HGOXKG7XSESCKG4YGRWV5GMEQUGRBAE2QERQYM6KHGCJSNLVLQNUL77BCHX4DJHI2VVY3Q4JXOPLANKIEIGQYXX3PLVAYEJTQJAS2AQ4HLWKYNED5OEISD5TINFURC6XG5KD7OZSFLEGOSQBR3KGOKU74LHP3C6G6ROKSCR3X3STN3RLHT2AGLFGM3BFBST23OLZ2POBP6TZRMSBRPBDIMVFSEX47F775UCB4OH75NKAUHBSLGKBFCMMBR7RSAFHAJJLATTVN2TYKJK7GXZJFJZRWAO3OTX664NGVOTBBFIQLG5DF6YBTFARTOMEGLN47BPSLKGMLK2BJAHZDSGTC2SJXYULZFY7IIQDEMPD2N2TBEK7PPSYMFDYJU26VP7YZM32GQJJMETLGQDFS7W7T5JIU3SLH2ODL3LPFFNKPG6XDX76COD7PR6HZ7756HR47TW7OWA7T5R7AJEMHWA====END diff -Nru python-hypothesis-3.44.1/benchmark-data/text-valid=always-interesting=never python-hypothesis-3.71.11/benchmark-data/text-valid=always-interesting=never --- python-hypothesis-3.44.1/benchmark-data/text-valid=always-interesting=never 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/text-valid=always-interesting=never 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for text [text()], with the validity -# condition "always" and the interestingness condition "never". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 389 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 2344.62 bytes, standard deviation: 386.42 bytes -# -# Additional interesting statistics: -# -# * Ranging from 1417 [once] to 5701 [once] bytes. -# * Median size: 2294 -# * 99% of examples had at least 1694 bytes -# * 99% of examples had at most 3421 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 3472: STARTPCOE3GB3CISKWEKFW4ZDD5RTJD7LZLJI4RUQZWPDJGQ32C6OUHUXCKR2VIU4RT6NTM37T36P37775T5P347777XRR4MCT7X2SFJTXTYYNM7XW27H5HXZZ6HXHTV6ZZ2Z4Z7I5SKX5GWMS6M4G5V77DRZZ2NNJT57TFT2S5J7244SLVU4TSJM6PTLTY3YHHPTPGJ5OWJ7ZN4RHPPMM4VTYY3CAPHXDXWUNDT5W5CWM3LOPYB5S3LYVTPZ5TLHEPJLOPAZ4Y2JLH45ROIKO25P5PA7DXF4P4JFRZDTDMFBTQOXMHGOX4MWX4ZAK3D563PH3EQ5K7WWT5JWF5N5U24HGL6YKCYCDDUP2HMI3M7SHRVQUUMNZK3ZZUX4W7ZNK2U4JAGI7ZJZFXRFB6EWVS23U74X2LZHSFXD4NFGE3X4APFU6DDDJZZYU535MHN5TM4UIVHAOO5XS6FYYLZRBPH7HJU5WNZE6WE3C5H3BEMOZV6Z2EZLJCUOHHBYRTKTYO5XOS7B2BNP6WS7GLZZ5LCIOSHO2PL4PKTCASRAY4HCXEJWYVDSZW3WBMSWJ3A56QMWHNPRK4E3J6TIUMK446WJRYFK7TQTKJ3OO7ESAGBLPC2KDAHPYYZ552PFIRTO6Q2MRB7Q73B445XKPSPMRHB55DII27Z63QGCALDBFHWW2Y4WW76VVJIW2Z474U7NQU6BJSZMVAXVKTPXIPOZFFSK2E5R5YNWZK2U7IQNV5LAEZTP5LVMKY5DLWEDZCB32OAYFMUXCLWW62B7A4E7EABG2EJ5FNXBEKZLZ25MNLZWRAVDCH6LLLULZCKP6Q3LR4FF4KL5D2CYZCN2VZNHHJ3KL3D5JL2ESTC6ERF4L7UQTW5JRCMHW7FURZVCXTOO2JZLRFSDPTWEGNI66K4DRIWG62AVFASSNGJMGSYJDWLNKMNTXYBJTEK3PE5IGZ7DO4JI33HLTJK2UFEYJ43ML62BPOKC4SADC6BMO6INZSC5QB6DQKQGWVLNG7F6RT2CPTXBMFMJ3PAUOOLYT5XAHUMCWIVNZT26VOXBLVEWJGI6GEXEXH7HUK5ODEEN7GBZZZVZOBNOBY4ENVBPNFQN3L37I3E5QKOCB7VJSII5NQ3VW4JO2VUNVQ22FUKYB5V4LLBC2CPJLH5VBFPRM6JREPDKOGWVQAJRF7GT7FFPX5M2XR2PQFQ7JO4ZTETPVELXMK6VXLDGNOBCYQZXCC5YG5APFKD4BNZFVMRW5VJ6LWKGMY36NV7LUFMY53OWFQ2QEGTHCWD5IGTLMJ4FN6VAVAWNMR23Z5BHNPS427MGPEMFOIMVFTXHIR7FHRNXI57RQY54RJFVIXZJKYRJQIPPRE33TWVBYDB6LJJ7OIL7EJZL5GGE3HGAUIZAHO4FKWM4ESS7V7JSLOT7MVSTEO4D3I43TDRKGMPS7CUMK5QW76F4RC5IJ36B55RO6I3C6V55NNUNLZR66ZX7IRGPZVXOT7ZOHK7NKHBZP4RQSNTANB342XT4G4255ZH4N6OKXYLOJJISMH3NSWC236XYU2VKXQJ62KNSQ5K5BTNDJLR6ZOJBPF6JYVZHVBBTQENM42J26EWNF2AJ2C6GI37VI7VP3PO6UQ4UHU6YEPKVPJKZLATOYSDKEXU27GQVIXJXOO6F4WPZCZ3G22WUHTJ3HJCW2XEKTQNMQXOQUFPH6SKESBGMJBEZ7DHM67PUYZNVLG24XAC3OLNIS4CUXONRLCXPU6XRL4AQJNF6BB34ORRUS5XHLPUXQZB4KUZFI3XC6QRCGNJ3GLYQZ5C3I6QVT2NBIZCZDIVVPKLP7WYHYO5SFKDCNIQZHTOOK5LVXCU7WW7PK2DMLVZ7BM27VDCFAGWEMEJG3OZNBS6FGCT2E52UVVIHS2UD2MT3RLVHT5RM5VQKAJDZDZH22HLVIU4EDKC3TK5J2PNRKBKRSYBMMWKRWSETMOUZJJA2I7S5EZZP5PLMWSAZX7EDEWOIOCU52B6FWIZW5VPQAS6Y2LAEXQ2OYPXVNNWUHK5MVPTY3JZI4LN5W3KR7Z2OC6TTUEDNNWWCLSIJ77IJVNDJOOKVCHVF5XUTBP5NCBQXLEDG7ZWUDGTYRBE2LZ6XLFPQVAPU5W2KSX65L5XDVGZFBW6XUMYWUMPDVKBKWRNJITYNTDNN7J72T43BE4ZQWC6BN6PVVNRDVN2YWWXOUFSSHVS6347ZRX7GSBA6Z3GEI7GBI6MGTDL2DRWANN72P5E5FDQ3JCOC5TSL3WR5FN2QIP3AZFK7W2UVUFTINPJTPCTEXXRMS47J453VHAC7B3JZNNZY5SUBFQNU6T3B75NJQT2ZH7L6HBZ3I7OHHVLGBUF5TZ6222ORDPW2V7RXLMZDYN5WLWDH4G66UV7STOFJP3BXPFB4LYX6TS54IESIOCXG6TWQPRC32JD3OTFG6QWP6AJFH7CGMB6BBO5TZGESUECOCTZXN6IEQ6RQC5RSVX5P23Y56FK3TSL2X7JQI2WQZ2HF76J34FXN7UJK5TOINX5GQ4UDTBBOCZ33EM73MRZ2TMQCF6OO434EZOVST5JHKNAJCLIT3CICCZPMEIZVP7JCYLCNHOYI6WSDYLGCON6GW5R23XFR5IOKYXV6ILHJZWBXVD5TLJ5XKSR7FWXDJTSX76VTJUQXPOVHVNLINFX7VWDNDQP23UFOIYBJ75X2VNR4KZFH55JRCVVLCO2FHBUK5DHCT4IQPATQ4T5732UUXCNHNJOOJKFPQL4SF6VLCQ6SUMJ6OHPBM7VHADM54CNXJ3MYSSEKAT7KKU7MTBMALIW5NYBF6ONTTS5AXO2M46G6ZFF5XOIADCCAE2DEH3OHFFK7ZQAMQNNLGOV4B4E662XMSLPB55B752USUOYTM5X473RUBLZOTUPKRLGP3TDGG3PIZL22WA75V27PNWN7H35NJUTSH25RPZVOJIYJN7G4FQFOVRLJT2ESKW2PY64KVJUYQEBH4LSUZ5E5LFKGF7OOO73NB6WX2VZLXAWATOZ22XQ3GHRP7ONJCPZW74QKE7CDN6WTSD3BCUM5XFFRYZWKNHV6ZNXVPS6DWBHHEZZT2FYIQSL6MH7VPMK6A6DXCGP3XNPZPLAX5Y25223RO67HLGY4JG5UV33L5N236H3DJQVKF6T2URA5RXXE3FDK7FK5BHLORKFN2OYTE4KH2UMLZKV73K6ZU22VTRJW62UFJQMMLSQ54Q7BPABXHJ7YRRKQLHUXZG57OA7IFAKPR3PSQFW6NHKODVJUKVHDVXE6DXIUPQMF6BJFCLIDTO2EVT2PK6C3NR35I34VFVKSN433WNSGLKPKXVWRBGJKT6M6OQ5JTUVVWQJSAZNGR4FGMO7TXS2R7XPCRPS3U2VXLI2YVXW5GQKUC5C42RUNN5DLKL5DRO6FS5OWG356YU7FC2VGTK7XP77PLY7H55P377XV6PXR6ZNO776R63VWK7FQ====END diff -Nru python-hypothesis-3.44.1/benchmark-data/text-valid=always-interesting=size_lower_bound python-hypothesis-3.71.11/benchmark-data/text-valid=always-interesting=size_lower_bound --- python-hypothesis-3.44.1/benchmark-data/text-valid=always-interesting=size_lower_bound 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/text-valid=always-interesting=size_lower_bound 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for text [text()], with the validity -# condition "always" and the interestingness condition "size_lower_bound". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 393 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 7542.10 bytes, standard deviation: 8988.48 bytes -# -# Additional interesting statistics: -# -# * Ranging from 2 [13 times] to 52606 [once] bytes. -# * Median size: 4092 -# * 99% of examples had at least 2 bytes -# * 99% of examples had at most 36889 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 4032: STARTPCOD3GB3SJSLWDKEW7JDC5Q3ETYSHX2WCTH5GGFSY6JUE6YX6KQFUTTV6UWV4EU7IQRMD7747LZ2677773Z6XL5PP5KK535P6LGO7L3T53N56XYR656H76NOK7PV7W3OH7NL5IT7777LFG726DVJP3FM2MVWZBPVRIYO735BGVY732MP63KME7L2IGONXX5KS23DWGNBPWXN4XHFXXUJV5PHSEAWTBZD6V723YHR3H67VONV7P37W3FM6F6NVYG42XT53LLX645CDI3C5WT7HDVWLLL7LAWLAIWTV3VF563WJVCZCWWMV7T4J47OKS6XYYXNP2Q6NT3H5FA37N2Z447W5ODX3ISC2XYSAKT5SRGMRVAZ4YSUHL26W267TTFDEDXMESLNW5JUCPSLYHWTLCSNMK4HLCDUSL3OQKEWYI2AMZB5DW6PKRXJYPO7KZ5Z2Y7XSZZ4OB3IULLDNMOQKJLVOQO2LZU4SCRUMIGDT3ZLMTDGTYZ7SX3JPITS4KJ57LCZIC7555WLOQ6O5VKGIAKATN67NRCVLF3LMCZCWUXCCATT6JBSDSWQ4EE4IGQMHKXN3FTRSGFIJHABML5O7GDQW3XZE32PYZDRJJ3IZNHDJAOCMPA474S6NQSK2FICZ2KVKG2X6Y7PROBZF23TAU2LS2OZP4SRXM3BYZNU36INCKN77VWCB2XTG3ANTQBLVZZH6YTB7JJPNNGUTYZFZMXUUTV3WX2B5QA4B5UZ4LEKK53N5GC7J2T7PRIYWK722QWBTZVGLDSATPNBGCDSXMXWWT2VWRGBRGWFNPGSN4KNR3RCPD6KGX6BQYMYKZGULCRZAP2H5GRDZVWGS7FNJOKOJIPSK64BI25KSJQ7DF43OTF3M775FX2V6A7FLWTR4X6D5PWABTQ3OS2JBLJZ3BEL4OXPHXCFATLBLKCSC5EC6DRGIDGBBHETYRCMTXIHDN2IEQIEI6352KUP5W4D6JFR3ZH5CNJ45QD7SHSJCVIIZIPUY4LMKHCS2XYFALHZDKNQHGRYCQNKO6V2XCEIGKOFBESBUJXS7VJESV6ZNUPFGYDC5OQGCHJCXDQBYA3ZJN2XYNQMLBXQ2KOKRSKJDZ3CMSK6T5KN3VPLAEVADL727DHXOAFELWZVP3XBRB5FC5FBEKRDWTZ53BC6NOUI3ZRXQXGGVQKLAXZUC2ALBQPHSEKPKDMDPKPPW3OQB5OFKIC3KI5PRLM4U5DPPMAUBJ27LYDIJVGMVRO3OUMFY4L3TEHHBHTGIXETWSUPBTP6NQUQMDCM3NYAY5XUPNX2BVZAUHHK6KXOOTYZAPIIAUL6IQOH6KUIE7KYKY5ZNYXB5PYZZPN2N225S6XAM4SYKIIHHPD4GGFOXXXCEPIDBH6Z7IUCZIUSXWD6ZY4QFHYTFY3KD6R2S2NY4J7W2MIU5CIVTRJUUONZNOJIGM5B5DDQOD4KXKLQC636BJIKRAXKCJ5Z6XHZGH3NIIL6Q3ZHI6VXIGMOYUBO4ROG56BG6KRIRZR6KXEEWVJKYKQPSXAYL2CFJG6ESK7YODG7PIKASZ3YBFLCOTJ4GFKNN62D5X23JKYEYWDB3SHKXBCVDBMOWOC4DXKKVGK2PJG4WWTGSQ2ACRJYSQU3F7UMYJWQL4O6KTYGW35QJZ7JK45ORI563MOAHEHPRQMCCTS3N472H2VBUN7PTAYQNSLSAGOSVPARHEFTUECCUVKRWIKCTS62IOU2VEPANAZYRQT3SPYDV3NBVOCMILIXSQX2VS2L5YVR7XKCMTTHWNESOSFA6NPEAWJX4WSHD3KIIQDT532HKECBP64EGN6AOE73436IQ6TCRWWSWK4OROUV3KYHXAQLSWZECPT5ZDWZ5IOPUGIVF5S5RXUKS2Q2CAVI4EKQF3RV4GFRL6R3AZH4QZD7U2GFZD2DZFGQF3TRCKHUBGYNS3FMXACMA354HZ6F7KXPOY5H5VGVKBNML7DZOCD3IJSK5CAIN6QU43UFPLHOXSBB3RFILIK6KDW3IYMCS7477YQNQKBSRF3CD65WQY3UREYNWXCVDCEGK5RNCBVXGDQZQWJDNCQCFN5EVPIMORLUKZVLM57YNIA2JKO5AQGV33R2AY2KGDI6DG5Z7PKU2EL5EWWU75B5Y2FVOVPRACE5RU6WKQ2XAWUZEUKZAZPGQLY3V6PRY256C6CENGBXYWUW7LSD7BPUFIIQEI7C46SNE5WJUDKNZGJIUQECHZ2ZFRW3LI7SJTHZYOYMAIYXVVWGAK33LOE5QSCP7VEIKHJRCRGRUQVA4PJSYML2EFEE6VYJGQZFU2WUCM4WZSQNSQKTU2KB2R5UFMSHDSR4LKON6YNGEMEAF54A4MKEZCI75JCREZGZM2PEXQRAKC4SSZI74ICOIT5UK4FHAJRKGRQQVOIZYUMLE2UEQQMVJU6HUHWMHSE243JFGW6DJKS7VNRMJ5KARRZPMUO2RFRQMN6WGREMVMD3BRB4UFTYNPJH7WJPVFH2Q2N6DILF3BVZQMFDB2HND2AGUQ33R5TYKCXKZ2BBGE2KQEXUWGSYY2AORBAUGQOXJCIATQRNLDBBZWRQIVDLPJJEJ3BSBRWFC6FXE5SNANWCUWQLKAA5L264HEIUW3BX5RZAVZHWGCI4KFG3YGS2IKWM2YHIZQZZZZ4Q5L4MPMEZORKGNO2OFLGRLCTUNJXQ2ZOLVBU6TWVPNBID2X4KJZBLWBUGGPIQ34IWINCEPAH4M5A2OQOSMOFPVDOOO3S4C3AE4TK3UC6NSJW7ALMM4X2F3ESYFK6SEDJVCF6DG7JIPWUBBZXNID6RIXBL443YMI2J62IJTPW65FVQKXVI76LFJNCJQ5H4T3CHZMZWVK3MNABQRRZ6TPMGB3SBH4YFONFQ4R4MAV6N72HTNCITFDIBSKOTDGXGBY5A6VICOPLORDG4BBONXSG65I3AE7PYOXR2AP3PNUKYYYKFT4ZMTDTTMPDUJXQER6SL5NFLE3J7SQKTSOUGOI7VJKOOCML5DWKYMOEPAXLTXWQJQ36E6FGJTVGGM2DKMMOI75CGMIGX3VDF3ORMXKMHPX7QLBYXOIKCYHNRMJNA6WQARHNAL24KISJMMZWH4CO32BPS4A7ETGBN3LCWX2DXNTOREYBYAN45BSSXGXNVS3JQKVUOF3GAP27PCE4IWI2GBFI5DBWMAV7LZZJUVOMSZXYUNBDSO7V256EMXFS7Z2SDMFZN36RTA47MZCPUVOLTVDT72TAMYNK4LILHUPVKRSE63IKCRAW4GZVJXA4GDW4UQLZZT7XFI44LGUVIKW4OSFWYPAGMNVFVH4ZQTHFCHOJSTCTDRTONCFQ73HPSKYZGDMLBVOOE7TC26QLMDYDRFFRDCVUZUI2NSPIUPMP65Y4MKFKZWNWAYRD4HGVLQHSZ6WLRONA5BFIULTGNC4ERNHW6VZ6OMLXGAUDQTMQ33KK73TMEIM5QSWLVZYV5QGONMZEOLLTWGDNXNUAB44ZZYTOMXKFTNFGQRHSXI2P4SO6TGV6TTJ6STG7AY5U6TVCSA23O7M7NYAJZZ52RGMQP6ZEMEEQM7XYFG4VRG3W62AO5QTC5BDE3HOIO5IK2JDTIX64V3DEIC6WTSELKO5OT3TOJ4KMYBT55YV6SN6G7SE4SWSSBWD4OPCGPO63C5GL3CA7F2PNIFSJLWUKMNPJ34F7SUEOARW5DXH3SL77U7SXCDLRDU52FJCFPYNAX4QG5BQEEL2AZRB5QO3BAANXUG2LRKF2IGFZC6ICJJVHEHZ4256UC4YTEYB5DKOTIGOLS6RAGUKLFENVEAKBZSRZSRQCHEXRMYNTB443T7EDHGLEELNEJNQCDPTTF4IHI7XARRQDVFE7VFPSDQMAORDRQQC7A44HZXFVJNYJIXLLCIQ7LM6GWRAVS6C7ON6WC4VLQ6O7LINCV2YZQ4FOCFLY7WFYYY7UAYWMOPI4PXJV25T5NMEH6LXDVEDWASBIDGXBS7IA2GK37P57X26XT7P3777Z5OX2SJD772H4TNNIMA===END diff -Nru python-hypothesis-3.44.1/benchmark-data/text-valid=always-interesting=usually python-hypothesis-3.71.11/benchmark-data/text-valid=always-interesting=usually --- python-hypothesis-3.44.1/benchmark-data/text-valid=always-interesting=usually 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/text-valid=always-interesting=usually 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for text [text()], with the validity -# condition "always" and the interestingness condition "usually". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 391 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 8.03 bytes, standard deviation: 23.94 bytes -# -# Additional interesting statistics: -# -# * Ranging from 2 [898 times] to 290 [once] bytes. -# * Median size: 2 -# * 99% of examples had at least 2 bytes -# * 99% of examples had at most 129 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 576: STARTPCOL2V2NN7BSADH5FNI44PPATCH3BPZS5W3BY5WONXJ7564CJANGFARRNNNOSVJK2Q3LM6J45BHT6735J5Z77VV5B63U5DQRTOWGD63GQQPOQWXCA6MPE32Q6VXF5LIRUBEL6RRN646QYJEZAJTBHC63HBTIMNSOPHQWMQQ6AEK6HIOWYLOT22JLF753BMDNWDO2RMZERN44FK2RREWZBVUDUQXV4TQTNOLY7UG4OM6UZIDD2JDGRTTD6QSIS5HMDYGB56HHUFVHQGFIJPFKVV55NQGHVRUE2GIVUCMXIKT73M3ZGMFTJMD46X34VAPLIEA2W6HLK5KHZSH2QGQBBA6CVJAYMHDJFWGE2FPVVEAFLKJG4B2KH7P76SK4AEPBHKOBOVZCR3NVWG75WGXAAEPMEVZGCWYHNFBC6RH5NWZNVZP3JW43ZAYXQEJEJ6YFEYHQ4JKHRR2KIF3BRTAARLL3AYQ3MLFZQ7RCTN5J32CXWGGULZZ7D7TWIRODAXO26ALU26HIQVZ2QS6HBWDCMBIHOUXA2J5TCX3HZXF2P2PKNT7FH4BXV6H5AN7NGC4NEND diff -Nru python-hypothesis-3.44.1/benchmark-data/text-valid=usually-interesting=size_lower_bound python-hypothesis-3.71.11/benchmark-data/text-valid=usually-interesting=size_lower_bound --- python-hypothesis-3.44.1/benchmark-data/text-valid=usually-interesting=size_lower_bound 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/benchmark-data/text-valid=usually-interesting=size_lower_bound 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for text [text()], with the validity -# condition "usually" and the interestingness condition "size_lower_bound". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed 394 -# -# Key statistics for this benchmark: -# -# * 1000 examples -# * Mean size: 8751.32 bytes, standard deviation: 10378.56 bytes -# -# Additional interesting statistics: -# -# * Ranging from 2 [24 times] to 67837 [once] bytes. -# * Median size: 4892 -# * 99% of examples had at least 2 bytes -# * 99% of examples had at most 48101 bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. - -Data 4096: STARTPCOD3GCNSIO3SDMEV6RNAWQLSL4CCMKXOHGM5M7QPJ3HN6HOIZ7CQWIRPKX3XOUKASA4YRFC73Z7H3377X527P3773Y6GH635PWF6PZS3R7P3WFZ56XR7NTC5PTZHL575Z2V34WVL7LW77X2CFI7254PCO7X5HCK5ND7NPWZ25HNUWK2VR7X567VRL3LIVHUTXQWWHO5SLNCR4TJ6HWSW5L7764JM3R5WFH6TN3T7IH26XDXIXOX4MXPHN5GJ5YOLZL3XHW5NMOQ6YR3UGC43KSXPNFTC257NXNTPEPLSKP34VCFDRI33EP32JTWNL7QRYPAXVZ2Z5JGDPFLZ7VSZJ5HXQ724DTWZP5U6ZXGXXOZOFTNOSPD552WKZVHHVUOJ5LZMDQRM6CWW56XXELSSOQK4GM4VUFH2Z5IOLOOFHO7UXS6UWBDGVPUEL7HJAQIVW2PX4C2H2ETO5R4DYWAVKGK6WMRKUFHWCPXS45AP27JP3D5WX7LFV5RLDMFF6XTNFI5PDSUFBBLW53OLFI7PWFOXVTHTBP2WRR6M6J2TQUTHGOUMEI3Y5VVJUNHZK4KLOUGVCBZJDFSEW35VN3TE5BKJ3IISFY6TW56F2VTV6VYJT4WYC2RJQJ4PW4N4CJXUHZOIYJNICN4TGKLHPVOB7TWQ4WIB2ERXJHQBUBRXXHQSUFX2IMFXEM4WWXMVM3U3NPKCVPO2WT26ID7V6XGAKLUPNDSYQGG2JPJHLTGQ2AJ224KAFDK5KPOZJDQTYENOMOSPFWKXLP5MEM2O4FPKQB6HB4NMAJOVHGXX2OSEWJCY6WEFXJJWSYR3SBAMRYLNKEXOOFKGLUMKGPPELQOAWFOPCKCYN2FDZXYBNYBPMOSCKC43OPNIYPO2OHCU2M7BIPE7HFRYRDXCQ2MBTA5HFM4I4MLXKBJEHDRGHHDFKVD5O7YMRG6ZBBHEDK47HJ5TLVKME4EXDKPISHRJ4AFGJUPBGT72N7UQNS5MRTW4ZM5RNE7USSQWKLWTMLNWHHTAZIXO2QUWUEUZLLGLKYILCIHYTAS35Q4757ZYF7YM4RGS6YZTFNMUCSYN465DFINZS3QVVWUJOEQH4D6LOKT45IFX6JEYSV6STBU2XH2VCW3QRU7LQMGYWMVDBOTQNDKBSASLU55CNUXWOPUCBLIXTO7JUYN2S5BGNDKSOXVCJBBDUVPAMPVIKSSAHSJCSXZKFDNAMMLBXHLJX2FOA5F6F7AOB7AI6DPQHYSF4BWLUAS27YI6NZEQ4KJFSEOVAVFBIUHD7GU3ST6MBI2V7QPKNS4QUJYPPBCCE5JTM67F2L4NJF7NEOGXFCLJERLM3SDGHBCMRFLND53STX4NBLIFT2NCTSD4WUV3F2BGJNI3YTFEVH3AA7TKCHRUIGM5REHWFFV4LK6EE76X54VLJZSI7NW7YE3CJZBCKETWSKAAUNQJH62URRB2NMIZIFSLBHLN2DENHIQXO3UNIOENNO62XQE3YQBWC45KLEZEHWRFGQITP6RDLU7NUZ5TVEOQXVBEOZ6IIPZU5Z2PE7K74SY3AZVX5FGN3YGYM5QZUD2X5CCXFLIUFDY3WCB2MQF6NY5KBZIRJP6OXEGMF2RPDMYHDEGBTRKNQWT7KGW5D2KT4A3VHSPIDOFEAI6Q64PIMT4JCJWRBEALIJ2E3LESRKB2LEHBYRGNXBBEIUKMSAFUWFUA6RBGYC26D3OPBZK7YTHF5QG26PRDO2JJWD3JBIYBEGC5BVASDPU7VQTHSTC7AOVA5RZYKATIYLEVPR5IUUGKMY62UJDT7JSJOLOQWLNE7ZMDWHRF62TZXQJQQXKWR4QHGXPDK3EMR57TTOVG5NZTCSFBGQONUVLCFVJYAOEMFZUXOQ2RTKGNR3EEXSTMKOL4E6F264TEBI3FTIHGMQE66F3SS5KT6ZVLU2TZPRLNGW4SLZTHSFCN6UGTVQAX4FMPR7W47QG7SHTPO2HVJAJNIWQP3C2WGOQQEVXLRQLBDJHXHJVGC7IJSESMQ6LQDMGFD73WEEFPMKJ3M2PPOYGA422A7DDDQLO3WHQGZD2XESLUNL3IYHCAAJSOXKBCREZOF4RQ32QBAYOE2FSI55Q4GJ34CQ5EUGZPPW7O7JIP42DBSVKS4V2BSH4GRH4UDG4TWWSFJQ53A6W445RZ5DPQCD7S2SMCZLTNZGBWMWNAFBE5F6XIOKI3ORKHCLHDHJNPO4IVZKRBXR3ZF4LV27247WETHUP34U4LWSYYGWBMR2UPXRGFAMBY2BJI572F6R4JDA2MPSE7W7FFFO2XPDWLAFWKHUPJMFUX7CYUE3PUHL62R2BE3KDSVNFXR4BAA7URUFTBT2ZSCLFPXQV4VQXQOIBDKRVLYO6DTM6EPKNDFARLTPZHVGTDTL7RXRYUOK5EYCHBSND4XCKSN3NAGYKPPKU47CSMCBPZBT7LUF4SUV4ME2Z3KQTJQOD53PVSODQAKUMC6D4ZVWMAQTJ4O7XXYGWFWV4RVMHIS4KL5RT4WSSCH6S6LOKKGREXGCALR3V6VRND5RY2YL5CDMSHKHNIINAF6PJFIA4R4NVGW6XI7FLKCH672VGFATYQ2JEKCENSEQOVJDCHEZGRIYKN2W4KOMWIHW5XFQI3CKASJ7MMTVAB5GS4HNZDBO7BIGNTYIXFDHI4PFT4GECQ6LTHJCRSHDVRWW6PPFJAY6ONTNC5TNU4FBSPNX4TWTTZFGGF6HDCMMPLL35STAUJASWUJDQ4REPBCHP4QOGTIADSGHDN63YKS4YX62BVJHSSMZ7O6NWI2HD7ISWAOXPMFJGHGADBVXM5CCIVQNAC2IHQGZCHC2RQPGA6DKH5EXNM2OLU6G62YKWYYF3MEIZ43AKRMLJDXWGONGUGDWI3KYYVQUU4XHIOIOLXFRFHNDODV4LZ7FVZH3JL47Y3GKTV7ZU2EWHB7I67XYYLFO7MRYKAA5DNQRQQON3ODSNCZCJENWDAC2L6FVPZDNIVD73AWOGW4JWYOVKG22FRSRVO3MDY7OTCF7E63M4UZWGLKR45U4TNKOBHFQGDA3MAMDZRLOS544AP5ZSSPMO23VSG6WF6ARLKXS7VPPWXXAXRYBXKQIE5XG5A74AAMAIOK7TC3AZJYYOLHZ4QJZPZQBB2576MYFW4P4AJEZYJOIT7GS5GNN7C2TPSQ2SBQC3UKKP4YQVT4CCQNU23ZYLSLWASMHZEV4C3U2WL3AJPKHUHTEARPGHIIKNHQU62FSAMAUMQZKI5KLOQZHUMWYELSI2G7657V2AZG5GSPB7FZPUQHHUIEZHEW62GOVU2NNWILIEHROFHCYXSEM7KSQGDC5EH2Z6HFWI3UN5VDIRQND6RRBZN32YBOW2ZTOH4LTGEWG7GQAZKEATTRGPRBSZ2VCIIDHJOA6ZXLWJFFXSMSFJ73NJAG22RJF4HYGYGPAEEO4WSZR5ADQCIDZNQBXOLV2N5RGUEY2TD2UMJ7BDU3KRXXS674NGQX3UVSXWDWS2P7PRMKTCHRLOKN6CAMMHUYGG7YKWRJ7GWALUBUIRSEZYRZA5SY4OCNHJBTU4GFZEZAADG62GHMLRR7ZOFXN4LRCPEN5PSABKHLKXHKA4KGIGNLFVEGQLW2OP4J5YSHC47J4NTUJURDIIF4WYSF3IMPD4PKSSJODJGGNCTLEKV4IUMGQZGOJ6CTCEJYJ2PACQM2RETSFROTT2TMZRHDEA7ZUAECDAW4J4K6DZWFB2OMKH5IGUXY34GUFQK2S6OHCJXI7ZA63KEHPW57V7OS2R7DQWJOT3R3XDS2SF4VBVJ742QMPOQIKKKQWD6Y7NKB54IBMD2JDPGMXRA2AOXHQACHRXOT7CFXSBR7WHTNBCMQJ7GOMYCZY5UXQ3S6J3QJYVCNSZCV3QJY4PHS4WVN36D56N4TTU4GCRUBXS6O6XC3MC5DUDSMYXQ7YXD33Z7UN4HCVSWR5VFVICAQZ3BRXX7KUNXRLFJLBBJUTKHMTOVACRFFTZDQ2Z2CBHPPRO2V5ERT7QGH5BHZLI75DGOMU5WIDS7TQS7AR4Q4F57PWJ7P367T6PXL577347GD55ST4677YA3JSFULI=END diff -Nru python-hypothesis-3.44.1/build.sh python-hypothesis-3.71.11/build.sh --- python-hypothesis-3.44.1/build.sh 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/build.sh 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,40 @@ +#!/usr/bin/env bash + +# This script is here to bootstrap the Hypothesis build process into a working +# version of Python, then hand over to the actual Hypothesis build runner (which +# is written in Python instead of bash). + +set -o xtrace +set -o errexit +set -o nounset + +ROOT="$(git -C "$(dirname "$0")" rev-parse --show-toplevel)" + +export HYPOTHESIS_ROOT="$ROOT" + +SCRIPTS="$ROOT/tooling/scripts" + +# shellcheck source=tooling/scripts/common.sh +source "$SCRIPTS/common.sh" + +"$SCRIPTS/ensure-python.sh" 3.6.5 + +PYTHON=$(pythonloc 3.6.5)/bin/python + +TOOL_REQUIREMENTS="$ROOT/requirements/tools.txt" + +TOOL_HASH=$("$PYTHON" "$SCRIPTS/tool-hash.py" < "$TOOL_REQUIREMENTS") + +TOOL_VIRTUALENV="$VIRTUALENVS/build-$TOOL_HASH" +TOOL_PYTHON="$TOOL_VIRTUALENV/bin/python" + +export PYTHONPATH="$ROOT/tooling/src" + +if ! "$TOOL_PYTHON" -m hypothesistooling check-installed ; then + rm -rf "$TOOL_VIRTUALENV" + "$PYTHON" -m pip install --upgrade virtualenv + "$PYTHON" -m virtualenv "$TOOL_VIRTUALENV" + "$TOOL_PYTHON" -m pip install --no-warn-script-location -r requirements/tools.txt +fi + +"$TOOL_PYTHON" -m hypothesistooling "$@" diff -Nru python-hypothesis-3.44.1/.circleci/config.yml python-hypothesis-3.71.11/.circleci/config.yml --- python-hypothesis-3.44.1/.circleci/config.yml 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/.circleci/config.yml 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,21 @@ +version: 2 +jobs: + build: + macos: + xcode: 9.3.0 + steps: + - checkout + - run: brew update + - run: brew install readline xz ncurses + - restore_cache: + keys: + - v2-runtimes- + - run: ./build.sh install-core + - run: ./build.sh check-py27 + - run: ./build.sh check-py36 + - save_cache: + key: v2-runtimes-{{ epoch }} + paths: + - ~/.cache/hypothesis-build-runtimes + - ~/.cache/pip + - /usr/local/Homebrew diff -Nru python-hypothesis-3.44.1/circle.yml python-hypothesis-3.71.11/circle.yml --- python-hypothesis-3.44.1/circle.yml 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/circle.yml 1970-01-01 00:00:00.000000000 +0000 @@ -1,19 +0,0 @@ -test: - override: - - scripts/run_circle.py - -machine: - # Courtesy of https://pewpewthespells.com/blog/building_python_on_circleci.html - pre: - - export PATH=/usr/local/bin:$PATH:/Users/distiller/Library/Python/2.7/bin - - pip install --user --ignore-installed --upgrade virtualenv - - ln -s $HOME/Library/Python/2.7/bin/virtualenv /usr/local/bin/virtualenv - - cd "$(brew --repository)" && git fetch && git reset --hard origin/master - - brew update - -dependencies: - override: - - make install-core - - cache_directories: - - ~/.cache/hypothesis-build-runtimes diff -Nru python-hypothesis-3.44.1/CITATION python-hypothesis-3.71.11/CITATION --- python-hypothesis-3.44.1/CITATION 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/CITATION 2018-09-24 10:46:59.000000000 +0000 @@ -1,19 +1,20 @@ -Please use one of the following samples to cite the hypothesis version (change -x.y) from this installation +Please use one of the following samples to cite the hypothesis version +(change x.y to the version you are using) from this installation. +You may wish to include the DOI, https://doi.org/10.5281/zenodo.1412597 Text: -[Hypothesis] Hypothesis x.y, 2016 -David R. MacIver, https://github.com/HypothesisWorks/hypothesis-python +[Hypothesis] Hypothesis x.y, 2018 +David R. MacIver, https://github.com/HypothesisWorks/hypothesis BibTeX: @misc{Hypothesisx.y, - title = {{H}ypothesis x.y}, - author = {David R. MacIver}, - year = {2016}, - howpublished = {\href{https://github.com/HypothesisWorks/hypothesis-python}{\texttt{https://github.com/HypothesisWorks/hypothesis-python}}}, + title = {{H}ypothesis x.y}, + author = {David R. MacIver}, + year = {2018}, + howpublished = {\href{https://github.com/HypothesisWorks/hypothesis}{\texttt{https://github.com/HypothesisWorks/hypothesis}}}, } -If you are unsure about which version of hypothesis you are using run: `pip show -hypothesis`. +If you are unsure about which version of Hypothesis you are using run: +`pip show hypothesis` for the Python version. diff -Nru python-hypothesis-3.44.1/CODE_OF_CONDUCT.rst python-hypothesis-3.71.11/CODE_OF_CONDUCT.rst --- python-hypothesis-3.44.1/CODE_OF_CONDUCT.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/CODE_OF_CONDUCT.rst 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,47 @@ +--------------- +Code of conduct +--------------- + +Hypothesis's community is an inclusive space, and everyone in it is expected to abide by a code of conduct. +This applies in issues, pull requests, etc. as well as in the various Hypothesis community spaces. + +At the high level the code of conduct goes like this: + +1. Be kind +2. Be respectful +3. Be helpful + +While it is impossible to enumerate everything that is unkind, disrespectful or unhelpful, here are some specific things that are definitely against the code of conduct: + +1. -isms and -phobias (e.g. racism, sexism, transphobia and homophobia) are unkind, disrespectful *and* unhelpful. Just don't. +2. All software is broken. This is not a moral failing on the part of the authors. Don't give people a hard time for bad code. +3. It's OK not to know things. Everybody was a beginner once, nobody should be made to feel bad for it. +4. It's OK not to *want* to know something. If you think someone's question is fundamentally flawed, you should still ask permission before explaining what they should actually be asking. +5. Note that "I was just joking" is not a valid defence. +6. Don't suggest violence as a response to things, e.g. "People who do/think X should be Y-ed". + Even if you think it is obvious hyperbole and that it's very clear that no actual threat is meant, + it still contributes to a culture that makes people feel unsafe. + + +~~~~~~~~~~~~~~~~~~~~~~~~ +Resolution of Violations +~~~~~~~~~~~~~~~~~~~~~~~~ + +David R. MacIver (the project lead) acts as the main point of contact and enforcer for code of conduct violations. +You can email him at david@drmaciver.com, message him as DRMacIver on irc.freenode.net, or for violations on GitHub +that you want to draw his attention to you can also mention him as @DRMacIver. + +Other people (especially Hypothesis team members) should feel free to call people on code of conduct violations when they see them, +and it is appreciated but not required (especially if doing so would make you feel uncomfortable or unsafe). + +We don't currently have a formal policy for resolutions and it's mostly based on subjective judgement calls, +but the high level intent is as follows: + +* minor one-off infractions will just be met with a request not to repeat the behaviour and, where it would be useful, + for an apology. +* Major infractions and repeat offenders will be banned from the community. + +If you disagree with David's judgement on any particular event, please feel free to tell him so. + +Also, people who have a track record of bad behaviour outside of the Hypothesis community may be banned even +if they obey all these rules if their presence is making people uncomfortable. diff -Nru python-hypothesis-3.44.1/conjecture-rust/Cargo.toml python-hypothesis-3.71.11/conjecture-rust/Cargo.toml --- python-hypothesis-3.44.1/conjecture-rust/Cargo.toml 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/conjecture-rust/Cargo.toml 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,17 @@ +[package] +name = "conjecture" +version = '0.3.0' +authors = ["David R. MacIver "] + +homepage = "https://github.com/HypothesisWorks/hypothesis/tree/master/conjecture-rust" +repository = "https://github.com/HypothesisWorks/hypothesis/" + +description = "Core engine for Hypothesis implementations" + +readme = "README.md" +license = "MPL-2.0" + +[dependencies] + +rand = '0.3' +conjecture = '0.1.0' diff -Nru python-hypothesis-3.44.1/conjecture-rust/CHANGELOG.md python-hypothesis-3.71.11/conjecture-rust/CHANGELOG.md --- python-hypothesis-3.44.1/conjecture-rust/CHANGELOG.md 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/conjecture-rust/CHANGELOG.md 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,27 @@ +# Conjecture for Rust 0.3.0 (2018-07-16) + +This release adds support for annotating interesting examples +to indicate that they are logically distinct. When multiple distinct +reasons for being interesting are found, Conjecture will attempt to +shrink all of them. + +# Conjecture for Rust 0.2.1 (2018-06-25) + +This release fixes an occasional assertion failure that could occur +when shrinking a failing test. + +# Conjecture for Rust 0.2.0 (2018-06-25) + +This release brings over all of the core code and API that was previously in +hypothesis-ruby. + +# Conjecture for Rust 0.1.1 (2018-06-23) + +This is an essentially no-op release that just updates the package homepage and +puts this package under the Hypothesis continuous release system. + +# Conjecture for Rust 0.1.0 (2018-06-19) + +This is an initial empty package release of Conjecture for Rust, solely +to start fleshing out the release system and package dependency architecture +between this and Hypothesis for Ruby. It literally does nothing. diff -Nru python-hypothesis-3.44.1/conjecture-rust/README.md python-hypothesis-3.71.11/conjecture-rust/README.md --- python-hypothesis-3.44.1/conjecture-rust/README.md 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/conjecture-rust/README.md 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,8 @@ +# Conjecture for Rust + +Conjecture is the core engine for Hypothesis. This is a Rust implementation of it, +designed to be shared between multiple library implementations. Currently only +Hypothesis for Ruby uses it. + +It is unlikely that you want to use this library directly if you are not working +on a Hypothesis implementation, and it exists primarily to share code between them. diff -Nru python-hypothesis-3.44.1/conjecture-rust/src/data.rs python-hypothesis-3.71.11/conjecture-rust/src/data.rs --- python-hypothesis-3.44.1/conjecture-rust/src/data.rs 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/conjecture-rust/src/data.rs 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,207 @@ +// Module representing core data types that Hypothesis +// needs. + +use rand::{ChaChaRng, Rng}; +use std::collections::HashSet; +use std::cmp::Ordering; + +pub type DataStream = Vec; + +#[derive(Debug, Clone)] +pub struct FailedDraw; + +#[derive(Debug, Clone)] +enum BitGenerator { + Random(ChaChaRng), + Recorded(DataStream), +} + +// Records information corresponding to a single draw call. +#[derive(Debug, Clone)] +pub struct DrawInProgress { + depth: usize, + start: usize, + end: Option, +} + +// Records information corresponding to a single draw call. +#[derive(Debug, Clone)] +pub struct Draw { + pub depth: usize, + pub start: usize, + pub end: usize, +} + +// Main entry point for running a test: +// A test function takes a DataSource, uses it to +// produce some data, and the DataSource records the +// relevant information about what they did. +#[derive(Debug, Clone)] +pub struct DataSource { + bitgenerator: BitGenerator, + record: DataStream, + sizes: Vec, + draws: Vec, + draw_stack: Vec, + written_indices: HashSet, +} + +impl DataSource { + fn new(generator: BitGenerator) -> DataSource { + return DataSource { + bitgenerator: generator, + record: DataStream::new(), + sizes: Vec::new(), + draws: Vec::new(), + draw_stack: Vec::new(), + written_indices: HashSet::new(), + }; + } + + pub fn from_random(random: ChaChaRng) -> DataSource { + return DataSource::new(BitGenerator::Random(random)); + } + + pub fn from_vec(record: DataStream) -> DataSource { + return DataSource::new(BitGenerator::Recorded(record)); + } + + pub fn start_draw(&mut self) { + let i = self.draws.len(); + let depth = self.draw_stack.len(); + let start = self.record.len(); + + self.draw_stack.push(i); + self.draws.push(DrawInProgress { + start: start, + end: None, + depth: depth, + }); + } + + pub fn stop_draw(&mut self) { + assert!(self.draws.len() > 0); + assert!(self.draw_stack.len() > 0); + let i = self.draw_stack.pop().unwrap(); + let end = self.record.len(); + self.draws[i].end = Some(end); + } + + pub fn write(&mut self, value: u64) -> Result<(), FailedDraw> { + match self.bitgenerator { + BitGenerator::Recorded(ref mut v) if self.record.len() >= v.len() => Err(FailedDraw), + _ => { + self.sizes.push(0); + self.record.push(value); + Ok(()) + } + } + } + + pub fn bits(&mut self, n_bits: u64) -> Result { + self.sizes.push(n_bits); + let mut result = match self.bitgenerator { + BitGenerator::Random(ref mut random) => random.next_u64(), + BitGenerator::Recorded(ref mut v) => if self.record.len() >= v.len() { + return Err(FailedDraw); + } else { + v[self.record.len()] + }, + }; + + if n_bits < 64 { + let mask = (1 << n_bits) - 1; + result &= mask; + }; + + self.record.push(result); + + return Ok(result); + } + + pub fn to_result(mut self, status: Status) -> TestResult { + TestResult { + record: self.record, + status: status, + written_indices: self.written_indices, + sizes: self.sizes, + draws: self.draws + .drain(..) + .filter_map(|d| match d { + DrawInProgress { + depth, + start, + end: Some(end), + } if start < end => + { + Some(Draw { + start: start, + end: end, + depth: depth, + }) + } + DrawInProgress { end: None, .. } => { + assert!(status == Status::Invalid || status == Status::Overflow); + None + } + _ => None, + }) + .collect(), + } + } +} + +// Status indicates the result that we got from completing +// a single test execution. +#[derive(Debug, Clone, Eq, PartialEq, Copy)] +pub enum Status { + // The test tried to read more data than we had for it. + Overflow, + + // Some important precondition of the test was not + // satisfied. + Invalid, + + // This test ran successfully to completion without + // anything of note happening. + Valid, + + // This was an interesting test execution! (Usually this + // means failing, but for things like find it may not). + Interesting(u64), +} + +// Once a data source is finished it "decays" to a +// TestResult, that retains a trace of all the information +// we needed from the DataSource. It is these we keep around, +// not the original DataSource objects. +#[derive(Debug, Clone)] +pub struct TestResult { + pub record: DataStream, + pub status: Status, + pub draws: Vec, + pub sizes: Vec, + pub written_indices: HashSet, +} + + +impl Ord for TestResult { + fn cmp(&self, other: &TestResult) -> Ordering { + self.record.len().cmp(&other.record.len()). + then(self.record.cmp(&other.record)) + } +} + +impl PartialOrd for TestResult { + fn partial_cmp(&self, other: &TestResult) -> Option { + Some(self.cmp(other)) + } +} + +impl PartialEq for TestResult { + fn eq(&self, other: &TestResult) -> bool { + self.record == other.record + } +} + +impl Eq for TestResult { } diff -Nru python-hypothesis-3.44.1/conjecture-rust/src/distributions.rs python-hypothesis-3.71.11/conjecture-rust/src/distributions.rs --- python-hypothesis-3.44.1/conjecture-rust/src/distributions.rs 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/conjecture-rust/src/distributions.rs 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,297 @@ +use data::{DataSource, FailedDraw}; + +use std::cmp::{Ord, Ordering, PartialOrd, Reverse}; +use std::collections::BinaryHeap; +use std::mem; + +use std::u64::MAX as MAX64; + +type Draw = Result; + +pub fn weighted(source: &mut DataSource, probability: f64) -> Result { + // TODO: Less bit-hungry implementation. + + let truthy = (probability * (u64::max_value() as f64 + 1.0)).floor() as u64; + let probe = source.bits(64)?; + Ok(match (truthy, probe) { + (0, _) => false, + (MAX64, _) => true, + (_, 0) => false, + (_, 1) => true, + _ => probe >= MAX64 - truthy, + }) +} + +pub fn bounded_int(source: &mut DataSource, max: u64) -> Draw { + let bitlength = 64 - max.leading_zeros() as u64; + if bitlength == 0 { + source.write(0)?; + return Ok(0); + } + loop { + let probe = source.bits(bitlength)?; + if probe <= max { + return Ok(probe); + } + } +} + +#[derive(Debug, Clone)] +pub struct Repeat { + min_count: u64, + max_count: u64, + p_continue: f64, + + current_count: u64, +} + +impl Repeat { + pub fn new(min_count: u64, max_count: u64, expected_count: f64) -> Repeat { + Repeat { + min_count: min_count, + max_count: max_count, + p_continue: 1.0 - 1.0 / (1.0 + expected_count), + current_count: 0, + } + } + + pub fn reject(&mut self) { + assert!(self.current_count > 0); + self.current_count -= 1; + } + + pub fn should_continue(&mut self, source: &mut DataSource) -> Result { + if self.min_count == self.max_count { + if self.current_count < self.max_count { + self.current_count += 1; + return Ok(true); + } else { + return Ok(false); + } + } else if self.current_count < self.min_count { + source.write(1)?; + self.current_count += 1; + return Ok(true); + } else if self.current_count >= self.max_count { + source.write(0)?; + return Ok(false); + } + + let result = weighted(source, self.p_continue)?; + if result { + self.current_count += 1; + } else { + } + return Ok(result); + } +} + +#[derive(Debug, Clone)] +struct SamplerEntry { + primary: usize, + alternate: usize, + use_alternate: f32, +} + +impl SamplerEntry { + fn single(i: usize) -> SamplerEntry { + SamplerEntry { + primary: i, + alternate: i, + use_alternate: 0.0, + } + } +} + +impl Ord for SamplerEntry { + fn cmp(&self, other: &SamplerEntry) -> Ordering { + return self.primary + .cmp(&other.primary) + .then(self.alternate.cmp(&other.alternate)); + } +} + +impl PartialOrd for SamplerEntry { + fn partial_cmp(&self, other: &SamplerEntry) -> Option { + return Some(self.cmp(other)); + } +} + +impl PartialEq for SamplerEntry { + fn eq(&self, other: &SamplerEntry) -> bool { + return self.cmp(other) == Ordering::Equal; + } +} + +impl Eq for SamplerEntry {} + +#[derive(Debug, Clone)] +pub struct Sampler { + table: Vec, +} + +impl Sampler { + pub fn new(weights: Vec) -> Sampler { + // FIXME: The correct thing to do here is to allow this, + // return early, and make this reject the data, but we don't + // currently have the status built into our data properly... + assert!(weights.len() > 0); + + let mut table = Vec::new(); + + let mut small = BinaryHeap::new(); + let mut large = BinaryHeap::new(); + + let total: f32 = weights.iter().sum(); + + let mut scaled_probabilities = Vec::new(); + + let n = weights.len() as f32; + + for (i, w) in weights.iter().enumerate() { + let scaled = n * w / total; + scaled_probabilities.push(scaled); + if scaled == 1.0 { + table.push(SamplerEntry::single(i)) + } else if scaled > 1.0 { + large.push(Reverse(i)); + } else { + assert!(scaled < 1.0); + small.push(Reverse(i)); + } + } + + while !(small.is_empty() || large.is_empty()) { + let Reverse(lo) = small.pop().unwrap(); + let Reverse(hi) = large.pop().unwrap(); + + assert!(lo != hi); + assert!(scaled_probabilities[hi] > 1.0); + assert!(scaled_probabilities[lo] < 1.0); + scaled_probabilities[hi] = (scaled_probabilities[hi] + scaled_probabilities[lo]) - 1.0; + table.push(SamplerEntry { + primary: lo, + alternate: hi, + use_alternate: 1.0 - scaled_probabilities[lo], + }); + + if scaled_probabilities[hi] < 1.0 { + small.push(Reverse(hi)) + } else if scaled_probabilities[hi] > 1.0 { + large.push(Reverse(hi)) + } else { + table.push(SamplerEntry::single(hi)) + } + } + for &Reverse(i) in small.iter() { + table.push(SamplerEntry::single(i)) + } + for &Reverse(i) in large.iter() { + table.push(SamplerEntry::single(i)) + } + + for ref mut entry in table.iter_mut() { + if entry.alternate < entry.primary { + mem::swap(&mut entry.primary, &mut entry.alternate); + entry.use_alternate = 1.0 - entry.use_alternate; + } + } + + table.sort(); + assert!(table.len() > 0); + return Sampler { table: table }; + } + + pub fn sample(&self, source: &mut DataSource) -> Draw { + assert!(self.table.len() > 0); + let i = bounded_int(source, self.table.len() as u64 - 1)? as usize; + let entry = &self.table[i]; + let use_alternate = weighted(source, entry.use_alternate as f64)?; + if use_alternate { + Ok(entry.alternate) + } else { + Ok(entry.primary) + } + } +} + +pub fn good_bitlengths() -> Sampler { + let weights = vec![ + 4.0, + 4.0, + 4.0, + 4.0, + 4.0, + 4.0, + 4.0, + 4.0, // 1 byte + 2.0, + 2.0, + 2.0, + 2.0, + 2.0, + 2.0, + 2.0, + 2.0, // 2 bytes + 1.0, + 1.0, + 1.0, + 1.0, + 1.0, + 1.0, + 1.0, + 1.0, // 3 bytes + 0.5, + 0.5, + 0.5, + 0.5, + 0.5, + 0.5, + 0.5, + 0.5, // 4 bytes + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, // 5 bytes + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, // 6 bytes + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, // 7 bytes + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, // 8 bytes (last bit spare for sign) + ]; + assert!(weights.len() == 63); + Sampler::new(weights) +} + +pub fn integer_from_bitlengths(source: &mut DataSource, bitlengths: &Sampler) -> Draw { + let bitlength = bitlengths.sample(source)? as u64 + 1; + let base = source.bits(bitlength)? as i64; + let sign = source.bits(1)?; + if sign > 0 { + Ok(-base) + } else { + Ok(base) + } +} diff -Nru python-hypothesis-3.44.1/conjecture-rust/src/engine.rs python-hypothesis-3.71.11/conjecture-rust/src/engine.rs --- python-hypothesis-3.44.1/conjecture-rust/src/engine.rs 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/conjecture-rust/src/engine.rs 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,719 @@ +// Core module that provides a main execution loop and +// the API that can be used to get test data from it. + +use rand::{ChaChaRng, Rng, SeedableRng}; + +use std::cmp::Reverse; +use std::collections::{HashMap, HashSet}; +use std::mem; +use std::sync::mpsc::{sync_channel, Receiver, SyncSender}; +use std::thread; + +use data::{DataSource, DataStream, Status, TestResult}; +use intminimize::minimize_integer; + +#[derive(Debug, Clone)] +enum LoopExitReason { + Complete, + MaxExamples, + Shutdown, +} + +#[derive(Debug)] +enum LoopCommand { + RunThis(DataSource), + Finished(LoopExitReason, MainGenerationLoop), +} + +#[derive(Debug)] +struct MainGenerationLoop { + receiver: Receiver, + sender: SyncSender, + max_examples: u64, + random: ChaChaRng, + + best_example: Option, + minimized_examples: HashMap, + fully_minimized: HashSet, + + valid_examples: u64, + invalid_examples: u64, + interesting_examples: u64, +} + +type StepResult = Result<(), LoopExitReason>; + +impl MainGenerationLoop { + fn run(mut self) { + let result = self.loop_body(); + match result { + // Silent shutdown when the main thread terminates + Err(LoopExitReason::Shutdown) => (), + Err(reason) => { + // Must clone because otherwise it is borrowed. + let shutdown_sender = self.sender.clone(); + shutdown_sender + .send(LoopCommand::Finished(reason, self)) + .unwrap() + } + Ok(_) => panic!("BUG: Generation loop was not supposed to return normally."), + } + } + + fn loop_body(&mut self) -> StepResult { + self.generate_examples()?; + + // At the start of this loop we can only have example in + // self.minimized_examples, but as we shrink we may find other ones. + // The reason why we loop is twofold: + // a) This allows us to include newly discovered examples. Labels that + // are not found in self.minimized_examples at the beginning of the + // loop will be added for the next iteration around. + // b) If we've previously marked a label as finished it can become + // unfinished again if when shrinking another label, as when trying + // to shrink one label we might accidentally find an improved shrink + // for another. + // + // In principle this might cause us to loop for a very long time before + // eventually settling on a fixed point, but when that happens we + // should hit limits on shrinking (which we haven't implemented yet). + while self.minimized_examples.len() > self.fully_minimized.len() { + let keys: Vec = self.minimized_examples.keys().map(|i| *i).collect(); + for label in keys.iter() { + if self.fully_minimized.insert(*label) { + let target = self.minimized_examples[label].clone(); + let mut shrinker = Shrinker::new( + self, target, |r| { + r.status == Status::Interesting(*label) + }); + + shrinker.run()?; + } + } + } + + return Err(LoopExitReason::Complete); + } + + fn generate_examples(&mut self) -> Result { + while self.valid_examples < self.max_examples + && self.invalid_examples < 10 * self.max_examples + { + let r = self.random.gen(); + let result = self.execute(DataSource::from_random(r))?; + match result.status { + Status::Interesting(_) => return Ok(result), + _ => (), + } + } + return Err(LoopExitReason::MaxExamples); + } + + fn execute(&mut self, source: DataSource) -> Result { + let result = match self.sender.send(LoopCommand::RunThis(source)) { + Ok(_) => match self.receiver.recv() { + Ok(t) => t, + Err(_) => return Err(LoopExitReason::Shutdown), + }, + Err(_) => return Err(LoopExitReason::Shutdown), + }; + match result.status { + Status::Overflow => (), + Status::Invalid => self.invalid_examples += 1, + Status::Valid => self.valid_examples += 1, + Status::Interesting(n) => { + self.best_example = Some(result.clone()); + let mut changed = false; + self.minimized_examples.entry(n).or_insert_with(|| {result.clone()}); + self.minimized_examples.entry(n).and_modify(|e| { + if result < *e { + changed = true; + *e = result.clone() + }; + }); + if changed { + self.fully_minimized.remove(&n); + } + self.interesting_examples += 1; + } + } + + Ok(result) + } +} + +struct Shrinker<'owner, Predicate> { + _predicate: Predicate, + shrink_target: TestResult, + changes: u64, + expensive_passes_enabled: bool, + main_loop: &'owner mut MainGenerationLoop, +} + +impl<'owner, Predicate> Shrinker<'owner, Predicate> +where + Predicate: Fn(&TestResult) -> bool, +{ + fn new( + main_loop: &'owner mut MainGenerationLoop, + shrink_target: TestResult, + predicate: Predicate, + ) -> Shrinker<'owner, Predicate> { + assert!(predicate(&shrink_target)); + Shrinker { + main_loop: main_loop, + _predicate: predicate, + shrink_target: shrink_target, + changes: 0, + expensive_passes_enabled: false, + } + } + + fn predicate(&mut self, result: &TestResult) -> bool { + let succeeded = (self._predicate)(result); + if succeeded + && ( + // In the presence of writes it may be the case that we thought + // we were going to shrink this but didn't actually succeed because + // the written value was used. + result.record.len() < self.shrink_target.record.len() || ( + result.record.len() == self.shrink_target.record.len() && + result.record < self.shrink_target.record + ) + ) { + self.changes += 1; + self.shrink_target = result.clone(); + } + succeeded + } + + fn run(&mut self) -> StepResult { + let mut prev = self.changes + 1; + + while prev != self.changes { + prev = self.changes; + self.adaptive_delete()?; + self.minimize_individual_blocks()?; + self.minimize_duplicated_blocks()?; + if prev == self.changes { + self.expensive_passes_enabled = true; + } + if !self.expensive_passes_enabled { + continue; + } + + self.reorder_blocks()?; + self.lower_and_delete()?; + self.delete_all_ranges()?; + } + Ok(()) + } + + fn lower_and_delete(&mut self) -> StepResult { + let mut i = 0; + while i < self.shrink_target.record.len() { + if self.shrink_target.record[i] > 0 { + let mut attempt = self.shrink_target.record.clone(); + attempt[i] -= 1; + let (succeeded, result) = self.execute(&attempt)?; + if !succeeded && result.record.len() < self.shrink_target.record.len() { + let mut j = 0; + while j < self.shrink_target.draws.len() { + // Having to copy this is an annoying consequence of lexical lifetimes - + // if we borrowed it immutably then we'd not be allowed to call self.incorporate + // down below. Fortunately these things are tiny structs of integers so it doesn't + // really matter. + let d = self.shrink_target.draws[j].clone(); + if d.start > i { + let mut attempt2 = attempt.clone(); + attempt2.drain(d.start..d.end); + if self.incorporate(&attempt2)? { + break; + } + } + j += 1; + } + } + } + i += 1; + } + Ok(()) + } + + fn reorder_blocks(&mut self) -> StepResult { + let mut i = 0; + while i < self.shrink_target.record.len() { + let mut j = i + 1; + while j < self.shrink_target.record.len() { + assert!(i < self.shrink_target.record.len()); + if self.shrink_target.record[i] == 0 { + break; + } + if self.shrink_target.record[j] < self.shrink_target.record[i] { + let mut attempt = self.shrink_target.record.clone(); + attempt.swap(i, j); + self.incorporate(&attempt)?; + } + j += 1; + } + i += 1; + } + Ok(()) + } + + fn try_delete_range( + &mut self, + target: &TestResult, + i: usize, + k: usize, + ) -> Result { + // Attempts to delete k non-overlapping draws starting from the draw at index i. + + let mut stack: Vec<(usize, usize)> = Vec::new(); + let mut j = i; + while j < target.draws.len() && stack.len() < k { + let m = target.draws[j].start; + let n = target.draws[j].end; + assert!(m < n); + if m < n && (stack.len() == 0 || stack[stack.len() - 1].1 <= m) { + stack.push((m, n)) + } + j += 1; + } + + let mut attempt = target.record.clone(); + while stack.len() > 0 { + let (m, n) = stack.pop().unwrap(); + attempt.drain(m..n); + } + + if attempt.len() >= self.shrink_target.record.len() { + Ok(false) + } else { + self.incorporate(&attempt) + } + } + + fn adaptive_delete(&mut self) -> StepResult { + let mut i = 0; + let target = self.shrink_target.clone(); + + while i < target.draws.len() { + // This is an adaptive pass loosely modelled after timsort. If + // little or nothing is deletable here then we don't try any more + // deletions than the naive greedy algorithm would, but if it looks + // like we have an opportunity to delete a lot then we try to do so. + + // What we're trying to do is to find a large k such that we can + // delete k but not k + 1 draws starting from this point, and we + // want to do that in O(log(k)) rather than O(k) test executions. + + // We try a quite careful sequence of small shrinks here before we + // move on to anything big. This is because if we try to be + // aggressive too early on we'll tend to find that we lose out when + // the example is "nearly minimal". + if self.try_delete_range(&target, i, 2)? { + if self.try_delete_range(&target, i, 3)? && self.try_delete_range(&target, i, 4)? { + let mut hi = 5; + // At this point it looks like we've got a pretty good + // opportunity for a long run here. We do an exponential + // probe upwards to try and find some k where we can't + // delete many intervals. We do this rather than choosing + // that upper bound to immediately be large because we + // don't really expect k to be huge. If it turns out that + // it is, the subsequent example is going to be so tiny that + // it doesn't really matter if we waste a bit of extra time + // here. + while self.try_delete_range(&target, i, hi)? { + assert!(hi <= target.draws.len()); + hi *= 2; + } + // We now know that we can delete the first lo intervals but + // not the first hi. We preserve that property while doing + // a binary search to find the point at which we stop being + // able to delete intervals. + let mut lo = 4; + while lo + 1 < hi { + let mid = lo + (hi - lo) / 2; + if self.try_delete_range(&target, i, mid)? { + lo = mid; + } else { + hi = mid; + } + } + } + } else { + self.try_delete_range(&target, i, 1)?; + } + // We unconditionally bump i because we have always tried deleting + // one more example than we succeeded at deleting, so we expect the + // next example to be undeletable. + i += 1; + } + return Ok(()); + } + + fn delete_all_ranges(&mut self) -> StepResult { + let mut i = 0; + while i < self.shrink_target.record.len() { + let start_length = self.shrink_target.record.len(); + + let mut j = i + 1; + while j < self.shrink_target.record.len() { + assert!(j > i); + let mut attempt = self.shrink_target.record.clone(); + attempt.drain(i..j); + assert!(attempt.len() + (j - i) == self.shrink_target.record.len()); + let deleted = self.incorporate(&attempt)?; + if !deleted { + j += 1; + } + } + if start_length == self.shrink_target.record.len() { + i += 1; + } + } + Ok(()) + } + + fn try_lowering_value(&mut self, i: usize, v: u64) -> Result { + if v >= self.shrink_target.record[i] { + return Ok(false); + } + + let mut attempt = self.shrink_target.record.clone(); + attempt[i] = v; + let (succeeded, result) = self.execute(&attempt)?; + assert!(result.record.len() <= self.shrink_target.record.len()); + let lost_bytes = self.shrink_target.record.len() - result.record.len(); + if !succeeded && result.status == Status::Valid && lost_bytes > 0 { + attempt.drain(i + 1..i + lost_bytes + 1); + assert!(attempt.len() + lost_bytes == self.shrink_target.record.len()); + self.incorporate(&attempt) + } else { + Ok(succeeded) + } + } + + fn minimize_individual_blocks(&mut self) -> StepResult { + let mut i = 0; + + while i < self.shrink_target.record.len() { + if !self.shrink_target.written_indices.contains(&i) { + minimize_integer(self.shrink_target.record[i], |v| { + self.try_lowering_value(i, v) + })?; + } + + i += 1; + } + + Ok(()) + } + + fn calc_duplicates(&self) -> Vec> { + assert!(self.shrink_target.record.len() == self.shrink_target.sizes.len()); + let mut duplicates: HashMap<(u64, u64), Vec> = HashMap::new(); + for (i, (u, v)) in self.shrink_target + .record + .iter() + .zip(self.shrink_target.sizes.iter()) + .enumerate() + { + if !self.shrink_target.written_indices.contains(&i) { + duplicates + .entry((*u, *v)) + .or_insert_with(|| Vec::new()) + .push(i); + } + } + + let mut result: Vec> = duplicates + .drain() + .filter_map(|(_, elements)| { + if elements.len() > 1 { + Some(elements) + } else { + None + } + }) + .collect(); + result.sort_by_key(|v| Reverse(v.len())); + result + } + + fn minimize_duplicated_blocks(&mut self) -> StepResult { + let mut i = 0; + let mut targets = self.calc_duplicates(); + + while i < targets.len() { + let target = mem::replace(&mut targets[i], Vec::new()); + let max_target = *target.iter().max().unwrap(); + + i += 1; + assert!(target.len() > 0); + let v = self.shrink_target.record[target[0]]; + + let w = minimize_integer(v, |t| { + if max_target >= self.shrink_target.record.len() { + return Ok(false); + } + let mut attempt = self.shrink_target.record.clone(); + for i in &target { + attempt[*i] = t + } + self.incorporate(&attempt) + })?; + if w != v { + targets = self.calc_duplicates(); + } + } + Ok(()) + } + + fn execute(&mut self, buf: &DataStream) -> Result<(bool, TestResult), LoopExitReason> { + // TODO: Later there will be caching here + let result = self.main_loop.execute(DataSource::from_vec(buf.clone()))?; + Ok((self.predicate(&result), result)) + } + + fn incorporate(&mut self, buf: &DataStream) -> Result { + assert!( + buf.len() <= self.shrink_target.record.len(), + "Expected incorporate to not increase length, but buf.len() = {} \ + while shrink target was {}", + buf.len(), + self.shrink_target.record.len() + ); + if buf.len() == self.shrink_target.record.len() { + assert!(buf < &self.shrink_target.record); + } + if self.shrink_target.record.starts_with(buf) { + return Ok(false); + } + let (succeeded, _) = self.execute(buf)?; + Ok(succeeded) + } +} + +#[derive(Debug, Clone, Eq, PartialEq)] +enum EngineState { + AwaitingCompletion, + ReadyToProvide, +} + +#[derive(Debug)] +pub struct Engine { + // The next response from the main loop. Once + // this is set to Some(Finished(_)) it stays that way, + // otherwise it is cleared on access. + loop_response: Option, + + state: EngineState, + + // Communication channels with the main testing loop + handle: Option>, + receiver: Receiver, + sender: SyncSender, +} + +impl Clone for Engine { + fn clone(&self) -> Engine { + panic!("BUG: The Engine was unexpectedly cloned"); + } +} + +impl Engine { + pub fn new(max_examples: u64, seed: &[u32]) -> Engine { + let (send_local, recv_remote) = sync_channel(1); + let (send_remote, recv_local) = sync_channel(1); + + let main_loop = MainGenerationLoop { + max_examples: max_examples, + random: ChaChaRng::from_seed(seed), + sender: send_remote, + receiver: recv_remote, + best_example: None, + minimized_examples: HashMap::new(), + fully_minimized: HashSet::new(), + valid_examples: 0, + invalid_examples: 0, + interesting_examples: 0, + }; + + let handle = thread::Builder::new() + .name("Hypothesis main loop".to_string()) + .spawn(move || { + main_loop.run(); + }) + .unwrap(); + + Engine { + loop_response: None, + sender: send_local, + receiver: recv_local, + handle: Some(handle), + state: EngineState::ReadyToProvide, + } + } + + pub fn mark_finished(&mut self, source: DataSource, status: Status) -> () { + self.consume_test_result(source.to_result(status)) + } + + pub fn next_source(&mut self) -> Option { + assert!(self.state == EngineState::ReadyToProvide); + self.state = EngineState::AwaitingCompletion; + + self.await_loop_response(); + + let mut local_result = None; + mem::swap(&mut local_result, &mut self.loop_response); + + match local_result { + Some(LoopCommand::RunThis(source)) => return Some(source), + None => panic!("BUG: Loop response should not be empty at this point"), + _ => { + self.loop_response = local_result; + return None; + } + } + } + + pub fn list_minimized_examples(&self) -> Vec { + match &self.loop_response { + &Some(LoopCommand::Finished( + _, + MainGenerationLoop { + ref minimized_examples, + .. + }, + )) => { + let mut results: Vec = minimized_examples.values().map(|v| v.clone()).collect(); + results.sort(); + results + }, + _ => Vec::new(), + } + } + + pub fn best_source(&self) -> Option { + match &self.loop_response { + &Some(LoopCommand::Finished( + _, + MainGenerationLoop { + best_example: Some(ref result), + .. + }, + )) => Some(DataSource::from_vec(result.record.clone())), + _ => None, + } + } + + + fn consume_test_result(&mut self, result: TestResult) -> () { + assert!(self.state == EngineState::AwaitingCompletion); + self.state = EngineState::ReadyToProvide; + + if self.has_shutdown() { + return (); + } + + // NB: Deliberately not matching on result. If this fails, + // that's OK - it means the loop has shut down and when we ask + // for data from it we'll get its shutdown response. + let _ = self.sender.send(result); + } + + pub fn was_unsatisfiable(&self) -> bool { + match &self.loop_response { + &Some(LoopCommand::Finished(_, ref main_loop)) => { + main_loop.interesting_examples == 0 && main_loop.valid_examples == 0 + } + _ => false, + } + } + + fn has_shutdown(&mut self) -> bool { + match &self.loop_response { + &Some(LoopCommand::Finished(..)) => true, + _ => false, + } + } + + fn await_thread_termination(&mut self) { + let mut maybe_handle = None; + mem::swap(&mut self.handle, &mut maybe_handle); + if let Some(handle) = maybe_handle { + if let Err(boxed_msg) = handle.join() { + // FIXME: This is awful but as far as I can tell this is + // genuinely the only way to get the actual message out of the + // panic in the child thread! It's boxed as an Any, and the + // debug of Any just says "Any". Fortunately the main loop is + // very much under our control so this doesn't matter too much + // here, but yuck! + if let Some(msg) = boxed_msg.downcast_ref::<&str>() { + panic!(msg.to_string()); + } else if let Some(msg) = boxed_msg.downcast_ref::() { + panic!(msg.clone()); + } else { + panic!("BUG: Unexpected panic format in main loop"); + } + } + } + } + + fn await_loop_response(&mut self) -> () { + if self.loop_response.is_none() { + match self.receiver.recv() { + Ok(response) => { + self.loop_response = Some(response); + if self.has_shutdown() { + self.await_thread_termination(); + } + } + Err(_) => { + self.await_thread_termination(); + panic!("BUG: Unexpected silent termination of generation loop.") + } + } + } + } +} + + +#[cfg(test)] +mod tests { + use super::*; + use data::FailedDraw; + + fn run_to_results(mut f: F) -> Vec + where F: FnMut(&mut DataSource) -> Result { + let seed: [u32; 2] = [0, 0]; + let mut engine = Engine::new(1000, &seed); + while let Some(mut source) = engine.next_source() { + if let Ok(status) = f(&mut source) { + engine.mark_finished(source, status); + } else { + engine.mark_finished(source, Status::Overflow); + } + } + engine.list_minimized_examples() + } + + #[test] + fn minimizes_all_examples(){ + let results = run_to_results(|source| { + let n = source.bits(64)?; + if n >= 100 { + Ok(Status::Interesting(n % 2)) + } else { + Ok(Status::Valid) + } + }); + + assert!(results.len() == 2); + assert_eq!(results[0].record[0], 100); + assert_eq!(results[1].record[0], 101); + } +} diff -Nru python-hypothesis-3.44.1/conjecture-rust/src/intminimize.rs python-hypothesis-3.71.11/conjecture-rust/src/intminimize.rs --- python-hypothesis-3.44.1/conjecture-rust/src/intminimize.rs 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/conjecture-rust/src/intminimize.rs 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,149 @@ +use std::cmp::min; + +const SMALL: u64 = 5; + +struct Minimizer<'a, F: 'a> { + criterion: &'a mut F, + best: u64, +} + +impl<'a, F, T> Minimizer<'a, F> +where + F: 'a + FnMut(u64) -> Result, +{ + fn test(&mut self, candidate: u64) -> Result { + if candidate == self.best { + return Ok(true); + } + if candidate > self.best { + return Ok(false); + } + let result = (self.criterion)(candidate)?; + if result { + self.best = candidate; + } + Ok(result) + } + + fn modify(&mut self, g: G) -> Result + where + G: Fn(u64) -> u64, + { + let x = g(self.best); + self.test(x) + } +} + +pub fn minimize_integer(start: u64, mut criterion: F) -> Result +where + F: FnMut(u64) -> Result, +{ + if start == 0 { + return Ok(start); + } + + for i in 0..min(start, SMALL) { + if criterion(i)? { + return Ok(i); + } + } + if start <= SMALL { + return Ok(start); + } + + let mut minimizer = Minimizer { + best: start, + criterion: &mut criterion, + }; + + loop { + if !minimizer.modify(|x| x >> 1)? { + break; + } + } + + for i in 0..64 { + minimizer.modify(|x| x ^ (1 << i))?; + } + + assert!(minimizer.best >= SMALL); + + for i in 0..64 { + let left_mask = 1 << i; + let mut right_mask = left_mask >> 1; + while right_mask != 0 { + minimizer.modify(|x| { + if x & left_mask == 0 || x & right_mask != 0 { + x + } else { + x ^ (right_mask | left_mask) + } + })?; + right_mask >>= 1; + } + } + + if !minimizer.modify(|x| x - 1)? { + return Ok(minimizer.best); + } + + let mut lo = 0; + let mut hi = minimizer.best; + while lo + 1 < hi { + let mid = lo + (hi - lo) / 2; + if minimizer.test(mid)? { + hi = mid; + } else { + lo = mid; + } + } + + Ok(minimizer.best) +} + +#[cfg(test)] +mod tests { + use super::*; + + fn non_failing_minimize(start: u64, criterion: F) -> u64 + where + F: Fn(u64) -> bool, + { + let mut best = start; + + loop { + let ran: Result = minimize_integer(best, |x| Ok(criterion(x))); + let result = ran.unwrap(); + assert!(result <= best); + if result == best { + return best; + } + best = result; + } + } + + #[test] + fn minimize_down_to() { + let n = non_failing_minimize(100, |x| x >= 10); + assert_eq!(n, 10); + } + + #[test] + fn unset_relevant_bits() { + let x = 0b101010101010; + let y = 0b111111111111; + let n = non_failing_minimize(y, |k| k & x == x); + assert_eq!(n, x); + } + + #[test] + fn sort_bits() { + let x: u64 = 0b1011011011000111; + let y: u64 = 0b0000001111111111; + let c = x.count_ones(); + assert_eq!(c, y.count_ones()); + + let n = non_failing_minimize(x, |k| k.count_ones() == c); + assert_eq!(y, n); + } +} diff -Nru python-hypothesis-3.44.1/conjecture-rust/src/lib.rs python-hypothesis-3.71.11/conjecture-rust/src/lib.rs --- python-hypothesis-3.44.1/conjecture-rust/src/lib.rs 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/conjecture-rust/src/lib.rs 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,7 @@ +extern crate core; +extern crate rand; + +pub mod data; +pub mod distributions; +pub mod engine; +pub mod intminimize; diff -Nru python-hypothesis-3.44.1/CONTRIBUTING.rst python-hypothesis-3.71.11/CONTRIBUTING.rst --- python-hypothesis-3.44.1/CONTRIBUTING.rst 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/CONTRIBUTING.rst 2018-09-24 10:46:59.000000000 +0000 @@ -29,8 +29,37 @@ You can read more about how we document Hypothesis in ``guides/documentation.rst`` The process for submitting source code PRs is generally more involved -(don't worry, we'll help you through it), so do read the rest of this document -first. +(don't worry, we'll help you through it), so do read the rest of this document. +If you're planning a larger change, the contributor guides (in the ``guides/`` +directory) will make sure you're on the right track. + +---------------------------------- +Installing from source and testing +---------------------------------- + +If you want to install directly from the source code (e.g. because you want to +make changes and install the changed version) you can do this with: + +.. code:: bash + + pip install -r requirements/test.txt + pip install -r requirements/tools.txt + pip install -e hypothesis-python/ + + # You don't need to run the tests, but here's the command: + pytest hypothesis-python/tests/cover/ + +You may wish to do all of this in a +`virtualenv `_. For example: + +.. code:: bash + + virtualenv venv + source venv/bin/activate + pip install hypothesis + +Will create an isolated environment where you can install and try out +Hypothesis without affecting your system packages. ----------------------- Copyright and Licensing @@ -62,6 +91,8 @@ or open an issue. If it's really small feel free to open a work in progress pull request sketching out the idea, but it's best to get feedback from the Hypothesis maintainers before sinking a bunch of work into it. +If you're working on an existing issue, leave a comment so we can try to avoid +duplicating your work before you open a pull request. In general work-in-progress pull requests are totally welcome if you want early feedback or help with some of the tricky details. Don't be afraid to ask for help. @@ -84,70 +115,64 @@ breaks things, that's our fault not yours - the whole point of this process is to ensure that problems get caught before we merge rather than after. - -~~~~~~~~~~~~~~~~ -The Release File -~~~~~~~~~~~~~~~~ - -All changes to Hypothesis get released automatically when they are merged to -master. - -In order to update the version and change log entry, you have to create a -release file. This is a normal restructured text file called RELEASE.rst that -lives in the root of the repository and will be used as the change log entry. - -It should start with following lines: - -* RELEASE_TYPE: major -* RELEASE_TYPE: minor -* RELEASE_TYPE: patch - -This specifies the component of the version number that should be updated, with -the meaning of each component following `semver `_. As a -rule of thumb if it's a bug fix it's probably a patch version update, if it's -a new feature it's definitely a minor version update, and you probably -shouldn't ever need to use a major version update unless you're part of the -core team and we've discussed it a lot. - -This line will be removed from the final change log entry. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Pull request or external package? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +New strategies can be added to Hypothesis, or published as an external package +on PyPI - either is fine for most strategies. If in doubt, ask! + +It's generally much easier to get things working outside, because there's +more freedom to experiment and fewer requirements in stability and API style. +We're happy to review and help with external packages as well as pull requests; +several parts of Hypothesis started life outside and were integrated later +(with permission, of course). For clarity, we suggest naming your package +in the pattern of ``hypothesis-regex`` and ``hypothesis-protobuf`` on PyPI. + +On the other hand, being inside gets you access to some deeper implementation +features (if you need them) and better long-term guarantees about maintenance. +We particularly encourage pull requests for new composable primitives that +make implementing other strategies easier, or for widely used types in the +Python standard library. Strategies for other things are also welcome; +anything with external dependencies just goes in ``hypothesis.extra``. ~~~~~~~~~ The build ~~~~~~~~~ -The build is orchestrated by a giant Makefile which handles installation of the relevant pythons. -Actually running the tests is managed by `tox `_, but the Makefile +The build is driven by a ``build.sh`` shell script, which delegates to a custom Python-based build system. +Actually running the tests is managed by `tox `_, but the build system will call out to the relevant tox environments so you mostly don't have to know anything about that -unless you want to make changes to the test config. You also mostly don't need to know anything about make -except to type 'make' followed by the name of the task you want to run. +unless you want to make changes to the test config. You also mostly don't need to know anything about the build system +except to type ``./build.sh`` followed by the name of the task you want to run. All of it will be checked on CI so you don't *have* to run anything locally, but you might find it useful to do so: A full Travis run takes about twenty minutes, and there's often a queue, so running a smaller set of tests locally can be helpful. -The makefile should be "fairly" portable, but is currently only known to work on Linux or OS X. It *might* work +The build system should be "fairly" portable, but is currently only known to work on Linux or OS X. It *might* work on a BSD or on Windows with cygwin installed, but it hasn't been tried. If you try it and find it doesn't work, please do submit patches to fix that. Some notable commands: -'make format' will reformat your code according to the Hypothesis coding style. You should use this before each +``./build.sh check-coverage`` will verify 100% code coverage by running a +curated subset of the test suite. + +``./build.sh check-py36`` (etc.) will run most of the test suite against a +particular python version. + +``./build.sh format`` will reformat your code according to the Hypothesis coding style. You should use this before each commit ideally, but you only really have to use it when you want your code to be ready to merge. -You can also use 'make check-format', which will run format and some linting and will then error if you have a +You can also use ``./build.sh check-format``, which will run format and some linting and will then error if you have a git diff. Note: This will error even if you started with a git diff, so if you've got any uncommitted changes this will necessarily report an error. -'make check' will run check-format and all of the tests. Warning: This will take a *very* long time. On Travis the -build currently takes more than an hour of total time (it runs in parallel on Travis so you don't have to wait -quite that long). If you've got a multi-core machine you can run 'make -j 2' (or any higher number if you want -more) to run 2 jobs in parallel, but to be honest you're probably better off letting Travis run this step. - -You can also run a number of finer grained make tasks - check ``.travis.yml`` for a short list and -the Makefile for details. +Look in ``.travis.yml`` for a short list of other supported build tasks. Note: The build requires a lot of different versions of python, so rather than have you install them yourself, -the makefile will install them itself in a local directory. This means that the first time you run a task you +the build system will install them itself in a local directory. This means that the first time you run a task you may have to wait a while as the build downloads and installs the right version of python for you. -------------------- @@ -162,24 +187,43 @@ * `Adam Sven Johnson `_ * `Alex Stapleton `_ * `Alex Willmer `_ (alex@moreati.org.uk) -* `Ben Peterson `_ (killthrush@hotmail.com_) +* `Ben Peterson `_ (killthrush@hotmail.com) +* `Bill Tucker `_ (imbilltucker@gmail.com) +* `Buck Evan, copyright Google LLC `_ +* `Cameron McGill `_ * `Charles O'Farrell `_ * `Charlie Tanksley `_ +* `Chase Garner `_ (chase@garner.red) * `Chris Down `_ * `Christopher Martin `_ (ch.martin@gmail.com) +* `Conrad Ho `_ (conrad.alwin.ho@gmail.com) * `Cory Benfield `_ * `Cristi Cobzarenco `_ (cristi@reinfer.io) * `David Bonner `_ (dbonner@gmail.com) +* `David Chudzicki `_ (dchudz@gmail.com) * `Derek Gustafson `_ * `Dion Misic `_ (dion.misic@gmail.com) +* `Emmanuel Leblond `_ * `Florian Bruhin `_ * `follower `_ +* `Gary Donovan `_ +* `Graham Williamson `_ +* `Grant David Bachman `_ (grantbachman@gmail.com) +* `Gregory Petrosyan `_ +* `Jack Massey `_ +* `Jakub Nabaglo `_ (j@nab.gl) * `Jeremy Thurgood `_ +* `J.J. Green `_ * `JP Viljoen `_ (froztbyte@froztbyte.net) +* `Joey Tuong `_ * `Jonty Wareing `_ (jonty@jonty.co.uk) * `jwg4 `_ +* `Karthikeyan Singaravelan `_ (tir.karthi@gmail.com) * `kbara `_ +* `Kyle Reeve `_ (krzw92@gmail.com) * `Lee Begg `_ +* `Louis Taylor `_ +* `Luke Barone-Adesi `_ * `marekventur `_ * `Marius Gedminas `_ (marius@gedmin.as) * `Markus Unterwaditzer `_ (markus@unterwaditzer.net) @@ -188,11 +232,19 @@ * `Maxim Kulkin `_ (maxim.kulkin@gmail.com) * `mulkieran `_ * `Nicholas Chammas `_ +* `Paul Lorett Amazona `_ * `Peadar Coyle `_ (peadarcoyle@gmail.com) * `Richard Boulton `_ (richard@tartarus.org) * `Sam Hames `_ +* `Sanyam Khurana `_ * `Saul Shanabrook `_ (s.shanabrook@gmail.com) +* `Stuart Cook `_ +* `Sushobhit `_ (sushobhitsolanki@gmail.com) * `Tariq Khokhar `_ (tariq@khokhar.net) +* `Tessa Bradbury `_ +* `Tim Martin `_ (tim@asymptotic.co.uk) +* `Tom McDermott `_ (sponster@gmail.com) +* `Vidya Rani `_ (vidyarani.d.g@gmail.com) * `Will Hall `_ (wrsh07@gmail.com) * `Will Thompson `_ (will@willthompson.co.uk) * `Zac Hatfield-Dodds `_ (zac.hatfield.dodds@gmail.com) diff -Nru python-hypothesis-3.44.1/.coveragerc python-hypothesis-3.71.11/.coveragerc --- python-hypothesis-3.44.1/.coveragerc 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/.coveragerc 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ -[run] -branch = True -include = - **/.tox/*/lib/*/site-packages/hypothesis/*.py - **/.tox/*/lib/*/site-packages/hypothesis/**/*.py -omit = - **/pytestplugin.py - **/strategytests.py - **/compat*.py - **/extra/__init__.py - **/.tox/*/lib/*/site-packages/hypothesis/internal/coverage.py - -[report] -exclude_lines = - @abc.abstractmethod - @abc.abstractproperty - NotImplementedError - pragma: no cover - __repr__ - __ne__ - __copy__ - __deepcopy__ diff -Nru python-hypothesis-3.44.1/debian/changelog python-hypothesis-3.71.11/debian/changelog --- python-hypothesis-3.44.1/debian/changelog 2018-07-30 08:43:38.000000000 +0000 +++ python-hypothesis-3.71.11/debian/changelog 2018-09-24 11:47:07.000000000 +0000 @@ -1,15 +1,22 @@ -python-hypothesis (3.44.1-2ubuntu2) cosmic; urgency=medium +python-hypothesis (3.71.11-1) unstable; urgency=medium - * Run the autopkg tests for the default Python3 version only, package - is not yet ready for Python 3.7. + * Team upload. - -- Matthias Klose Mon, 30 Jul 2018 10:43:38 +0200 + [ Ondřej Nový ] + * Convert git repository from git-dpm to gbp layout + * Use 'python3 -m sphinx' instead of sphinx-build for building docs + + [ Mattia Rizzolo ] + * New upstream version 3.71.11. + + Compatibility with Python 3.7. Closes: #904646 + * Update watch file to the new tarball names. Closes: #904647 + * Fix paths after upstream shuffled files around. + * d/rules: Drop unneeded override_dh_python3. + * d/rules: Add a comment on why the tests are skipped. + * Add new dependency on python(3)-dateutil. + * Fix autopkgtest to fit the new version. -python-hypothesis (3.44.1-2ubuntu1) bionic; urgency=medium - - * Fix Numpy dtype test on big-endian platforms - - -- Graham Inggs Wed, 14 Mar 2018 06:21:22 +0000 + -- Mattia Rizzolo Mon, 24 Sep 2018 13:47:07 +0200 python-hypothesis (3.44.1-2) unstable; urgency=medium diff -Nru python-hypothesis-3.44.1/debian/control python-hypothesis-3.71.11/debian/control --- python-hypothesis-3.44.1/debian/control 2018-03-14 06:21:22.000000000 +0000 +++ python-hypothesis-3.71.11/debian/control 2018-09-24 11:47:07.000000000 +0000 @@ -1,8 +1,7 @@ Source: python-hypothesis Section: python Priority: optional -Maintainer: Ubuntu Developers -XSBC-Original-Maintainer: Debian Python Modules Team +Maintainer: Debian Python Modules Team Uploaders: Tristan Seligmann , Vincent Bernat , @@ -25,13 +24,13 @@ python3-sphinx, python3-sphinx-rtd-theme, Standards-Version: 4.1.3 -Homepage: https://github.com/DRMacIver/hypothesis +Homepage: https://github.com/HypothesisWorks/hypothesis Vcs-Git: https://salsa.debian.org/python-team/modules/python-hypothesis.git Vcs-Browser: https://salsa.debian.org/python-team/modules/python-hypothesis Package: python-hypothesis Architecture: all -Depends: python-enum34, ${misc:Depends}, ${python:Depends} +Depends: python-dateutil, python-enum34, ${misc:Depends}, ${python:Depends} Suggests: python-hypothesis-doc Description: advanced Quickcheck style testing library for Python 2 Hypothesis is a library for testing your Python code against a much @@ -49,7 +48,7 @@ Package: python3-hypothesis Architecture: all -Depends: ${misc:Depends}, ${python3:Depends} +Depends: python3-dateutil, ${misc:Depends}, ${python3:Depends} Suggests: python-hypothesis-doc Description: advanced Quickcheck style testing library for Python 3 Hypothesis is a library for testing your Python code against a much diff -Nru python-hypothesis-3.44.1/debian/.git-dpm python-hypothesis-3.71.11/debian/.git-dpm --- python-hypothesis-3.44.1/debian/.git-dpm 2018-02-16 09:05:45.000000000 +0000 +++ python-hypothesis-3.71.11/debian/.git-dpm 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ -# see git-dpm(1) from git-dpm package -ac77b37f828c9c25f214db67a45bda7fdc9f865f -ac77b37f828c9c25f214db67a45bda7fdc9f865f -ac77b37f828c9c25f214db67a45bda7fdc9f865f -ac77b37f828c9c25f214db67a45bda7fdc9f865f -python-hypothesis_3.44.1.orig.tar.gz -83fec72102163608d41e6bbe2d155f2ac564b018 -488917 -debianTag="debian/%e%v" -patchedTag="patched/%e%v" -upstreamTag="upstream/%e%u" diff -Nru python-hypothesis-3.44.1/debian/patches/endian.patch python-hypothesis-3.71.11/debian/patches/endian.patch --- python-hypothesis-3.44.1/debian/patches/endian.patch 2018-03-13 05:58:31.000000000 +0000 +++ python-hypothesis-3.71.11/debian/patches/endian.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,37 +0,0 @@ -Description: Fix Numpy dtype test on big-endian platforms -Bug: https://github.com/HypothesisWorks/hypothesis-python/issues/1164 -Forwarded: https://github.com/HypothesisWorks/hypothesis-python/pull/1165 -Author: Zac Hatfield-Dodds -Last-Update: 2018-03-13 - ---- a/tests/numpy/test_gen_data.py -+++ b/tests/numpy/test_gen_data.py -@@ -17,6 +17,8 @@ - - from __future__ import division, print_function, absolute_import - -+import sys -+ - import numpy as np - import pytest - from flaky import flaky -@@ -185,12 +187,14 @@ - assert field.shape == () - - --@given(nps.integer_dtypes(endianness='>')) --def test_can_restrict_endianness(dt): -- if dt.itemsize == 1: -- assert dt.byteorder == '|' -+@pytest.mark.parametrize('byteorder', ['<', '>']) -+@given(data=st.data()) -+def test_can_restrict_endianness(data, byteorder): -+ dtype = data.draw(nps.integer_dtypes(byteorder, sizes=(16, 32, 64))) -+ if byteorder == ('<' if sys.byteorder == 'little' else '>'): -+ assert dtype.byteorder == '=' - else: -- assert dt.byteorder == '>' -+ assert dtype.byteorder == byteorder - - - @given(nps.integer_dtypes(sizes=8)) diff -Nru python-hypothesis-3.44.1/debian/patches/series python-hypothesis-3.71.11/debian/patches/series --- python-hypothesis-3.44.1/debian/patches/series 2018-03-12 11:43:26.000000000 +0000 +++ python-hypothesis-3.71.11/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -endian.patch diff -Nru python-hypothesis-3.44.1/debian/python-hypothesis-doc.examples python-hypothesis-3.71.11/debian/python-hypothesis-doc.examples --- python-hypothesis-3.44.1/debian/python-hypothesis-doc.examples 2018-02-16 09:37:50.000000000 +0000 +++ python-hypothesis-3.71.11/debian/python-hypothesis-doc.examples 2018-09-24 11:47:07.000000000 +0000 @@ -1 +1 @@ -examples/* +hypothesis-python/examples/* diff -Nru python-hypothesis-3.44.1/debian/rules python-hypothesis-3.71.11/debian/rules --- python-hypothesis-3.44.1/debian/rules 2018-02-16 09:05:45.000000000 +0000 +++ python-hypothesis-3.71.11/debian/rules 2018-09-24 11:47:07.000000000 +0000 @@ -5,18 +5,14 @@ export PYBUILD_NAME=hypothesis %: - dh $@ --with python2,python3,pypy,sphinxdoc --buildsystem=pybuild - - -override_dh_python3: - dh_python3 - rm -rf debian/python3-hypothesis/usr/lib/python3.? + dh $@ --with python2,python3,pypy,sphinxdoc --sourcedirectory=hypothesis-python --buildsystem=pybuild override_dh_auto_build: dh_auto_build PYTHONPATH=. \ http_proxy='127.0.0.1:9' \ https_proxy='127.0.0.1:9' \ - sphinx-build -N -b html docs/ $(CURDIR)/.pybuild/docs/html/ + python3 -m sphinx -N -b html hypothesis-python/docs/ $(CURDIR)/.pybuild/docs/html/ +# The tests take a long time to run and are somwhat flaky override_dh_auto_test: diff -Nru python-hypothesis-3.44.1/debian/tests/control python-hypothesis-3.71.11/debian/tests/control --- python-hypothesis-3.44.1/debian/tests/control 2018-07-30 08:43:36.000000000 +0000 +++ python-hypothesis-3.71.11/debian/tests/control 2018-09-24 11:47:07.000000000 +0000 @@ -1,4 +1,4 @@ -Test-Command: for p in $(pyversions -s); do $p -m pytest -c /dev/null --assert=plain tests/cover tests/nocover tests/datetime tests/numpy tests/py2; done +Test-Command: cd hypothesis-python ; for p in $(pyversions -s); do $p -m pytest -c /dev/null --assert=plain -k 'not dateutil' tests/cover tests/nocover tests/datetime tests/numpy tests/py2; done Depends: python-all, python-flaky, @@ -8,7 +8,7 @@ python-pytest, python-tz, -Test-Command: for p in $(py3versions -d); do $p -m pytest -c /dev/null --assert=plain tests/cover tests/nocover tests/datetime tests/numpy tests/py3; done +Test-Command: cd hypothesis-python ; for p in $(py3versions -s); do $p -m pytest -c /dev/null --assert=plain -k 'not dateutil' tests/cover tests/nocover tests/datetime tests/numpy tests/py3; done Depends: python3-all, python3-flaky, diff -Nru python-hypothesis-3.44.1/debian/watch python-hypothesis-3.71.11/debian/watch --- python-hypothesis-3.44.1/debian/watch 2018-02-16 09:05:45.000000000 +0000 +++ python-hypothesis-3.71.11/debian/watch 2018-09-24 11:44:50.000000000 +0000 @@ -1,3 +1,2 @@ -version=3 -opts=uversionmangle=s/-?(rc|a|b|c|alpha)/~$1/,filenamemangle=s/.+\/v?(\d\S*)\.tar\.gz/hypothesis-$1\.tar\.gz/ \ -https://github.com/DRMacIver/hypothesis/releases .*/archive/v?(.+)\.tar\.gz +version=4 +https://github.com/HypothesisWorks/hypothesis/releases .*/archive/hypothesis-python-@ANY_VERSION@@ARCHIVE_EXT@ diff -Nru python-hypothesis-3.44.1/docs/changes.rst python-hypothesis-3.71.11/docs/changes.rst --- python-hypothesis-3.44.1/docs/changes.rst 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/docs/changes.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,3091 +0,0 @@ -========= -Changelog -========= - -This is a record of all past Hypothesis releases and what went into them, -in reverse chronological order. All previous releases should still be available -on pip. - -Hypothesis APIs come in three flavours: - -* Public: Hypothesis releases since 1.0 are `semantically versioned `_ - with respect to these parts of the API. These will not break except between - major version bumps. All APIs mentioned in this documentation are public unless - explicitly noted otherwise. -* Semi-public: These are APIs that are considered ready to use but are not wholly - nailed down yet. They will not break in patch releases and will *usually* not break - in minor releases, but when necessary minor releases may break semi-public APIs. -* Internal: These may break at any time and you really should not use them at - all. - -You should generally assume that an API is internal unless you have specific -information to the contrary. - -------------------- -3.44.1 - 2017-12-18 -------------------- - -This release fixes :issue:`997`, in which under some circumstances the body of -tests run under Hypothesis would not show up when run under coverage even -though the tests were run and the code they called outside of the test file -would show up normally. - -------------------- -3.44.0 - 2017-12-17 -------------------- - -This release adds a new feature: The :ref:`@reproduce_failure `, -designed to make it easy to use Hypothesis's binary format for examples to -reproduce a problem locally without having to share your example database -between machines. - -This also changes when seeds are printed: - -* They will no longer be printed for - normal falsifying examples, as there are now adequate ways of reproducing those - for all cases, so it just contributes noise. -* They will once again be printed when reusing examples from the database, as - health check failures should now be more reliable in this scenario so it will - almost always work in this case. - -This work was funded by `Smarkets `_. - -------------------- -3.43.1 - 2017-12-17 -------------------- - -This release fixes a bug with Hypothesis's database management - examples that -were found in the course of shrinking were saved in a way that indicated that -they had distinct causes, and so they would all be retried on the start of the -next test. The intended behaviour, which is now what is implemented, is that -only a bounded subset of these examples would be retried. - -------------------- -3.43.0 - 2017-12-17 -------------------- - -:exc:`~hypothesis.errors.HypothesisDeprecationWarning` now inherits from -:exc:`python:FutureWarning` instead of :exc:`python:DeprecationWarning`, -as recommended by :pep:`565` for user-facing warnings (:issue:`618`). -If you have not changed the default warnings settings, you will now see -each distinct :exc:`~hypothesis.errors.HypothesisDeprecationWarning` -instead of only the first. - -------------------- -3.42.2 - 2017-12-12 -------------------- - -This patch fixes :issue:`1017`, where instances of a list or tuple subtype -used as an argument to a strategy would be coerced to tuple. - -------------------- -3.42.1 - 2017-12-10 -------------------- - -This release has some internal cleanup, which makes reading the code -more pleasant and may shrink large examples slightly faster. - -------------------- -3.42.0 - 2017-12-09 -------------------- - -This release deprecates :ref:`faker-extra`, which was designed as a transition -strategy but does not support example shrinking or coverage-guided discovery. - -------------------- -3.41.0 - 2017-12-06 -------------------- - -:func:`~hypothesis.strategies.sampled_from` can now sample from -one-dimensional numpy ndarrays. Sampling from multi-dimensional -ndarrays still results in a deprecation warning. Thanks to Charlie -Tanksley for this patch. - -------------------- -3.40.1 - 2017-12-04 -------------------- - -This release makes two changes: - -* It makes the calculation of some of the metadata that Hypothesis uses for - shrinking occur lazily. This should speed up performance of test case - generation a bit because it no longer calculates information it doesn't need. -* It improves the shrinker for certain classes of nested examples. e.g. when - shrinking lists of lists, the shrinker is now able to concatenate two - adjacent lists together into a single list. As a result of this change, - shrinking may get somewhat slower when the minimal example found is large. - -------------------- -3.40.0 - 2017-12-02 -------------------- - -This release improves how various ways of seeding Hypothesis interact with the -example database: - -* Using the example database with :func:`~hypothesis.seed` is now deprecated. - You should set ``database=None`` if you are doing that. This will only warn - if you actually load examples from the database while using ``@seed``. -* The :attr:`~hypothesis.settings.derandomize` will behave the same way as - ``@seed``. -* Using ``--hypothesis-seed`` will disable use of the database. -* If a test used examples from the database, it will not suggest using a seed - to reproduce it, because that won't work. - -This work was funded by `Smarkets `_. - -------------------- -3.39.0 - 2017-12-01 -------------------- - -This release adds a new health check that checks if the smallest "natural" -possible example of your test case is very large - this will tend to cause -Hypothesis to generate bad examples and be quite slow. - -This work was funded by `Smarkets `_. - -------------------- -3.38.9 - 2017-11-29 -------------------- - -This is a documentation release to improve the documentation of shrinking -behaviour for Hypothesis's strategies. - -------------------- -3.38.8 - 2017-11-29 -------------------- - -This release improves the performance of -:func:`~hypothesis.strategies.characters` when using ``blacklist_characters`` -and :func:`~hypothesis.strategies.from_regex` when using negative character -classes. - -The problems this fixes were found in the course of work funded by -`Smarkets `_. - -------------------- -3.38.7 - 2017-11-29 -------------------- - -This is a patch release for :func:`~hypothesis.strategies.from_regex`, which -had a bug in handling of the :obj:`python:re.VERBOSE` flag (:issue:`992`). -Flags are now handled correctly when parsing regex. - -------------------- -3.38.6 - 2017-11-28 -------------------- - -This patch changes a few byte-string literals from double to single quotes, -thanks to an update in :pypi:`unify`. There are no user-visible changes. - -------------------- -3.38.5 - 2017-11-23 -------------------- - -This fixes the repr of strategies using lambda that are defined inside -decorators to include the lambda source. - -This would mostly have been visible when using the -:ref:`statistics ` functionality - lambdas used for e.g. filtering -would have shown up with a ```` as their body. This can still happen, -but it should happen less often now. - -------------------- -3.38.4 - 2017-11-22 -------------------- - -This release updates the reported :ref:`statistics ` so that they -show approximately what fraction of your test run time is spent in data -generation (as opposed to test execution). - -This work was funded by `Smarkets `_. - -------------------- -3.38.3 - 2017-11-21 -------------------- - -This is a documentation release, which ensures code examples are up to date -by running them as doctests in CI (:issue:`711`). - -------------------- -3.38.2 - 2017-11-21 -------------------- - -This release changes the behaviour of the :attr:`~hypothesis.settings.deadline` -setting when used with :func:`~hypothesis.strategies.data`: Time spent inside -calls to ``data.draw`` will no longer be counted towards the deadline time. - -As a side effect of some refactoring required for this work, the way flaky -tests are handled has changed slightly. You are unlikely to see much difference -from this, but some error messages will have changed. - -This work was funded by `Smarkets `_. - -------------------- -3.38.1 - 2017-11-21 -------------------- - -This patch has a variety of non-user-visible refactorings, removing various -minor warts ranging from indirect imports to typos in comments. - -------------------- -3.38.0 - 2017-11-18 -------------------- - -This release overhauls :doc:`the health check system ` -in a variety of small ways. -It adds no new features, but is nevertheless a minor release because it changes -which tests are likely to fail health checks. - -The most noticeable effect is that some tests that used to fail health checks -will now pass, and some that used to pass will fail. These should all be -improvements in accuracy. In particular: - -* New failures will usually be because they are now taking into account things - like use of :func:`~hypothesis.strategies.data` and - :func:`~hypothesis.assume` inside the test body. -* New failures *may* also be because for some classes of example the way data - generation performance was measured was artificially faster than real data - generation (for most examples that are hitting performance health checks the - opposite should be the case). -* Tests that used to fail health checks and now pass do so because the health - check system used to run in a way that was subtly different than the main - Hypothesis data generation and lacked some of its support for e.g. large - examples. - -If your data generation is especially slow, you may also see your tests get -somewhat faster, as there is no longer a separate health check phase. This will -be particularly noticeable when rerunning test failures. - -This work was funded by `Smarkets `_. - -------------------- -3.37.0 - 2017-11-12 -------------------- - -This is a deprecation release for some health check related features. - -The following are now deprecated: - -* Passing :attr:`~hypothesis.HealthCheck.exception_in_generation` to - :attr:`~hypothesis.settings.suppress_health_check`. This no longer does - anything even when passed - All errors that occur during data generation - will now be immediately reraised rather than going through the health check - mechanism. -* Passing :attr:`~hypothesis.HealthCheck.random_module` to - :attr:`~hypothesis.settings.suppress_health_check`. This hasn't done anything - for a long time, but was never explicitly deprecated. Hypothesis always seeds - the random module when running @given tests, so this is no longer an error - and suppressing it doesn't do anything. -* Passing non-:class:`~hypothesis.HealthCheck` values in - :attr:`~hypothesis.settings.suppress_health_check`. This was previously - allowed but never did anything useful. - -In addition, passing a non-iterable value as :attr:`~hypothesis.settings.suppress_health_check` -will now raise an error immediately (it would never have worked correctly, but -it would previously have failed later). Some validation error messages have -also been updated. - -This work was funded by `Smarkets `_. - -------------------- -3.36.1 - 2017-11-10 -------------------- - -This is a yak shaving release, mostly concerned with our own tests. - -While :func:`~python:inspect.getfullargspec` was documented as deprecated -in Python 3.5, it never actually emitted a warning. Our code to silence -this (nonexistent) warning has therefore been removed. - -We now run our tests with ``DeprecationWarning`` as an error, and made some -minor changes to our own tests as a result. This required similar upstream -updates to :pypi:`coverage` and :pypi:`execnet` (a test-time dependency via -:pypi:`pytest-xdist`). - -There is no user-visible change in Hypothesis itself, but we encourage you -to consider enabling deprecations as errors in your own tests. - -------------------- -3.36.0 - 2017-11-06 -------------------- - -This release adds a setting to the public API, and does some internal cleanup: - -- The :attr:`~hypothesis.settings.derandomize` setting is now documented (:issue:`890`) -- Removed - and disallowed - all 'bare excepts' in Hypothesis (:issue:`953`) -- Documented the :attr:`~hypothesis.settings.strict` setting as deprecated, and - updated the build so our docs always match deprecations in the code. - -------------------- -3.35.0 - 2017-11-06 -------------------- - -This minor release supports constraining :func:`~hypothesis.strategies.uuids` -to generate a particular version of :class:`~python:uuid.UUID` (:issue:`721`). - -Thanks to Dion Misic for this feature. - -------------------- -3.34.1 - 2017-11-02 -------------------- - -This patch updates the documentation to suggest -:func:`builds(callable) ` instead of -:func:`just(callable()) `. - -------------------- -3.34.0 - 2017-11-02 -------------------- - -Hypothesis now emits deprecation warnings if you apply -:func:`@given ` more than once to a target. - -Applying :func:`@given ` repeatedly wraps the target multiple -times. Each wrapper will search the space of of possible parameters separately. -This is equivalent but will be much more inefficient than doing it with a -single call to :func:`@given `. - -For example, instead of -``@given(booleans()) @given(integers())``, you could write -``@given(booleans(), integers())`` - -------------------- -3.33.1 - 2017-11-02 -------------------- - -This is a bugfix release: - -- :func:`~hypothesis.strategies.builds` would try to infer a strategy for - required positional arguments of the target from type hints, even if they - had been given to :func:`~hypothesis.strategies.builds` as positional - arguments (:issue:`946`). Now it only infers missing required arguments. -- An internal introspection function wrongly reported ``self`` as a required - argument for bound methods, which might also have affected - :func:`~hypothesis.strategies.builds`. Now it knows better. - -------------------- -3.33.0 - 2017-10-16 -------------------- - -This release supports strategy inference for more field types in Django -:func:`~hypothesis.extra.django.models` - you can now omit an argument for -Date, Time, Duration, Slug, IP Address, and UUID fields. (:issue:`642`) - -Strategy generation for fields with grouped choices now selects choices from -each group, instead of selecting from the group names. - -------------------- -3.32.2 - 2017-10-15 -------------------- - -This patch removes the ``mergedb`` tool, introduced in Hypothesis 1.7.1 -on an experimental basis. It has never actually worked, and the new -:doc:`Hypothesis example database ` is designed to make such a -tool unnecessary. - -------------------- -3.32.1 - 2017-10-13 -------------------- - -This patch has two improvements for strategies based on enumerations. - -- :func:`~hypothesis.strategies.from_type` now handles enumerations correctly, - delegating to :func:`~hypothesis.strategies.sampled_from`. Previously it - noted that ``Enum.__init__`` has no required arguments and therefore delegated - to :func:`~hypothesis.strategies.builds`, which would subsequently fail. -- When sampling from an :class:`python:enum.Flag`, we also generate combinations - of members. Eg for ``Flag('Permissions', 'READ, WRITE, EXECUTE')`` we can now - generate, ``Permissions.READ``, ``Permissions.READ|WRITE``, and so on. - -------------------- -3.32.0 - 2017-10-09 -------------------- - -This changes the default value of -:attr:`use_coverage=True ` to True when -running on pypy (it was already True on CPython). - -It was previously set to False because we expected it to be too slow, but -recent benchmarking shows that actually performance of the feature on pypy is -fairly acceptable - sometimes it's slower than on CPython, sometimes it's -faster, but it's generally within a factor of two either way. - -------------------- -3.31.6 - 2017-10-08 -------------------- - -This patch improves the quality of strategies inferred from Numpy dtypes: - -* Integer dtypes generated examples with the upper half of their (non-sign) bits - set to zero. The inferred strategies can now produce any representable integer. -* Fixed-width unicode- and byte-string dtypes now cap the internal example - length, which should improve example and shrink quality. -* Numpy arrays can only store fixed-size strings internally, and allow shorter - strings by right-padding them with null bytes. Inferred string strategies - no longer generate such values, as they can never be retrieved from an array. - This improves shrinking performance by skipping useless values. - -This has already been useful in Hypothesis - we found an overflow bug in our -Pandas support, and as a result :func:`~hypothesis.extra.pandas.indexes` and -:func:`~hypothesis.extra.pandas.range_indexes` now check that ``min_size`` -and ``max_size`` are at least zero. - -------------------- -3.31.5 - 2017-10-08 -------------------- - -This release fixes a performance problem in tests where -:attr:`~hypothesis.settings.use_coverage` is set to True. - -Tests experience a slow-down proportionate to the amount of code they cover. -This is still the case, but the factor is now low enough that it should be -unnoticeable. Previously it was large and became much larger in 3.28.4. - -------------------- -3.31.4 - 2017-10-08 -------------------- - -:func:`~hypothesis.strategies.from_type` failed with a very confusing error -if passed a :func:`~python:typing.NewType` (:issue:`901`). These psudeo-types -are now unwrapped correctly, and strategy inference works as expected. - -------------------- -3.31.3 - 2017-10-06 -------------------- - -This release makes some small optimisations to our use of coverage that should -reduce constant per-example overhead. This is probably only noticeable on -examples where the test itself is quite fast. On no-op tests that don't test -anything you may see up to a fourfold speed increase (which is still -significantly slower than without coverage). On more realistic tests the speed -up is likely to be less than that. - -------------------- -3.31.2 - 2017-09-30 -------------------- - -This release fixes some formatting and small typos/grammar issues in the -documentation, specifically the page docs/settings.rst, and the inline docs -for the various settings. - -------------------- -3.31.1 - 2017-09-30 -------------------- - -This release improves the handling of deadlines so that they act better with -the shrinking process. This fixes :issue:`892`. - -This involves two changes: - -1. The deadline is raised during the initial generation and shrinking, and then - lowered to the set value for final replay. This restricts our attention to - examples which exceed the deadline by a more significant margin, which - increases their reliability. -2. When despite the above a test still becomes flaky because it is - significantly faster on rerun than it was on its first run, the error - message is now more explicit about the nature of this problem, and includes - both the initial test run time and the new test run time. - -In addition, this release also clarifies the documentation of the deadline -setting slightly to be more explicit about where it applies. - -This work was funded by `Smarkets `_. - -------------------- -3.31.0 - 2017-09-29 -------------------- - -This release blocks installation of Hypothesis on Python 3.3, which -:PEP:`reached its end of life date on 2017-09-29 <398>`. - -This should not be of interest to anyone but downstream maintainers - -if you are affected, migrate to a secure version of Python as soon as -possible or at least seek commercial support. - -------------------- -3.30.4 - 2017-09-27 -------------------- - -This release makes several changes: - -1. It significantly improves Hypothesis's ability to use coverage information - to find interesting examples. -2. It reduces the default :attr:`~hypothesis.settings.max_examples` setting from 200 to 100. This takes - advantage of the improved algorithm meaning fewer examples are typically - needed to get the same testing and is sufficiently better at covering - interesting behaviour, and offsets some of the performance problems of - running under coverage. -3. Hypothesis will always try to start its testing with an example that is near - minimized. - -The new algorithm for 1 also makes some changes to Hypothesis's low level data -generation which apply even with coverage turned off. They generally reduce the -total amount of data generated, which should improve test performance somewhat. -Between this and 3 you should see a noticeable reduction in test runtime (how -much so depends on your tests and how much example size affects their -performance. On our benchmarks, where data generation dominates, we saw up to -a factor of two performance improvement, but it's unlikely to be that large. - -------------------- -3.30.3 - 2017-09-25 -------------------- - -This release fixes some formatting and small typos/grammar issues in the -documentation, specifically the page docs/details.rst, and some inline -docs linked from there. - -------------------- -3.30.2 - 2017-09-24 -------------------- - -This release changes Hypothesis's caching approach for functions in -``hypothesis.strategies``. Previously it would have cached extremely -aggressively and cache entries would never be evicted. Now it adopts a -least-frequently used, least recently used key invalidation policy, and is -somewhat more conservative about which strategies it caches. - -Workloads which create strategies based on dynamic values, e.g. by using -:ref:`flatmap ` or :func:`~hypothesis.strategies.composite`, -will use significantly less memory. - -------------------- -3.30.1 - 2017-09-22 -------------------- - -This release fixes a bug where when running with -:attr:`use_coverage=True ` inside an -existing running instance of coverage, Hypothesis would frequently put files -that the coveragerc excluded in the report for the enclosing coverage. - -------------------- -3.30.0 - 2017-09-20 -------------------- - -This release introduces two new features: - -* When a test fails, either with a health check failure or a falsifying example, - Hypothesis will print out a seed that led to that failure, if the test is not - already running with a fixed seed. You can then recreate that failure using either - the :func:`@seed ` decorator or (if you are running pytest) with ``--hypothesis-seed``. -* :pypi:`pytest` users can specify a seed to use for :func:`@given ` based tests by passing - the ``--hypothesis-seed`` command line argument. - -This work was funded by `Smarkets `_. - -------------------- -3.29.0 - 2017-09-19 -------------------- - -This release makes Hypothesis coverage aware. Hypothesis now runs all test -bodies under coverage, and uses this information to guide its testing. - -The :attr:`~hypothesis.settings.use_coverage` setting can be used to disable -this behaviour if you want to test code that is sensitive to coverage being -enabled (either because of performance or interaction with the trace function). - -The main benefits of this feature are: - -* Hypothesis now observes when examples it discovers cover particular lines - or branches and stores them in the database for later. -* Hypothesis will make some use of this information to guide its exploration of - the search space and improve the examples it finds (this is currently used - only very lightly and will likely improve significantly in future releases). - -This also has the following side-effects: - -* Hypothesis now has an install time dependency on the :pypi:`coverage` package. -* Tests that are already running Hypothesis under coverage will likely get - faster. -* Tests that are not running under coverage now run their test bodies under - coverage by default. - - -This feature is only partially supported under pypy. It is significantly slower -than on CPython and is turned off by default as a result, but it should still -work correctly if you want to use it. - -------------------- -3.28.3 - 2017-09-18 -------------------- - -This release is an internal change that affects how Hypothesis handles -calculating certain properties of strategies. - -The primary effect of this is that it fixes a bug where use of -:func:`~hypothesis.deferred` could sometimes trigger an internal assertion -error. However the fix for this bug involved some moderately deep changes to -how Hypothesis handles certain constructs so you may notice some additional -knock-on effects. - -In particular the way Hypothesis handles drawing data from strategies that -cannot generate any values has changed to bail out sooner than it previously -did. This may speed up certain tests, but it is unlikely to make much of a -difference in practice for tests that were not already failing with -Unsatisfiable. - -------------------- -3.28.2 - 2017-09-18 -------------------- - -This is a patch release that fixes a bug in the :mod:`hypothesis.extra.pandas` -documentation where it incorrectly referred to :func:`~hypothesis.extra.pandas.column` -instead of :func:`~hypothesis.extra.pandas.columns`. - -------------------- -3.28.1 - 2017-09-16 -------------------- - -This is a refactoring release. It moves a number of internal uses -of :func:`~python:collections.namedtuple` over to using attrs based classes, and removes a couple -of internal namedtuple classes that were no longer in use. - -It should have no user visible impact. - -------------------- -3.28.0 - 2017-09-15 -------------------- - -This release adds support for testing :pypi:`pandas` via the :ref:`hypothesis.extra.pandas ` -module. - -It also adds a dependency on :pypi:`attrs`. - -This work was funded by `Stripe `_. - -------------------- -3.27.1 - 2017-09-14 -------------------- - -This release fixes some formatting and broken cross-references in the -documentation, which includes editing docstrings - and thus a patch release. - -------------------- -3.27.0 - 2017-09-13 -------------------- - -This release introduces a :attr:`~hypothesis.settings.deadline` -setting to Hypothesis. - -When set this turns slow tests into errors. By default it is unset but will -warn if you exceed 200ms, which will become the default value in a future -release. - -This work was funded by `Smarkets `_. - -------------------- -3.26.0 - 2017-09-12 -------------------- - -Hypothesis now emits deprecation warnings if you are using the legacy -SQLite example database format, or the tool for merging them. These were -already documented as deprecated, so this doesn't change their deprecation -status, only that we warn about it. - -------------------- -3.25.1 - 2017-09-12 -------------------- - -This release fixes a bug with generating :doc:`numpy datetime and timedelta types `: -When inferring the strategy from the dtype, datetime and timedelta dtypes with -sub-second precision would always produce examples with one second resolution. -Inferring a strategy from a time dtype will now always produce example with the -same precision. - -------------------- -3.25.0 - 2017-09-12 -------------------- - -This release changes how Hypothesis shrinks and replays examples to take into -account that it can encounter new bugs while shrinking the bug it originally -found. Previously it would end up replacing the originally found bug with the -new bug and show you only that one. Now it is (often) able to recognise when -two bugs are distinct and when it finds more than one will show both. - -------------------- -3.24.2 - 2017-09-11 -------------------- - -This release removes the (purely internal and no longer useful) -``strategy_test_suite`` function and the corresponding strategytests module. - -------------------- -3.24.1 - 2017-09-06 -------------------- - -This release improves the reduction of examples involving floating point -numbers to produce more human readable examples. - -It also has some general purpose changes to the way the minimizer works -internally, which may see some improvement in quality and slow down of test -case reduction in cases that have nothing to do with floating point numbers. - -------------------- -3.24.0 - 2017-09-05 -------------------- - -Hypothesis now emits deprecation warnings if you use ``some_strategy.example()`` inside a -test function or strategy definition (this was never intended to be supported, -but is sufficiently widespread that it warrants a deprecation path). - -------------------- -3.23.3 - 2017-09-05 -------------------- - -This is a bugfix release for :func:`~hypothesis.strategies.decimals` -with the ``places`` argument. - -- No longer fails health checks (:issue:`725`, due to internal filtering) -- Specifying a ``min_value`` and ``max_value`` without any decimals with - ``places`` places between them gives a more useful error message. -- Works for any valid arguments, regardless of the decimal precision context. - -------------------- -3.23.2 - 2017-09-01 -------------------- - -This is a small refactoring release that removes a now-unused parameter to an -internal API. It shouldn't have any user visible effect. - -------------------- -3.23.1 - 2017-09-01 -------------------- - -Hypothesis no longer propagates the dynamic scope of settings into strategy -definitions. - -This release is a small change to something that was never part of the public -API and you will almost certainly not notice any effect unless you're doing -something surprising, but for example the following code will now give a -different answer in some circumstances: - -.. code-block:: python - - import hypothesis.strategies as st - from hypothesis import settings - - CURRENT_SETTINGS = st.builds(lambda: settings.default) - -(We don't actually encourage you writing code like this) - -Previously this would have generated the settings that were in effect at the -point of definition of ``CURRENT_SETTINGS``. Now it will generate the settings -that are used for the current test. - -It is very unlikely to be significant enough to be visible, but you may also -notice a small performance improvement. - -------------------- -3.23.0 - 2017-08-31 -------------------- - -This release adds a ``unique`` argument to :func:`~hypothesis.extra.numpy.arrays` -which behaves the same ways as the corresponding one for -:func:`~hypothesis.strategies.lists`, requiring all of the elements in the -generated array to be distinct. - -------------------- -3.22.2 - 2017-08-29 -------------------- - -This release fixes an issue where Hypothesis would raise a ``TypeError`` when -using the datetime-related strategies if running with ``PYTHONOPTIMIZE=2``. -This bug was introduced in v3.20.0. (See :issue:`822`) - -------------------- -3.22.1 - 2017-08-28 -------------------- - -Hypothesis now transparently handles problems with an internal unicode cache, -including file truncation or read-only filesystems (:issue:`767`). -Thanks to Sam Hames for the patch. - -------------------- -3.22.0 - 2017-08-26 -------------------- - -This release provides what should be a substantial performance improvement to -numpy arrays generated using :ref:`provided numpy support `, -and adds a new ``fill_value`` argument to :func:`~hypothesis.extra.numpy.arrays` -to control this behaviour. - -This work was funded by `Stripe `_. - -------------------- -3.21.3 - 2017-08-26 -------------------- - -This release fixes some extremely specific circumstances that probably have -never occurred in the wild where users of -:func:`~hypothesis.searchstrategy.deferred` might have seen a RuntimeError from -too much recursion, usually in cases where no valid example could have been -generated anyway. - -------------------- -3.21.2 - 2017-08-25 -------------------- - -This release fixes some minor bugs in argument validation: - - * :ref:`hypothesis.extra.numpy ` dtype strategies would raise an internal error - instead of an InvalidArgument exception when passed an invalid - endianness specification. - * :func:`~hypothesis.strategies.fractions` would raise an internal error instead of an InvalidArgument - if passed ``float("nan")`` as one of its bounds. - * The error message for passing ``float("nan")`` as a bound to various - strategies has been improved. - * Various bound arguments will now raise InvalidArgument in cases where - they would previously have raised an internal TypeError or - ValueError from the relevant conversion function. - * :func:`~hypothesis.strategies.streaming` would not have emitted a - deprecation warning when called with an invalid argument. - -------------------- -3.21.1 - 2017-08-24 -------------------- - -This release fixes a bug where test failures that were the result of -an :func:`@example ` would print an extra stack trace before re-raising the -exception. - -------------------- -3.21.0 - 2017-08-23 -------------------- - -This release deprecates Hypothesis's strict mode, which turned Hypothesis's -deprecation warnings into errors. Similar functionality can be achieved -by using :func:`simplefilter('error', HypothesisDeprecationWarning) `. - -------------------- -3.20.0 - 2017-08-22 -------------------- - -This release renames the relevant arguments on the -:func:`~hypothesis.strategies.datetimes`, :func:`~hypothesis.strategies.dates`, -:func:`~hypothesis.strategies.times`, and :func:`~hypothesis.strategies.timedeltas` -strategies to ``min_value`` and ``max_value``, to make them consistent with the -other strategies in the module. - -The old argument names are still supported but will emit a deprecation warning -when used explicitly as keyword arguments. Arguments passed positionally will -go to the new argument names and are not deprecated. - -------------------- -3.19.3 - 2017-08-22 -------------------- - -This release provides a major overhaul to the internals of how Hypothesis -handles shrinking. - -This should mostly be visible in terms of getting better examples for tests -which make heavy use of :func:`~hypothesis.strategies.composite`, -:func:`~hypothesis.strategies.data` or :ref:`flatmap ` where the data -drawn depends a lot on previous choices, especially where size parameters are -affected. Previously Hypothesis would have struggled to reliably produce -good examples here. Now it should do much better. Performance should also be -better for examples with a non-zero ``min_size``. - -You may see slight changes to example generation (e.g. improved example -diversity) as a result of related changes to internals, but they are unlikely -to be significant enough to notice. - -------------------- -3.19.2 - 2017-08-21 -------------------- - -This release fixes two bugs in :mod:`hypothesis.extra.numpy`: - -* :func:`~hypothesis.extra.numpy.unicode_string_dtypes` didn't work at all due - to an incorrect dtype specifier. Now it does. -* Various impossible conditions would have been accepted but would error when - they fail to produced any example. Now they raise an explicit InvalidArgument - error. - -------------------- -3.19.1 - 2017-08-21 -------------------- - -This is a bugfix release for :issue:`739`, where bounds for -:func:`~hypothesis.strategies.fractions` or floating-point -:func:`~hypothesis.strategies.decimals` were not properly converted to -integers before passing them to the integers strategy. -This excluded some values that should have been possible, and could -trigger internal errors if the bounds lay between adjacent integers. - -You can now bound :func:`~hypothesis.strategies.fractions` with two -arbitrarily close fractions. - -It is now an explicit error to supply a min_value, max_value, and -max_denominator to :func:`~hypothesis.strategies.fractions` where the value -bounds do not include a fraction with denominator at most max_denominator. - -------------------- -3.19.0 - 2017-08-20 -------------------- - -This release adds the :func:`~hypothesis.strategies.from_regex` strategy, -which generates strings that contain a match of a regular expression. - -Thanks to Maxim Kulkin for creating the -`hypothesis-regex `_ -package and then helping to upstream it! (:issue:`662`) - -------------------- -3.18.5 - 2017-08-18 -------------------- - -This is a bugfix release for :func:`~hypothesis.strategies.integers`. -Previously the strategy would hit an internal assertion if passed non-integer -bounds for ``min_value`` and ``max_value`` that had no integers between them. -The strategy now raises InvalidArgument instead. - -------------------- -3.18.4 - 2017-08-18 -------------------- - -Release to fix a bug where mocks can be used as test runners under certain -conditions. Specifically, if a mock is injected into a test via pytest -fixtures or patch decorators, and that mock is the first argument in the -list, hypothesis will think it represents self and turns the mock -into a test runner. If this happens, the affected test always passes -because the mock is executed instead of the test body. Sometimes, it -will also fail health checks. - -Fixes :issue:`491` and a section of :issue:`198`. -Thanks to Ben Peterson for this bug fix. - -------------------- -3.18.3 - 2017-08-17 -------------------- - -This release should improve the performance of some tests which -experienced a slow down as a result of the 3.13.0 release. - -Tests most likely to benefit from this are ones that make extensive -use of ``min_size`` parameters, but others may see some improvement -as well. - -------------------- -3.18.2 - 2017-08-16 -------------------- - -This release fixes a bug introduced in 3.18.0. If the arguments -``whitelist_characters`` and ``blacklist_characters`` to -:func:`~hypothesis.strategies.characters` both contained elements, then an -``InvalidArgument`` exception would be raised. - -Thanks to Zac Hatfield-Dodds for reporting and fixing this. - -------------------- -3.18.1 - 2017-08-14 -------------------- - -This is a bug fix release to fix :issue:`780`, where -:func:`~hypothesis.strategies.sets` and similar would trigger health check -errors if their element strategy could only produce one element (e.g. -if it was :func:`~hypothesis.strategies.just`). - -------------------- -3.18.0 - 2017-08-13 -------------------- - -This is a feature release: - -* :func:`~hypothesis.strategies.characters` now accepts - ``whitelist_characters``, particular characters which will be added to those - it produces. (:issue:`668`) -* A bug fix for the internal function ``_union_interval_lists()``, and a rename - to ``_union_intervals()``. It now correctly handles all cases where intervals - overlap, and it always returns the result as a tuple for tuples. - -Thanks to Alex Willmer for these. - -------------------- -3.17.0 - 2017-08-07 -------------------- - -This release documents :ref:`the previously undocumented phases feature `, -making it part of the public API. It also updates how the example -database is used. Principally: - -* A ``Phases.reuse`` argument will now correctly control whether examples - from the database are run (it previously did exactly the wrong thing and - controlled whether examples would be *saved*). -* Hypothesis will no longer try to rerun *all* previously failing examples. - Instead it will replay the smallest previously failing example and a - selection of other examples that are likely to trigger any other bugs that - will found. This prevents a previous failure from dominating your tests - unnecessarily. -* As a result of the previous change, Hypothesis will be slower about clearing - out old examples from the database that are no longer failing (because it can - only clear out ones that it actually runs). - -------------------- -3.16.1 - 2017-08-07 -------------------- - -This release makes an implementation change to how Hypothesis handles certain -internal constructs. - -The main effect you should see is improvement to the behaviour and performance -of collection types, especially ones with a ``min_size`` parameter. Many cases -that would previously fail due to being unable to generate enough valid -examples will now succeed, and other cases should run slightly faster. - -------------------- -3.16.0 - 2017-08-04 -------------------- - -This release introduces a deprecation of the timeout feature. This results in -the following changes: - -* Creating a settings object with an explicit timeout will emit a deprecation - warning. -* If your test stops because it hits the timeout (and has not found a bug) then - it will emit a deprecation warning. -* There is a new value ``unlimited`` which you can import from hypothesis. - ``settings(timeout=unlimited)`` will *not* cause a deprecation warning. -* There is a new health check, ``hung_test``, which will trigger after a test - has been running for five minutes if it is not suppressed. - -------------------- -3.15.0 - 2017-08-04 -------------------- - -This release deprecates two strategies, :func:`~hypothesis.strategies.choices` and -:func:`~hypothesis.strategies.streaming`. - -Both of these are somewhat confusing to use and are entirely redundant since the -introduction of the :func:`~hypothesis.strategies.data` strategy for interactive -drawing in tests, and their use should be replaced with direct use of -:func:`~hypothesis.strategies.data` instead. - -------------------- -3.14.2 - 2017-08-03 -------------------- - -This fixes a bug where Hypothesis would not work correctly on Python 2.7 if you -had the :mod:`python:typing` module :pypi:`backport ` installed. - -------------------- -3.14.1 - 2017-08-02 -------------------- - -This raises the maximum depth at which Hypothesis starts cutting off data -generation to a more reasonable value which it is harder to hit by accident. - -This resolves (:issue:`751`), in which some examples which previously worked -would start timing out, but it will also likely improve the data generation -quality for complex data types. - -------------------- -3.14.0 - 2017-07-23 -------------------- - -Hypothesis now understands inline type annotations (:issue:`293`): - -- If the target of :func:`~hypothesis.strategies.builds` has type annotations, - a default strategy for missing required arguments is selected based on the - type. Type-based strategy selection will only override a default if you - pass :const:`hypothesis.infer` as a keyword argument. - -- If :func:`@given ` wraps a function with type annotations, - you can pass :const:`~hypothesis.infer` as a keyword argument and the - appropriate strategy will be substituted. - -- You can check what strategy will be inferred for a type with the new - :func:`~hypothesis.strategies.from_type` function. - -- :func:`~hypothesis.strategies.register_type_strategy` teaches Hypothesis - which strategy to infer for custom or unknown types. You can provide a - strategy, or for more complex cases a function which takes the type and - returns a strategy. - -------------------- -3.13.1 - 2017-07-20 -------------------- - -This is a bug fix release for :issue:`514` - Hypothesis would continue running -examples after a :class:`~python:unittest.SkipTest` exception was raised, -including printing a falsifying example. Skip exceptions from the standard -:mod:`python:unittest` module, and ``pytest``, ``nose``, or ``unittest2`` -modules now abort the test immediately without printing output. - -------------------- -3.13.0 - 2017-07-16 -------------------- - -This release has two major aspects to it: The first is the introduction of -:func:`~hypothesis.strategies.deferred`, which allows more natural definition -of recursive (including mutually recursive) strategies. - -The second is a number of engine changes designed to support this sort of -strategy better. These should have a knock-on effect of also improving the -performance of any existing strategies that currently generate a lot of data -or involve heavy nesting by reducing their typical example size. - -------------------- -3.12.0 - 2017-07-07 -------------------- - -This release makes some major internal changes to how Hypothesis represents -data internally, as a prelude to some major engine changes that should improve -data quality. There are no API changes, but it's a significant enough internal -change that a minor version bump seemed warranted. - -User facing impact should be fairly mild, but includes: - -* All existing examples in the database will probably be invalidated. Hypothesis - handles this automatically, so you don't need to do anything, but if you see - all your examples disappear that's why. -* Almost all data distributions have changed significantly. Possibly for the better, - possibly for the worse. This may result in new bugs being found, but it may - also result in Hypothesis being unable to find bugs it previously did. -* Data generation may be somewhat faster if your existing bottleneck was in - draw_bytes (which is often the case for large examples). -* Shrinking will probably be slower, possibly significantly. - -If you notice any effects you consider to be a significant regression, please -open an issue about them. - -------------------- -3.11.6 - 2017-06-19 -------------------- - -This release involves no functionality changes, but is the first to ship wheels -as well as an sdist. - -------------------- -3.11.5 - 2017-06-18 -------------------- - -This release provides a performance improvement to shrinking. For cases where -there is some non-trivial "boundary" value (e.g. the bug happens for all values -greater than some other value), shrinking should now be substantially faster. -Other types of bug will likely see improvements too. - -This may also result in some changes to the quality of the final examples - it -may sometimes be better, but is more likely to get slightly worse in some edge -cases. If you see any examples where this happens in practice, please report -them. - -------------------- -3.11.4 - 2017-06-17 -------------------- - -This is a bugfix release: Hypothesis now prints explicit examples when -running in verbose mode. (:issue:`313`) - -------------------- -3.11.3 - 2017-06-11 -------------------- - -This is a bugfix release: Hypothesis no longer emits a warning if you try to -use :func:`~hypothesis.strategies.sampled_from` with -:class:`python:collections.OrderedDict`. (:issue:`688`) - -------------------- -3.11.2 - 2017-06-10 -------------------- - -This is a documentation release. Several outdated snippets have been updated -or removed, and many cross-references are now hyperlinks. - -------------------- -3.11.1 - 2017-05-28 -------------------- - -This is a minor ergonomics release. Tracebacks shown by pytest no longer -include Hypothesis internals for test functions decorated with :func:`@given `. - -------------------- -3.11.0 - 2017-05-23 -------------------- - -This is a feature release, adding datetime-related strategies to the core strategies. - -:func:`~hypotheses.extra.pytz.timezones` allows you to sample pytz timezones from -the Olsen database. Use directly in a recipe for tz-aware datetimes, or -compose with :func:`~hypothesis.strategies.none` to allow a mix of aware and naive output. - -The new :func:`~hypothesis.strategies.dates`, :func:`~hypothesis.strategies.times`, -:func:`~hypothesis.strategies.datetimes`, and :func:`~hypothesis.strategies.timedeltas` -strategies are all constrained by objects of their type. -This means that you can generate dates bounded by a single day -(i.e. a single date), or datetimes constrained to the microsecond. - -:func:`~hypothesis.strategies.times` and :func:`~hypothesis.strategies.datetimes` -take an optional ``timezones=`` argument, which -defaults to :func:`~hypothesis.strategies.none` for naive times. You can use our extra strategy -based on pytz, or roll your own timezones strategy with dateutil or even -the standard library. - -The old ``dates``, ``times``, and ``datetimes`` strategies in -``hypothesis.extra.datetimes`` are deprecated in favor of the new -core strategies, which are more flexible and have no dependencies. - -------------------- -3.10.0 - 2017-05-22 -------------------- - -Hypothesis now uses :func:`python:inspect.getfullargspec` internally. -On Python 2, there are no visible changes. - -On Python 3 :func:`@given ` and :func:`@composite ` -now preserve :pep:`3107` annotations on the -decorated function. Keyword-only arguments are now either handled correctly -(e.g. :func:`@composite `), or caught in validation instead of silently discarded -or raising an unrelated error later (e.g. :func:`@given `). - ------------------- -3.9.1 - 2017-05-22 ------------------- - -This is a bugfix release: the default field mapping for a DateTimeField in the -Django extra now respects the ``USE_TZ`` setting when choosing a strategy. - ------------------- -3.9.0 - 2017-05-19 ------------------- - -This is feature release, expanding the capabilities of the -:func:`~hypothesis.strategies.decimals` strategy. - -* The new (optional) ``places`` argument allows you to generate decimals with - a certain number of places (e.g. cents, thousandths, satoshis). -* If allow_infinity is None, setting min_bound no longer excludes positive - infinity and setting max_value no longer excludes negative infinity. -* All of ``NaN``, ``-Nan``, ``sNaN``, and ``-sNaN`` may now be drawn if - allow_nan is True, or if allow_nan is None and min_value or max_value is None. -* min_value and max_value may be given as decimal strings, e.g. ``"1.234"``. - - ------------------- -3.8.5 - 2017-05-16 ------------------- - -Hypothesis now imports :mod:`python:sqlite3` when a SQLite database is used, rather -than at module load, improving compatibility with Python implementations -compiled without SQLite support (such as BSD or Jython). - ------------------- -3.8.4 - 2017-05-16 ------------------- - -This is a compatibility bugfix release. ``sampled_from`` no longer raises -a deprecation warning when sampling from an ``Enum``, as all enums have a -reliable iteration order. - ------------------- -3.8.3 - 2017-05-09 ------------------- - -This release removes a version check for older versions of pytest when using -the Hypothesis pytest plugin. The pytest plugin will now run unconditionally -on all versions of pytest. This breaks compatibility with any version of pytest -prior to 2.7.0 (which is more than two years old). - -The primary reason for this change is that the version check was a frequent -source of breakage when pytest change their versioning scheme. If you are not -working on pytest itself and are not running a very old version of it, this -release probably doesn't affect you. - ------------------- -3.8.2 - 2017-04-26 ------------------- - -This is a code reorganisation release that moves some internal test helpers -out of the main source tree so as to not have changes to them trigger releases -in future. - ------------------- -3.8.1 - 2017-04-26 ------------------- - -This is a documentation release. Almost all code examples are now doctests -checked in CI, eliminating stale examples. - ------------------- -3.8.0 - 2017-04-23 ------------------- - -This is a feature release, adding the :func:`~hypothesis.strategies.iterables` strategy, equivalent -to ``lists(...).map(iter)`` but with a much more useful repr. You can use -this strategy to check that code doesn't accidentally depend on sequence -properties such as indexing support or repeated iteration. - ------------------- -3.7.4 - 2017-04-22 ------------------- - -This is a bug fix release for a single bug: - -* In 3.7.3, using :func:`@example ` and a pytest fixture in the same test could - cause the test to fail to fill the arguments, and throw a TypeError. - ------------------- -3.7.3 - 2017-04-21 ------------------- - -This release should include no user visible changes and is purely a refactoring -release. This modularises the behaviour of the core :func:`~hypothesis.given` function, breaking -it up into smaller and more accessible parts, but its actual behaviour should -remain unchanged. - ------------------- -3.7.2 - 2017-04-21 ------------------- - -This reverts an undocumented change in 3.7.1 which broke installation on -debian stable: The specifier for the hypothesis[django] extra\_requires had -introduced a wild card, which was not supported on the default version of pip. - ------------------- -3.7.1 - 2017-04-21 ------------------- - -This is a bug fix and internal improvements release. - -* In particular Hypothesis now tracks a tree of where it has already explored. - This allows it to avoid some classes of duplicate examples, and significantly - improves the performance of shrinking failing examples by allowing it to - skip some shrinks that it can determine can't possibly work. -* Hypothesis will no longer seed the global random arbitrarily unless you have - asked it to using :py:meth:`~hypothesis.strategies.random_module` -* Shrinking would previously have not worked correctly in some special cases - on Python 2, and would have resulted in suboptimal examples. - ------------------- -3.7.0 - 2017-03-20 ------------------- - -This is a feature release. - -New features: - -* Rule based stateful testing now has an :func:`@invariant ` decorator that specifies - methods that are run after init and after every step, allowing you to - encode properties that should be true at all times. Thanks to Tom Prince for - this feature. -* The :func:`~hypothesis.strategies.decimals` strategy now supports ``allow_nan`` and ``allow_infinity`` flags. -* There are :ref:`significantly more strategies available for numpy `, including for - generating arbitrary data types. Thanks to Zac Hatfield Dodds for this - feature. -* When using the :func:`~hypothesis.strategies.data` strategy you can now add a label as an argument to - ``draw()``, which will be printed along with the value when an example fails. - Thanks to Peter Inglesby for this feature. - -Bug fixes: - -* Bug fix: :func:`~hypothesis.strategies.composite` now preserves functions' docstrings. -* The build is now reproducible and doesn't depend on the path you build it - from. Thanks to Chris Lamb for this feature. -* numpy strategies for the void data type did not work correctly. Thanks to - Zac Hatfield Dodds for this fix. - -There have also been a number of performance optimizations: - -* The :func:`~hypothesis.strategies.permutations` strategy is now significantly faster to use for large - lists (the underlying algorithm has gone from O(n^2) to O(n)). -* Shrinking of failing test cases should have got significantly faster in - some circumstances where it was previously struggling for a long time. -* Example generation now involves less indirection, which results in a small - speedup in some cases (small enough that you won't really notice it except in - pathological cases). - - ------------------- -3.6.1 - 2016-12-20 ------------------- - -This release fixes a dependency problem and makes some small behind the scenes -improvements. - -* The fake-factory dependency was renamed to faker. If you were depending on - it through hypothesis[django] or hypothesis[fake-factory] without pinning it - yourself then it would have failed to install properly. This release changes - it so that hypothesis[fakefactory] (which can now also be installed as - hypothesis[faker]) will install the renamed faker package instead. -* This release also removed the dependency of hypothesis[django] on - hypothesis[fakefactory] - it was only being used for emails. These now use - a custom strategy that isn't from fakefactory. As a result you should also - see performance improvements of tests which generated User objects or other - things with email fields, as well as better shrinking of email addresses. -* The distribution of code using nested calls to :func:`~hypothesis.strategies.one_of` or the ``|`` operator for - combining strategies has been improved, as branches are now flattened to give - a more uniform distribution. -* Examples using :func:`~hypothesis.strategies.composite` or ``.flatmap`` should now shrink better. In particular - this will affect things which work by first generating a length and then - generating that many items, which have historically not shrunk very well. - ------------------- -3.6.0 - 2016-10-31 ------------------- - -This release reverts Hypothesis to its old pretty printing of lambda functions -based on attempting to extract the source code rather than decompile the bytecode. -This is unfortunately slightly inferior in some cases and may result in you -occasionally seeing things like ``lambda x: `` in statistics reports and -strategy reprs. - -This removes the dependencies on uncompyle6, xdis and spark-parser. - -The reason for this is that the new functionality was based on uncompyle6, which -turns out to introduce a hidden GPLed dependency - it in turn depended on xdis, -and although the library was licensed under the MIT license, it contained some -GPL licensed source code and thus should have been released under the GPL. - -My interpretation is that Hypothesis itself was never in violation of the GPL -(because the license it is under, the Mozilla Public License v2, is fully -compatible with being included in a GPL licensed work), but I have not consulted -a lawyer on the subject. Regardless of the answer to this question, adding a -GPLed dependency will likely cause a lot of users of Hypothesis to inadvertently -be in violation of the GPL. - -As a result, if you are running Hypothesis 3.5.x you really should upgrade to -this release immediately. - ------------------- -3.5.3 - 2016-10-05 ------------------- - -This is a bug fix release. - -Bugs fixed: - -* If the same test was running concurrently in two processes and there were - examples already in the test database which no longer failed, Hypothesis - would sometimes fail with a FileNotFoundError (IOError on Python 2) because - an example it was trying to read was deleted before it was read. (:issue:`372`). -* Drawing from an :func:`~hypothesis.strategies.integers` strategy with both a min_value and a max_value - would reject too many examples needlessly. Now it repeatedly redraws until - satisfied. (:pull:`366`. Thanks to Calen Pennington for the contribution). - ------------------- -3.5.2 - 2016-09-24 ------------------- - -This is a bug fix release. - -* The Hypothesis pytest plugin broke pytest support for doctests. Now it doesn't. - ------------------- -3.5.1 - 2016-09-23 ------------------- - -This is a bug fix release. - -* Hypothesis now runs cleanly in -B and -BB modes, avoiding mixing bytes and unicode. -* :class:`python:unittest.TestCase` tests would not have shown up in the new statistics mode. Now they - do. -* Similarly, stateful tests would not have shown up in statistics and now they do. -* Statistics now print with pytest node IDs (the names you'd get in pytest verbose mode). - ------------------- -3.5.0 - 2016-09-22 ------------------- - -This is a feature release. - -* :func:`~hypothesis.strategies.fractions` and :func:`~hypothesis.strategies.decimals` strategies now support min_value and max_value - parameters. Thanks go to Anne Mulhern for the development of this feature. -* The Hypothesis pytest plugin now supports a --hypothesis-show-statistics parameter - that gives detailed statistics about the tests that were run. Huge thanks to - Jean-Louis Fuchs and Adfinis-SyGroup for funding the development of this feature. -* There is a new :func:`~hypothesis.event` function that can be used to add custom statistics. - -Additionally there have been some minor bug fixes: - -* In some cases Hypothesis should produce fewer duplicate examples (this will mostly - only affect cases with a single parameter). -* py.test command line parameters are now under an option group for Hypothesis (thanks - to David Keijser for fixing this) -* Hypothesis would previously error if you used :pep:`3107` function annotations on your tests under - Python 3.4. -* The repr of many strategies using lambdas has been improved to include the lambda body - (this was previously supported in many but not all cases). - ------------------- -3.4.2 - 2016-07-13 ------------------- - -This is a bug fix release, fixing a number of problems with the settings system: - -* Test functions defined using :func:`@given ` can now be called from other threads - (:issue:`337`) -* Attempting to delete a settings property would previously have silently done - the wrong thing. Now it raises an AttributeError. -* Creating a settings object with a custom database_file parameter was silently - getting ignored and the default was being used instead. Now it's not. - ------------------- -3.4.1 - 2016-07-07 ------------------- - -This is a bug fix release for a single bug: - -* On Windows when running two Hypothesis processes in parallel (e.g. using - pytest-xdist) they could race with each other and one would raise an exception - due to the non-atomic nature of file renaming on Windows and the fact that you - can't rename over an existing file. This is now fixed. - ------------------- -3.4.0 - 2016-05-27 ------------------- - -This release is entirely provided by `Lucas Wiman `_: - -Strategies constructed by :func:`~hypothesis.extra.django.models` will now respect much more of -Django's validations out of the box. Wherever possible full_clean() should -succeed. - -In particular: - -* The max_length, blank and choices kwargs are now respected. -* Add support for DecimalField. -* If a field includes validators, the list of validators are used to filter the field strategy. - ------------------- -3.3.0 - 2016-05-27 ------------------- - -This release went wrong and is functionally equivalent to 3.2.0. Ignore it. - ------------------- -3.2.0 - 2016-05-19 ------------------- - -This is a small single-feature release: - -* All tests using :func:`@given ` now fix the global random seed. This removes the health - check for that. If a non-zero seed is required for the final falsifying - example, it will be reported. Otherwise Hypothesis will assume randomization - was not a significant factor for the test and be silent on the subject. If you - use :func:`~hypothesis.strategies.random_module` this will continue to work and will always - display the seed. - ------------------- -3.1.3 - 2016-05-01 ------------------- - -Single bug fix release - -* Another charmap problem. In 3.1.2 :func:`~hypothesis.strategies.text` and - :func:`~hypothesis.strategies.characters` would break on systems - which had ``/tmp`` mounted on a different partition than the Hypothesis storage - directory (usually in home). This fixes that. - ------------------- -3.1.2 - 2016-04-30 ------------------- - -Single bug fix release: - -* Anything which used a :func:`~hypothesis.strategies.text` or - :func:`~hypothesis.strategies.characters` strategy was broken on Windows - and I hadn't updated appveyor to use the new repository location so I didn't - notice. This is now fixed and windows support should work correctly. - ------------------- -3.1.1 - 2016-04-29 ------------------- - -Minor bug fix release. - -* Fix concurrency issue when running tests that use :func:`~hypothesis.strategies.text` from multiple - processes at once (:issue:`302`, thanks to Alex Chan). -* Improve performance of code using :func:`~hypothesis.strategies.lists` with max_size (thanks to - Cristi Cobzarenco). -* Fix install on Python 2 with ancient versions of pip so that it installs the - enum34 backport (thanks to Donald Stufft for telling me how to do this). -* Remove duplicated __all__ exports from hypothesis.strategies (thanks to - Piët Delport). -* Update headers to point to new repository location. -* Allow use of strategies that can't be used in :func:`~hypothesis.find` - (e.g. :func:`~hypothesis.strategies.choices`) in stateful testing. - - ------------------- -3.1.0 - 2016-03-06 ------------------- - -* Add a :func:`~hypothesis.strategies.nothing` strategy that never successfully generates values. -* :func:`~hypothesis.strategies.sampled_from` and :func:`~hypothesis.strategies.one_of` - can both now be called with an empty argument - list, in which case they also never generate any values. -* :func:`~hypothesis.strategies.one_of` may now be called with a single argument that is a collection of strategies - as well as as varargs. -* Add a :func:`~hypothesis.strategies.runner` strategy which returns the instance of the current test object - if there is one. -* 'Bundle' for RuleBasedStateMachine is now a normal(ish) strategy and can be used - as such. -* Tests using RuleBasedStateMachine should now shrink significantly better. -* Hypothesis now uses a pretty-printing library internally, compatible with IPython's - pretty printing protocol (actually using the same code). This may improve the quality - of output in some cases. -* As a 'phases' setting that allows more fine grained control over which parts of the - process Hypothesis runs -* Add a suppress_health_check setting which allows you to turn off specific health checks - in a fine grained manner. -* Fix a bug where lists of non fixed size would always draw one more element than they - included. This mostly didn't matter, but if would cause problems with empty strategies - or ones with side effects. -* Add a mechanism to the Django model generator to allow you to explicitly request the - default value (thanks to Jeremy Thurgood for this one). - ------------------- -3.0.5 - 2016-02-25 ------------------- - -* Fix a bug where Hypothesis would now error on py.test development versions. - ------------------- -3.0.4 - 2016-02-24 ------------------- - -* Fix a bug where Hypothesis would error when running on Python 2.7.3 or - earlier because it was trying to pass a :class:`python:bytearray` object - to :func:`python:struct.unpack` (which is only supported since 2.7.4). - ------------------- -3.0.3 - 2016-02-23 ------------------- - -* Fix version parsing of py.test to work with py.test release candidates -* More general handling of the health check problem where things could fail because - of a cache miss - now one "free" example is generated before the start of the - health check run. - ------------------- -3.0.2 - 2016-02-18 ------------------- - -* Under certain circumstances, strategies involving :func:`~hypothesis.strategies.text` buried inside some - other strategy (e.g. ``text().filter(...)`` or ``recursive(text(), ...))`` would cause - a test to fail its health checks the first time it ran. This was caused by having - to compute some related data and cache it to disk. On travis or anywhere else - where the ``.hypothesis`` directory was recreated this would have caused the tests - to fail their health check on every run. This is now fixed for all the known cases, - although there could be others lurking. - ------------------- -3.0.1 - 2016-02-18 ------------------- - -* Fix a case where it was possible to trigger an "Unreachable" assertion when - running certain flaky stateful tests. -* Improve shrinking of large stateful tests by eliminating a case where it was - hard to delete early steps. -* Improve efficiency of drawing :func:`binary(min_size=n, max_size=n) ` significantly by - provide a custom implementation for fixed size blocks that can bypass a lot - of machinery. -* Set default home directory based on the current working directory at the - point Hypothesis is imported, not whenever the function first happens to be - called. - ------------------- -3.0.0 - 2016-02-17 ------------------- - -Codename: This really should have been 2.1. - -Externally this looks like a very small release. It has one small breaking change -that probably doesn't affect anyone at all (some behaviour that never really worked -correctly is now outright forbidden) but necessitated a major version bump and one -visible new feature. - -Internally this is a complete rewrite. Almost nothing other than the public API is -the same. - -New features: - -* Addition of :func:`~hypothesis.strategies.data` strategy which allows you to draw arbitrary data interactively - within the test. -* New "exploded" database format which allows you to more easily check the example - database into a source repository while supporting merging. -* Better management of how examples are saved in the database. -* Health checks will now raise as errors when they fail. It was too easy to have - the warnings be swallowed entirely. - -New limitations: - -* :func:`~hypothesis.strategies.choices` and :func:`~hypothesis.strategies.streaming` - strategies may no longer be used with :func:`~hypothesis.find`. Neither may - :func:`~hypothesis.strategies.data` (this is the change that necessitated a major version bump). - -Feature removal: - -* The ForkingTestCase executor has gone away. It may return in some more working - form at a later date. - -Performance improvements: - -* A new model which allows flatmap, composite strategies and stateful testing to - perform *much* better. They should also be more reliable. -* Filtering may in some circumstances have improved significantly. This will - help especially in cases where you have lots of values with individual filters - on them, such as lists(x.filter(...)). -* Modest performance improvements to the general test runner by avoiding expensive - operations - -In general your tests should have got faster. If they've instead got significantly -slower, I'm interested in hearing about it. - -Data distribution: - -The data distribution should have changed significantly. This may uncover bugs the -previous version missed. It may also miss bugs the previous version could have -uncovered. Hypothesis is now producing less strongly correlated data than it used -to, but the correlations are extended over more of the structure. - -Shrinking: - -Shrinking quality should have improved. In particular Hypothesis can now perform -simultaneous shrinking of separate examples within a single test (previously it -was only able to do this for elements of a single collection). In some cases -performance will have improved, in some cases it will have got worse but generally -shouldn't have by much. - ------------------- -2.0.0 - 2016-01-10 ------------------- - -Codename: A new beginning - -This release cleans up all of the legacy that accrued in the course of -Hypothesis 1.0. These are mostly things that were emitting deprecation warnings -in 1.19.0, but there were a few additional changes. - -In particular: - -* non-strategy values will no longer be converted to strategies when used in - given or find. -* FailedHealthCheck is now an error and not a warning. -* Handling of non-ascii reprs in user types have been simplified by using raw - strings in more places in Python 2. -* given no longer allows mixing positional and keyword arguments. -* given no longer works with functions with defaults. -* given no longer turns provided arguments into defaults - they will not appear - in the argspec at all. -* the basic() strategy no longer exists. -* the n_ary_tree strategy no longer exists. -* the average_list_length setting no longer exists. Note: If you're using - using recursive() this will cause you a significant slow down. You should - pass explicit average_size parameters to collections in recursive calls. -* @rule can no longer be applied to the same method twice. -* Python 2.6 and 3.3 are no longer officially supported, although in practice - they still work fine. - -This also includes two non-deprecation changes: - -* given's keyword arguments no longer have to be the rightmost arguments and - can appear anywhere in the method signature. -* The max_shrinks setting would sometimes not have been respected. - - -------------------- -1.19.0 - 2016-01-09 -------------------- - -Codename: IT COMES - -This release heralds the beginning of a new and terrible age of Hypothesis 2.0. - -It's primary purpose is some final deprecations prior to said release. The goal -is that if your code emits no warnings under this release then it will probably run -unchanged under Hypothesis 2.0 (there are some caveats to this: 2.0 will drop -support for some Python versions, and if you're using internal APIs then as usual -that may break without warning). - -It does have two new features: - -* New @seed() decorator which allows you to manually seed a test. This may be - harmlessly combined with and overrides the derandomize setting. -* settings objects may now be used as a decorator to fix those settings to a - particular @given test. - -API changes (old usage still works but is deprecated): - -* Settings has been renamed to settings (lower casing) in order to make the - decorator usage more natural. -* Functions for the storage directory that were in hypothesis.settings are now - in a new hypothesis.configuration module. - -Additional deprecations: - -* the average_list_length setting has been deprecated in favour of being - explicit. -* the basic() strategy has been deprecated as it is impossible to support - it under a Conjecture based model, which will hopefully be implemented at - some point in the 2.x series. -* the n_ary_tree strategy (which was never actually part of the public API) - has been deprecated. -* Passing settings or random as keyword arguments to given is deprecated (use - the new functionality instead) - - -Bug fixes: - -* No longer emit PendingDeprecationWarning for __iter__ and StopIteration in - streaming() values. -* When running in health check mode with non strict, don't print quite so - many errors for an exception in reify. -* When an assumption made in a test or a filter is flaky, tests will now - raise Flaky instead of UnsatisfiedAssumption. - - ------------------------------------------------------------------------ -`1.18.1 `_ - 2015-12-22 ------------------------------------------------------------------------ - -Two behind the scenes changes: - -* Hypothesis will no longer write generated code to the file system. This - will improve performance on some systems (e.g. if you're using - `PythonAnywhere `_ which is running your - code from NFS) and prevent some annoying interactions with auto-restarting - systems. -* Hypothesis will cache the creation of some strategies. This can significantly - improve performance for code that uses flatmap or composite and thus has to - instantiate strategies a lot. - ------------------------------------------------------------------------ -`1.18.0 `_ - 2015-12-21 ------------------------------------------------------------------------ - -Features: - -* Tests and find are now explicitly seeded off the global random module. This - means that if you nest one inside the other you will now get a health check - error. It also means that you can control global randomization by seeding - random. -* There is a new random_module() strategy which seeds the global random module - for you and handles things so that you don't get a health check warning if - you use it inside your tests. -* floats() now accepts two new arguments: allow\_nan and allow\_infinity. These - default to the old behaviour, but when set to False will do what the names - suggest. - -Bug fixes: - -* Fix a bug where tests that used text() on Python 3.4+ would not actually be - deterministic even when explicitly seeded or using the derandomize mode, - because generation depended on dictionary iteration order which was affected - by hash randomization. -* Fix a bug where with complicated strategies the timing of the initial health - check could affect the seeding of the subsequent test, which would also - render supposedly deterministic tests non-deterministic in some scenarios. -* In some circumstances flatmap() could get confused by two structurally - similar things it could generate and would produce a flaky test where the - first time it produced an error but the second time it produced the other - value, which was not an error. The same bug was presumably also possible in - composite(). -* flatmap() and composite() initial generation should now be moderately faster. - This will be particularly noticeable when you have many values drawn from the - same strategy in a single run, e.g. constructs like lists(s.flatmap(f)). - Shrinking performance *may* have suffered, but this didn't actually produce - an interestingly worse result in any of the standard scenarios tested. - ------------------------------------------------------------------------ -`1.17.1 `_ - 2015-12-16 ------------------------------------------------------------------------ - -A small bug fix release, which fixes the fact that the 'note' function could -not be used on tests which used the @example decorator to provide explicit -examples. - ------------------------------------------------------------------------ -`1.17.0 `_ - 2015-12-15 ------------------------------------------------------------------------ - -This is actually the same release as 1.16.1, but 1.16.1 has been pulled because -it contains the following additional change that was not intended to be in a -patch release (it's perfectly stable, but is a larger change that should have -required a minor version bump): - -* Hypothesis will now perform a series of "health checks" as part of running - your tests. These detect and warn about some common error conditions that - people often run into which wouldn't necessarily have caused the test to fail - but would cause e.g. degraded performance or confusing results. - ------------------------------------------------------------------------ -`1.16.1 `_ - 2015-12-14 ------------------------------------------------------------------------ - -Note: This release has been removed. - -A small bugfix release that allows bdists for Hypothesis to be built -under 2.7 - the compat3.py file which had Python 3 syntax wasn't intended -to be loaded under Python 2, but when building a bdist it was. In particular -this would break running setup.py test. - ------------------------------------------------------------------------ -`1.16.0 `_ - 2015-12-08 ------------------------------------------------------------------------ - -There are no public API changes in this release but it includes a behaviour -change that I wasn't comfortable putting in a patch release. - -* Functions from hypothesis.strategies will no longer raise InvalidArgument - on bad arguments. Instead the same errors will be raised when a test - using such a strategy is run. This may improve startup time in some - cases, but the main reason for it is so that errors in strategies - won't cause errors in loading, and it can interact correctly with things - like pytest.mark.skipif. -* Errors caused by accidentally invoking the legacy API are now much less - confusing, although still throw NotImplementedError. -* hypothesis.extra.django is 1.9 compatible. -* When tests are run with max_shrinks=0 this will now still rerun the test - on failure and will no longer print "Trying example:" before each run. - Additionally note() will now work correctly when used with max_shrinks=0. - ------------------------------------------------------------------------ -`1.15.0 `_ - 2015-11-24 ------------------------------------------------------------------------ - -A release with two new features. - -* A 'characters' strategy for more flexible generation of text with particular - character ranges and types, kindly contributed by `Alexander Shorin `_. -* Add support for preconditions to the rule based stateful testing. Kindly - contributed by `Christopher Armstrong `_ - - ------------------------------------------------------------------------ -`1.14.0 `_ - 2015-11-01 ------------------------------------------------------------------------ - - -New features: - -* Add 'note' function which lets you include additional information in the - final test run's output. -* Add 'choices' strategy which gives you a choice function that emulates - random.choice. -* Add 'uuid' strategy that generates UUIDs' -* Add 'shared' strategy that lets you create a strategy that just generates a - single shared value for each test run - -Bugs: - -* Using strategies of the form streaming(x.flatmap(f)) with find or in stateful - testing would have caused InvalidArgument errors when the resulting values - were used (because code that expected to only be called within a test context - would be invoked). - - ------------------------------------------------------------------------ -`1.13.0 `_ - 2015-10-29 ------------------------------------------------------------------------ - -This is quite a small release, but deprecates some public API functions -and removes some internal API functionality so gets a minor version bump. - -* All calls to the 'strategy' function are now deprecated, even ones which - pass just a SearchStrategy instance (which is still a no-op). -* Never documented hypothesis.extra entry_points mechanism has now been removed ( - it was previously how hypothesis.extra packages were loaded and has been deprecated - and unused for some time) -* Some corner cases that could previously have produced an OverflowError when simplifying - failing cases using hypothesis.extra.datetimes (or dates or times) have now been fixed. -* Hypothesis load time for first import has been significantly reduced - it used to be - around 250ms (on my SSD laptop) and now is around 100-150ms. This almost never - matters but was slightly annoying when using it in the console. -* hypothesis.strategies.randoms was previously missing from \_\_all\_\_. - ------------------------------------------------------------------------ -`1.12.0 `_ - 2015-10-18 ------------------------------------------------------------------------ - -* Significantly improved performance of creating strategies using the functions - from the hypothesis.strategies module by deferring the calculation of their - repr until it was needed. This is unlikely to have been an performance issue - for you unless you were using flatmap, composite or stateful testing, but for - some cases it could be quite a significant impact. -* A number of cases where the repr of strategies build from lambdas is improved -* Add dates() and times() strategies to hypothesis.extra.datetimes -* Add new 'profiles' mechanism to the settings system -* Deprecates mutability of Settings, both the Settings.default top level property - and individual settings. -* A Settings object may now be directly initialized from a parent Settings. -* @given should now give a better error message if you attempt to use it with a - function that uses destructuring arguments (it still won't work, but it will - error more clearly), -* A number of spelling corrections in error messages -* py.test should no longer display the intermediate modules Hypothesis generates - when running in verbose mode -* Hypothesis should now correctly handle printing objects with non-ascii reprs - on python 3 when running in a locale that cannot handle ascii printing to - stdout. -* Add a unique=True argument to lists(). This is equivalent to - unique_by=lambda x: x, but offers a more convenient syntax. - - ------------------------------------------------------------------------ -`1.11.4 `_ - 2015-09-27 ------------------------------------------------------------------------ - -* Hide modifications Hypothesis needs to make to sys.path by undoing them - after we've imported the relevant modules. This is a workaround for issues - cryptography experienced on windows. -* Slightly improved performance of drawing from sampled_from on large lists - of alternatives. -* Significantly improved performance of drawing from one_of or strategies - using \| (note this includes a lot of strategies internally - floats() - and integers() both fall into this category). There turned out to be a - massive performance regression introduced in 1.10.0 affecting these which - probably would have made tests using Hypothesis significantly slower than - they should have been. - ------------------------------------------------------------------------ -`1.11.3 `_ - 2015-09-23 ------------------------------------------------------------------------ - -* Better argument validation for datetimes() strategy - previously setting - max_year < datetime.MIN_YEAR or min_year > datetime.MAX_YEAR would not have - raised an InvalidArgument error and instead would have behaved confusingly. -* Compatibility with being run on pytest < 2.7 (achieved by disabling the - plugin). - ------------------------------------------------------------------------ -`1.11.2 `_ - 2015-09-23 ------------------------------------------------------------------------ - -Bug fixes: - -* Settings(database=my_db) would not be correctly inherited when used as a - default setting, so that newly created settings would use the database_file - setting and create an SQLite example database. -* Settings.default.database = my_db would previously have raised an error and - now works. -* Timeout could sometimes be significantly exceeded if during simplification - there were a lot of examples tried that didn't trigger the bug. -* When loading a heavily simplified example using a basic() strategy from the - database this could cause Python to trigger a recursion error. -* Remove use of deprecated API in pytest plugin so as to not emit warning - -Misc: - -* hypothesis-pytest is now part of hypothesis core. This should have no - externally visible consequences, but you should update your dependencies to - remove hypothesis-pytest and depend on only Hypothesis. -* Better repr for hypothesis.extra.datetimes() strategies. -* Add .close() method to abstract base class for Backend (it was already present - in the main implementation). - ------------------------------------------------------------------------ -`1.11.1 `_ - 2015-09-16 ------------------------------------------------------------------------ - -Bug fixes: - -* When running Hypothesis tests in parallel (e.g. using pytest-xdist) there was a race - condition caused by code generation. -* Example databases are now cached per thread so as to not use sqlite connections from - multiple threads. This should make Hypothesis now entirely thread safe. -* floats() with only min_value or max_value set would have had a very bad distribution. -* Running on 3.5, Hypothesis would have emitted deprecation warnings because of use of - inspect.getargspec - ------------------------------------------------------------------------ -`1.11.0 `_ - 2015-08-31 ------------------------------------------------------------------------ - -* text() with a non-string alphabet would have used the repr() of the the alphabet - instead of its contexts. This is obviously silly. It now works with any sequence - of things convertible to unicode strings. -* @given will now work on methods whose definitions contains no explicit positional - arguments, only varargs (`bug #118 `_). - This may have some knock on effects because it means that @given no longer changes the - argspec of functions other than by adding defaults. -* Introduction of new @composite feature for more natural definition of strategies you'd - previously have used flatmap for. - ------------------------------------------------------------------------ -`1.10.6 `_ - 2015-08-26 ------------------------------------------------------------------------ - -Fix support for fixtures on Django 1.7. - -------------------- -1.10.4 - 2015-08-21 -------------------- - -Tiny bug fix release: - -* If the database_file setting is set to None, this would have resulted in - an error when running tests. Now it does the same as setting database to - None. - ------------------------------------------------------------------------ -`1.10.3 `_ - 2015-08-19 ------------------------------------------------------------------------ - -Another small bug fix release. - -* lists(elements, unique_by=some_function, min_size=n) would have raised a - ValidationError if n > Settings.default.average_list_length because it would - have wanted to use an average list length shorter than the minimum size of - the list, which is impossible. Now it instead defaults to twice the minimum - size in these circumstances. -* basic() strategy would have only ever produced at most ten distinct values - per run of the test (which is bad if you e.g. have it inside a list). This - was obviously silly. It will now produce a much better distribution of data, - both duplicated and non duplicated. - - ------------------------------------------------------------------------ -`1.10.2 `_ - 2015-08-19 ------------------------------------------------------------------------ - -This is a small bug fix release: - -* star imports from hypothesis should now work correctly. -* example quality for examples using flatmap will be better, as the way it had - previously been implemented was causing problems where Hypothesis was - erroneously labelling some examples as being duplicates. - ------------------------------------------------------------------------ -`1.10.0 `_ - 2015-08-04 ------------------------------------------------------------------------ - -This is just a bugfix and performance release, but it changes some -semi-public APIs, hence the minor version bump. - -* Significant performance improvements for strategies which are one\_of() - many branches. In particular this included recursive() strategies. This - should take the case where you use one recursive() strategy as the base - strategy of another from unusably slow (tens of seconds per generated - example) to reasonably fast. -* Better handling of just() and sampled_from() for values which have an - incorrect \_\_repr\_\_ implementation that returns non-ASCII unicode - on Python 2. -* Better performance for flatmap from changing the internal morpher API - to be significantly less general purpose. -* Introduce a new semi-public BuildContext/cleanup API. This allows - strategies to register cleanup activities that should run once the - example is complete. Note that this will interact somewhat weirdly with - find. -* Better simplification behaviour for streaming strategies. -* Don't error on lambdas which use destructuring arguments in Python 2. -* Add some better reprs for a few strategies that were missing good ones. -* The Random instances provided by randoms() are now copyable. -* Slightly more debugging information about simplify when using a debug - verbosity level. -* Support using given for functions with varargs, but not passing arguments - to it as positional. - ---------------------------------------------------------------------- -`1.9.0 `_ - 2015-07-27 ---------------------------------------------------------------------- - -Codename: The great bundling. - -This release contains two fairly major changes. - -The first is the deprecation of the hypothesis-extra mechanism. From -now on all the packages that were previously bundled under it other -than hypothesis-pytest (which is a different beast and will remain -separate). The functionality remains unchanged and you can still import -them from exactly the same location, they just are no longer separate -packages. - -The second is that this introduces a new way of building strategies -which lets you build up strategies recursively from other strategies. - -It also contains the minor change that calling .example() on a -strategy object will give you examples that are more representative of -the actual data you'll get. There used to be some logic in there to make -the examples artificially simple but this proved to be a bad idea. - ---------------------------------------------------------------------- -`1.8.5 `_ - 2015-07-24 ---------------------------------------------------------------------- - -This contains no functionality changes but fixes a mistake made with -building the previous package that would have broken installation on -Windows. - ---------------------------------------------------------------------- -`1.8.4 `_ - 2015-07-20 ---------------------------------------------------------------------- - -Bugs fixed: - -* When a call to floats() had endpoints which were not floats but merely - convertible to one (e.g. integers), these would be included in the generated - data which would cause it to generate non-floats. -* Splitting lambdas used in the definition of flatmap, map or filter over - multiple lines would break the repr, which would in turn break their usage. - - ---------------------------------------------------------------------- -`1.8.3 `_ - 2015-07-20 ---------------------------------------------------------------------- - -"Falsifying example" would not have been printed when the failure came from an -explicit example. - ---------------------------------------------------------------------- -`1.8.2 `_ - 2015-07-18 ---------------------------------------------------------------------- - -Another small bugfix release: - -* When using ForkingTestCase you would usually not get the falsifying example - printed if the process exited abnormally (e.g. due to os._exit). -* Improvements to the distribution of characters when using text() with a - default alphabet. In particular produces a better distribution of ascii and - whitespace in the alphabet. - ------------------- -1.8.1 - 2015-07-17 ------------------- - -This is a small release that contains a workaround for people who have -bad reprs returning non ascii text on Python 2.7. This is not a bug fix -for Hypothesis per se because that's not a thing that is actually supposed -to work, but Hypothesis leans more heavily on repr than is typical so it's -worth having a workaround for. - ---------------------------------------------------------------------- -`1.8.0 `_ - 2015-07-16 ---------------------------------------------------------------------- - -New features: - -* Much more sensible reprs for strategies, especially ones that come from - hypothesis.strategies. These should now have as reprs python code that - would produce the same strategy. -* lists() accepts a unique_by argument which forces the generated lists to be - only contain elements unique according to some function key (which must - return a hashable value). -* Better error messages from flaky tests to help you debug things. - -Mostly invisible implementation details that may result in finding new bugs -in your code: - -* Sets and dictionary generation should now produce a better range of results. -* floats with bounds now focus more on 'critical values', trying to produce - values at edge cases. -* flatmap should now have better simplification for complicated cases, as well - as generally being (I hope) more reliable. - -Bug fixes: - -* You could not previously use assume() if you were using the forking executor. - - ---------------------------------------------------------------------- -`1.7.2 `_ - 2015-07-10 ---------------------------------------------------------------------- - -This is purely a bug fix release: - -* When using floats() with stale data in the database you could sometimes get - values in your tests that did not respect min_value or max_value. -* When getting a Flaky error from an unreliable test it would have incorrectly - displayed the example that caused it. -* 2.6 dependency on backports was incorrectly specified. This would only have - caused you problems if you were building a universal wheel from Hypothesis, - which is not how Hypothesis ships, so unless you're explicitly building wheels - for your dependencies and support Python 2.6 plus a later version of Python - this probably would never have affected you. -* If you use flatmap in a way that the strategy on the right hand side depends - sensitively on the left hand side you may have occasionally seen Flaky errors - caused by producing unreliable examples when minimizing a bug. This use case - may still be somewhat fraught to be honest. This code is due a major rearchitecture - for 1.8, but in the meantime this release fixes the only source of this error that - I'm aware of. - ---------------------------------------------------------------------- -`1.7.1 `_ - 2015-06-29 ---------------------------------------------------------------------- - -Codename: There is no 1.7.0. - -A slight technical hitch with a premature upload means there's was a yanked -1.7.0 release. Oops. - -The major feature of this release is Python 2.6 support. Thanks to Jeff Meadows -for doing most of the work there. - -Other minor features - -* strategies now has a permutations() function which returns a strategy - yielding permutations of values from a given collection. -* if you have a flaky test it will print the exception that it last saw before - failing with Flaky, even if you do not have verbose reporting on. -* Slightly experimental git merge script available as "python -m - hypothesis.tools.mergedbs". Instructions on how to use it in the docstring - of that file. - -Bug fixes: - -* Better performance from use of filter. In particular tests which involve large - numbers of heavily filtered strategies should perform a lot better. -* floats() with a negative min_value would not have worked correctly (worryingly, - it would have just silently failed to run any examples). This is now fixed. -* tests using sampled\_from would error if the number of sampled elements was smaller - than min\_satisfying\_examples. - - ------------------- -1.6.2 - 2015-06-08 ------------------- - -This is just a few small bug fixes: - -* Size bounds were not validated for values for a binary() strategy when - reading examples from the database. -* sampled\_from is now in __all__ in hypothesis.strategies -* floats no longer consider negative integers to be simpler than positive - non-integers -* Small floating point intervals now correctly count members, so if you have a - floating point interval so narrow there are only a handful of values in it, - this will no longer cause an error when Hypothesis runs out of values. - ------------------- -1.6.1 - 2015-05-21 ------------------- - -This is a small patch release that fixes a bug where 1.6.0 broke the use -of flatmap with the deprecated API and assumed the passed in function returned -a SearchStrategy instance rather than converting it to a strategy. - ---------------------------------------------------------------------- -`1.6.0 `_ - 2015-05-21 ---------------------------------------------------------------------- - - -This is a smallish release designed to fix a number of bugs and smooth out -some weird behaviours. - -* Fix a critical bug in flatmap where it would reuse old strategies. If all - your flatmap code was pure you're fine. If it's not, I'm surprised it's - working at all. In particular if you want to use flatmap with django models, - you desperately need to upgrade to this version. -* flatmap simplification performance should now be better in some cases where - it previously had to redo work. -* Fix for a bug where invalid unicode data with surrogates could be generated - during simplification (it was already filtered out during actual generation). -* The Hypothesis database is now keyed off the name of the test instead of the - type of data. This makes much more sense now with the new strategies API and - is generally more robust. This means you will lose old examples on upgrade. -* The database will now not delete values which fail to deserialize correctly, - just skip them. This is to handle cases where multiple incompatible strategies - share the same key. -* find now also saves and loads values from the database, keyed off a hash of the - function you're finding from. -* Stateful tests now serialize and load values from the database. They should have - before, really. This was a bug. -* Passing a different verbosity level into a test would not have worked entirely - correctly, leaving off some messages. This is now fixed. -* Fix a bug where derandomized tests with unicode characters in the function - body would error on Python 2.7. - - ---------------------------------------------------------------------- -`1.5.0 `_ - 2015-05-14 ---------------------------------------------------------------------- - - -Codename: Strategic withdrawal. - -The purpose of this release is a radical simplification of the API for building -strategies. Instead of the old approach of @strategy.extend and things that -get converted to strategies, you just build strategies directly. - -The old method of defining strategies will still work until Hypothesis 2.0, -because it's a major breaking change, but will now emit deprecation warnings. - -The new API is also a lot more powerful as the functions for defining strategies -give you a lot of dials to turn. See :doc:`the updated data section ` for -details. - -Other changes: - - * Mixing keyword and positional arguments in a call to @given is deprecated as well. - * There is a new setting called 'strict'. When set to True, Hypothesis will raise - warnings instead of merely printing them. Turning it on by default is inadvisable because - it means that Hypothesis minor releases can break your code, but it may be useful for - making sure you catch all uses of deprecated APIs. - * max_examples in settings is now interpreted as meaning the maximum number - of unique (ish) examples satisfying assumptions. A new setting max_iterations - which defaults to a larger value has the old interpretation. - * Example generation should be significantly faster due to a new faster parameter - selection algorithm. This will mostly show up for simple data types - for complex - ones the parameter selection is almost certainly dominated. - * Simplification has some new heuristics that will tend to cut down on cases - where it could previously take a very long time. - * timeout would previously not have been respected in cases where there were a lot - of duplicate examples. You probably wouldn't have previously noticed this because - max_examples counted duplicates, so this was very hard to hit in a way that mattered. - * A number of internal simplifications to the SearchStrategy API. - * You can now access the current Hypothesis version as hypothesis.__version__. - * A top level function is provided for running the stateful tests without the - TestCase infrastructure. - ---------------------------------------------------------------------- -`1.4.0 `_ - 2015-05-04 ---------------------------------------------------------------------- - -Codename: What a state. - -The *big* feature of this release is the new and slightly experimental -stateful testing API. You can read more about that in :doc:`the -appropriate section `. - -Two minor features the were driven out in the course of developing this: - -* You can now set settings.max_shrinks to limit the number of times - Hypothesis will try to shrink arguments to your test. If this is set to - <= 0 then Hypothesis will not rerun your test and will just raise the - failure directly. Note that due to technical limitations if max_shrinks - is <= 0 then Hypothesis will print *every* example it calls your test - with rather than just the failing one. Note also that I don't consider - settings max_shrinks to zero a sensible way to run your tests and it - should really be considered a debug feature. -* There is a new debug level of verbosity which is even *more* verbose than - verbose. You probably don't want this. - -Breakage of semi-public SearchStrategy API: - -* It is now a required invariant of SearchStrategy that if u simplifies to - v then it is not the case that strictly_simpler(u, v). i.e. simplifying - should not *increase* the complexity even though it is not required to - decrease it. Enforcing this invariant lead to finding some bugs where - simplifying of integers, floats and sets was suboptimal. -* Integers in basic data are now required to fit into 64 bits. As a result - python integer types are now serialized as strings, and some types have - stopped using quite so needlessly large random seeds. - -Hypothesis Stateful testing was then turned upon Hypothesis itself, which lead -to an amazing number of minor bugs being found in Hypothesis itself. - -Bugs fixed (most but not all from the result of stateful testing) include: - -* Serialization of streaming examples was flaky in a way that you would - probably never notice: If you generate a template, simplify it, serialize - it, deserialize it, serialize it again and then deserialize it you would - get the original stream instead of the simplified one. -* If you reduced max_examples below the number of examples already saved in - the database, you would have got a ValueError. Additionally, if you had - more than max_examples in the database all of them would have been - considered. -* @given will no longer count duplicate examples (which it never called - your function with) towards max_examples. This may result in your tests - running slower, but that's probably just because they're trying more - examples. -* General improvements to example search which should result in better - performance and higher quality examples. In particular parameters which - have a history of producing useless results will be more aggressively - culled. This is useful both because it decreases the chance of useless - examples and also because it's much faster to not check parameters which - we were unlikely to ever pick! -* integers_from and lists of types with only one value (e.g. [None]) would - previously have had a very high duplication rate so you were probably - only getting a handful of examples. They now have a much lower - duplication rate, as well as the improvements to search making this - less of a problem in the first place. -* You would sometimes see simplification taking significantly longer than - your defined timeout. This would happen because timeout was only being - checked after each *successful* simplification, so if Hypothesis was - spending a lot of time unsuccessfully simplifying things it wouldn't - stop in time. The timeout is now applied for unsuccessful simplifications - too. -* In Python 2.7, integers_from strategies would have failed during - simplification with an OverflowError if their starting point was at or - near to the maximum size of a 64-bit integer. -* flatmap and map would have failed if called with a function without a - __name__ attribute. -* If max_examples was less than min_satisfying_examples this would always - error. Now min_satisfying_examples is capped to max_examples. Note that - if you have assumptions to satisfy here this will still cause an error. - -Some minor quality improvements: - -* Lists of streams, flatmapped strategies and basic strategies should now - now have slightly better simplification. - ---------------------------------------------------------------------- -`1.3.0 `_ - 2015-05-22 ---------------------------------------------------------------------- - -New features: - -* New verbosity level API for printing intermediate results and exceptions. -* New specifier for strings generated from a specified alphabet. -* Better error messages for tests that are failing because of a lack of enough - examples. - -Bug fixes: - -* Fix error where use of ForkingTestCase would sometimes result in too many - open files. -* Fix error where saving a failing example that used flatmap could error. -* Implement simplification for sampled_from, which apparently never supported - it previously. Oops. - - -General improvements: - -* Better range of examples when using one_of or sampled_from. -* Fix some pathological performance issues when simplifying lists of complex - values. -* Fix some pathological performance issues when simplifying examples that - require unicode strings with high codepoints. -* Random will now simplify to more readable examples. - - ---------------------------------------------------------------------- -`1.2.1 `_ - 2015-04-16 ---------------------------------------------------------------------- - -A small patch release for a bug in the new executors feature. Tests which require -doing something to their result in order to fail would have instead reported as -flaky. - ---------------------------------------------------------------------- -`1.2.0 `_ - 2015-04-15 ---------------------------------------------------------------------- - -Codename: Finders keepers. - -A bunch of new features and improvements. - -* Provide a mechanism for customizing how your tests are executed. -* Provide a test runner that forks before running each example. This allows - better support for testing native code which might trigger a segfault or a C - level assertion failure. -* Support for using Hypothesis to find examples directly rather than as just as - a test runner. -* New streaming type which lets you generate infinite lazily loaded streams of - data - perfect for if you need a number of examples but don't know how many. -* Better support for large integer ranges. You can now use integers_in_range - with ranges of basically any size. Previously large ranges would have eaten - up all your memory and taken forever. -* Integers produce a wider range of data than before - previously they would - only rarely produce integers which didn't fit into a machine word. Now it's - much more common. This percolates to other numeric types which build on - integers. -* Better validation of arguments to @given. Some situations that would - previously have caused silently wrong behaviour will now raise an error. -* Include +/- sys.float_info.max in the set of floating point edge cases that - Hypothesis specifically tries. -* Fix some bugs in floating point ranges which happen when given - +/- sys.float_info.max as one of the endpoints... (really any two floats that - are sufficiently far apart so that x, y are finite but y - x is infinite). - This would have resulted in generating infinite values instead of ones inside - the range. - ---------------------------------------------------------------------- -`1.1.1 `_ - 2015-04-07 ---------------------------------------------------------------------- - -Codename: Nothing to see here - -This is just a patch release put out because it fixed some internal bugs that would -block the Django integration release but did not actually affect anything anyone could -previously have been using. It also contained a minor quality fix for floats that -I'd happened to have finished in time. - -* Fix some internal bugs with object lifecycle management that were impossible to - hit with the previously released versions but broke hypothesis-django. -* Bias floating point numbers somewhat less aggressively towards very small numbers - - ---------------------------------------------------------------------- -`1.1.0 `_ - 2015-04-06 ---------------------------------------------------------------------- - -Codename: No-one mention the M word. - -* Unicode strings are more strongly biased towards ascii characters. Previously they - would generate all over the space. This is mostly so that people who try to - shape their unicode strings with assume() have less of a bad time. -* A number of fixes to data deserialization code that could theoretically have - caused mysterious bugs when using an old version of a Hypothesis example - database with a newer version. To the best of my knowledge a change that could - have triggered this bug has never actually been seen in the wild. Certainly - no-one ever reported a bug of this nature. -* Out of the box support for Decimal and Fraction. -* new dictionary specifier for dictionaries with variable keys. -* Significantly faster and higher quality simplification, especially for - collections of data. -* New filter() and flatmap() methods on Strategy for better ways of building - strategies out of other strategies. -* New BasicStrategy class which allows you to define your own strategies from - scratch without needing an existing matching strategy or being exposed to the - full horror or non-public nature of the SearchStrategy interface. - - ---------------------------------------------------------------------- -`1.0.0 `_ - 2015-03-27 ---------------------------------------------------------------------- - -Codename: Blast-off! - -There are no code changes in this release. This is precisely the 0.9.2 release -with some updated documentation. - ------------------- -0.9.2 - 2015-03-26 ------------------- - -Codename: T-1 days. - -* floats_in_range would not actually have produced floats_in_range unless that - range happened to be (0, 1). Fix this. - ------------------- -0.9.1 - 2015-03-25 ------------------- - -Codename: T-2 days. - -* Fix a bug where if you defined a strategy using map on a lambda then the results would not be saved in the database. -* Significant performance improvements when simplifying examples using lists, strings or bounded integer ranges. - ------------------- -0.9.0 - 2015-03-23 ------------------- - -Codename: The final countdown - -This release could also be called 1.0-RC1. - -It contains a teeny tiny bugfix, but the real point of this release is to declare -feature freeze. There will be zero functionality changes between 0.9.0 and 1.0 unless -something goes really really wrong. No new features will be added, no breaking API changes -will occur, etc. This is the final shakedown before I declare Hypothesis stable and ready -to use and throw a party to celebrate. - -Bug bounty for any bugs found between now and 1.0: I will buy you a drink (alcoholic, -caffeinated, or otherwise) and shake your hand should we ever find ourselves in the -same city at the same time. - -The one tiny bugfix: - -* Under pypy, databases would fail to close correctly when garbage collected, leading to a memory leak and a confusing error message if you were repeatedly creating databases and not closing them. It is very unlikely you were doing this and the chances of you ever having noticed this bug are very low. - ------------------- -0.7.2 - 2015-03-22 ------------------- - -Codename: Hygienic macros or bust - -* You can now name an argument to @given 'f' and it won't break (issue #38) -* strategy_test_suite is now named strategy_test_suite as the documentation claims and not in fact strategy_test_suitee -* Settings objects can now be used as a context manager to temporarily override the default values inside their context. - - ------------------- -0.7.1 - 2015-03-21 ------------------- - -Codename: Point releases go faster - -* Better string generation by parametrizing by a limited alphabet -* Faster string simplification - previously if simplifying a string with high range unicode characters it would try every unicode character smaller than that. This was pretty pointless. Now it stops after it's a short range (it can still reach smaller ones through recursive calls because of other simplifying operations). -* Faster list simplification by first trying a binary chop down the middle -* Simultaneous simplification of identical elements in a list. So if a bug only triggers when you have duplicates but you drew e.g. [-17, -17], this will now simplify to [0, 0]. - - -------------------- -0.7.0, - 2015-03-20 -------------------- - -Codename: Starting to look suspiciously real - -This is probably the last minor release prior to 1.0. It consists of stability -improvements, a few usability things designed to make Hypothesis easier to try -out, and filing off some final rough edges from the API. - -* Significant speed and memory usage improvements -* Add an example() method to strategy objects to give an example of the sort of data that the strategy generates. -* Remove .descriptor attribute of strategies -* Rename descriptor_test_suite to strategy_test_suite -* Rename the few remaining uses of descriptor to specifier (descriptor already has a defined meaning in Python) - - ---------------------------------------------------------- -0.6.0 - 2015-03-13 ---------------------------------------------------------- - -Codename: I'm sorry, were you using that API? - -This is primarily a "simplify all the weird bits of the API" release. As a result there are a lot of breaking changes. If -you just use @given with core types then you're probably fine. - -In particular: - -* Stateful testing has been removed from the API -* The way the database is used has been rendered less useful (sorry). The feature for reassembling values saved from other - tests doesn't currently work. This will probably be brought back in post 1.0. -* SpecificationMapper is no longer a thing. Instead there is an ExtMethod called strategy which you extend to specify how - to convert other types to strategies. -* Settings are now extensible so you can add your own for configuring a strategy -* MappedSearchStrategy no longer needs an unpack method -* Basically all the SearchStrategy internals have changed massively. If you implemented SearchStrategy directly rather than - using MappedSearchStrategy talk to me about fixing it. -* Change to the way extra packages work. You now specify the package. This - must have a load() method. Additionally any modules in the package will be - loaded in under hypothesis.extra - -Bug fixes: - -* Fix for a bug where calling falsify on a lambda with a non-ascii character - in its body would error. - -Hypothesis Extra: - -hypothesis-fakefactory\: An extension for using faker data in hypothesis. Depends - on fake-factory. - ------------------- -0.5.0 - 2015-02-10 ------------------- - -Codename: Read all about it. - -Core hypothesis: - -* Add support back in for pypy and python 3.2 -* @given functions can now be invoked with some arguments explicitly provided. If all arguments that hypothesis would have provided are passed in then no falsification is run. -* Related to the above, this means that you can now use pytest fixtures and mark.parametrize with Hypothesis without either interfering with the other. -* Breaking change: @given no longer works for functions with varargs (varkwargs are fine). This might be added back in at a later date. -* Windows is now fully supported. A limited version (just the tests with none of the extras) of the test suite is run on windows with each commit so it is now a first class citizen of the Hypothesis world. -* Fix a bug for fuzzy equality of equal complex numbers with different reprs (this can happen when one coordinate is zero). This shouldn't affect users - that feature isn't used anywhere public facing. -* Fix generation of floats on windows and 32-bit builds of python. I was using some struct.pack logic that only worked on certain word sizes. -* When a test times out and hasn't produced enough examples this now raises a Timeout subclass of Unfalsifiable. -* Small search spaces are better supported. Previously something like a @given(bool, bool) would have failed because it couldn't find enough examples. Hypothesis is now aware of the fact that these are small search spaces and will not error in this case. -* Improvements to parameter search in the case of hard to satisfy assume. Hypothesis will now spend less time exploring parameters that are unlikely to provide anything useful. -* Increase chance of generating "nasty" floats -* Fix a bug that would have caused unicode warnings if you had a sampled_from that was mixing unicode and byte strings. -* Added a standard test suite that you can use to validate a custom strategy you've defined is working correctly. - -Hypothesis extra: - -First off, introducing Hypothesis extra packages! - -These are packages that are separated out from core Hypothesis because they have one or more dependencies. Every -hypothesis-extra package is pinned to a specific point release of Hypothesis and will have some version requirements -on its dependency. They use entry_points so you will usually not need to explicitly import them, just have them installed -on the path. - -This release introduces two of them: - -hypothesis-datetime: - -Does what it says on the tin: Generates datetimes for Hypothesis. Just install the package and datetime support will start -working. - -Depends on pytz for timezone support - -hypothesis-pytest: - -A very rudimentary pytest plugin. All it does right now is hook the display of falsifying examples into pytest reporting. - -Depends on pytest. - - ------------------- -0.4.3 - 2015-02-05 ------------------- - -Codename: TIL narrow Python builds are a thing - -This just fixes the one bug. - -* Apparently there is such a thing as a "narrow python build" and OS X ships with these by default - for python 2.7. These are builds where you only have two bytes worth of unicode. As a result, - generating unicode was completely broken on OS X. Fix this by only generating unicode codepoints - in the range supported by the system. - - ------------------- -0.4.2 - 2015-02-04 ------------------- - -Codename: O(dear) - -This is purely a bugfix release: - -* Provide sensible external hashing for all core types. This will significantly improve - performance of tracking seen examples which happens in literally every falsification - run. For Hypothesis fixing this cut 40% off the runtime of the test suite. The behaviour - is quadratic in the number of examples so if you're running the default configuration - this will be less extreme (Hypothesis's test suite runs at a higher number of examples - than default), but you should still see a significant improvement. -* Fix a bug in formatting of complex numbers where the string could get incorrectly truncated. - - ------------------- -0.4.1 - 2015-02-03 ------------------- - -Codename: Cruel and unusual edge cases - -This release is mostly about better test case generation. - -Enhancements: - -* Has a cool release name -* text_type (str in python 3, unicode in python 2) example generation now - actually produces interesting unicode instead of boring ascii strings. -* floating point numbers are generated over a much wider range, with particular - attention paid to generating nasty numbers - nan, infinity, large and small - values, etc. -* examples can be generated using pieces of examples previously saved in the - database. This allows interesting behaviour that has previously been discovered - to be propagated to other examples. -* improved parameter exploration algorithm which should allow it to more reliably - hit interesting edge cases. -* Timeout can now be disabled entirely by setting it to any value <= 0. - - -Bug fixes: - -* The descriptor on a OneOfStrategy could be wrong if you had descriptors which - were equal but should not be coalesced. e.g. a strategy for one_of((frozenset({int}), {int})) - would have reported its descriptor as {int}. This is unlikely to have caused you - any problems -* If you had strategies that could produce NaN (which float previously couldn't but - e.g. a Just(float('nan')) could) then this would have sent hypothesis into an infinite - loop that would have only been terminated when it hit the timeout. -* Given elements that can take a long time to minimize, minimization of floats or tuples - could be quadratic or worse in the that value. You should now see much better performance - for simplification, albeit at some cost in quality. - -Other: - -* A lot of internals have been been rewritten. This shouldn't affect you at all, but - it opens the way for certain of hypothesis's oddities to be a lot more extensible by - users. Whether this is a good thing may be up for debate... - - ------------------- -0.4.0 - 2015-01-21 ------------------- - -FLAGSHIP FEATURE: Hypothesis now persists examples for later use. It stores -data in a local SQLite database and will reuse it for all tests of the same -type. - -LICENSING CHANGE: Hypothesis is now released under the Mozilla Public License -2.0. This applies to all versions from 0.4.0 onwards until further notice. -The previous license remains applicable to all code prior to 0.4.0. - -Enhancements: - -* Printing of failing examples. I was finding that the pytest runner was not - doing a good job of displaying these, and that Hypothesis itself could do - much better. -* Drop dependency on six for cross-version compatibility. It was easy - enough to write the shim for the small set of features that we care about - and this lets us avoid a moderately complex dependency. -* Some improvements to statistical distribution of selecting from small (<= - 3 elements) -* Improvements to parameter selection for finding examples. - -Bugs fixed: - -* could_have_produced for lists, dicts and other collections would not have - examined the elements and thus when using a union of different types of - list this could result in Hypothesis getting confused and passing a value - to the wrong strategy. This could potentially result in exceptions being - thrown from within simplification. -* sampled_from would not work correctly on a single element list. -* Hypothesis could get *very* confused by values which are - equal despite having different types being used in descriptors. Hypothesis - now has its own more specific version of equality it uses for descriptors - and tracking. It is always more fine grained than Python equality: Things - considered != are not considered equal by hypothesis, but some things that - are considered == are distinguished. If your test suite uses both frozenset - and set tests this bug is probably affecting you. - ------------------- -0.3.2 - 2015-01-16 ------------------- - -* Fix a bug where if you specified floats_in_range with integer arguments - Hypothesis would error in example simplification. -* Improve the statistical distribution of the floats you get for the - floats_in_range strategy. I'm not sure whether this will affect users in - practice but it took my tests for various conditions from flaky to rock - solid so it at the very least improves discovery of the artificial cases - I'm looking for. -* Improved repr() for strategies and RandomWithSeed instances. -* Add detection for flaky test cases where hypothesis managed to find an - example which breaks it but on the final invocation of the test it does - not raise an error. This will typically happen with too much recursion - errors but could conceivably happen in other circumstances too. -* Provide a "derandomized" mode. This allows you to run hypothesis with - zero real randomization, making your build nice and deterministic. The - tests run with a seed calculated from the function they're testing so you - should still get a good distribution of test cases. -* Add a mechanism for more conveniently defining tests which just sample - from some collection. -* Fix for a really subtle bug deep in the internals of the strategy table. - In some circumstances if you were to define instance strategies for both - a parent class and one or more of its subclasses you would under some - circumstances get the strategy for the wrong superclass of an instance. - It is very unlikely anyone has ever encountered this in the wild, but it - is conceivably possible given that a mix of namedtuple and tuple are used - fairly extensively inside hypothesis which do exhibit this pattern of - strategy. - - ------------------- -0.3.1 - 2015-01-13 ------------------- - -* Support for generation of frozenset and Random values -* Correct handling of the case where a called function mutates it argument. - This involved introducing a notion of a strategies knowing how to copy - their argument. The default method should be entirely acceptable and the - worst case is that it will continue to have the old behaviour if you - don't mark your strategy as mutable, so this shouldn't break anything. -* Fix for a bug where some strategies did not correctly implement - could_have_produced. It is very unlikely that any of these would have - been seen in the wild, and the consequences if they had been would have - been minor. -* Re-export the @given decorator from the main hypothesis namespace. It's - still available at the old location too. -* Minor performance optimisation for simplifying long lists. - - ------------------- -0.3.0 - 2015-01-12 ------------------- - -* Complete redesign of the data generation system. Extreme breaking change - for anyone who was previously writing their own SearchStrategy - implementations. These will not work any more and you'll need to modify - them. -* New settings system allowing more global and modular control of Verifier - behaviour. -* Decouple SearchStrategy from the StrategyTable. This leads to much more - composable code which is a lot easier to understand. -* A significant amount of internal API renaming and moving. This may also - break your code. -* Expanded available descriptors, allowing for generating integers or - floats in a specific range. -* Significantly more robust. A very large number of small bug fixes, none - of which anyone is likely to have ever noticed. -* Deprecation of support for pypy and python 3 prior to 3.3. 3.3 and 3.4. - Supported versions are 2.7.x, 3.3.x, 3.4.x. I expect all of these to - remain officially supported for a very long time. I would not be - surprised to add pypy support back in later but I'm not going to do so - until I know someone cares about it. In the meantime it will probably - still work. - - ------------------- -0.2.2 - 2015-01-08 ------------------- - -* Fix an embarrassing complete failure of the installer caused by my being - bad at version control - - ------------------- -0.2.1 - 2015-01-07 ------------------- - -* Fix a bug in the new stateful testing feature where you could make - __init__ a @requires method. Simplification would not always work if the - prune method was able to successfully shrink the test. - - ------------------- -0.2.0 - 2015-01-07 ------------------- - -* It's aliiive. -* Improve python 3 support using six. -* Distinguish between byte and unicode types. -* Fix issues where FloatStrategy could raise. -* Allow stateful testing to request constructor args. -* Fix for issue where test annotations would timeout based on when the - module was loaded instead of when the test started - - ------------------- -0.1.4 - 2013-12-14 ------------------- - -* Make verification runs time bounded with a configurable timeout - - ------------------- -0.1.3 - 2013-05-03 ------------------- - -* Bugfix: Stateful testing behaved incorrectly with subclassing. -* Complex number support -* support for recursive strategies -* different error for hypotheses with unsatisfiable assumptions - ------------------- -0.1.2 - 2013-03-24 ------------------- - -* Bugfix: Stateful testing was not minimizing correctly and could - throw exceptions. -* Better support for recursive strategies. -* Support for named tuples. -* Much faster integer generation. - - ------------------- -0.1.1 - 2013-03-24 ------------------- - -* Python 3.x support via 2to3. -* Use new style classes (oops). - - ------------------- -0.1.0 - 2013-03-23 ------------------- - -* Introduce stateful testing. -* Massive rewrite of internals to add flags and strategies. - - ------------------- -0.0.5 - 2013-03-13 ------------------- - -* No changes except trying to fix packaging - ------------------- -0.0.4 - 2013-03-13 ------------------- - -* No changes except that I checked in a failing test case for 0.0.3 - so had to replace the release. Doh - ------------------- -0.0.3 - 2013-03-13 ------------------- - -* Improved a few internals. -* Opened up creating generators from instances as a general API. -* Test integration. - ------------------- -0.0.2 - 2013-03-12 ------------------- - -* Starting to tighten up on the internals. -* Change API to allow more flexibility in configuration. -* More testing. - ------------------- -0.0.1 - 2013-03-10 ------------------- - -* Initial release. -* Basic working prototype. Demonstrates idea, probably shouldn't be used. diff -Nru python-hypothesis-3.44.1/docs/community.rst python-hypothesis-3.71.11/docs/community.rst --- python-hypothesis-3.44.1/docs/community.rst 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/docs/community.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -========= -Community -========= - -The Hypothesis community is small for the moment but is full of excellent people -who can answer your questions and help you out. Please do join us. - -The two major places for community discussion are: - -* `The mailing list `_. -* An IRC channel, #hypothesis on freenode, which is more active than the mailing list. - -Feel free to use these to ask for help, provide feedback, or discuss anything remotely -Hypothesis related at all. - ---------------- -Code of conduct ---------------- - -Hypothesis's community is an inclusive space, and everyone in it is expected to abide by a code of conduct. - -At the high level the code of conduct goes like this: - -1. Be kind -2. Be respectful -3. Be helpful - -While it is impossible to enumerate everything that is unkind, disrespectful or unhelpful, here are some specific things that are definitely against the code of conduct: - -1. -isms and -phobias (e.g. racism, sexism, transphobia and homophobia) are unkind, disrespectful *and* unhelpful. Just don't. -2. All software is broken. This is not a moral failing on the part of the authors. Don't give people a hard time for bad code. -3. It's OK not to know things. Everybody was a beginner once, nobody should be made to feel bad for it. -4. It's OK not to *want* to know something. If you think someone's question is fundamentally flawed, you should still ask permission before explaining what they should actually be asking. -5. Note that "I was just joking" is not a valid defence. - -What happens when this goes wrong? -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -For minor infractions, I'll just call people on it and ask them to apologise and not do it again. You should -feel free to do this too if you're comfortable doing so. - -Major infractions and repeat offenders will be banned from the community. - -Also, people who have a track record of bad behaviour outside of the Hypothesis community may be banned even -if they obey all these rules if their presence is making people uncomfortable. - -At the current volume level it's not hard for me to pay attention to the whole community, but if you think I've -missed something please feel free to alert me. You can either message me as DRMacIver on freenode or send a me -an email at david@drmaciver.com. diff -Nru python-hypothesis-3.44.1/docs/conf.py python-hypothesis-3.71.11/docs/conf.py --- python-hypothesis-3.44.1/docs/conf.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/docs/conf.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,136 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -# -*- coding: utf-8 -*- - -from __future__ import division, print_function, absolute_import - -import os -import sys -import datetime - -sys.path.append( - os.path.join(os.path.dirname(__file__), '..', 'src') -) - - -autodoc_member_order = 'bysource' - -extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.doctest', - 'sphinx.ext.extlinks', - 'sphinx.ext.viewcode', - 'sphinx.ext.intersphinx', -] - -templates_path = ['_templates'] - -source_suffix = '.rst' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'Hypothesis' -copyright = u'2013-%s, David R. MacIver' % datetime.datetime.utcnow().year -author = u'David R. MacIver' - -_d = {} -with open(os.path.join(os.path.dirname(__file__), '..', 'src', - 'hypothesis', 'version.py')) as f: - exec(f.read(), _d) - version = _d['__version__'] - release = _d['__version__'] - -language = None - -exclude_patterns = ['_build'] - -pygments_style = 'sphinx' - -todo_include_todos = False - -intersphinx_mapping = { - 'python': ('https://docs.python.org/3/', None), - 'numpy': ('https://docs.scipy.org/doc/numpy/', None), - 'pandas': ('https://pandas.pydata.org/pandas-docs/stable/', None), - 'pytest': ('https://docs.pytest.org/en/stable/', None), -} - -autodoc_mock_imports = ['numpy', 'pandas'] - -doctest_global_setup = ''' -# Some standard imports -from hypothesis import * -from hypothesis.strategies import * -# Run deterministically, and don't save examples -import random -random.seed(0) -doctest_settings = settings(database=None, derandomize=True) -settings.register_profile('doctests', doctest_settings) -settings.load_profile('doctests') -# Never show deprecated behaviour in code examples -import warnings -warnings.filterwarnings('error', category=DeprecationWarning) -''' - -# This config value must be a dictionary of external sites, mapping unique -# short alias names to a base URL and a prefix. -# See http://sphinx-doc.org/ext/extlinks.html -_repo = 'https://github.com/HypothesisWorks/hypothesis-python/' -extlinks = { - 'commit': (_repo + 'commit/%s', 'commit '), - 'gh-file': (_repo + 'blob/master/%s', ''), - 'gh-link': (_repo + '%s', ''), - 'issue': (_repo + 'issues/%s', 'issue #'), - 'pull': (_repo + 'pulls/%s', 'pull request #'), - 'pypi': ('https://pypi.python.org/pypi/%s', ''), -} - -# -- Options for HTML output ---------------------------------------------- - -if os.environ.get('READTHEDOCS', None) != 'True': - # only import and set the theme if we're building docs locally - import sphinx_rtd_theme - html_theme = 'sphinx_rtd_theme' - html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] - -html_static_path = ['_static'] - -htmlhelp_basename = 'Hypothesisdoc' - -# -- Options for LaTeX output --------------------------------------------- - -latex_elements = { -} - -latex_documents = [ - (master_doc, 'Hypothesis.tex', u'Hypothesis Documentation', - u'David R. MacIver', 'manual'), -] - -man_pages = [ - (master_doc, 'hypothesis', u'Hypothesis Documentation', - [author], 1) -] - -texinfo_documents = [ - (master_doc, 'Hypothesis', u'Hypothesis Documentation', - author, 'Hypothesis', 'Advanced property-based testing for Python.', - 'Miscellaneous'), -] diff -Nru python-hypothesis-3.44.1/docs/database.rst python-hypothesis-3.71.11/docs/database.rst --- python-hypothesis-3.44.1/docs/database.rst 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/docs/database.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,67 +0,0 @@ -=============================== -The Hypothesis Example Database -=============================== - -When Hypothesis finds a bug it stores enough information in its database to reproduce it. This -enables you to have a classic testing workflow of find a bug, fix a bug, and be confident that -this is actually doing the right thing because Hypothesis will start by retrying the examples that -broke things last time. - ------------ -Limitations ------------ - -The database is best thought of as a cache that you never need to invalidate: Information may be -lost when you upgrade a Hypothesis version or change your test, so you shouldn't rely on it for -correctness - if there's an example you want to ensure occurs each time then :ref:`there's a feature for -including them in your source code ` - but it helps the development -workflow considerably by making sure that the examples you've just found are reproduced. - --------------- -File locations --------------- - -The default storage format is as a fairly opaque directory structure. Each test -corresponds to a directory, and each example to a file within that directory. -The standard location for it is .hypothesis/examples in your current working -directory. You can override this, either by setting either the database\_file property on -a settings object (you probably want to specify it on settings.default) or by setting the -HYPOTHESIS\_DATABASE\_FILE environment variable. - -There is also a legacy sqlite3 based format. This is mostly still supported for -compatibility reasons, and support will be dropped in some future version of -Hypothesis. If you use a database file name ending in .db, .sqlite or .sqlite3 -that format will be used instead. - --------------------------------------------- -Upgrading Hypothesis and changing your tests --------------------------------------------- - -The design of the Hypothesis database is such that you can put arbitrary data in the database -and not get wrong behaviour. When you upgrade Hypothesis, old data *might* be invalidated, but -this should happen transparently. It should never be the case that e.g. changing the strategy -that generates an argument sometimes gives you data from the old strategy. - ------------------------------ -Sharing your example database ------------------------------ - -.. note:: - If specific examples are important for correctness you should use the - :func:`@example ` decorator, as the example database may discard entries due to - changes in your code or dependencies. For most users, we therefore - recommend using the example database locally and possibly persisting it - between CI builds, but not tracking it under version control. - -The examples database can be shared simply by checking the directory into -version control, for example with the following ``.gitignore``:: - - # Ignore files cached by Hypothesis... - .hypothesis/ - # except for the examples directory - !.hypothesis/examples/ - -Like everything under ``.hypothesis/``, the examples directory will be -transparently created on demand. Unlike the other subdirectories, -``examples/`` is designed to handle merges, deletes, etc if you just add the -directory into git, mercurial, or any similar version control system. diff -Nru python-hypothesis-3.44.1/docs/data.rst python-hypothesis-3.71.11/docs/data.rst --- python-hypothesis-3.44.1/docs/data.rst 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/docs/data.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,336 +0,0 @@ -============================= -What you can generate and how -============================= - -*Most things should be easy to generate and everything should be possible.* - -To support this principle Hypothesis provides strategies for most built-in -types with arguments to constrain or adjust the output, as well as higher-order -strategies that can be composed to generate more complex types. - -This document is a guide to what strategies are available for generating data -and how to build them. Strategies have a variety of other important internal -features, such as how they simplify, but the data they can generate is the only -public part of their API. - -Functions for building strategies are all available in the hypothesis.strategies -module. The salient functions from it are as follows: - -.. automodule:: hypothesis.strategies - :members: - -.. _shrinking: - -~~~~~~~~~ -Shrinking -~~~~~~~~~ - -When using strategies it is worth thinking about how the data *shrinks*. -Shrinking is the process by which Hypothesis tries to produce human readable -examples when it finds a failure - it takes a complex example and turns it -into a simpler one. - -Each strategy defines an order in which it shrinks - you won't usually need to -care about this much, but it can be worth being aware of as it can affect what -the best way to write your own strategies is. - -The exact shrinking behaviour is not a guaranteed part of the API, but it -doesn't change that often and when it does it's usually because we think the -new way produces nicer examples. - -Possibly the most important one to be aware of is -:func:`~hypothesis.strategies.one_of`, which has a preference for values -produced by strategies earlier in its argument list. Most of the others should -largely "do the right thing" without you having to think about it. - - -~~~~~~~~~~~~~~~~~~~ -Adapting strategies -~~~~~~~~~~~~~~~~~~~ - -Often it is the case that a strategy doesn't produce exactly what you want it -to and you need to adapt it. Sometimes you can do this in the test, but this -hurts reuse because you then have to repeat the adaption in every test. - -Hypothesis gives you ways to build strategies from other strategies given -functions for transforming the data. - -------- -Mapping -------- - -``map`` is probably the easiest and most useful of these to use. If you have a -strategy ``s`` and a function ``f``, then an example ``s.map(f).example()`` is -``f(s.example())``, i.e. we draw an example from ``s`` and then apply ``f`` to it. - -e.g.: - -.. doctest:: - - >>> lists(integers()).map(sorted).example() - [-158104205405429173199472404790070005365, -131418136966037518992825706738877085689, -49279168042092131242764306881569217089, 2564476464308589627769617001898573635] - -Note that many things that you might use mapping for can also be done with -:func:`~hypothesis.strategies.builds`. - -.. _filtering: - ---------- -Filtering ---------- - -``filter`` lets you reject some examples. ``s.filter(f).example()`` is some -example of ``s`` such that ``f(example)`` is truthy. - -.. doctest:: - - >>> integers().filter(lambda x: x > 11).example() - 87034457550488036879331335314643907276 - >>> integers().filter(lambda x: x > 11).example() - 145321388071838806577381808280858991039 - -It's important to note that ``filter`` isn't magic and if your condition is too -hard to satisfy then this can fail: - -.. doctest:: - - >>> integers().filter(lambda x: False).example() - Traceback (most recent call last): - ... - hypothesis.errors.NoExamples: Could not find any valid examples in 20 tries - -In general you should try to use ``filter`` only to avoid corner cases that you -don't want rather than attempting to cut out a large chunk of the search space. - -A technique that often works well here is to use map to first transform the data -and then use ``filter`` to remove things that didn't work out. So for example if -you wanted pairs of integers (x,y) such that x < y you could do the following: - - -.. doctest:: - - >>> tuples(integers(), integers()).map(sorted).filter(lambda x: x[0] < x[1]).example() - [-145066798798423346485767563193971626126, -19139012562996970506504843426153630262] - -.. _flatmap: - ----------------------------- -Chaining strategies together ----------------------------- - -Finally there is ``flatmap``. ``flatmap`` draws an example, then turns that -example into a strategy, then draws an example from *that* strategy. - -It may not be obvious why you want this at first, but it turns out to be -quite useful because it lets you generate different types of data with -relationships to each other. - -For example suppose we wanted to generate a list of lists of the same -length: - -.. code-block:: pycon - - >>> rectangle_lists = integers(min_value=0, max_value=10).flatmap( - ... lambda n: lists(lists(integers(), min_size=n, max_size=n))) - >>> find(rectangle_lists, lambda x: True) - [] - >>> find(rectangle_lists, lambda x: len(x) >= 10) - [[], [], [], [], [], [], [], [], [], []] - >>> find(rectangle_lists, lambda t: len(t) >= 3 and len(t[0]) >= 3) - [[0, 0, 0], [0, 0, 0], [0, 0, 0]] - >>> find(rectangle_lists, lambda t: sum(len(s) for s in t) >= 10) - [[0], [0], [0], [0], [0], [0], [0], [0], [0], [0]] - -In this example we first choose a length for our tuples, then we build a -strategy which generates lists containing lists precisely of that length. The -finds show what simple examples for this look like. - -Most of the time you probably don't want ``flatmap``, but unlike ``filter`` and -``map`` which are just conveniences for things you could just do in your tests, -``flatmap`` allows genuinely new data generation that you wouldn't otherwise be -able to easily do. - -(If you know Haskell: Yes, this is more or less a monadic bind. If you don't -know Haskell, ignore everything in these parentheses. You do not need to -understand anything about monads to use this, or anything else in Hypothesis). - - --------------- -Recursive data --------------- - -Sometimes the data you want to generate has a recursive definition. e.g. if you -wanted to generate JSON data, valid JSON is: - -1. Any float, any boolean, any unicode string. -2. Any list of valid JSON data -3. Any dictionary mapping unicode strings to valid JSON data. - -The problem is that you cannot call a strategy recursively and expect it to not just -blow up and eat all your memory. The other problem here is that not all unicode strings -display consistently on different machines, so we'll restrict them in our doctest. - -The way Hypothesis handles this is with the :py:func:`recursive` function -which you pass in a base case and a function that, given a strategy for your data type, -returns a new strategy for it. So for example: - -.. doctest:: - - >>> from string import printable; from pprint import pprint - >>> json = recursive(none() | booleans() | floats() | text(printable), - ... lambda children: lists(children) | dictionaries(text(printable), children)) - >>> pprint(json.example()) - {'': 'wkP!4', - '\nLdy': None, - '"uHuds:8a{h\\:694K~{mY>a1yA:#CmDYb': {}, - '#1J1': [')gnP', - inf, - ['6', 11881275561.716116, "v'A?qyp_sB\n$62g", ''], - -1e-05, - 'aF\rl', - [-2.599459969184803e+250, True, True, None], - [True, - '9qP\x0bnUJH5', - 3.0741121405774857e-131, - None, - '', - -inf, - 'L&', - 1.5, - False, - None]], - 'cx.': None} - >>> pprint(json.example()) - [5.321430774293539e+16, [], 1.1045114769709281e-125] - >>> pprint(json.example()) - {'a': []} - -That is, we start with our leaf data and then we augment it by allowing lists and dictionaries of anything we can generate as JSON data. - -The size control of this works by limiting the maximum number of values that can be drawn from the base strategy. So for example if -we wanted to only generate really small JSON we could do this as: - - -.. doctest:: - - >>> small_lists = recursive(booleans(), lists, max_leaves=5) - >>> small_lists.example() - True - >>> small_lists.example() - [False, False, True, True, True] - >>> small_lists.example() - True - -.. _composite-strategies: - -~~~~~~~~~~~~~~~~~~~~ -Composite strategies -~~~~~~~~~~~~~~~~~~~~ - -The :func:`@composite ` decorator lets you combine other strategies in more or less -arbitrary ways. It's probably the main thing you'll want to use for -complicated custom strategies. - -The composite decorator works by giving you a function as the first argument -that you can use to draw examples from other strategies. For example, the -following gives you a list and an index into it: - -.. doctest:: - - >>> @composite - ... def list_and_index(draw, elements=integers()): - ... xs = draw(lists(elements, min_size=1)) - ... i = draw(integers(min_value=0, max_value=len(xs) - 1)) - ... return (xs, i) - -``draw(s)`` is a function that should be thought of as returning ``s.example()``, -except that the result is reproducible and will minimize correctly. The -decorated function has the initial argument removed from the list, but will -accept all the others in the expected order. Defaults are preserved. - -.. doctest:: - - >>> list_and_index() - list_and_index() - >>> list_and_index().example() - ([-57328788235238539257894870261848707608], 0) - - >>> list_and_index(booleans()) - list_and_index(elements=booleans()) - >>> list_and_index(booleans()).example() - ([True], 0) - -Note that the repr will work exactly like it does for all the built-in -strategies: it will be a function that you can call to get the strategy in -question, with values provided only if they do not match the defaults. - -You can use :func:`assume ` inside composite functions: - -.. code-block:: python - - @composite - def distinct_strings_with_common_characters(draw): - x = draw(text(), min_size=1) - y = draw(text(alphabet=x)) - assume(x != y) - return (x, y) - -This works as :func:`assume ` normally would, filtering out any examples for which the -passed in argument is falsey. - - -.. _interactive-draw: - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Drawing interactively in tests -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -There is also the :func:`~hypothesis.strategies.data` strategy, which gives you a means of using -strategies interactively. Rather than having to specify everything up front in -:func:`@given ` you can draw from strategies in the body of your test: - -.. code-block:: python - - @given(data()) - def test_draw_sequentially(data): - x = data.draw(integers()) - y = data.draw(integers(min_value=x)) - assert x < y - -If the test fails, each draw will be printed with the falsifying example. e.g. -the above is wrong (it has a boundary condition error), so will print: - -.. code-block:: pycon - - Falsifying example: test_draw_sequentially(data=data(...)) - Draw 1: 0 - Draw 2: 0 - -As you can see, data drawn this way is simplified as usual. - -Test functions using the :func:`~hypothesis.strategies.data` strategy do not support explicit -:func:`@example(...) `\ s. In this case, the best option is usually to construct -your data with :func:`@composite ` or the explicit example, and unpack this within -the body of the test. - -Optionally, you can provide a label to identify values generated by each call -to ``data.draw()``. These labels can be used to identify values in the output -of a falsifying example. - -For instance: - -.. code-block:: python - - @given(data()) - def test_draw_sequentially(data): - x = data.draw(integers(), label='First number') - y = data.draw(integers(min_value=x), label='Second number') - assert x < y - -will produce the output: - -.. code-block:: pycon - - Falsifying example: test_draw_sequentially(data=data(...)) - Draw 1 (First number): 0 - Draw 2 (Second number): 0 diff -Nru python-hypothesis-3.44.1/docs/details.rst python-hypothesis-3.71.11/docs/details.rst --- python-hypothesis-3.44.1/docs/details.rst 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/docs/details.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,544 +0,0 @@ -============================= -Details and advanced features -============================= - -This is an account of slightly less common Hypothesis features that you don't need -to get started but will nevertheless make your life easier. - - ----------------------- -Additional test output ----------------------- - -Normally the output of a failing test will look something like: - -.. code:: - - Falsifying example: test_a_thing(x=1, y="foo") - -With the ``repr`` of each keyword argument being printed. - -Sometimes this isn't enough, either because you have values with a ``repr`` that -isn't very descriptive or because you need to see the output of some -intermediate steps of your test. That's where the ``note`` function comes in: - -.. doctest:: - - >>> from hypothesis import given, note, strategies as st - >>> @given(st.lists(st.integers()), st.randoms()) - ... def test_shuffle_is_noop(ls, r): - ... ls2 = list(ls) - ... r.shuffle(ls2) - ... note("Shuffle: %r" % (ls2)) - ... assert ls == ls2 - ... - >>> try: - ... test_shuffle_is_noop() - ... except AssertionError: - ... print('ls != ls2') - Falsifying example: test_shuffle_is_noop(ls=[0, 0, 1], r=RandomWithSeed(0)) - Shuffle: [0, 1, 0] - ls != ls2 - -The note is printed in the final run of the test in order to include any -additional information you might need in your test. - - -.. _statistics: - ---------------- -Test Statistics ---------------- - -If you are using py.test you can see a number of statistics about the executed tests -by passing the command line argument ``--hypothesis-show-statistics``. This will include -some general statistics about the test: - -For example if you ran the following with ``--hypothesis-show-statistics``: - -.. code-block:: python - - from hypothesis import given, strategies as st - - @given(st.integers()) - def test_integers(i): - pass - - -You would see: - -.. code-block:: none - - test_integers: - - - 100 passing examples, 0 failing examples, 0 invalid examples - - Typical runtimes: ~ 1ms - - Fraction of time spent in data generation: ~ 12% - - Stopped because settings.max_examples=100 - -The final "Stopped because" line is particularly important to note: It tells you the -setting value that determined when the test should stop trying new examples. This -can be useful for understanding the behaviour of your tests. Ideally you'd always want -this to be ``max_examples``. - -In some cases (such as filtered and recursive strategies) you will see events mentioned -which describe some aspect of the data generation: - -.. code-block:: python - - from hypothesis import given, strategies as st - - @given(st.integers().filter(lambda x: x % 2 == 0)) - def test_even_integers(i): - pass - -You would see something like: - -.. code-block:: none - - test_even_integers: - - - 100 passing examples, 0 failing examples, 36 invalid examples - - Typical runtimes: 0-1 ms - - Fraction of time spent in data generation: ~ 16% - - Stopped because settings.max_examples=100 - - Events: - * 80.88%, Retried draw from integers().filter(lambda x: ) to satisfy filter - * 26.47%, Aborted test because unable to satisfy integers().filter(lambda x: ) - -You can also mark custom events in a test using the ``event`` function: - -.. autofunction:: hypothesis.event - -.. code:: python - - from hypothesis import given, event, strategies as st - - @given(st.integers().filter(lambda x: x % 2 == 0)) - def test_even_integers(i): - event("i mod 3 = %d" % (i % 3,)) - - -You will then see output like: - -.. code-block:: none - - test_even_integers: - - - 100 passing examples, 0 failing examples, 38 invalid examples - - Typical runtimes: 0-1 ms - - Fraction of time spent in data generation: ~ 16% - - Stopped because settings.max_examples=100 - - Events: - * 80.43%, Retried draw from integers().filter(lambda x: ) to satisfy filter - * 31.88%, i mod 3 = 0 - * 27.54%, Aborted test because unable to satisfy integers().filter(lambda x: ) - * 21.74%, i mod 3 = 1 - * 18.84%, i mod 3 = 2 - -Arguments to ``event`` can be any hashable type, but two events will be considered the same -if they are the same when converted to a string with ``str``. - ------------------- -Making assumptions ------------------- - -Sometimes Hypothesis doesn't give you exactly the right sort of data you want - it's -mostly of the right shape, but some examples won't work and you don't want to care about -them. You *can* just ignore these by aborting the test early, but this runs the risk of -accidentally testing a lot less than you think you are. Also it would be nice to spend -less time on bad examples - if you're running 200 examples per test (the default) and -it turns out 150 of those examples don't match your needs, that's a lot of wasted time. - -.. autofunction:: hypothesis.assume - -For example suppose you had the following test: - - -.. code:: python - - @given(floats()) - def test_negation_is_self_inverse(x): - assert x == -(-x) - - -Running this gives us: - -.. code:: - - Falsifying example: test_negation_is_self_inverse(x=float('nan')) - AssertionError - -This is annoying. We know about NaN and don't really care about it, but as soon as Hypothesis -finds a NaN example it will get distracted by that and tell us about it. Also the test will -fail and we want it to pass. - -So lets block off this particular example: - -.. code:: python - - from math import isnan - - @given(floats()) - def test_negation_is_self_inverse_for_non_nan(x): - assume(not isnan(x)) - assert x == -(-x) - -And this passes without a problem. - -In order to avoid the easy trap where you assume a lot more than you intended, Hypothesis -will fail a test when it can't find enough examples passing the assumption. - -If we'd written: - -.. code:: python - - @given(floats()) - def test_negation_is_self_inverse_for_non_nan(x): - assume(False) - assert x == -(-x) - -Then on running we'd have got the exception: - -.. code:: - - Unsatisfiable: Unable to satisfy assumptions of hypothesis test_negation_is_self_inverse_for_non_nan. Only 0 examples considered satisfied assumptions - -~~~~~~~~~~~~~~~~~~~ -How good is assume? -~~~~~~~~~~~~~~~~~~~ - -Hypothesis has an adaptive exploration strategy to try to avoid things which falsify -assumptions, which should generally result in it still being able to find examples in -hard to find situations. - -Suppose we had the following: - - -.. code:: python - - @given(lists(integers())) - def test_sum_is_positive(xs): - assert sum(xs) > 0 - -Unsurprisingly this fails and gives the falsifying example ``[]``. - -Adding ``assume(xs)`` to this removes the trivial empty example and gives us ``[0]``. - -Adding ``assume(all(x > 0 for x in xs))`` and it passes: the sum of a list of -positive integers is positive. - -The reason that this should be surprising is not that it doesn't find a -counter-example, but that it finds enough examples at all. - -In order to make sure something interesting is happening, suppose we wanted to -try this for long lists. e.g. suppose we added an ``assume(len(xs) > 10)`` to it. -This should basically never find an example: a naive strategy would find fewer -than one in a thousand examples, because if each element of the list is -negative with probability one-half, you'd have to have ten of these go the right -way by chance. In the default configuration Hypothesis gives up long before -it's tried 1000 examples (by default it tries 200). - -Here's what happens if we try to run this: - - -.. code:: python - - @given(lists(integers())) - def test_sum_is_positive(xs): - assume(len(xs) > 10) - assume(all(x > 0 for x in xs)) - print(xs) - assert sum(xs) > 0 - - In: test_sum_is_positive() - [17, 12, 7, 13, 11, 3, 6, 9, 8, 11, 47, 27, 1, 31, 1] - [6, 2, 29, 30, 25, 34, 19, 15, 50, 16, 10, 3, 16] - [25, 17, 9, 19, 15, 2, 2, 4, 22, 10, 10, 27, 3, 1, 14, 17, 13, 8, 16, 9, 2... - [17, 65, 78, 1, 8, 29, 2, 79, 28, 18, 39] - [13, 26, 8, 3, 4, 76, 6, 14, 20, 27, 21, 32, 14, 42, 9, 24, 33, 9, 5, 15, ... - [2, 1, 2, 2, 3, 10, 12, 11, 21, 11, 1, 16] - -As you can see, Hypothesis doesn't find *many* examples here, but it finds some - enough to -keep it happy. - -In general if you *can* shape your strategies better to your tests you should - for example -:py:func:`integers(1, 1000) ` is a lot better than -``assume(1 <= x <= 1000)``, but ``assume`` will take you a long way if you can't. - ---------------------- -Defining strategies ---------------------- - -The type of object that is used to explore the examples given to your test -function is called a :class:`~hypothesis.SearchStrategy`. -These are created using the functions -exposed in the :mod:`hypothesis.strategies` module. - -Many of these strategies expose a variety of arguments you can use to customize -generation. For example for integers you can specify ``min`` and ``max`` values of -integers you want. -If you want to see exactly what a strategy produces you can ask for an example: - -.. doctest:: - - >>> integers(min_value=0, max_value=10).example() - 9 - -Many strategies are built out of other strategies. For example, if you want -to define a tuple you need to say what goes in each element: - -.. doctest:: - - >>> from hypothesis.strategies import tuples - >>> tuples(integers(), integers()).example() - (-85296636193678268231691518597782489127, 68871684356256783618296489618877951982) - -Further details are :doc:`available in a separate document `. - ------------------------------------- -The gory details of given parameters ------------------------------------- - -.. autofunction:: hypothesis.given - -The :func:`@given ` decorator may be used -to specify which arguments of a function should -be parametrized over. You can use either positional or keyword arguments or a mixture -of the two. - -For example all of the following are valid uses: - -.. code:: python - - @given(integers(), integers()) - def a(x, y): - pass - - @given(integers()) - def b(x, y): - pass - - @given(y=integers()) - def c(x, y): - pass - - @given(x=integers()) - def d(x, y): - pass - - @given(x=integers(), y=integers()) - def e(x, **kwargs): - pass - - @given(x=integers(), y=integers()) - def f(x, *args, **kwargs): - pass - - - class SomeTest(TestCase): - @given(integers()) - def test_a_thing(self, x): - pass - -The following are not: - -.. code:: python - - @given(integers(), integers(), integers()) - def g(x, y): - pass - - @given(integers()) - def h(x, *args): - pass - - @given(integers(), x=integers()) - def i(x, y): - pass - - @given() - def j(x, y): - pass - - -The rules for determining what are valid uses of ``given`` are as follows: - -1. You may pass any keyword argument to ``given``. -2. Positional arguments to ``given`` are equivalent to the rightmost named - arguments for the test function. -3. Positional arguments may not be used if the underlying test function has - varargs, arbitrary keywords, or keyword-only arguments. -4. Functions tested with ``given`` may not have any defaults. - -The reason for the "rightmost named arguments" behaviour is so that -using :func:`@given ` with instance methods works: ``self`` -will be passed to the function as normal and not be parametrized over. - -The function returned by given has all the same arguments as the original -test, minus those that are filled in by ``given``. - -------------------------- -Custom function execution -------------------------- - -Hypothesis provides you with a hook that lets you control how it runs -examples. - -This lets you do things like set up and tear down around each example, run -examples in a subprocess, transform coroutine tests into normal tests, etc. - -The way this works is by introducing the concept of an executor. An executor -is essentially a function that takes a block of code and run it. The default -executor is: - -.. code:: python - - def default_executor(function): - return function() - -You define executors by defining a method execute_example on a class. Any -test methods on that class with :func:`@given ` used on them will use -``self.execute_example`` as an executor with which to run tests. For example, -the following executor runs all its code twice: - -.. code:: python - - from unittest import TestCase - - class TestTryReallyHard(TestCase): - @given(integers()) - def test_something(self, i): - perform_some_unreliable_operation(i) - - def execute_example(self, f): - f() - return f() - -Note: The functions you use in map, etc. will run *inside* the executor. i.e. -they will not be called until you invoke the function passed to ``execute_example``. - -An executor must be able to handle being passed a function which returns None, -otherwise it won't be able to run normal test cases. So for example the following -executor is invalid: - -.. code:: python - - from unittest import TestCase - - class TestRunTwice(TestCase): - def execute_example(self, f): - return f()() - -and should be rewritten as: - -.. code:: python - - from unittest import TestCase - import inspect - - class TestRunTwice(TestCase): - def execute_example(self, f): - result = f() - if inspect.isfunction(result): - result = result() - return result - - -------------------------------- -Using Hypothesis to find values -------------------------------- - -You can use Hypothesis's data exploration features to find values satisfying -some predicate. This is generally useful for exploring custom strategies -defined with :func:`@composite `, or -experimenting with conditions for filtering data. - -.. autofunction:: hypothesis.find - -.. doctest:: - - >>> from hypothesis import find - >>> from hypothesis.strategies import sets, lists, integers - >>> find(lists(integers()), lambda x: sum(x) >= 10) - [10] - >>> find(lists(integers()), lambda x: sum(x) >= 10 and len(x) >= 3) - [0, 0, 10] - >>> find(sets(integers()), lambda x: sum(x) >= 10 and len(x) >= 3) - {0, 1, 9} - -The first argument to :func:`~hypothesis.find` describes data in the usual way for an argument to -:func:`~hypothesis.given`, and supports :doc:`all the same data types `. The second is a -predicate it must satisfy. - -Of course not all conditions are satisfiable. If you ask Hypothesis for an -example to a condition that is always false it will raise an error: - -.. doctest:: - - >>> find(integers(), lambda x: False) - Traceback (most recent call last): - ... - hypothesis.errors.NoSuchExample: No examples of condition lambda x: - -(The ``lambda x: unknown`` is because Hypothesis can't retrieve the source code -of lambdas from the interactive python console. It gives a better error message -most of the time which contains the actual condition) - - -.. _type-inference: - -------------------- -Inferred Strategies -------------------- - -In some cases, Hypothesis can work out what to do when you omit arguments. -This is based on introspection, *not* magic, and therefore has well-defined -limits. - -:func:`~hypothesis.strategies.builds` will check the signature of the -``target`` (using :func:`~python:inspect.getfullargspec`). -If there are required arguments with type annotations and -no strategy was passed to :func:`~hypothesis.strategies.builds`, -:func:`~hypothesis.strategies.from_type` is used to fill them in. -You can also pass the special value :const:`hypothesis.infer` as a keyword -argument, to force this inference for arguments with a default value. - -.. doctest:: - - >>> def func(a: int, b: str): - ... return [a, b] - >>> builds(func).example() - [72627971792323936471739212691379790782, ''] - -:func:`@given ` does not perform any implicit inference -for required arguments, as this would break compatibility with pytest fixtures. -:const:`~hypothesis.infer` can be used as a keyword argument to explicitly -fill in an argument from its type annotation. - -.. code:: python - - @given(a=infer) - def test(a: int): pass - # is equivalent to - @given(a=integers()) - def test(a): pass - -~~~~~~~~~~~ -Limitations -~~~~~~~~~~~ - -:pep:`3107` type annotations are not supported on Python 2, and Hypothesis -does not inspect :pep:`484` type comments at runtime. While -:func:`~hypothesis.strategies.from_type` will work as usual, inference in -:func:`~hypothesis.strategies.builds` and :func:`@given ` -will only work if you manually create the ``__annotations__`` attribute -(e.g. by using ``@annotations(...)`` and ``@returns(...)`` decorators). -The :mod:`python:typing` module is fully supported on Python 2 if you have -the backport installed. - -The :mod:`python:typing` module is provisional and has a number of internal -changes between Python 3.5.0 and 3.6.1, including at minor versions. These -are all supported on a best-effort basis, but you may encounter problems with -an old version of the module. Please report them to us, and consider -updating to a newer version of Python as a workaround. diff -Nru python-hypothesis-3.44.1/docs/development.rst python-hypothesis-3.71.11/docs/development.rst --- python-hypothesis-3.44.1/docs/development.rst 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/docs/development.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,53 +0,0 @@ -============================== -Ongoing Hypothesis Development -============================== - -Hypothesis development is managed by me, `David R. MacIver `_. -I am the primary author of Hypothesis. - -*However*, I no longer do unpaid feature development on Hypothesis. My roles as leader of the project are: - -1. Helping other people do feature development on Hypothesis -2. Fixing bugs and other code health issues -3. Improving documentation -4. General release management work -5. Planning the general roadmap of the project -6. Doing sponsored development on tasks that are too large or in depth for other people to take on - -So all new features must either be sponsored or implemented by someone else. -That being said, the maintenance team takes an active role in shepherding pull requests and -helping people write a new feature (see :gh-file:`CONTRIBUTING.rst` for -details and :pull:`154` for an example of how the process goes). This isn't -"patches welcome", it's "we will help you write a patch". - - -.. _release-policy: - -Release Policy -============== - -Hypothesis releases follow `semantic versioning `_. - -We maintain backwards-compatibility wherever possible, and use deprecation -warnings to mark features that have been superseded by a newer alternative. -If you want to detect this, you can -:mod:`upgrade warnings to errors in the usual ways `. - -We use continuous deployment to ensure that you can always use our newest and -shiniest features - every change to the source tree is automatically built and -published on PyPI as soon as it's merged onto master, after code review and -passing our extensive test suite. - - -Project Roadmap -=============== - -Hypothesis does not have a long-term release plan. However some visibility -into our plans for future :doc:`compatibility ` may be useful: - -- We value compatibility, and maintain it as far as practical. This generally - excludes things which are end-of-life upstream, or have an unstable API. -- We would like to drop Python 2 support when it it reaches end of life in - 2020. Ongoing support is likely to depend on commercial funding. -- We intend to support PyPy3 as soon as it supports a recent enough version of - Python 3. See :issue:`602`. diff -Nru python-hypothesis-3.44.1/docs/django.rst python-hypothesis-3.71.11/docs/django.rst --- python-hypothesis-3.44.1/docs/django.rst 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/docs/django.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,168 +0,0 @@ -.. _hypothesis-django: - -=========================== -Hypothesis for Django users -=========================== - -Hypothesis offers a number of features specific for Django testing, available -in the :mod:`hypothesis[django]` :doc:`extra `. This is tested -against each supported series with mainstream or extended support - -if you're still getting security patches, you can test with Hypothesis. - -Using it is quite straightforward: All you need to do is subclass -:class:`hypothesis.extra.django.TestCase` or -:class:`hypothesis.extra.django.TransactionTestCase` -and you can use :func:`@given ` as normal, -and the transactions will be per example -rather than per test function as they would be if you used :func:`@given ` with a normal -django test suite (this is important because your test function will be called -multiple times and you don't want them to interfere with each other). Test cases -on these classes that do not use -:func:`@given ` will be run as normal. - -I strongly recommend not using -:class:`~hypothesis.extra.django.TransactionTestCase` -unless you really have to. -Because Hypothesis runs this in a loop the performance problems it normally has -are significantly exacerbated and your tests will be really slow. -If you are using :class:`~hypothesis.extra.django.TransactionTestCase`, -you may need to use ``@settings(suppress_health_check=[HealthCheck.too_slow])`` -to avoid :doc:`errors due to slow example generation `. - -In addition to the above, Hypothesis has some support for automatically -deriving strategies for your model types, which you can then customize further. - -.. warning:: - Hypothesis creates saved models. This will run inside your testing - transaction when using the test runner, but if you use the dev console this - will leave debris in your database. - -For example, using the trivial django project I have for testing: - -.. code-block:: python - - >>> from hypothesis.extra.django.models import models - >>> from toystore.models import Customer - >>> c = models(Customer).example() - >>> c - - >>> c.email - 'jaime.urbina@gmail.com' - >>> c.name - '\U00109d3d\U000e07be\U000165f8\U0003fabf\U000c12cd\U000f1910\U00059f12\U000519b0\U0003fabf\U000f1910\U000423fb\U000423fb\U00059f12\U000e07be\U000c12cd\U000e07be\U000519b0\U000165f8\U0003fabf\U0007bc31' - >>> c.age - -873375803 - -Hypothesis has just created this with whatever the relevant type of data is. - -Obviously the customer's age is implausible, so lets fix that: - -.. code-block:: python - - >>> from hypothesis.strategies import integers - >>> c = models(Customer, age=integers(min_value=0, max_value=120)).example() - >>> c - - >>> c.age - 5 - -You can use this to override any fields you like. Sometimes this will be -mandatory: If you have a non-nullable field of a type Hypothesis doesn't know -how to create (e.g. a foreign key) then the models function will error unless -you explicitly pass a strategy to use there. - -Foreign keys are not automatically derived. If they're nullable they will default -to always being null, otherwise you always have to specify them. e.g. suppose -we had a Shop type with a foreign key to company, we would define a strategy -for it as: - -.. code:: python - - shop_strategy = models(Shop, company=models(Company)) - ---------------- -Tips and tricks ---------------- - -Custom field types -================== - -If you have a custom Django field type you can register it with Hypothesis's -model deriving functionality by registering a default strategy for it: - -.. code-block:: python - - >>> from toystore.models import CustomishField, Customish - >>> models(Customish).example() - hypothesis.errors.InvalidArgument: Missing arguments for mandatory field - customish for model Customish - >>> from hypothesis.extra.django.models import add_default_field_mapping - >>> from hypothesis.strategies import just - >>> add_default_field_mapping(CustomishField, just("hi")) - >>> x = models(Customish).example() - >>> x.customish - 'hi' - -Note that this mapping is on exact type. Subtypes will not inherit it. - - -Generating child models -======================= - -For the moment there's no explicit support in hypothesis-django for generating -dependent models. i.e. a Company model will generate no Shops. However if you -want to generate some dependent models as well, you can emulate this by using -the *flatmap* function as follows: - -.. code:: python - - from hypothesis.strategies import lists, just - - def generate_with_shops(company): - return lists(models(Shop, company=just(company))).map(lambda _: company) - - company_with_shops_strategy = models(Company).flatmap(generate_with_shops) - -Lets unpack what this is doing: - -The way flatmap works is that we draw a value from the original strategy, then -apply a function to it which gives us a new strategy. We then draw a value from -*that* strategy. So in this case we're first drawing a company, and then we're -drawing a list of shops belonging to that company: The *just* strategy is a -strategy such that drawing it always produces the individual value, so -``models(Shop, company=just(company))`` is a strategy that generates a Shop belonging -to the original company. - -So the following code would give us a list of shops all belonging to the same -company: - -.. code:: python - - models(Company).flatmap(lambda c: lists(models(Shop, company=just(c)))) - -The only difference from this and the above is that we want the company, not -the shops. This is where the inner map comes in. We build the list of shops -and then throw it away, instead returning the company we started for. This -works because the models that Hypothesis generates are saved in the database, -so we're essentially running the inner strategy purely for the side effect of -creating those children in the database. - - -Using default field values -========================== - -Hypothesis ignores field defaults and always tries to generate values, even if -it doesn't know how to. You can tell it to use the default value for a field -instead of generating one by passing ``fieldname=default_value`` to -``models()``: - -.. code:: python - - >>> from toystore.models import DefaultCustomish - >>> models(DefaultCustomish).example() - hypothesis.errors.InvalidArgument: Missing arguments for mandatory field - customish for model DefaultCustomish - >>> from hypothesis.extra.django.models import default_value - >>> x = models(DefaultCustomish, customish=default_value).example() - >>> x.customish - 'b' diff -Nru python-hypothesis-3.44.1/docs/endorsements.rst python-hypothesis-3.71.11/docs/endorsements.rst --- python-hypothesis-3.44.1/docs/endorsements.rst 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/docs/endorsements.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,195 +0,0 @@ -============ -Testimonials -============ - -This is a page for listing people who are using Hypothesis and how excited they -are about that. If that's you and your name is not on the list, `this file is in -Git `_ -and I'd love it if you sent me a pull request to fix that. - ---------------------------------------------------------------------------------------- -`Stripe `_ ---------------------------------------------------------------------------------------- - -At Stripe we use Hypothesis to test every piece of our machine -learning model training pipeline (powered by scikit). Before we -migrated, our tests were filled with hand-crafted pandas Dataframes -that weren't representative at all of our actual very complex -data. Because we needed to craft examples for each test, we took the -easy way out and lived with extremely low test coverage. - -Hypothesis changed all that. Once we had our strategies for generating -Dataframes of features it became trivial to slightly customize each -strategy for new tests. Our coverage is now close to 90%. - -Full-stop, property-based testing is profoundly more powerful - and -has caught or prevented far more bugs - than our old style of -example-based testing. - ---------------------------------------------------------------------------------------- -Kristian Glass - Director of Technology at `LaterPay GmbH `_ ---------------------------------------------------------------------------------------- - -Hypothesis has been brilliant for expanding the coverage of our test cases, -and also for making them much easier to read and understand, -so we're sure we're testing the things we want in the way we want. - ------------------------------------------------ -`Seth Morton `_ ------------------------------------------------ - -When I first heard about Hypothesis, I knew I had to include it in my two -open-source Python libraries, `natsort `_ -and `fastnumbers `_ . Quite frankly, -I was a little appalled at the number of bugs and "holes" I found in the code. I can -now say with confidence that my libraries are more robust to "the wild." In -addition, Hypothesis gave me the confidence to expand these libraries to fully -support Unicode input, which I never would have had the stomach for without such -thorough testing capabilities. Thanks! - -------------------------------------------- -`Sixty North `_ -------------------------------------------- - -At Sixty North we use Hypothesis for testing -`Segpy `_ an open source Python library for -shifting data between Python data structures and SEG Y files which contain -geophysical data from the seismic reflection surveys used in oil and gas -exploration. - -This is our first experience of property-based testing – as opposed to example-based -testing. Not only are our tests more powerful, they are also much better -explanations of what we expect of the production code. In fact, the tests are much -closer to being specifications. Hypothesis has located real defects in our code -which went undetected by traditional test cases, simply because Hypothesis is more -relentlessly devious about test case generation than us mere humans! We found -Hypothesis particularly beneficial for Segpy because SEG Y is an antiquated format -that uses legacy text encodings (EBCDIC) and even a legacy floating point format -we implemented from scratch in Python. - -Hypothesis is sure to find a place in most of our future Python codebases and many -existing ones too. - -------------------------------------------- -`mulkieran `_ -------------------------------------------- - -Just found out about this excellent QuickCheck for Python implementation and -ran up a few tests for my `bytesize `_ -package last night. Refuted a few hypotheses in the process. - -Looking forward to using it with a bunch of other projects as well. - ------------------------------------------------ -`Adam Johnson `_ ------------------------------------------------ - -I have written a small library to serialize ``dict``\s to MariaDB's dynamic -columns binary format, -`mariadb-dyncol `_. When I first -developed it, I thought I had tested it really well - there were hundreds of -test cases, some of them even taken from MariaDB's test suite itself. I was -ready to release. - -Lucky for me, I tried Hypothesis with David at the PyCon UK sprints. Wow! It -found bug after bug after bug. Even after a first release, I thought of a way -to make the tests do more validation, which revealed a further round of bugs! -Most impressively, Hypothesis found a complicated off-by-one error in a -condition with 4095 versus 4096 bytes of data - something that I would never -have found. - -Long live Hypothesis! (Or at least, property-based testing). - -------------------------------------------- -`Josh Bronson `_ -------------------------------------------- - -Adopting Hypothesis improved `bidict `_'s -test coverage and significantly increased our ability to make changes to -the code with confidence that correct behavior would be preserved. -Thank you, David, for the great testing tool. - --------------------------------------------- -`Cory Benfield `_ --------------------------------------------- - -Hypothesis is the single most powerful tool in my toolbox for working with -algorithmic code, or any software that produces predictable output from a wide -range of sources. When using it with -`Priority `_, Hypothesis consistently found -errors in my assumptions and extremely subtle bugs that would have taken months -of real-world use to locate. In some cases, Hypothesis found subtle deviations -from the correct output of the algorithm that may never have been noticed at -all. - -When it comes to validating the correctness of your tools, nothing comes close -to the thoroughness and power of Hypothesis. - ------------------------------------------- -`Jon Moore `_ ------------------------------------------- - -One extremely satisfied user here. Hypothesis is a really solid implementation -of property-based testing, adapted well to Python, and with good features -such as failure-case shrinkers. I first used it on a project where we needed -to verify that a vendor's Python and non-Python implementations of an algorithm -matched, and it found about a dozen cases that previous example-based testing -and code inspections had not. Since then I've been evangelizing for it at our firm. - --------------------------------------------- -`Russel Winder `_ --------------------------------------------- - -I am using Hypothesis as an integral part of my Python workshops. Testing is an integral part of Python -programming and whilst unittest and, better, py.test can handle example-based testing, property-based -testing is increasingly far more important than example-base testing, and Hypothesis fits the bill. - ---------------------------------------------- -`Wellfire Interactive `_ ---------------------------------------------- - -We've been using Hypothesis in a variety of client projects, from testing -Django-related functionality to domain-specific calculations. It both speeds -up and simplifies the testing process since there's so much less tedious and -error-prone work to do in identifying edge cases. Test coverage is nice but -test depth is even nicer, and it's much easier to get meaningful test depth -using Hypothesis. - --------------------------------------------------- -`Cody Kochmann `_ --------------------------------------------------- - -Hypothesis is being used as the engine for random object generation with my -open source function fuzzer -`battle_tested `_ -which maps all behaviors of a function allowing you to minimize the chance of -unexpected crashes when running code in production. - -With how efficient Hypothesis is at generating the edge cases that cause -unexpected behavior occur, -`battle_tested `_ -is able to map out the entire behavior of most functions in less than a few -seconds. - -Hypothesis truly is a masterpiece. I can't thank you enough for building it. - - ---------------------------------------------------- -`Merchise Autrement `_ ---------------------------------------------------- - -Just minutes after our first use of hypothesis `we uncovered a subtle bug`__ -in one of our most used library. Since then, we have increasingly used -hypothesis to improve the quality of our testing in libraries and applications -as well. - -__ https://github.com/merchise/xoutil/commit/0a4a0f529812fed363efb653f3ade2d2bc203945 - -------------------------------------------- -`Your name goes here `_ -------------------------------------------- - -I know there are many more, because I keep finding out about new people I'd never -even heard of using Hypothesis. If you're looking to way to give back to a tool you -love, adding your name here only takes a moment and would really help a lot. As per -instructions at the top, just send me a pull request and I'll add you to the list. diff -Nru python-hypothesis-3.44.1/docs/examples.rst python-hypothesis-3.71.11/docs/examples.rst --- python-hypothesis-3.44.1/docs/examples.rst 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/docs/examples.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,469 +0,0 @@ -================== -Some more examples -================== - -This is a collection of examples of how to use Hypothesis in interesting ways. -It's small for now but will grow over time. - -All of these examples are designed to be run under `py.test`_ (`nose`_ should probably -work too). - ----------------------------------- -How not to sort by a partial order ----------------------------------- - -The following is an example that's been extracted and simplified from a real -bug that occurred in an earlier version of Hypothesis. The real bug was a lot -harder to find. - -Suppose we've got the following type: - -.. code:: python - - class Node(object): - def __init__(self, label, value): - self.label = label - self.value = tuple(value) - - def __repr__(self): - return "Node(%r, %r)" % (self.label, self.value) - - def sorts_before(self, other): - if len(self.value) >= len(other.value): - return False - return other.value[:len(self.value)] == self.value - - -Each node is a label and a sequence of some data, and we have the relationship -sorts_before meaning the data of the left is an initial segment of the right. -So e.g. a node with value ``[1, 2]`` will sort before a node with value ``[1, 2, 3]``, -but neither of ``[1, 2]`` nor ``[1, 3]`` will sort before the other. - -We have a list of nodes, and we want to topologically sort them with respect to -this ordering. That is, we want to arrange the list so that if ``x.sorts_before(y)`` -then x appears earlier in the list than y. We naively think that the easiest way -to do this is to extend the partial order defined here to a total order by -breaking ties arbitrarily and then using a normal sorting algorithm. So we -define the following code: - -.. code:: python - - from functools import total_ordering - - - @total_ordering - class TopoKey(object): - def __init__(self, node): - self.value = node - - def __lt__(self, other): - if self.value.sorts_before(other.value): - return True - if other.value.sorts_before(self.value): - return False - - return self.value.label < other.value.label - - - def sort_nodes(xs): - xs.sort(key=TopoKey) - -This takes the order defined by ``sorts_before`` and extends it by breaking ties by -comparing the node labels. - -But now we want to test that it works. - -First we write a function to verify that our desired outcome holds: - -.. code:: python - - def is_prefix_sorted(xs): - for i in range(len(xs)): - for j in range(i+1, len(xs)): - if xs[j].sorts_before(xs[i]): - return False - return True - -This will return false if it ever finds a pair in the wrong order and -return true otherwise. - -Given this function, what we want to do with Hypothesis is assert that for all -sequences of nodes, the result of calling ``sort_nodes`` on it is sorted. - -First we need to define a strategy for Node: - -.. code:: python - - from hypothesis import settings, strategy - import hypothesis.strategies as s - - NodeStrategy = s.builds( - Node, - s.integers(), - s.lists(s.booleans(), average_size=5, max_size=10)) - -We want to generate *short* lists of values so that there's a decent chance of -one being a prefix of the other (this is also why the choice of bool as the -elements). We then define a strategy which builds a node out of an integer and -one of those short lists of booleans. - -We can now write a test: - -.. code:: python - - from hypothesis import given - - @given(s.lists(NodeStrategy)) - def test_sorting_nodes_is_prefix_sorted(xs): - sort_nodes(xs) - assert is_prefix_sorted(xs) - -this immediately fails with the following example: - -.. code:: python - - [Node(0, (False, True)), Node(0, (True,)), Node(0, (False,))] - - -The reason for this is that because False is not a prefix of (True, True) nor vice -versa, sorting things the first two nodes are equal because they have equal labels. -This makes the whole order non-transitive and produces basically nonsense results. - -But this is pretty unsatisfying. It only works because they have the same label. Perhaps -we actually wanted our labels to be unique. Lets change the test to do that. - -.. code:: python - - def deduplicate_nodes_by_label(nodes): - table = {} - for node in nodes: - table[node.label] = node - return list(table.values()) - - - NodeSet = s.lists(Node).map(deduplicate_nodes_by_label) - -We define a function to deduplicate nodes by labels, and then map that over a strategy -for lists of nodes to give us a strategy for lists of nodes with unique labels. We can -now rewrite the test to use that: - - -.. code:: python - - @given(NodeSet) - def test_sorting_nodes_is_prefix_sorted(xs): - sort_nodes(xs) - assert is_prefix_sorted(xs) - -Hypothesis quickly gives us an example of this *still* being wrong: - -.. code:: python - - [Node(0, (False,)), Node(-1, (True,)), Node(-2, (False, False))]) - - -Now this is a more interesting example. None of the nodes will sort equal. What is -happening here is that the first node is strictly less than the last node because -(False,) is a prefix of (False, False). This is in turn strictly less than the middle -node because neither is a prefix of the other and -2 < -1. The middle node is then -less than the first node because -1 < 0. - -So, convinced that our implementation is broken, we write a better one: - -.. code:: python - - def sort_nodes(xs): - for i in hrange(1, len(xs)): - j = i - 1 - while j >= 0: - if xs[j].sorts_before(xs[j+1]): - break - xs[j], xs[j+1] = xs[j+1], xs[j] - j -= 1 - -This is just insertion sort slightly modified - we swap a node backwards until swapping -it further would violate the order constraints. The reason this works is because our -order is a partial order already (this wouldn't produce a valid result for a general -topological sorting - you need the transitivity). - -We now run our test again and it passes, telling us that this time we've successfully -managed to sort some nodes without getting it completely wrong. Go us. - --------------------- -Time zone arithmetic --------------------- - -This is an example of some tests for pytz which check that various timezone -conversions behave as you would expect them to. These tests should all pass, -and are mostly a demonstration of some useful sorts of thing to test with -Hypothesis, and how the hypothesis-datetime extra package works. - -.. doctest:: - - >>> from datetime import timedelta - >>> from hypothesis.extra.pytz import timezones - - >>> # The datetimes strategy is naive by default, so tell it to use timezones - >>> aware_datetimes = datetimes(timezones=timezones()) - - >>> @given(aware_datetimes, timezones(), timezones()) - ... def test_convert_via_intermediary(dt, tz1, tz2): - ... """Test that converting between timezones is not affected - ... by a detour via another timezone. - ... """ - ... assert dt.astimezone(tz1).astimezone(tz2) == dt.astimezone(tz2) - - >>> @given(aware_datetimes, timezones()) - ... def test_convert_to_and_fro(dt, tz2): - ... """If we convert to a new timezone and back to the old one - ... this should leave the result unchanged. - ... """ - ... tz1 = dt.tzinfo - ... assert dt == dt.astimezone(tz2).astimezone(tz1) - - >>> @given(aware_datetimes, timezones()) - ... def test_adding_an_hour_commutes(dt, tz): - ... """When converting between timezones it shouldn't matter - ... if we add an hour here or add an hour there. - ... """ - ... an_hour = timedelta(hours=1) - ... assert (dt + an_hour).astimezone(tz) == dt.astimezone(tz) + an_hour - - >>> @given(aware_datetimes, timezones()) - ... def test_adding_a_day_commutes(dt, tz): - ... """When converting between timezones it shouldn't matter - ... if we add a day here or add a day there. - ... """ - ... a_day = timedelta(days=1) - ... assert (dt + a_day).astimezone(tz) == dt.astimezone(tz) + a_day - - >>> # And we can check that our tests pass - >>> test_convert_via_intermediary() - >>> test_convert_to_and_fro() - >>> test_adding_an_hour_commutes() - >>> test_adding_a_day_commutes() - -------------------- -Condorcet's Paradox -------------------- - -A classic paradox in voting theory, called Condorcet's paradox, is that -majority preferences are not transitive. That is, there is a population -and a set of three candidates A, B and C such that the majority of the -population prefer A to B, B to C and C to A. - -Wouldn't it be neat if we could use Hypothesis to provide an example of this? - -Well as you can probably guess from the presence of this section, we can! This -is slightly surprising because it's not really obvious how we would generate an -election given the types that Hypothesis knows about. - -The trick here turns out to be twofold: - -1. We can generate a type that is *much larger* than an election, extract an election out of that, and rely on minimization to throw away all the extraneous detail. -2. We can use assume and rely on Hypothesis's adaptive exploration to focus on the examples that turn out to generate interesting elections - -Without further ado, here is the code: - -.. code:: python - - from hypothesis import given, assume - from hypothesis.strategies import integers, lists - from collections import Counter - - - def candidates(votes): - return {candidate for vote in votes for candidate in vote} - - - def build_election(votes): - """ - Given a list of lists we extract an election out of this. We do this - in two phases: - - 1. First of all we work out the full set of candidates present in all - votes and throw away any votes that do not have that whole set. - 2. We then take each vote and make it unique, keeping only the first - instance of any candidate. - - This gives us a list of total orderings of some set. It will usually - be a lot smaller than the starting list, but that's OK. - """ - all_candidates = candidates(votes) - votes = list(filter(lambda v: set(v) == all_candidates, votes)) - if not votes: - return [] - rebuilt_votes = [] - for vote in votes: - rv = [] - for v in vote: - if v not in rv: - rv.append(v) - assert len(rv) == len(all_candidates) - rebuilt_votes.append(rv) - return rebuilt_votes - - - @given(lists(lists(integers(min_value=1, max_value=5)))) - def test_elections_are_transitive(election): - election = build_election(election) - # Small elections are unlikely to be interesting - assume(len(election) >= 3) - all_candidates = candidates(election) - # Elections with fewer than three candidates certainly can't exhibit - # intransitivity - assume(len(all_candidates) >= 3) - - # Now we check if the election is transitive - - # First calculate the pairwise counts of how many prefer each candidate - # to the other - counts = Counter() - for vote in election: - for i in range(len(vote)): - for j in range(i+1, len(vote)): - counts[(vote[i], vote[j])] += 1 - - # Now look at which pairs of candidates one has a majority over the - # other and store that. - graph = {} - all_candidates = candidates(election) - for i in all_candidates: - for j in all_candidates: - if counts[(i, j)] > counts[(j, i)]: - graph.setdefault(i, set()).add(j) - - # Now for each triple assert that it is transitive. - for x in all_candidates: - for y in graph.get(x, ()): - for z in graph.get(y, ()): - assert x not in graph.get(z, ()) - -The example Hypothesis gives me on my first run (your mileage may of course -vary) is: - -.. code:: python - - [[3, 1, 4], [4, 3, 1], [1, 4, 3]] - -Which does indeed do the job: The majority (votes 0 and 1) prefer 3 to 1, the -majority (votes 0 and 2) prefer 1 to 4 and the majority (votes 1 and 2) prefer -4 to 3. This is in fact basically the canonical example of the voting paradox, -modulo variations on the names of candidates. - -------------------- -Fuzzing an HTTP API -------------------- - -Hypothesis's support for testing HTTP services is somewhat nascent. There are -plans for some fully featured things around this, but right now they're -probably quite far down the line. - -But you can do a lot yourself without any explicit support! Here's a script -I wrote to throw random data against the API for an entirely fictitious service -called Waspfinder (this is only lightly obfuscated and you can easily figure -out who I'm actually talking about, but I don't want you to run this code and -hammer their API without their permission). - -All this does is use Hypothesis to generate random JSON data matching the -format their API asks for and check for 500 errors. More advanced tests which -then use the result and go on to do other things are definitely also possible. - -.. code:: python - - import unittest - from hypothesis import given, assume, settings, strategies as st - from collections import namedtuple - import requests - import os - import random - import time - import math - - # These tests will be quite slow because we have to talk to an external - # service. Also we'll put in a sleep between calls so as to not hammer it. - # As a result we reduce the number of test cases and turn off the timeout. - settings.default.max_examples = 100 - settings.default.timeout = -1 - - Goal = namedtuple("Goal", ("slug",)) - - - # We just pass in our API credentials via environment variables. - waspfinder_token = os.getenv('WASPFINDER_TOKEN') - waspfinder_user = os.getenv('WASPFINDER_USER') - assert waspfinder_token is not None - assert waspfinder_user is not None - - GoalData = st.fixed_dictionaries({ - 'title': st.text(), - 'goal_type': st.sampled_from([ - "hustler", "biker", "gainer", "fatloser", "inboxer", - "drinker", "custom"]), - 'goaldate': st.one_of(st.none(), st.floats()), - 'goalval': st.one_of(st.none(), st.floats()), - 'rate': st.one_of(st.none(), st.floats()), - 'initval': st.floats(), - 'panic': st.floats(), - 'secret': st.booleans(), - 'datapublic': st.booleans(), - }) - - - needs2 = ['goaldate', 'goalval', 'rate'] - - - class WaspfinderTest(unittest.TestCase): - - @given(GoalData) - def test_create_goal_dry_run(self, data): - # We want slug to be unique for each run so that multiple test runs - # don't interfere with each other. If for some reason some slugs trigger - # an error and others don't we'll get a Flaky error, but that's OK. - slug = hex(random.getrandbits(32))[2:] - - # Use assume to guide us through validation we know about, otherwise - # we'll spend a lot of time generating boring examples. - - # Title must not be empty - assume(data["title"]) - - # Exactly two of these values should be not None. The other will be - # inferred by the API. - - assume(len([1 for k in needs2 if data[k] is not None]) == 2) - for v in data.values(): - if isinstance(v, float): - assume(not math.isnan(v)) - data["slug"] = slug - - # The API nicely supports a dry run option, which means we don't have - # to worry about the user account being spammed with lots of fake goals - # Otherwise we would have to make sure we cleaned up after ourselves - # in this test. - data["dryrun"] = True - data["auth_token"] = waspfinder_token - for d, v in data.items(): - if v is None: - data[d] = "null" - else: - data[d] = str(v) - result = requests.post( - "https://waspfinder.example.com/api/v1/users/" - "%s/goals.json" % (waspfinder_user,), data=data) - - # Lets not hammer the API too badly. This will of course make the - # tests even slower than they otherwise would have been, but that's - # life. - time.sleep(1.0) - - # For the moment all we're testing is that this doesn't generate an - # internal error. If we didn't use the dry run option we could have - # then tried doing more with the result, but this is a good start. - self.assertNotEqual(result.status_code, 500) - - if __name__ == '__main__': - unittest.main() - -.. _py.test: https://docs.pytest.org/en/latest/ -.. _nose: https://nose.readthedocs.io/en/latest/ diff -Nru python-hypothesis-3.44.1/docs/extras.rst python-hypothesis-3.71.11/docs/extras.rst --- python-hypothesis-3.44.1/docs/extras.rst 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/docs/extras.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,99 +0,0 @@ -=================== -Additional packages -=================== - -Hypothesis itself does not have any dependencies, but there are some packages that -need additional things installed in order to work. - -You can install these dependencies using the setuptools extra feature as e.g. -``pip install hypothesis[django]``. This will check installation of compatible versions. - -You can also just install hypothesis into a project using them, ignore the version -constraints, and hope for the best. - -In general "Which version is Hypothesis compatible with?" is a hard question to answer -and even harder to regularly test. Hypothesis is always tested against the latest -compatible version and each package will note the expected compatibility range. If -you run into a bug with any of these please specify the dependency version. - -There are seperate pages for :doc:`django` and :doc:`numpy`. - --------------------- -hypothesis[pytz] --------------------- - -.. automodule:: hypothesis.extra.pytz - :members: - - --------------------- -hypothesis[datetime] --------------------- - -.. automodule:: hypothesis.extra.datetime - :members: - - -.. _faker-extra: - ------------------------ -hypothesis[fakefactory] ------------------------ - -.. note:: - This extra package is deprecated. We strongly recommend using native - Hypothesis strategies, which are more effective at both finding and - shrinking failing examples for your tests. - - The :func:`~hypothesis.strategies.from_regex`, - :func:`~hypothesis.strategies.text` (with some specific alphabet), and - :func:`~hypothesis.strategies.sampled_from` strategies may be particularly - useful. - -:pypi:`Faker` (previously :pypi:`fake-factory`) is a Python package that -generates fake data for you. It's great for bootstraping your database, -creating good-looking XML documents, stress-testing a database, or anonymizing -production data. However, it's not designed for automated testing - data from -Hypothesis looks less realistic, but produces minimal bug-triggering examples -and uses coverage information to check more cases. - -``hypothesis.extra.fakefactory`` lets you use Faker generators to parametrize -Hypothesis tests. This was only ever meant to ease your transition to -Hypothesis, but we've improved Hypothesis enough since then that we no longer -recommend using Faker for automated tests under any circumstances. - -hypothesis.extra.fakefactory defines a function fake_factory which returns a -strategy for producing text data from any Faker provider. - -So for example the following will parametrize a test by an email address: - -.. code-block:: pycon - - >>> fake_factory('email').example() - 'tnader@prosacco.info' - - >>> fake_factory('name').example() - 'Zbyněk Černý CSc.' - -You can explicitly specify the locale (otherwise it uses any of the available -locales), either as a single locale or as several: - -.. code-block:: pycon - - >>> fake_factory('name', locale='en_GB').example() - 'Antione Gerlach' - >>> fake_factory('name', locales=['en_GB', 'cs_CZ']).example() - 'Miloš Šťastný' - >>> fake_factory('name', locales=['en_GB', 'cs_CZ']).example() - 'Harm Sanford' - -You can use custom Faker providers via the ``providers`` argument: - -.. code-block:: pycon - - >>> from faker.providers import BaseProvider - >>> class KittenProvider(BaseProvider): - ... def meows(self): - ... return 'meow %d' % (self.random_number(digits=10),) - >>> fake_factory('meows', providers=[KittenProvider]).example() - 'meow 9139348419' diff -Nru python-hypothesis-3.44.1/docs/healthchecks.rst python-hypothesis-3.71.11/docs/healthchecks.rst --- python-hypothesis-3.44.1/docs/healthchecks.rst 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/docs/healthchecks.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,30 +0,0 @@ -============= -Health checks -============= - -Hypothesis tries to detect common mistakes and things that will cause difficulty -at run time in the form of a number of 'health checks'. - -These include detecting and warning about: - -* Strategies with very slow data generation -* Strategies which filter out too much -* Recursive strategies which branch too much -* Tests that are unlikely to complete in a reasonable amount of time. - -If any of these scenarios are detected, Hypothesis will emit a warning about them. - -The general goal of these health checks is to warn you about things that you are doing that might -appear to work but will either cause Hypothesis to not work correctly or to perform badly. - -To selectively disable health checks, use the suppress_health_check setting. -The argument for this parameter is a list with elements drawn from any of -the class-level attributes of the HealthCheck class. - -To disable all health checks, set the perform_health_check settings parameter -to False. - -.. module:: hypothesis -.. autoclass:: HealthCheck - :undoc-members: - :inherited-members: diff -Nru python-hypothesis-3.44.1/docs/index.rst python-hypothesis-3.71.11/docs/index.rst --- python-hypothesis-3.44.1/docs/index.rst 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/docs/index.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,80 +0,0 @@ -====================== -Welcome to Hypothesis! -====================== - -`Hypothesis `_ is a Python library for -creating unit tests which are simpler to write and more powerful when run, -finding edge cases in your code you wouldn't have thought to look for. It is -stable, powerful and easy to add to any existing test suite. - -It works by letting you write tests that assert that something should be true -for every case, not just the ones you happen to think of. - -Think of a normal unit test as being something like the following: - -1. Set up some data. -2. Perform some operations on the data. -3. Assert something about the result. - -Hypothesis lets you write tests which instead look like this: - -1. For all data matching some specification. -2. Perform some operations on the data. -3. Assert something about the result. - -This is often called property based testing, and was popularised by the -Haskell library `Quickcheck `_. - -It works by generating random data matching your specification and checking -that your guarantee still holds in that case. If it finds an example where it doesn't, -it takes that example and cuts it down to size, simplifying it until it finds a -much smaller example that still causes the problem. It then saves that example -for later, so that once it has found a problem with your code it will not forget -it in the future. - -Writing tests of this form usually consists of deciding on guarantees that -your code should make - properties that should always hold true, -regardless of what the world throws at you. Examples of such guarantees -might be: - -* Your code shouldn't throw an exception, or should only throw a particular type of exception (this works particularly well if you have a lot of internal assertions). -* If you delete an object, it is no longer visible. -* If you serialize and then deserialize a value, then you get the same value back. - -Now you know the basics of what Hypothesis does, the rest of this -documentation will take you through how and why. It's divided into a -number of sections, which you can see in the sidebar (or the -menu at the top if you're on mobile), but you probably want to begin with -the :doc:`Quick start guide `, which will give you a worked -example of how to use Hypothesis and a detailed outline -of the things you need to know to begin testing your code with it, or -check out some of the -`introductory articles `_. - - -.. toctree:: - :maxdepth: 1 - :hidden: - - quickstart - details - settings - data - extras - django - numpy - healthchecks - database - stateful - supported - examples - community - manifesto - endorsements - usage - strategies - changes - development - support - packaging - reproducing diff -Nru python-hypothesis-3.44.1/docs/manifesto.rst python-hypothesis-3.71.11/docs/manifesto.rst --- python-hypothesis-3.44.1/docs/manifesto.rst 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/docs/manifesto.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,60 +0,0 @@ -========================= -The Purpose of Hypothesis -========================= - -What is Hypothesis for? - -From the perspective of a user, the purpose of Hypothesis is to make it easier for -you to write better tests. - -From my perspective as the author, that is of course also a purpose of Hypothesis, -but (if you will permit me to indulge in a touch of megalomania for a moment), the -larger purpose of Hypothesis is to drag the world kicking and screaming into a new -and terrifying age of high quality software. - -Software is, as they say, eating the world. Software is also `terrible`_. It's buggy, -insecure and generally poorly thought out. This combination is clearly a recipe for -disaster. - -And the state of software testing is even worse. Although it's fairly uncontroversial -at this point that you *should* be testing your code, can you really say with a straight -face that most projects you've worked on are adequately tested? - -A lot of the problem here is that it's too hard to write good tests. Your tests encode -exactly the same assumptions and fallacies that you had when you wrote the code, so they -miss exactly the same bugs that you missed when you wrote the code. - -Meanwhile, there are all sorts of tools for making testing better that are basically -unused. The original Quickcheck is from *1999* and the majority of developers have -not even heard of it, let alone used it. There are a bunch of half-baked implementations -for most languages, but very few of them are worth using. - -The goal of Hypothesis is to bring advanced testing techniques to the masses, and to -provide an implementation that is so high quality that it is easier to use them than -it is not to use them. Where I can, I will beg, borrow and steal every good idea -I can find that someone has had to make software testing better. Where I can't, I will -invent new ones. - -Quickcheck is the start, but I also plan to integrate ideas from fuzz testing (a -planned future feature is to use coverage information to drive example selection, and -the example saving database is already inspired by the workflows people use for fuzz -testing), and am open to and actively seeking out other suggestions and ideas. - -The plan is to treat the social problem of people not using these ideas as a bug to -which there is a technical solution: Does property-based testing not match your workflow? -That's a bug, let's fix it by figuring out how to integrate Hypothesis into it. -Too hard to generate custom data for your application? That's a bug. Let's fix it by -figuring out how to make it easier, or how to take something you're already using to -specify your data and derive a generator from that automatically. Find the explanations -of these advanced ideas hopelessly obtuse and hard to follow? That's a bug. Let's provide -you with an easy API that lets you test your code better without a PhD in software -verification. - -Grand ambitions, I know, and I expect ultimately the reality will be somewhat less -grand, but so far in about three months of development, Hypothesis has become the most -solid implementation of Quickcheck ever seen in a mainstream language (as long as we don't -count Scala as mainstream yet), and at the same time managed to -significantly push forward the state of the art, so I think there's -reason to be optimistic. - -.. _terrible: https://www.youtube.com/watch?v=csyL9EC0S0c diff -Nru python-hypothesis-3.44.1/docs/numpy.rst python-hypothesis-3.71.11/docs/numpy.rst --- python-hypothesis-3.44.1/docs/numpy.rst 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/docs/numpy.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,53 +0,0 @@ -=================================== -Hypothesis for the Scientific Stack -=================================== - -.. _hypothesis-numpy: - ------ -numpy ------ - -Hypothesis offers a number of strategies for `NumPy `_ testing, -available in the :mod:`hypothesis[numpy]` :doc:`extra `. -It lives in the ``hypothesis.extra.numpy`` package. - -The centerpiece is the :func:`~hypothesis.extra.numpy.arrays` strategy, which generates arrays with -any dtype, shape, and contents you can specify or give a strategy for. -To make this as useful as possible, strategies are provided to generate array -shapes and generate all kinds of fixed-size or compound dtypes. - - -.. automodule:: hypothesis.extra.numpy - :members: - -.. _hypothesis-pandas: - ------- -pandas ------- - -Hypothesis provides strategies for several of the core pandas data types: -:class:`pandas.Index`, :class:`pandas.Series` and :class:`pandas.DataFrame`. - -The general approach taken by the pandas module is that there are multiple -strategies for generating indexes, and all of the other strategies take the -number of entries they contain from their index strategy (with sensible defaults). -So e.g. a Series is specified by specifying its :class:`numpy.dtype` (and/or -a strategy for generating elements for it). - -.. automodule:: hypothesis.extra.pandas - :members: - -~~~~~~~~~~~~~~~~~~ -Supported Versions -~~~~~~~~~~~~~~~~~~ - -There is quite a lot of variation between pandas versions. We only -commit to supporting the latest version of pandas, but older minor versions are -supported on a "best effort" basis. Hypothesis is currently tested against -and confirmed working with Pandas 0.19, 0.20, and 0.21. - -Releases that are not the latest patch release of their minor version are not -tested or officially supported, but will probably also work unless you hit a -pandas bug. diff -Nru python-hypothesis-3.44.1/docs/packaging.rst python-hypothesis-3.71.11/docs/packaging.rst --- python-hypothesis-3.44.1/docs/packaging.rst 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/docs/packaging.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,103 +0,0 @@ -==================== -Packaging Guidelines -==================== - -Downstream packagers often want to package Hypothesis. Here are some guidelines. - -The primary guideline is this: If you are not prepared to keep up with the Hypothesis release schedule, -don't. You will annoy me and are doing your users a disservice. - -Hypothesis has a very frequent release schedule. It's rare that it goes a week without a release, -and there are often multiple releases in a given week. - -If you *are* prepared to keep up with this schedule, you might find the rest of this document useful. - ----------------- -Release tarballs ----------------- - -These are available from :gh-link:`the GitHub releases page `. The -tarballs on pypi are intended for installation from a Python tool such as pip and should not -be considered complete releases. Requests to include additional files in them will not be granted. Their absence -is not a bug. - - ------------- -Dependencies ------------- - -~~~~~~~~~~~~~~~ -Python versions -~~~~~~~~~~~~~~~ - -Hypothesis is designed to work with a range of Python versions. Currently supported are: - -* pypy-2.6.1 (earlier versions of pypy *may* work) -* CPython 2.7.x -* CPython 3.4.x -* CPython 3.5.x -* CPython 3.6.x - -If you feel the need to have separate Python 3 and Python 2 packages you can, but Hypothesis works unmodified -on either. - -~~~~~~~~~~~~~~~~~~~~~~ -Other Python libraries -~~~~~~~~~~~~~~~~~~~~~~ - -Hypothesis has *mandatory* dependencies on the following libraries: - -* :pypi:`attrs` -* :pypi:`coverage` -* :pypi:`enum34` is required on Python 2.7 - -Hypothesis has *optional* dependencies on the following libraries: - -* :pypi:`pytz` (almost any version should work) -* :pypi:`Faker`, version 0.7 or later -* `Django `_, all supported versions -* :pypi:`numpy`, 1.10 or later (earlier versions will probably work fine) -* :pypi:`pandas`, 1.8 or later -* :pypi:`py.test ` (2.8.0 or greater). This is a mandatory dependency for testing Hypothesis itself but optional for users. - -The way this works when installing Hypothesis normally is that these features become available if the relevant -library is installed. - ------------------- -Testing Hypothesis ------------------- - -If you want to test Hypothesis as part of your packaging you will probably not want to use the mechanisms -Hypothesis itself uses for running its tests, because it has a lot of logic for installing and testing against -different versions of Python. - -The tests must be run with py.test. A version more recent than 2.8.0 is strongly encouraged, but it may work -with earlier versions (however py.test specific logic is disabled before 2.8.0). - -Tests are organised into a number of top level subdirectories of the tests/ directory. - -* cover: This is a small, reasonably fast, collection of tests designed to give 100% coverage of all but a select - subset of the files when run under Python 3. -* nocover: This is a much slower collection of tests that should not be run under coverage for performance reasons. -* py2: Tests that can only be run under Python 2 -* py3: Tests that can only be run under Python 3 -* datetime: This tests the subset of Hypothesis that depends on pytz -* fakefactory: This tests the subset of Hypothesis that depends on fakefactory. -* django: This tests the subset of Hypothesis that depends on django (this also depends on fakefactory). - - -An example invocation for running the coverage subset of these tests: - -.. code-block:: bash - - pip install -e . - pip install pytest # you will probably want to use your own packaging here - python -m pytest tests/cover - --------- -Examples --------- - -* `arch linux `_ -* `fedora `_ -* `gentoo `_ diff -Nru python-hypothesis-3.44.1/docs/quickstart.rst python-hypothesis-3.71.11/docs/quickstart.rst --- python-hypothesis-3.44.1/docs/quickstart.rst 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/docs/quickstart.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,312 +0,0 @@ -================= -Quick start guide -================= - -This document should talk you through everything you need to get started with -Hypothesis. - ----------- -An example ----------- - -Suppose we've written a `run length encoding -`_ system and we want to test -it out. - -We have the following code which I took straight from the -`Rosetta Code `_ wiki (OK, I -removed some commented out code and fixed the formatting, but there are no -functional modifications): - - -.. code:: python - - def encode(input_string): - count = 1 - prev = '' - lst = [] - for character in input_string: - if character != prev: - if prev: - entry = (prev, count) - lst.append(entry) - count = 1 - prev = character - else: - count += 1 - else: - entry = (character, count) - lst.append(entry) - return lst - - - def decode(lst): - q = '' - for character, count in lst: - q += character * count - return q - - -We want to write a test for this that will check some invariant of these -functions. - -The invariant one tends to try when you've got this sort of encoding / -decoding is that if you encode something and then decode it then you get the same -value back. - -Lets see how you'd do that with Hypothesis: - - -.. code:: python - - from hypothesis import given - from hypothesis.strategies import text - - @given(text()) - def test_decode_inverts_encode(s): - assert decode(encode(s)) == s - -(For this example we'll just let pytest discover and run the test. We'll cover -other ways you could have run it later). - -The text function returns what Hypothesis calls a search strategy. An object -with methods that describe how to generate and simplify certain kinds of -values. The @given decorator then takes our test function and turns it into a -parametrized one which, when called, will run the test function over a wide -range of matching data from that strategy. - -Anyway, this test immediately finds a bug in the code: - -.. code:: - - Falsifying example: test_decode_inverts_encode(s='') - - UnboundLocalError: local variable 'character' referenced before assignment - -Hypothesis correctly points out that this code is simply wrong if called on -an empty string. - -If we fix that by just adding the following code to the beginning of the function -then Hypothesis tells us the code is correct (by doing nothing as you'd expect -a passing test to). - -.. code:: python - - - if not input_string: - return [] - -If we wanted to make sure this example was always checked we could add it in -explicitly: - -.. code:: python - - from hypothesis import given, example - from hypothesis.strategies import text - - @given(text()) - @example('') - def test_decode_inverts_encode(s): - assert decode(encode(s)) == s - -You don't have to do this, but it can be useful both for clarity purposes and -for reliably hitting hard to find examples. Also in local development -Hypothesis will just remember and reuse the examples anyway, but there's not -currently a very good workflow for sharing those in your CI. - -It's also worth noting that both example and given support keyword arguments as -well as positional. The following would have worked just as well: - -.. code:: python - - @given(s=text()) - @example(s='') - def test_decode_inverts_encode(s): - assert decode(encode(s)) == s - -Suppose we had a more interesting bug and forgot to reset the count -each time. Say we missed a line in our ``encode`` method: - -.. code:: python - - def encode(input_string): - count = 1 - prev = '' - lst = [] - for character in input_string: - if character != prev: - if prev: - entry = (prev, count) - lst.append(entry) - # count = 1 # Missing reset operation - prev = character - else: - count += 1 - else: - entry = (character, count) - lst.append(entry) - return lst - -Hypothesis quickly informs us of the following example: - -.. code:: - - Falsifying example: test_decode_inverts_encode(s='001') - -Note that the example provided is really quite simple. Hypothesis doesn't just -find *any* counter-example to your tests, it knows how to simplify the examples -it finds to produce small easy to understand ones. In this case, two identical -values are enough to set the count to a number different from one, followed by -another distinct value which should have reset the count but in this case -didn't. - -The examples Hypothesis provides are valid Python code you can run. Any -arguments that you explicitly provide when calling the function are not -generated by Hypothesis, and if you explicitly provide *all* the arguments -Hypothesis will just call the underlying function the once rather than -running it multiple times. - ----------- -Installing ----------- - -Hypothesis is :pypi:`available on pypi as "hypothesis" `. You can install it with: - -.. code:: bash - - pip install hypothesis - -If you want to install directly from the source code (e.g. because you want to -make changes and install the changed version) you can do this with: - -.. code:: bash - - pip install -e . - -You should probably run the tests first to make sure nothing is broken. You can -do this with: - -.. code:: bash - - python setup.py test - -Note that if they're not already installed this will try to install the test -dependencies. - -You may wish to do all of this in a `virtualenv `_. For example: - -.. code:: bash - - virtualenv venv - source venv/bin/activate - pip install hypothesis - -Will create an isolated environment for you to try hypothesis out in without -affecting your system installed packages. - -------------- -Running tests -------------- - -In our example above we just let pytest discover and run our tests, but we could -also have run it explicitly ourselves: - -.. code:: python - - if __name__ == '__main__': - test_decode_inverts_encode() - -We could also have done this as a unittest TestCase: - - -.. code:: python - - import unittest - - - class TestEncoding(unittest.TestCase): - @given(text()) - def test_decode_inverts_encode(self, s): - self.assertEqual(decode(encode(s)), s) - - if __name__ == '__main__': - unittest.main() - -A detail: This works because Hypothesis ignores any arguments it hasn't been -told to provide (positional arguments start from the right), so the self -argument to the test is simply ignored and works as normal. This also means -that Hypothesis will play nicely with other ways of parameterizing tests. e.g -it works fine if you use pytest fixtures for some arguments and Hypothesis for -others. - -------------- -Writing tests -------------- - -A test in Hypothesis consists of two parts: A function that looks like a normal -test in your test framework of choice but with some additional arguments, and -a :func:`@given ` decorator that specifies -how to provide those arguments. - -Here are some other examples of how you could use that: - - -.. code:: python - - from hypothesis import given - import hypothesis.strategies as st - - @given(st.integers(), st.integers()) - def test_ints_are_commutative(x, y): - assert x + y == y + x - - @given(x=st.integers(), y=st.integers()) - def test_ints_cancel(x, y): - assert (x + y) - y == x - - @given(st.lists(st.integers())) - def test_reversing_twice_gives_same_list(xs): - # This will generate lists of arbitrary length (usually between 0 and - # 100 elements) whose elements are integers. - ys = list(xs) - ys.reverse() - ys.reverse() - assert xs == ys - - @given(st.tuples(st.booleans(), st.text())) - def test_look_tuples_work_too(t): - # A tuple is generated as the one you provided, with the corresponding - # types in those positions. - assert len(t) == 2 - assert isinstance(t[0], bool) - assert isinstance(t[1], str) - - -Note that as we saw in the above example you can pass arguments to :func:`@given ` -either as positional or as keywords. - --------------- -Where to start --------------- - -You should now know enough of the basics to write some tests for your code -using Hypothesis. The best way to learn is by doing, so go have a try. - -If you're stuck for ideas for how to use this sort of test for your code, here -are some good starting points: - -1. Try just calling functions with appropriate random data and see if they - crash. You may be surprised how often this works. e.g. note that the first - bug we found in the encoding example didn't even get as far as our - assertion: It crashed because it couldn't handle the data we gave it, not - because it did the wrong thing. -2. Look for duplication in your tests. Are there any cases where you're testing - the same thing with multiple different examples? Can you generalise that to - a single test using Hypothesis? -3. `This piece is designed for an F# implementation - `_, but - is still very good advice which you may find helps give you good ideas for - using Hypothesis. - -If you have any trouble getting started, don't feel shy about -:doc:`asking for help `. diff -Nru python-hypothesis-3.44.1/docs/reproducing.rst python-hypothesis-3.71.11/docs/reproducing.rst --- python-hypothesis-3.44.1/docs/reproducing.rst 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/docs/reproducing.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,120 +0,0 @@ -==================== -Reproducing Failures -==================== - -One of the things that is often concerning for people using randomized testing -like Hypothesis is the question of how to reproduce failing test cases. - -Fortunately Hypothesis has a number of features in support of this. The one you -will use most commonly when developing locally is `the example database `, -which means that you shouldn't have to think about the problem at all for local -use - test failures will just automatically reproduce without you having to do -anything. - -The example database is perfectly suitable for sharing between machines, but -there currently aren't very good work flows for that, so Hypothesis provides a -number of ways to make examples reproducible by adding them to the source code -of your tests. This is particularly useful when e.g. you are trying to run an -example that has failed on your CI, or otherwise share them between machines. - -.. _providing-explicit-examples: - ---------------------------- -Providing explicit examples ---------------------------- - -You can explicitly ask Hypothesis to try a particular example, using - -.. autofunction:: hypothesis.example - -Hypothesis will run all examples you've asked for first. If any of them fail it -will not go on to look for more examples. - -It doesn't matter whether you put the example decorator before or after given. -Any permutation of the decorators in the above will do the same thing. - -Note that examples can be positional or keyword based. If they're positional then -they will be filled in from the right when calling, so either of the following -styles will work as expected: - -.. code:: python - - @given(text()) - @example("Hello world") - @example(x="Some very long string") - def test_some_code(x): - assert True - - from unittest import TestCase - - class TestThings(TestCase): - @given(text()) - @example("Hello world") - @example(x="Some very long string") - def test_some_code(self, x): - assert True - -As with ``@given``, it is not permitted for a single example to be a mix of -positional and keyword arguments. -Either are fine, and you can use one in one example and the other in another -example if for some reason you really want to, but a single example must be -consistent. - -------------------------------------- -Reproducing a test run with ``@seed`` -------------------------------------- - -.. autofunction:: hypothesis.seed - -When a test fails unexpectedly, usually due to a health check failure, -Hypothesis will print out a seed that led to that failure, if the test is not -already running with a fixed seed. You can then recreate that failure using either -the ``@seed`` decorator or (if you are running :pypi:`pytest`) with -``--hypothesis-seed``. - -.. _reproduce_failure: - -------------------------------------------------------- -Reproducing an example with with ``@reproduce_failure`` -------------------------------------------------------- - -Hypothesis has an opaque binary representation that it uses for all examples it -generates. This representation is not intended to be stable across versions or -with respect to changes in the test, but can be used to to reproduce failures -with the ``@reproduce_example`` decorator. - -.. autofunction:: hypothesis.reproduce_failure - -The intent is that you should never write this decorator by hand, but it is -instead provided by Hypothesis. -When a test fails with a falsifying example, Hypothesis may print out a -suggestion to use ``@reproduce_failure`` on the test to recreate the problem -as follows: - -.. doctest:: - - >>> from hypothesis import settings, given, PrintSettings - >>> import hypothesis.strategies as st - >>> @given(st.floats()) - ... @settings(print_blob=PrintSettings.ALWAYS) - ... def test(f): - ... assert f == f - ... - >>> try: - ... test() - ... except AssertionError: - ... pass - Falsifying example: test(f=nan) - - You can reproduce this example by temporarily adding @reproduce_failure(..., b'AAD/8AAAAAAAAQA=') as a decorator on your test case - -Adding the suggested decorator to the test should reproduce the failure (as -long as everything else is the same - changing the versions of Python or -anything else involved, might of course affect the behaviour of the test! Note -that changing the version of Hypothesis will result in a different error - -each ``@reproduce_failure`` invocation is specific to a Hypothesis version). - -When to do this is controlled by the :attr:`~hypothesis.settings.print_blob` -setting, which may be one of the following values: - -.. autoclass:: hypothesis.PrintSettings diff -Nru python-hypothesis-3.44.1/docs/settings.rst python-hypothesis-3.71.11/docs/settings.rst --- python-hypothesis-3.44.1/docs/settings.rst 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/docs/settings.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,315 +0,0 @@ -======== -Settings -======== - -Hypothesis tries to have good defaults for its behaviour, but sometimes that's -not enough and you need to tweak it. - -The mechanism for doing this is the :class:`~hypothesis.settings` object. -You can set up a :func:`@given ` based test to use this using a settings -decorator: - -:func:`@given ` invocation is as follows: - -.. code:: python - - from hypothesis import given, settings - - @given(integers()) - @settings(max_examples=500) - def test_this_thoroughly(x): - pass - -This uses a :class:`~hypothesis.settings` object which causes the test to receive a much larger -set of examples than normal. - -This may be applied either before or after the given and the results are -the same. The following is exactly equivalent: - - -.. code:: python - - from hypothesis import given, settings - - @settings(max_examples=500) - @given(integers()) - def test_this_thoroughly(x): - pass - ------------------- -Available settings ------------------- - -.. module:: hypothesis -.. autoclass:: settings - :members: max_examples, max_iterations, min_satisfying_examples, - max_shrinks, timeout, strict, database_file, stateful_step_count, - database, perform_health_check, suppress_health_check, buffer_size, - phases, deadline, use_coverage, derandomize - -.. _phases: - -~~~~~~~~~~~~~~~~~~~~~ -Controlling What Runs -~~~~~~~~~~~~~~~~~~~~~ - -Hypothesis divides tests into four logically distinct phases: - -1. Running explicit examples :ref:`provided with the @example decorator `. -2. Rerunning a selection of previously failing examples to reproduce a previously seen error -3. Generating new examples. -4. Attempting to shrink an example found in phases 2 or 3 to a more manageable - one (explicit examples cannot be shrunk). - -The phases setting provides you with fine grained control over which of these run, -with each phase corresponding to a value on the :class:`~hypothesis._settings.Phase` enum: - -1. ``Phase.explicit`` controls whether explicit examples are run. -2. ``Phase.reuse`` controls whether previous examples will be reused. -3. ``Phase.generate`` controls whether new examples will be generated. -4. ``Phase.shrink`` controls whether examples will be shrunk. - -The phases argument accepts a collection with any subset of these. e.g. -``settings(phases=[Phase.generate, Phase.shrink])`` will generate new examples -and shrink them, but will not run explicit examples or reuse previous failures, -while ``settings(phases=[Phase.explicit])`` will only run the explicit -examples. - -.. _verbose-output: - -~~~~~~~~~~~~~~~~~~~~~~~~~~ -Seeing intermediate result -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -To see what's going on while Hypothesis runs your tests, you can turn -up the verbosity setting. This works with both :func:`~hypothesis.core.find` -and :func:`@given `. - -.. doctest:: - - >>> from hypothesis import find, settings, Verbosity - >>> from hypothesis.strategies import lists, booleans - >>> find(lists(integers()), any, settings=settings(verbosity=Verbosity.verbose)) - Trying example [] - Found satisfying example [-106641080167757791735701986170810016341, - -129665482689688858331316879188241401294, - -17902751879921353864928802351902980929, - 86547910278013668694989468221154862503, - 99789676068743906931733548810810835946, - -56833685188912180644827795048092269385, - -12891126493032945632804716628985598019, - 57797823215504994933565345605235342532, - 98214819714866425575119206029702237685] - Shrunk example to [-106641080167757791735701986170810016341, - -129665482689688858331316879188241401294, - -17902751879921353864928802351902980929, - 86547910278013668694989468221154862503, - 99789676068743906931733548810810835946, - -56833685188912180644827795048092269385, - -12891126493032945632804716628985598019, - 57797823215504994933565345605235342532, - 98214819714866425575119206029702237685] - Shrunk example to [-106641080167757791735701986170810016341, - -129665482689688858331316879188241401294, - -17902751879921353864928802351902980929, - 86547910278013668694989468221154862503] - Shrunk example to [-106641080167757791735701986170810016341, - 164695784672172929935660921670478470673] - Shrunk example to [164695784672172929935660921670478470673] - Shrunk example to [164695784672172929935660921670478470673] - Shrunk example to [164695784672172929935660921670478470673] - Shrunk example to [1] - [1] - -The four levels are quiet, normal, verbose and debug. normal is the default, -while in quiet Hypothesis will not print anything out, even the final -falsifying example. debug is basically verbose but a bit more so. You probably -don't want it. - -You can also override the default by setting the environment variable -:envvar:`HYPOTHESIS_VERBOSITY_LEVEL` to the name of the level you want. So e.g. -setting ``HYPOTHESIS_VERBOSITY_LEVEL=verbose`` will run all your tests printing -intermediate results and errors. - -If you are using ``pytest``, you may also need to -:doc:`disable output capturing for passing tests `. - -------------------------- -Building settings objects -------------------------- - -Settings can be created by calling :class:`~hypothesis.settings` with any of the available settings -values. Any absent ones will be set to defaults: - -.. doctest:: - - >>> from hypothesis import settings - >>> settings().max_examples - 100 - >>> settings(max_examples=10).max_examples - 10 - - -You can also copy settings from other settings: - -.. doctest:: - - >>> s = settings(max_examples=10) - >>> t = settings(s, max_iterations=20) - >>> s.max_examples - 10 - >>> t.max_iterations - 20 - >>> s.max_iterations - 1000 - >>> s.max_shrinks - 500 - >>> t.max_shrinks - 500 - ----------------- -Default settings ----------------- - -At any given point in your program there is a current default settings, -available as ``settings.default``. As well as being a settings object in its own -right, all newly created settings objects which are not explicitly based off -another settings are based off the default, so will inherit any values that are -not explicitly set from it. - -You can change the defaults by using profiles (see next section), but you can -also override them locally by using a settings object as a :ref:`context manager ` - - -.. doctest:: - - >>> with settings(max_examples=150): - ... print(settings.default.max_examples) - ... print(settings().max_examples) - 150 - 150 - >>> settings().max_examples - 100 - -Note that after the block exits the default is returned to normal. - -You can use this by nesting test definitions inside the context: - -.. code:: python - - from hypothesis import given, settings - - with settings(max_examples=500): - @given(integers()) - def test_this_thoroughly(x): - pass - -All settings objects created or tests defined inside the block will inherit their -defaults from the settings object used as the context. You can still override them -with custom defined settings of course. - -Warning: If you use define test functions which don't use :func:`@given ` -inside a context block, these will not use the enclosing settings. This is because the context -manager only affects the definition, not the execution of the function. - -.. _settings_profiles: - -~~~~~~~~~~~~~~~~~ -settings Profiles -~~~~~~~~~~~~~~~~~ - -Depending on your environment you may want different default settings. -For example: during development you may want to lower the number of examples -to speed up the tests. However, in a CI environment you may want more examples -so you are more likely to find bugs. - -Hypothesis allows you to define different settings profiles. These profiles -can be loaded at any time. - -Loading a profile changes the default settings but will not change the behavior -of tests that explicitly change the settings. - -.. doctest:: - - >>> from hypothesis import settings - >>> settings.register_profile("ci", settings(max_examples=1000)) - >>> settings().max_examples - 100 - >>> settings.load_profile("ci") - >>> settings().max_examples - 1000 - -Instead of loading the profile and overriding the defaults you can retrieve profiles for -specific tests. - -.. doctest:: - - >>> with settings.get_profile("ci"): - ... print(settings().max_examples) - ... - 1000 - -Optionally, you may define the environment variable to load a profile for you. -This is the suggested pattern for running your tests on CI. -The code below should run in a `conftest.py` or any setup/initialization section of your test suite. -If this variable is not defined the Hypothesis defined defaults will be loaded. - -.. doctest:: - - >>> import os - >>> from hypothesis import settings, Verbosity - >>> settings.register_profile("ci", settings(max_examples=1000)) - >>> settings.register_profile("dev", settings(max_examples=10)) - >>> settings.register_profile("debug", settings(max_examples=10, verbosity=Verbosity.verbose)) - >>> settings.load_profile(os.getenv(u'HYPOTHESIS_PROFILE', 'default')) - -If you are using the hypothesis pytest plugin and your profiles are registered -by your conftest you can load one with the command line option ``--hypothesis-profile``. - -.. code:: bash - - $ py.test tests --hypothesis-profile - - -~~~~~~~~ -Timeouts -~~~~~~~~ - -The `timeout` functionality of Hypothesis is being deprecated, and will -eventually be removed. For the moment, the timeout setting can still be set -and the old default timeout of one minute remains. - -If you want to future proof your code you can get -the future behaviour by setting it to the value `unlimited`, which you can -import from the main Hypothesis package: - -.. code:: python - - from hypothesis import given, settings, unlimited - from hypothesis import strategies as st - - @settings(timeout=unlimited) - @given(st.integers()) - def test_something_slow(i): - ... - -This will cause your code to run until it hits the normal Hypothesis example -limits, regardless of how long it takes. `timeout=unlimited` will remain a -valid setting after the timeout functionality has been deprecated (but will -then have its own deprecation cycle). - -There is however now a timing related health check which is designed to catch -tests that run for ages by accident. If you really want your test to run -forever, the following code will enable that: - -.. code:: python - - from hypothesis import given, settings, unlimited, HealthCheck - from hypothesis import strategies as st - - @settings(timeout=unlimited, suppress_health_check=[ - HealthCheck.hung_test - ]) - @given(st.integers()) - def test_something_slow(i): - ... diff -Nru python-hypothesis-3.44.1/docs/stateful.rst python-hypothesis-3.71.11/docs/stateful.rst --- python-hypothesis-3.44.1/docs/stateful.rst 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/docs/stateful.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,449 +0,0 @@ -================ -Stateful testing -================ - -Hypothesis offers support for a stateful style of test, where instead of -trying to produce a single data value that causes a specific test to fail, it -tries to generate a program that errors. In many ways, this sort of testing is -to classical property based testing as property based testing is to normal -example based testing. - -The idea doesn't originate with Hypothesis, though Hypothesis's implementation -and approach is mostly not based on an existing implementation and should be -considered some mix of novel and independent reinventions. - -This style of testing is useful both for programs which involve some sort -of mutable state and for complex APIs where there's no state per se but the -actions you perform involve e.g. taking data from one function and feeding it -into another. - -The idea is that you teach Hypothesis how to interact with your program: Be it -a server, a python API, whatever. All you need is to be able to answer the -question "Given what I've done so far, what could I do now?". After that, -Hypothesis takes over and tries to find sequences of actions which cause a -test failure. - -Right now the stateful testing is a bit new and experimental and should be -considered as a semi-public API: It may break between minor versions but won't -break between patch releases, and there are still some rough edges in the API -that will need to be filed off. - -This shouldn't discourage you from using it. Although it's not as robust as the -rest of Hypothesis, it's still pretty robust and more importantly is extremely -powerful. I found a number of really subtle bugs in Hypothesis by turning the -stateful testing onto a subset of the Hypothesis API, and you likely will find -the same. - -Enough preamble, lets see how to use it. - -The first thing to note is that there are two levels of API: The low level -but more flexible API and the higher level rule based API which is both -easier to use and also produces a much better display of data due to its -greater structure. We'll start with the more structured one. - -------------------------- -Rule based state machines -------------------------- - -Rule based state machines are the ones you're most likely to want to use. -They're significantly more user friendly and should be good enough for most -things you'd want to do. - -A rule based state machine is a collection of functions (possibly with side -effects) which may depend on both values that Hypothesis can generate and -also on values that have resulted from previous function calls. - -You define a rule based state machine as follows: - -.. code:: python - - import unittest - from collections import namedtuple - - from hypothesis import strategies as st - from hypothesis.stateful import RuleBasedStateMachine, Bundle, rule - - - Leaf = namedtuple('Leaf', ('label',)) - Split = namedtuple('Split', ('left', 'right')) - - - class BalancedTrees(RuleBasedStateMachine): - trees = Bundle('BinaryTree') - - @rule(target=trees, x=st.integers()) - def leaf(self, x): - return Leaf(x) - - @rule(target=trees, left=trees, right=trees) - def split(self, left, right): - return Split(left, right) - - @rule(tree=trees) - def check_balanced(self, tree): - if isinstance(tree, Leaf): - return - else: - assert abs(self.size(tree.left) - self.size(tree.right)) <= 1 - self.check_balanced(tree.left) - self.check_balanced(tree.right) - - def size(self, tree): - if isinstance(tree, Leaf): - return 1 - else: - return 1 + self.size(tree.left) + self.size(tree.right) - -In this we declare a Bundle, which is a named collection of previously generated -values. We define two rules which put data onto this bundle - one which just -generates leaves with integer labels, the other of which takes two previously -generated values and returns a new one. - -We can then integrate this into our test suite by getting a unittest TestCase -from it: - -.. code:: python - - TestTrees = BalancedTrees.TestCase - - if __name__ == '__main__': - unittest.main() - -(these will also be picked up by py.test if you prefer to use that). Running -this we get: - -.. code:: bash - - Step #1: v1 = leaf(x=0) - Step #2: v2 = split(left=v1, right=v1) - Step #3: v3 = split(left=v2, right=v1) - Step #4: check_balanced(tree=v3) - F - ====================================================================== - FAIL: runTest (hypothesis.stateful.BalancedTrees.TestCase) - ---------------------------------------------------------------------- - Traceback (most recent call last): - (...) - assert abs(self.size(tree.left) - self.size(tree.right)) <= 1 - AssertionError - -Note how it's printed out a very short program that will demonstrate the -problem. - -...the problem of course being that we've not actually written any code to -balance this tree at *all*, so of course it's not balanced. - -So lets balance some trees. - - -.. code:: python - - from collections import namedtuple - - from hypothesis import strategies as st - from hypothesis.stateful import RuleBasedStateMachine, Bundle, rule - - - Leaf = namedtuple('Leaf', ('label',)) - Split = namedtuple('Split', ('left', 'right')) - - - class BalancedTrees(RuleBasedStateMachine): - trees = Bundle('BinaryTree') - balanced_trees = Bundle('balanced BinaryTree') - - @rule(target=trees, x=st.integers()) - def leaf(self, x): - return Leaf(x) - - @rule(target=trees, left=trees, right=trees) - def split(self, left, right): - return Split(left, right) - - @rule(tree=balanced_trees) - def check_balanced(self, tree): - if isinstance(tree, Leaf): - return - else: - assert abs(self.size(tree.left) - self.size(tree.right)) <= 1, \ - repr(tree) - self.check_balanced(tree.left) - self.check_balanced(tree.right) - - @rule(target=balanced_trees, tree=trees) - def balance_tree(self, tree): - return self.split_leaves(self.flatten(tree)) - - def size(self, tree): - if isinstance(tree, Leaf): - return 1 - else: - return self.size(tree.left) + self.size(tree.right) - - def flatten(self, tree): - if isinstance(tree, Leaf): - return (tree.label,) - else: - return self.flatten(tree.left) + self.flatten(tree.right) - - def split_leaves(self, leaves): - assert leaves - if len(leaves) == 1: - return Leaf(leaves[0]) - else: - mid = len(leaves) // 2 - return Split( - self.split_leaves(leaves[:mid]), - self.split_leaves(leaves[mid:]), - ) - - -We've now written a really noddy tree balancing implementation. This takes -trees and puts them into a new bundle of data, and we only assert that things -in the balanced_trees bundle are actually balanced. - -If you run this it will sit there silently for a while (you can turn on -:ref:`verbose output ` to get slightly more information about -what's happening. debug will give you all the intermediate programs being run) -and then run, telling you your test has passed! Our balancing algorithm worked. - -Now lets break it to make sure the test is still valid: - -Changing the split to ``mid = max(len(leaves) // 3, 1)`` this should no longer -balance, which gives us the following counter-example: - -.. code:: python - - v1 = leaf(x=0) - v2 = split(left=v1, right=v1) - v3 = balance_tree(tree=v1) - v4 = split(left=v2, right=v2) - v5 = balance_tree(tree=v4) - check_balanced(tree=v5) - -Note that the example could be shrunk further by deleting v3. Due to some -technical limitations, Hypothesis was unable to find that particular shrink. -In general it's rare for examples produced to be long, but they won't always be -minimal. - -You can control the detailed behaviour with a settings object on the TestCase -(this is a normal hypothesis settings object using the defaults at the time -the TestCase class was first referenced). For example if you wanted to run -fewer examples with larger programs you could change the settings to: - -.. code:: python - - TestTrees.settings = settings(max_examples=100, stateful_step_count=100) - -Which doubles the number of steps each program runs and halves the number of -runs relative to the example. settings.timeout will also be respected as usual. - -Preconditions -------------- - -While it's possible to use :func:`~hypothesis.assume` in RuleBasedStateMachine rules, if you -use it in only a few rules you can quickly run into a situation where few or -none of your rules pass their assumptions. Thus, Hypothesis provides a -:func:`~hypothesis.stateful.precondition` decorator to avoid this problem. The :func:`~hypothesis.stateful.precondition` -decorator is used on ``rule``-decorated functions, and must be given a function -that returns True or False based on the RuleBasedStateMachine instance. - -.. autofunction:: hypothesis.stateful.precondition - -.. code:: python - - from hypothesis.stateful import RuleBasedStateMachine, rule, precondition - - class NumberModifier(RuleBasedStateMachine): - - num = 0 - - @rule() - def add_one(self): - self.num += 1 - - @precondition(lambda self: self.num != 0) - @rule() - def divide_with_one(self): - self.num = 1 / self.num - - -By using :func:`~hypothesis.stateful.precondition` here instead of :func:`~hypothesis.assume`, Hypothesis can filter the -inapplicable rules before running them. This makes it much more likely that a -useful sequence of steps will be generated. - -Note that currently preconditions can't access bundles; if you need to use -preconditions, you should store relevant data on the instance instead. - -Invariant ---------- - -Often there are invariants that you want to ensure are met after every step in -a process. It would be possible to add these as rules that are run, but they -would be run zero or multiple times between other rules. Hypothesis provides a -decorator that marks a function to be run after every step. - -.. autofunction:: hypothesis.stateful.invariant - -.. code:: python - - from hypothesis.stateful import RuleBasedStateMachine, rule, invariant - - class NumberModifier(RuleBasedStateMachine): - - num = 0 - - @rule() - def add_two(self): - self.num += 2 - if self.num > 50: - self.num += 1 - - @invariant() - def divide_with_one(self): - assert self.num % 2 == 0 - - NumberTest = NumberModifier.TestCase - -Invariants can also have :func:`~hypothesis.stateful.precondition`\ s applied to them, in which case -they will only be run if the precondition function returns true. - -Note that currently invariants can't access bundles; if you need to use -invariants, you should store relevant data on the instance instead. - ----------------------- -Generic state machines ----------------------- - -The class GenericStateMachine is the underlying machinery of stateful testing -in Hypothesis. In execution it looks much like the RuleBasedStateMachine but -it allows the set of steps available to depend in essentially arbitrary -ways on what has happened so far. For example, if you wanted to -use Hypothesis to test a game, it could choose each step in the machine based -on the game to date and the set of actions the game program is telling it it -has available. - -It essentially executes the following loop: - -.. code:: python - - machine = MyStateMachine() - try: - machine.check_invariants() - for _ in range(n_steps): - step = machine.steps().example() - machine.execute_step(step) - machine.check_invariants() - finally: - machine.teardown() - -Where ``steps`` and ``execute_step`` are methods you must implement, and -``teardown`` and ``check_invarants`` are methods you can implement if required. -``steps`` returns a strategy, which is allowed to depend arbitrarily on the -current state of the test execution. *Ideally* a good steps implementation -should be robust against minor changes in the state. Steps that change a lot -between slightly different executions will tend to produce worse quality -examples because they're hard to simplify. - -The steps method *may* depend on external state, but it's not advisable and -may produce flaky tests. - -If any of ``execute_step``, ``check_invariants`` or ``teardown`` produces an -exception, Hypothesis will try to find a minimal sequence of values steps such -that the following throws an exception: - -.. code:: python - - machine = MyStateMachine() - try: - machine.check_invariants() - for step in steps: - machine.execute_step(step) - machine.check_invariants() - finally: - machine.teardown() - -and such that at every point, the step executed is one that could plausible -have come from a call to ``steps`` in the current state. - -Here's an example of using stateful testing to test a broken implementation -of a set in terms of a list (note that you could easily do something close to -this example with the rule based testing instead, and probably should. This -is mostly for illustration purposes): - -.. code:: python - - import unittest - - from hypothesis.stateful import GenericStateMachine - from hypothesis.strategies import tuples, sampled_from, just, integers - - - class BrokenSet(GenericStateMachine): - def __init__(self): - self.data = [] - - def steps(self): - add_strategy = tuples(just("add"), integers()) - if not self.data: - return add_strategy - else: - return ( - add_strategy | - tuples(just("delete"), sampled_from(self.data))) - - def execute_step(self, step): - action, value = step - if action == 'delete': - try: - self.data.remove(value) - except ValueError: - pass - assert value not in self.data - else: - assert action == 'add' - self.data.append(value) - assert value in self.data - - - TestSet = BrokenSet.TestCase - - if __name__ == '__main__': - unittest.main() - - -Note that the strategy changes each time based on the data that's currently -in the state machine. - -Running this gives us the following: - -.. code:: bash - - Step #1: ('add', 0) - Step #2: ('add', 0) - Step #3: ('delete', 0) - F - ====================================================================== - FAIL: runTest (hypothesis.stateful.BrokenSet.TestCase) - ---------------------------------------------------------------------- - Traceback (most recent call last): - (...) - assert value not in self.data - AssertionError - -So it adds two elements, then deletes one, and throws an assertion when it -finds out that this only deleted one of the copies of the element. - - -------------------------- -More fine grained control -------------------------- - -If you want to bypass the TestCase infrastructure you can invoke these -manually. The stateful module exposes the function run_state_machine_as_test, -which takes an arbitrary function returning a GenericStateMachine and an -optional settings parameter and does the same as the class based runTest -provided. - -In particular this may be useful if you wish to pass parameters to a custom -__init__ in your subclass. diff -Nru python-hypothesis-3.44.1/docs/strategies.rst python-hypothesis-3.71.11/docs/strategies.rst --- python-hypothesis-3.44.1/docs/strategies.rst 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/docs/strategies.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +0,0 @@ -============================= -Projects extending Hypothesis -============================= - -The following is a non-exhaustive list of open source projects that make -Hypothesis strategies available. If you're aware of any others please add them -the list! The only inclusion criterion right now is that if it's a Python -library then it should be available on pypi. - -* `hs-dbus-signature `_ - strategy to generate arbitrary D-Bus signatures -* `hypothesis-regex `_ - - merged into Hypothesis as the :func:`~hypothesis.strategies.from_regex` strategy.* -* `lollipop-hypothesis `_ - - strategy to generate data based on - `Lollipop `_ schema definitions. -* `hypothesis-fspaths `_ - - strategy to generate filesystem paths. -* `hypothesis-protobuf `_ - - strategy to generate data based on `Protocol Buffer `_ schema definitions. - -If you're thinking about writing an extension, consider naming it -``hypothesis-{something}`` - a standard prefix makes the community more -visible and searching for extensions easier. diff -Nru python-hypothesis-3.44.1/docs/supported.rst python-hypothesis-3.71.11/docs/supported.rst --- python-hypothesis-3.44.1/docs/supported.rst 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/docs/supported.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,96 +0,0 @@ -============= -Compatibility -============= - -Hypothesis does its level best to be compatible with everything you could -possibly need it to be compatible with. Generally you should just try it and -expect it to work. If it doesn't, you can be surprised and check this document -for the details. - ---------------- -Python versions ---------------- - -Hypothesis is supported and tested on CPython 2.7 and CPython 3.4+. - -Hypothesis also supports PyPy2, and will support PyPy3 when there is a stable -release supporting Python 3.4+. Hypothesis does not currently work on Jython, -though could feasibly be made to do so. IronPython might work but hasn't been -tested. 32-bit and narrow builds should work, though this is currently only -tested on Windows. - -In general Hypothesis does not officially support anything except the latest -patch release of any version of Python it supports. Earlier releases should work -and bugs in them will get fixed if reported, but they're not tested in CI and -no guarantees are made. - ------------------ -Operating systems ------------------ - -In theory Hypothesis should work anywhere that Python does. In practice it is -only known to work and regularly tested on OS X, Windows and Linux, and you may -experience issues running it elsewhere. - -If you're using something else and it doesn't work, do get in touch and I'll try -to help, but unless you can come up with a way for me to run a CI server on that -operating system it probably won't stay fixed due to the inevitable march of time. - ------------------- -Testing frameworks ------------------- - -In general Hypothesis goes to quite a lot of effort to generate things that -look like normal Python test functions that behave as closely to the originals -as possible, so it should work sensibly out of the box with every test framework. - -If your testing relies on doing something other than calling a function and seeing -if it raises an exception then it probably *won't* work out of the box. In particular -things like tests which return generators and expect you to do something with them -(e.g. nose's yield based tests) will not work. Use a decorator or similar to wrap the -test to take this form. - -In terms of what's actually *known* to work: - - * Hypothesis integrates as smoothly with py.test and unittest as I can make it, - and this is verified as part of the CI. - * py.test fixtures work correctly with Hypothesis based functions, but note that - function based fixtures will only run once for the whole function, not once per - example. - * Nose works fine with hypothesis, and this is tested as part of the CI. yield based - tests simply won't work. - * Integration with Django's testing requires use of the :ref:`hypothesis-django` package. - The issue is that in Django's tests' normal mode of execution it will reset the - database one per test rather than once per example, which is not what you want. - -Coverage works out of the box with Hypothesis (and Hypothesis has 100% branch -coverage in its own tests). However you should probably not use Coverage, Hypothesis -and PyPy together. Because Hypothesis does quite a lot of CPU heavy work compared -to normal tests, it really exacerbates the performance problems the two normally -have working together. - ------------------ -Optional Packages ------------------ - -The supported versions of optional packages, for strategies in ``hypothesis.extra``, -are listed in the documentation for that extra. Our general goal is to support -all versions that are supported upstream. - ------------------------- -Regularly verifying this ------------------------- - -Everything mentioned above as explicitly supported is checked on every commit -with `Travis `_ and -`Appveyor `_ -and goes green before a release happens, so when I say they're supported I -really mean it. - -------------------- -Hypothesis versions -------------------- - -Backwards compatibility is better than backporting fixes, so we use -:ref:`semantic versioning ` and only support the most recent -version of Hypothesis. See :doc:`support` for more information. diff -Nru python-hypothesis-3.44.1/docs/support.rst python-hypothesis-3.71.11/docs/support.rst --- python-hypothesis-3.44.1/docs/support.rst 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/docs/support.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,19 +0,0 @@ -================ -Help and Support -================ - -For questions you are happy to ask in public, the :doc:`Hypothesis community ` is a -friendly place where I or others will be more than happy to help you out. You're also welcome to -ask questions on Stack Overflow. If you do, please tag them with 'python-hypothesis' so someone -sees them. - -For bugs and enhancements, please file an issue on the :issue:`GitHub issue tracker <>`. -Note that as per the :doc:`development policy `, enhancements will probably not get -implemented unless you're willing to pay for development or implement them yourself (with assistance from me). Bugs -will tend to get fixed reasonably promptly, though it is of course on a best effort basis. - -To see the versions of Python, optional dependencies, test runners, and operating systems Hypothesis -supports (meaning incompatibility is treated as a bug), see :doc:`supported`. - -If you need to ask questions privately or want more of a guarantee of bugs being fixed promptly, please contact me on -hypothesis-support@drmaciver.com to talk about availability of support contracts. diff -Nru python-hypothesis-3.44.1/docs/usage.rst python-hypothesis-3.71.11/docs/usage.rst --- python-hypothesis-3.44.1/docs/usage.rst 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/docs/usage.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -===================================== -Open Source Projects using Hypothesis -===================================== - -The following is a non-exhaustive list of open source projects I know are using Hypothesis. If you're aware of -any others please add them to the list! The only inclusion criterion right now is that if it's a Python library -then it should be available on pypi. - -* `aur `_ -* `argon2_cffi `_ -* `attrs `_ -* `axelrod `_ -* `bidict `_ -* `binaryornot `_ -* `brotlipy `_ -* :pypi:`chardet` -* `cmph-cffi `_ -* `cryptography `_ -* `dbus-signature-pyparsing `_ -* `fastnumbers `_ -* `flocker `_ -* `flownetpy `_ -* `funsize `_ -* `fusion-index `_ -* `hyper-h2 `_ -* `into-dbus-python `_ -* `justbases `_ -* `justbytes `_ -* `loris `_ -* `mariadb-dyncol `_ -* `mercurial `_ -* `natsort `_ -* `pretext `_ -* `priority `_ -* `PyCEbox `_ -* `PyPy `_ -* `pyrsistent `_ -* `python-humble-utils `_ -* `pyudev `_ -* `qutebrowser `_ -* `RubyMarshal `_ -* `Segpy `_ -* `simoa `_ -* `srt `_ -* `tchannel `_ -* `vdirsyncer `_ -* `wcag-contrast-ratio `_ -* `yacluster `_ -* `yturl `_ diff -Nru python-hypothesis-3.44.1/examples/README.rst python-hypothesis-3.71.11/examples/README.rst --- python-hypothesis-3.44.1/examples/README.rst 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/examples/README.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ -============================ -Examples of Hypothesis usage -============================ - -This is a directory for examples of using Hypothesis that show case its -features or demonstrate a useful way of testing something. - -Right now it's a bit small and fairly algorithmically focused. Pull requests to -add more examples would be *greatly* appreciated, especially ones using e.g. -the Django integration or testing something "Businessy". diff -Nru python-hypothesis-3.44.1/examples/test_binary_search.py python-hypothesis-3.71.11/examples/test_binary_search.py --- python-hypothesis-3.44.1/examples/test_binary_search.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/examples/test_binary_search.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,141 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -"""This file demonstrates testing a binary search. - -It's a useful example because the result of the binary search is so clearly -determined by the invariants it must satisfy, so we can simply test for those -invariants. - -It also demonstrates the useful testing technique of testing how the answer -should change (or not) in response to movements in the underlying data. - -""" - -from __future__ import division, print_function, absolute_import - -import hypothesis.strategies as st -from hypothesis import given - - -def binary_search(ls, v): - """Take a list ls and a value v such that ls is sorted and v is comparable - with the elements of ls. - - Return an index i such that 0 <= i <= len(v) with the properties: - - 1. ls.insert(i, v) is sorted - 2. ls.insert(j, v) is not sorted for j < i - - """ - # Without this check we will get an index error on the next line when the - # list is empty. - if not ls: - return 0 - - # Without this check we will miss the case where the insertion point should - # be zero: The invariant we maintain in the next section is that lo is - # always strictly lower than the insertion point. - if v <= ls[0]: - return 0 - - # Invariant: There is no insertion point i with i <= lo - lo = 0 - - # Invariant: There is an insertion point i with i <= hi - hi = len(ls) - while lo + 1 < hi: - mid = (lo + hi) // 2 - if v > ls[mid]: - # Inserting v anywhere below mid would result in an unsorted list - # because it's > the value at mid. Therefore mid is a valid new lo - lo = mid - # Uncommenting the following lines will cause this to return a valid - # insertion point which is not always minimal. - # elif v == ls[mid]: - # return mid - else: - # Either v == ls[mid] in which case mid is a valid insertion point - # or v < ls[mid], in which case all valid insertion points must be - # < hi. Either way, mid is a valid new hi. - hi = mid - assert lo + 1 == hi - # We now know that there is a valid insertion point <= hi and there is no - # valid insertion point < hi because hi - 1 is lo. Therefore hi is the - # answer we were seeking - return hi - - -def is_sorted(ls): - """Is this list sorted?""" - for i in range(len(ls) - 1): - if ls[i] > ls[i + 1]: - return False - return True - - -Values = st.integers() - -# We generate arbitrary lists and turn this into generating sorting lists -# by just sorting them. -SortedLists = st.lists(Values).map(sorted) - -# We could also do it this way, but that would be a bad idea: -# SortedLists = st.lists(Values).filter(is_sorted) -# The problem is that Hypothesis will only generate long sorted lists with very -# low probability, so we are much better off post-processing values into the -# form we want than filtering them out. - - -@given(ls=SortedLists, v=Values) -def test_insert_is_sorted(ls, v): - """We test the first invariant: binary_search should return an index such - that inserting the value provided at that index would result in a sorted - set.""" - ls.insert(binary_search(ls, v), v) - assert is_sorted(ls) - - -@given(ls=SortedLists, v=Values) -def test_is_minimal(ls, v): - """We test the second invariant: binary_search should return an index such - that no smaller index is a valid insertion point for v.""" - for i in range(binary_search(ls, v)): - ls2 = list(ls) - ls2.insert(i, v) - assert not is_sorted(ls2) - - -@given(ls=SortedLists, v=Values) -def test_inserts_into_same_place_twice(ls, v): - """In this we test a *consequence* of the second invariant: When we insert - a value into a list twice, the insertion point should be the same both - times. This is because we know that v is > the previous element and == the - next element. - - In theory if the former passes, this should always pass. In practice, - failures are detected by this test with much higher probability because it - deliberately puts the data into a shape that is likely to trigger a - failure. - - This is an instance of a good general category of test: Testing how the - function moves in responses to changes in the underlying data. - - """ - i = binary_search(ls, v) - ls.insert(i, v) - assert binary_search(ls, v) == i diff -Nru python-hypothesis-3.44.1/examples/test_rle.py python-hypothesis-3.71.11/examples/test_rle.py --- python-hypothesis-3.44.1/examples/test_rle.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/examples/test_rle.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,105 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -"""This example demonstrates testing a run length encoding scheme. That is, we -take a sequence and represent it by a shorter sequence where each 'run' of -consecutive equal elements is represented as a single element plus a count. So -e.g. - -[1, 1, 1, 1, 2, 1] is represented as [[1, 4], [2, 1], [1, 1]] - -This demonstrates the useful decode(encode(x)) == x invariant that is often -a fruitful source of testing with Hypothesis. - -It also has an example of testing invariants in response to changes in the -underlying data. - -""" - -from __future__ import division, print_function, absolute_import - -import hypothesis.strategies as st -from hypothesis import given, assume - - -def run_length_encode(seq): - """Encode a sequence as a new run-length encoded sequence.""" - if not seq: - return [] - # By starting off the count at zero we simplify the iteration logic - # slightly. - result = [[seq[0], 0]] - for s in seq: - if ( - # If you uncomment this line this branch will be skipped and we'll - # always append a new run of length 1. Note which tests fail. - # False and - s == result[-1][0] - # Try uncommenting this line and see what problems occur: - # and result[-1][-1] < 2 - ): - result[-1][1] += 1 - else: - result.append([s, 1]) - return result - - -def run_length_decode(seq): - """Take a previously encoded sequence and reconstruct the original from - it.""" - result = [] - for s, i in seq: - for _ in range(i): - result.append(s) - return result - - -# We use lists of a type that should have a relatively high duplication rate, -# otherwise we'd almost never get any runs. -Lists = st.lists(st.integers(0, 10)) - - -@given(Lists) -def test_decodes_to_starting_sequence(ls): - """If we encode a sequence and then decode the result, we should get the - original sequence back. - - Otherwise we've done something very wrong. - - """ - assert run_length_decode(run_length_encode(ls)) == ls - - -@given(Lists, st.integers(0, 100)) -def test_duplicating_an_element_does_not_increase_length(ls, i): - """The previous test could be passed by simply returning the input sequence - so we need something that tests the compression property of our encoding. - - In this test we deliberately introduce or extend a run and assert - that this does not increase the length of our encoding, because they - should be part of the same run in the final result. - - """ - # We use assume to get a valid index into the list. We could also have used - # e.g. flatmap, but this is relatively straightforward and will tend to - # perform better. - assume(i < len(ls)) - ls2 = list(ls) - # duplicating the value at i right next to it guarantees they are part of - # the same run in the resulting compression. - ls2.insert(i, ls2[i]) - assert len(run_length_encode(ls2)) == len(run_length_encode(ls)) diff -Nru python-hypothesis-3.44.1/.flake8 python-hypothesis-3.71.11/.flake8 --- python-hypothesis-3.44.1/.flake8 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/.flake8 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,10 @@ +[flake8] + +exclude = + compat.py, + hypothesis-python/src/hypothesis/vendor/*, + test_reflection.py, + test_imports.py, + hypothesis-python/tests/py2/*, + test_lambda_formatting.py +ignore = F811,D1,D205,D209,D213,D400,D401,D999,D202 diff -Nru python-hypothesis-3.44.1/.gitignore python-hypothesis-3.71.11/.gitignore --- python-hypothesis-3.44.1/.gitignore 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/.gitignore 2018-09-24 10:46:59.000000000 +0000 @@ -1,19 +1,38 @@ +# misc (editors, file systems, etc) + *.swo *.swp +.idea +.vagrant +.DS_Store +.hypothesis + +# generic build components + +.runtimes + +# python + *.pyc +*.pyo venv* .cache -.hypothesis +.pytest_cache +.mypy_cache docs/_build *.egg-info _build .tox .coverage -.runtimes -.idea -.vagrant -.DS_Store -deploy_key .pypirc -secrets.tar htmlcov +build +dist +.doctrees/ + +# encrypted files +secrets.tar +secrets + +# Rust build targets +target diff -Nru python-hypothesis-3.44.1/guides/api-style.rst python-hypothesis-3.71.11/guides/api-style.rst --- python-hypothesis-3.44.1/guides/api-style.rst 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/guides/api-style.rst 2018-09-24 10:46:59.000000000 +0000 @@ -2,6 +2,9 @@ House API Style =============== +Note: Currently this guide is very specific to the *Python* version of Hypothesis. +It needs updating for the Ruby version (and, in future, other versions). + Here are some guidelines for how to write APIs so that they "feel" like a Hypothesis API. This is particularly focused on writing new strategies, as that's the major place where we add APIs, but also applies more generally. @@ -105,6 +108,49 @@ ``max_size`` to ``None`` (even if internally it is bounded). +~~~~~~~~~~~~~~~ +Deferred Errors +~~~~~~~~~~~~~~~ + +As far as is reasonable, functions should raise errors when the test is run +(typically by deferring them until you try to draw from the strategy), +not when they are called. +This mostly applies to strategy functions and some error conditions in +``@given`` itself. + +Generally speaking this should be taken care of automatically by use of the +``@defines_strategy`` decorator. + +We do not currently do this for the ``TypeError`` that you will get from +calling the function incorrectly (e.g. with invalid keyword arguments or +missing required arguments). +In principle we could, but it would result in much harder to read function +signatures, so we would be trading off one form of comprehensibility for +another, and so far that hasn't seemed to be worth it. + +The main reasons for preferring this style are: + +* Errors at test import time tend to throw people and be correspondingly hard + for them to debug. + There's an expectation that errors in your test code result in failures in + your tests, and the fact that that test code happens to be defined in a + decorator doesn't seem to change that expectation for people. +* Things like deprecation warnings etc. localize better when they happen + inside the test - test runners will often swallow them or put them in silly + places if they're at import time, but will attach any output that happens + in the test to the test itself. +* There are a lot of cases where raising an error, deprecation warning, etc. + is *only* possible in a test - e.g. if you're using the inline style with + `data `_, + or if you're using + `flatmap `_ + or + `@composite `_ + then the strategy won't actually get evaluated until we run the test, + so that's the only place they can happen. + It's nice to be consistent, and it's weird if sometimes strategy errors result in + definition time errors and sometimes they result in test errors. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A catalogue of current violations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff -Nru python-hypothesis-3.44.1/guides/documentation.rst python-hypothesis-3.71.11/guides/documentation.rst --- python-hypothesis-3.44.1/guides/documentation.rst 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/guides/documentation.rst 2018-09-24 10:46:59.000000000 +0000 @@ -2,6 +2,9 @@ The Hypothesis Documentation Handbook ===================================== +Note: Currently this guide is very specific to the *Python* version of Hypothesis. +It needs updating for the Ruby version (and, in future, other versions). + Good documentation can make the difference between good code and useful code - and Hypothesis is written to be used, as widely as possible. @@ -57,11 +60,35 @@ That means every contributor gets to write their changelog! A changelog entry should be written in a new ``RELEASE.rst`` file in -the repository root, and: +the `hypothesis-python` directory (other projects will have a release file +in their corresponding directory, but the system is currently not functioning for `hypothesis-ruby`, +which is the only other such project at the moment). + +The first line of the file specifies the component +of the version number that will be updated, according to our +`semantic versioning `_ policy. + +- ``RELEASE_TYPE: major`` is for breaking changes, and will only be used by the + core team after extensive discussion. +- ``RELEASE_TYPE: minor`` is for anything that adds to the public (ie documented) + API, changes an argument signature, or adds a new deprecation or health check. + Minor (or patch) releases **must not** cause errors in any code that runs + without errors on an earlier version of Hypothesis, using only the public API. + Silent errors *may* be converted to noisy errors, but generally we prefer + to issue a deprecation warning and use the new behaviour if possible. + This stability policy only applies to use of Hypothesis itself, not the + results of user-written tests that use Hypothesis. +- ``RELEASE_TYPE: patch`` is for changes that are not visible in the public + interface, from improving a docstring to backwards-compatible improvements + in shrinking behaviour. + +This first line will be removed from the final change log entry. +The remaining lines are the actual changelog text for this release, +which should: - concisely describe what changed and why - use Sphinx cross-references to any functions or classes mentioned -- if closing an issue, mention it with the issue role to generate a link +- if closing an issue, mention it with the ``:issue:`` role to generate a link - finish with a note of thanks from the maintainers: "Thanks to for this bug fix / feature / contribution" (depending on which it is). If this is your first contribution, @@ -72,11 +99,9 @@ Updating Doctests ----------------- -We use the Sphinx `doctest` builder to ensure that all example code snippets +We use the Sphinx ``doctest`` builder to ensure that all example code snippets are kept up to date. To make this less tedious, you can run ``scripts/fix_doctests.py`` (under Python 3) to... fix failing doctests. The script is pretty good, but doesn't handle ``+ELLIPSIS`` or -``+NORMALIZE_WHITESPACE`` options. Check that output is stable (running -it again should give "All doctests are OK"), then review the diff before -committing. +``+NORMALIZE_WHITESPACE`` options. Review the diff before committing. diff -Nru python-hypothesis-3.44.1/guides/internals.rst python-hypothesis-3.71.11/guides/internals.rst --- python-hypothesis-3.44.1/guides/internals.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/guides/internals.rst 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,345 @@ +=================================== +How to Work on Hypothesis Internals +=================================== + +Note: Currently this guide is very specific to the *Python* version of Hypothesis. +Over time the core will be factored out into a small separate set of libraries - +the current migration plan is to move all of the Python code into Rust and have +the Python and Ruby versions both depend on this. Eventually we will likely need +to have more than one core library - e.g. a Java one as well. + +This is a guide to how to work on Hypothesis internals, +with a particular focus on helping people who are new to it. +Right now it is very rudimentary and is intended primarily for people who are +looking to get started writing shrink passes as part of our `current outreach +program to get more people doing that `_, +but it will expand over time. + +------------------------ +Bird's Eye View Concepts +------------------------ + +The core engine of Hypothesis is called Conjecture. + +The "fundamental idea" of Conjecture is that you can represent an arbitrary +randomized test case as the sequence of bytes read from the pseudo-random +number generator (PRNG) that produced it. +Whenever the test did something "random" it actually read the next bytes and +did what they told it to do. +But those bytes didn't *have* to come from a PRNG, and we can run the test +given any byte sequence we like. By manipulating the choice of bytes, we can achieve +more interesting effects than pure randomness would allow us to do, while +retaining the power and ease of use of random testing. + +The greatest strength of this idea is that we have a single source of truth +for what an example should look like: Every byte sequence is one that *could* +have come from a PRNG, and thus is a valid thing to try for our test. +The only ways it can fail to be a valid test input are for it to be too short +or for it to not satisfy one of the test's preconditions, and both are easily +detectable. + +The idea of shrinking in particular is that once we have this representation, +we can shrink arbitrary test cases based on it. We try to produce a string that +is *shortlex minimal*. What this means is that it has the shortest possible +length and among those strings of minimal length is lexicographically (i.e. the +normal order on strings - find the first byte at which they differ and use that +to decide) smallest. + +Ideally we could think of the shrinker as a generic function that takes a +string satisfying some predicate and returns the shortlex minimal string that +also satisfies it. + +We depart from this ideal in two ways: + +* we can only *approximate* such a minimal string. Finding the actual minimum is + intractable in general. +* we are only interested in minimizing things where the predicate goes through + the Hypothesis API, which lets us track how the data is used and use that to + guide the process. + +We then use a number of different transformations of the string to try and +reduce our input. These vary from principled general transformations to shameless +hacks that special case something we need to work well. + +One such example of a hack is the handling of floating point numbers. There are +a couple of lexicographic shrinks that are always valid but only really make +sense for our particular encoding of floats. We check if we're working +on something that is of the right size to be a float and apply those +transformations regardless of whether it is actually meant to be a float. +Worst case scenario it's not a float and they don't work, and we've run a few +extra test cases. + +-------------------------- +Useful Files to Know About +-------------------------- + +The code associated with Conjecture lives in +`src/hypothesis/internal/conjecture `_. +There are a number of files in there, +but the most important ones are ``engine.py`` and ``data.py``. +``data.py`` defines the core type that is used to represent test cases, +and ``engine.py`` contains the main driver for deciding what test cases to run. + +There is also ``minimizer.py``, which contains a general purpose lexicographic +minimizer. This is responsible for taking some byte string and a predicate over +byte strings and producing a string of the same length which is lexicographically +smaller. Unlike the shrinker in general, this *is* supposed to work on arbitrary +predicates and doesn't know anything about the testing API. We typically apply +this to subsets of the bytes for a test input with a predicate that knows how +to integrate those subsets into a larger test. This is the part of the code +that means we can do things like replacing an integer with a smaller one. + +------- +Testing +------- + +For general information about how to test Hypothesis, take a look at +the `testing guide `_, but there are a couple +of areas that it's worth specifically highlighting for making changes +to the engine: + +The first is `tests/cover/test_conjecture_engine.py `_, +which is a set of unit tests designed to put the engine into particular scenarios to exercise specific behaviours, +with a goal of achieving 100% coverage on it in isolation (though it currently does not quite achieve that for some specific edge cases. +We may fix and enforce this later). + +The other set of tests that are worth knowing about are the quality tests, +in `tests/quality `_. +These assert specific hard to satisfy properties about the examples that Hypothesis finds - +either their existence, or something about the final shrunk result. + +----------------------- +Engine Design Specifics +----------------------- + +There are a couple of code patterns that are mostly peculiar to Conjecture that +you may not have encountered before and are worth being aware of. + +~~~~~~~~~~~~~~~~~~~~ +Search State Objects +~~~~~~~~~~~~~~~~~~~~ + +There are a number of cases where we find ourself with a user-provided function +(where the "user" might still be something that is entirely our code) and we +want to pass a whole bunch of different examples to it in order to achieve some +result. Currently this includes each of the main engine, the Shrinker (in +``engine.py``) and the minimizer, but there are likely to be more in future. + +We typically organise such things in terms of an object that you create with +the function and possibly an initial argument that stores these on self and +has some ``run`` or similar method. They then run for a while, repeatedly +calling the function they were given. + +Generally speaking they do not call the function directly, but instead wrap +calls to it. This allows them to implement a certain amount of decision caching, +e.g. avoiding trying the same shrink twice, but also gives us a place where we +can update metadata about the search process. + +For objects whose goal is some form of optimisation (Shrinker, Minimizer) one +of the pieces of metadata they will typically track is a "current target". This +is typically the best example they have seen so far. By wrapping every call to +the predicate, we ensure that we never miss an example even when we're passing +through other things. + +For objects whose goal is some broader form of search (currently only +``ConjectureRunner``) this also allows them to keep track of *other* examples +of interest. For example, as part of our multiple bug discovery, +``ConjectureRunner`` keeps track of the smallest example of each distinct +failure that it has seen, and updates this automatically each time the test +function is called. This means that if during shrinking we "slip" and find a +different bug than the one we started with, we will *not* shrink to that, but +it will get remembered by the runner if it was either novel or better than our +current example. + +~~~~~~~~~~~ +Weird Loops +~~~~~~~~~~~ + +The loops inside a lot of the engine look very strange and unidiomatic. For +example: + +.. code-block:: python + + i = 0 + while i < len(self.intervals): + u, v = self.intervals[i] + if not self.incorporate_new_buffer( + self.shrink_target.buffer[:u] + self.shrink_target.buffer[v:] + ): + i += 1 + + +The more natural way to write this in Python would be: + +.. code-block:: python + + for u, v in self.intervals: + self.incorporate_new_buffer( + self.shrink_target.buffer[:u] + self.shrink_target.buffer[v:] + ) + +This is not equivalent in this case, and would exhibit the wrong behaviour. + +Every time ``incorporate_new_buffer`` succeeds, it changes the shape of the +current shrink target. This consequently changes the shape of intervals, both +its particular values and its current length - on each loop iteration the loop +might stop either because ``i`` increases or because ``len(self.intervals)`` +decreases. + +We do not reset ``i`` to zero on success, as this would cause us to retry deleting +things that we have already tried. This *might* work, but is less likely to. +In the event that none of the earlier deletions succeed, this causes us to do +retry the entire prefix uselessly, which can result in a pass taking O(n^2) time +to do O(n) deletions. + +An additional quirk is that we only increment ``i`` on failure. The reason for +this is that if we successfully deleted the current interval then the interval +in position ``i`` has been replaced with something else, which is probably the +next thing we would have tried deleting if we hadn't succeeded (or something +like it), so we don't want to advance past it. +This is specific to deletion: If we are just replacing the contents of +something then we expect it to still be in the same place, so there we increment +unconditionally. +Examples of this include ``zero_draws`` and ``minimize_individual_blocks``. + +------------ +The Shrinker +------------ + +The shrinking part of Hypothesis is organised into a single class called ``Shrinker`` +that lives in ``engine.py``. + +Its job is to take an initial ``ConjectureData`` object and some predicate that +it satisfies, and to try to produce a simpler ``ConjectureData`` object that +also satisfies that predicate. + +~~~~~~~~~~~~~~ +Search Process +~~~~~~~~~~~~~~ + +The search process mostly happens in the ``shrink`` method. It is split into +two parts: ``greedy_shrink`` and ``escape_local_minimum``. The former is a +greedy algorithm, meaning that it will only ever call the predicate with values +that are strictly smaller than our current best. This mostly works very well, +but sometimes it gets stuck. So what we do is after we have run that we try +restarting the process from something like our final state but a bit fuzzed and +run the greedy shrink again. We keep doing this as long as it results in a +smaller value than our previous best. + +The greedy shrinker is where almost all of the work happens. It is organised +into a large number of search passes, and is designed to run until all of those +passes fail to make any improvements. + +~~~~~~~~~~~~~ +Search Passes +~~~~~~~~~~~~~ + +Search passes are methods on the ``Shrinker`` class in ``engine.py``. They are +designed to take the current shrink target and try a number of things that might +be sensible shrinks of it. + +Typically the design of a search pass is that it should always try to run to +completion rather than exiting as soon as it's found something good, but that +it shouldn't retry things that are too like stuff it has already tried just +because something worked. So for example in the above loop, we try deleting +each interval (these roughly correspond to regions of the input that are +responsible for some particular value or small number of adjacent values). +When we succeed, we keep going and try deleting more intervals, but we don't +try to delete any intervals before the current index. + +The reason for this is that retrying things from the beginning might work but +probably won't. Thus if we restarted every time we made a change we would end +up doing a lot of useless work. Additionally, they are *more* likely to work +after other shrink passes have run because frequently other changes are likely +to unlock changes in the current pass that were previously impossible. e.g. +when we reorder some examples we might make a big region deletable that +previously contained something critical to the relevant behaviour of the test +but is now just noise. + +Because the shrinker runs in a big loop, if we've made progress the shrink pass +will always be run again (assuming we don't hit some limit that terminates the +shrink early, but by making the shrinker better we try to ensure that that +never happens). +This means that we will always get an opportunity to start again later if we +made progress, and if we didn't make progress we've tried everything anyway. + + +~~~~~~~~~~~~~~~~~~~~~~~ +Expensive Shrink Passes +~~~~~~~~~~~~~~~~~~~~~~~ + +We have a bunch of search passes that are considered "expensive". Typically +this means "quadratic or worse complexity". When shrinking we initially don't +run these, and the first time that we get to the end of our main passes and +have failed to make the input any smaller, we then turn them on. + +This allows the shrinker to switch from a good but slightly timid mode while its +input is large into a more aggressive DELETE ALL THE THINGS mode once that stops +working. By that point we've usually made our input small enough that quadratic +complexity is acceptable. + +We turn these on once and then they stay on. The reason for this is to avoid a +"flip-flopping" scenario where an expensive pass unlocks one trivial change that +the cheap passes can find and then they get stuck again and have to do an extra +useless run through the passes to prove that. + +~~~~~~~~~~~~~~~~~~~~~~ +Adaptive Shrink Passes +~~~~~~~~~~~~~~~~~~~~~~ + +A useful trick that some of the shrink passes use is to try a thing and if it +doesn't work take a look at what the test function did to guess *why* it didn't +work and try to repair that. + +Two example such passes are ``zero_draws`` and the various passes that try to +minimize individual blocks lexicographically. + +What happens in ``zero_draws`` is that we try replacing the region corresponding +to a draw with all zero bytes. If that doesn't work, we check if that was because +of changing the size of the example (e.g. doing that with a list will make the +list much shorter) and messing up the byte stream after that point. If this +was what happened then we try again with a sequence of zeroes that corresponds +to the size of the draw call in the version we tried that didn't work. + +The logic for what we do with block minimization is in ``try_shrinking_blocks``. +When it tries shrinking a block and it doesn't work, it checks if the sized +changed. If it does then it tries deleting the number of bytes that were lost +immediately after the shrunk block to see if it helps. + + +-------------- +Playing Around +-------------- + +I often find that it is informative to watch the shrink process in action using +Hypothesis's verbosity settings. This can give you an idea of what the format +of your data is, and how the shrink process transforms it. + +In particular, it is often useful to run a test with the flag ``-s`` to tell it +not to hide output and the environment variable ``HYPOTHESIS_VERBOSITY_LEVEL=debug``. +This will give you a very detailed log of what the testing process is running, +along with information about what passes in the shrinker rare running and how +they transform it. + +--------------- +Getting Started +--------------- + +The best way of getting started on working on the engine is to work on the +shrinker. This is because it has the most well defined problems, the best +documented code among the engine, and it's generally fun to work on. + +If you have not already done so, check out `Issue #1093 `_, +which collates a number of other issues about shrink quality that are good starting +points for people. + +The best place to get started thus is to take a look at those linked issues and +jump in and try things! Find one that you think sounds fun. Note that some +of them suggest not doing these as your first foray into the shrinker, as some +are harder than others. + +*Please* ask questions if you have any - either the main issue for general +purpose questions or specific issues for questions about a particular problem - +if you get stuck or if anything doesn't make sense. We're trying to make this +process easier for everyone to work on, so asking us questions is actively +helpful to us and we will be very grateful to you for doing so. diff -Nru python-hypothesis-3.44.1/guides/README.rst python-hypothesis-3.71.11/guides/README.rst --- python-hypothesis-3.44.1/guides/README.rst 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/guides/README.rst 2018-09-24 10:46:59.000000000 +0000 @@ -8,3 +8,6 @@ It is separate from the main documentation because it is not much use if you are merely *using* Hypothesis. It's purely for working on it. + +Most of these are currently written with the Python version of +Hypothesis in mind, but will evolve over time to be more multilingual. diff -Nru python-hypothesis-3.44.1/guides/review.rst python-hypothesis-3.71.11/guides/review.rst --- python-hypothesis-3.44.1/guides/review.rst 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/guides/review.rst 2018-09-24 10:46:59.000000000 +0000 @@ -2,18 +2,35 @@ The Hypothesis Code Review Handbook =================================== -Hypothesis has a process of reviewing every change, internal or external. -This is a document outlining that process. It's partly descriptive, partly -prescriptive, and entirely prone to change in response to circumstance -and need. We're still figuring this thing out! +Note: This review guide was written with the Python version in mind, +but should apply to *all* versions. If you find a place where it's a bit +too Python specific, please fix it or file an issue. + +This document outlines the process for reviewing changes to Hypothesis. It's +partly descriptive, partly prescriptive, and entirely prone to change in +response to circumstance and need. We're still figuring this thing out! + +----------------- +What Needs Review +----------------- + +The repository includes Hypothesis implementations for multiple languages, +which have different review requirements due to different levels of project +maturity: + +- all changes to hypothesis-python and the language-independent build + infrastructure must be signed off by at least one person with write access to + the repo other than the author of the change. (These requirements will apply + to any Hypothesis implementations with a 1.0 release.) +- changes by `DRMacIver `_ to hypothesis-ruby do + not require review, but will be posted as pull requests, often for long + enough that if someone wants to review and ask questions, they can. ---------------- How Review Works ---------------- -All changes to Hypothesis must be signed off by at least one person with -write access to the repo other than the author of the change. Once the -build is green and a reviewer has approved the change, anyone on the +Once the build is green and a reviewer has approved the change, anyone on the maintainer team may merge the request. More than one maintainer *may* review a change if they wish to, but it's @@ -71,21 +88,48 @@ an exception if both the author and another maintainer agree. -~~~~~~~~~~~~~~~~~~~~ -General Requirements -~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~ +Orthogonality +~~~~~~~~~~~~~ + +For all minor or patch releases, we enforce a hard and fast rule that they +contain no more than one user-visible change. Major releases are allowed +to bundle multiple changes together, but these should be structured as +smaller pull requests into some tracking branch. + +We are currently very bad at this, so reviewers should feel empowered +to be extra strict and provide a lot of push back on this. + +What counts as a user visible change is somewhat up to individual +judgement, but you should err in the direction of assuming that +if it might count then it does count. + +A good rule of thumb is that the ``RELEASE.rst`` uses the words "additionally" +or needs bullet points to be clear, it is likely too large. + +Ideally changes that are not user visible should also be self-contained +into their own releases, but a certain amount of leniency is permitted - +it's certainly OK to do a moderate amount of refactoring while you're +in the area, and if a pull request involves no release at all then the same +level of orthogonality is not required (but is still desirable). + +~~~~~~~~~~~~~~~~~~~~~~ +Clarity of Description +~~~~~~~~~~~~~~~~~~~~~~ + +The ``RELEASE.rst`` should contain a description of the change that +makes clear: -The following are required for almost every change: +1. The motivation for the change +2. The likely consequences of the change -1. Changes must be of reasonable size. If a change could logically - be broken up into several smaller changes that could be reviewed - separately on their own merits, it should be. -2. The motivation for each change should be clearly explained (this - doesn't have to be an essay, especially for small changes, but - at least a sentence of explanation is usually required). -3. The likely consequences of a change should be outlined (again, - this doesn't have an essay, and it may be sufficiently - self-explanatory that the motivation section is sufficient). +This doesn't have to be an essay. If you're following the orthogonality +requirements a paragraph or two is likely sufficient. + +Any additional information that is useful to reviewers should be provided +in the pull request comment. This can include e.g. background, why the +particular approach was taken, references to internals that are unlikely +to be of interest to users. ~~~~~~~~~~~~~~~~~~~~~ Functionality Changes @@ -101,17 +145,11 @@ 3. Hypothesis must never be *flaky*. Flakiness here is defined as anything where a test fails and this does not indicate a bug in Hypothesis or in the way the user wrote the code or the test. -4. The version number must be kept up to date, following - `Semantic Versioning `_ conventions: The third (patch) - number increases for things that don't change public facing functionality, - the second (minor) for things that do but are backwards compatible, and - the first (major) changes for things that aren't backwards compatible. - See the section on API changes for the latter two. -5. The changelog should be kept up to date by creating a RELEASE.rst file in - the root of the repository. Make sure you build the documentation and - manually inspect the resulting changelog to see that it looks good - there - are a lot of syntax mistakes possible in RST that don't result in a - compilation error. +4. The changelog (in ``RELEASE.rst``) should bump the minor or patch version + (see guides/documentation.rst for details), accurately describe the + changes, and shouldn't refer to internal-only APIs. For complicated + markup, consider building the docs and manually checking the changelog + for formatting errors that didn't result in a compilation error. ~~~~~~~~~~~ API Changes @@ -148,7 +186,8 @@ though other maintainers are welcome and likely to chip in to review as well. 9. We have a separate guide for `house API style `_ which should - be followed. + be followed. Note that currently this only covers the API style for the Python + version. We are still figuring out the API style for the Ruby version. ~~~~~~~~~ Bug Fixes @@ -166,6 +205,8 @@ Settings Changes ~~~~~~~~~~~~~~~~ +Note: This section currently only applies to the Python version. + It is tempting to use the Hypothesis settings object as a dumping ground for anything and everything that you can think of to control Hypothesis. This rapidly gets confusing for users and should be carefully avoided. @@ -193,7 +234,8 @@ Engine changes are anything that change a "fundamental" of how Hypothesis works. A good rule of thumb is that an engine change is anything that touches -a file in hypothesis.internal.conjecture. +a file in hypothesis.internal.conjecture (Python version) or Rust code (Ruby +version). All such changes should: @@ -221,3 +263,44 @@ change? Could they be improved? 3. Are there any more general changes suggested by this, and do they have appropriate issues and/or pull requests associated with them? + +~~~~~~~~~~~~~~~~~~~~ +Asking for more work +~~~~~~~~~~~~~~~~~~~~ + +Reviewers should in general not request changes that expand the scope of +a pull request beyond its original intended goal. The primary design +philosophy of our work-flow is that making correct changes should be cheap, +and scope creep on pull requests works against that - If you can't touch +something without having to touch a number of related areas as well, +changing things becomes expensive again. + +This of course doesn't cover things where additional work is required to +ensure the change is actually correct - for example, if you change public +functionality you certainly need to update its documentation. That isn't +scope creep, that's just the normal scope. + +If a pull request suggests additional work then between the reviewer and the +author people should ensure that there are relevant tracking issues for that +work (as per question 3 in "Non-Blocking Questions" above), but there is no +obligation for either of them to actually do any of the work on those issues. +By default it is the reviewer who should open these issues, but the author +is welcome to as well. + +That being said, it's legitimate to expand the scope of a pull request in +some cases. For example: + +* If not doing so is likely to cause problems later. For example, because + of backwards compatibility requirements it might make sense to ask for some + additional functionality that is likely to be added later so that the arguments + to a function are in a more sensible order. +* Cases where the added functionality feels extremely incomplete in some + way without an additional change. The litmus test here should be "this will + almost never be useful because...". This is still fairly subjective, but at + least one good use case where the change is a clear improvement over the status + quo is enough to indicate that this doesn't apply. + +If it's unclear, the reviewer should feel free to suggest additional work +(but if the author is someone new, please make sure that it's clear that this +is a suggestion and not a requirement!), but the author of the pull request should +feel equally free to decline the suggestion. diff -Nru python-hypothesis-3.44.1/guides/testing-hypothesis.rst python-hypothesis-3.71.11/guides/testing-hypothesis.rst --- python-hypothesis-3.44.1/guides/testing-hypothesis.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/guides/testing-hypothesis.rst 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,173 @@ +================== +Testing Hypothesis +================== + +Note: This guide is currently entirely specific to the Python version of +Hypothesis. + +This is a guide to the process of testing Hypothesis itself, both how to +run its tests and how to to write new ones. + +-------------------------- +General Testing Philosophy +-------------------------- + +The test suite for Hypothesis is unusually powerful - as you might hope! - +but the secret is actually more about attitude than technology. + +The key is that we treat any bug in Hypothesis as a bug in our test suite +too - and think about the kinds of bugs that might not be caught, then write +tests that would catch them. + +We also use a variety of tools to check our code automatically. This includes +formatting, import order, linting, and doctests (so examples in docs don't +break). All of this is checked in CI - which means that once the build is +green, humans can all focus on meaningful review rather than nitpicking +operator spacing. + +Similarly, we require all code to have tests with 100% branch coverage - as +a starting point, not the final goal. + +- Requiring full coverage can't guarantee that we've written all the tests + worth writing (for example, maybe we left off a useful assertion about the + result), but less than full coverage guarantees that there's some code we're + not testing at all. +- Tests beyond full coverage generally aim to demonstrate that a particular + feature works, or that some subtle failure case is not present - often + because when it was found and fixed, someone wrote a test to make sure it + couldn't come back! + +The ``tests/`` directory has some notes in the README file on where various +kinds of tests can be found or added. Go there for the practical stuff, or +just ask one of the maintainers for help on a pull request! + +Further reading: How `SQLite is tested `_, +`how the Space Shuttle was tested `_, +`how to misuse code coverage `_ +(for inspiration, *not* implementation). +Dan Luu writes about `fuzz testing `_ and +`broken processes `_, among other things. + +--------------------------------------- +Setting up a virtualenv to run tests in +--------------------------------------- + +If you want to run individual tests rather than relying on the make tasks +(which you probably will), it's easiest to do this in a virtualenv. + +The following will give you a working virtualenv for running tests in: + +.. code-block:: bash + + pip install virtualenv + python -m virtualenv testing-venv + + # On Windows: testing-venv\Scripts\activate + source testing-venv/bin/activate + + # Can also use pip install -e .[all] to get + # all optional dependencies + pip install -e . + + # Test specific dependencies. + pip install pytest-xdist flaky + +Now whenever you want to run tests you can just activate the virtualenv +using ``source testing-venv/bin/activate`` or ``testing-venv\Scripts\activate`` +and all of the dependencies will be available to you and your local copy +of Hypothesis will be on the path (so any edits will be picked up automatically +and you don't need to reinstall it in the local virtualenv). + +------------- +Running Tests +------------- + +In order to run tests outside of the make/tox/etc set up, you'll need an +environment where Hypothesis is on the path and all of the testing dependencies +are installed. +We recommend doing this inside a virtualenv as described in the previous section. + +All testing is done using `pytest `_, +with a couple of plugins installed. For advanced usage we recommend reading the +pytest documentation, but this section will give you a primer in enough of the +common commands and arguments to get started. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Selecting Which Files to Run +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following invocation runs all of the tests in the file +`tests/cover/test_conjecture_engine.py`: + +.. code-block:: + + python -m pytest tests/cover/test_conjecture_engine.py + +If you want to run multiple files you can pass them all as arguments, and if +you pass a directory then it will run all files in that directory. +For example the following runs all the files in `test_conjecture_engine.py` +and `test_slippage.py` + +.. code-block:: + + python -m pytest tests/cover/test_conjecture_engine.py tests/cover/test_slippage.py + +If you were running this in bash (if you're not sure: if you're not on Windows +you probably are) you could also use the syntax: + +.. code-block:: + + python -m pytest tests/cover/test_{conjecture_engine,slippage}.py + +And the following would run all tests under `tests/cover`: + +.. code-block:: + + python -m pytest tests/cover + + +~~~~~~~~~~~ +Test Layout +~~~~~~~~~~~ + +The top level structure of the tests in Hypothesis looks as follows: + +* ``cover`` contains tests that we measure coverage for. This is intended to + be a fairly minimal and fast set of tests that still gives pretty good + confidence in the behaviour of the test suite. It is currently failing at + both "minimal" and "fast", but we're trying to move it back in that + direction. Try not to add tests to this unless they're actually to cover + some specific target. +* ``nocover`` is a general dumping ground for slower tests that aren't needed + to achieve coverage. +* ``quality`` is for expensive tests about the distribution or shrinking of + examples. These will only be run on one Python version. +* ``py2`` and ``py3`` are for tests which only run on one major version of + Python. You can also write these in other directories using + ``pytest.mark.skipif``, but these directories are useful for things that + require a version-specific syntax. +* The remaining test directories are for testing specific extras modules and + should have the same name. + +As a rule of thumb when writing new tests, they should go in nocover unless +they are for a specific extras module or to deliberately target a particular +line for coverage. In the latter case, prefer fast unit tests over larger and +slower integration tests (we are not currently very good at this). + + +~~~~~~~~~~~~~~~~ +Useful Arguments +~~~~~~~~~~~~~~~~ + +Some useful arguments to pytest include: + +* You can pass ``-n 0`` to turn off ``pytest-xdist``'s parallel test execution. + Sometimes for running just a small number of tests its startup time is longer + than the time it saves (this will vary from system to system), so this can + be helpful if you find yourself waiting on test runners to start a lot. +* You can use ``-k`` to select a subset of tests to run. This matches on substrings + of the test names. For example ``-kfoo`` will only run tests that have "foo" as + a substring of their name. You can also use composite expressions here. + e.g. ``-k'foo and not bar'`` will run anything containing foo that doesn't + also contain bar. [More information on how to select tests to run can be found + in the pytest documentation](https://docs.pytest.org/en/latest/usage.html#specifying-tests-selecting-tests). diff -Nru python-hypothesis-3.44.1/hypothesis-python/.coveragerc python-hypothesis-3.71.11/hypothesis-python/.coveragerc --- python-hypothesis-3.44.1/hypothesis-python/.coveragerc 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/.coveragerc 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,24 @@ +[run] +branch = True +include = + **/.tox/*/lib/*/site-packages/hypothesis/*.py + **/.tox/*/lib/*/site-packages/hypothesis/**/*.py +omit = + **/pytestplugin.py + **/strategytests.py + **/compat*.py + **/extra/__init__.py + **/.tox/*/lib/*/site-packages/hypothesis/internal/coverage.py + +[report] +exclude_lines = + @abc.abstractmethod + @abc.abstractproperty + NotImplementedError + pragma: no cover + __repr__ + __ne__ + __copy__ + __deepcopy__ + except ImportError: + if PY2: diff -Nru python-hypothesis-3.44.1/hypothesis-python/docs/changes.rst python-hypothesis-3.71.11/hypothesis-python/docs/changes.rst --- python-hypothesis-3.44.1/hypothesis-python/docs/changes.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/docs/changes.rst 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,5358 @@ +========= +Changelog +========= + +This is a record of all past Hypothesis releases and what went into them, +in reverse chronological order. All previous releases should still be available +on pip. + +Hypothesis APIs come in three flavours: + +* Public: Hypothesis releases since 1.0 are `semantically versioned `_ + with respect to these parts of the API. These will not break except between + major version bumps. All APIs mentioned in this documentation are public unless + explicitly noted otherwise. +* Semi-public: These are APIs that are considered ready to use but are not wholly + nailed down yet. They will not break in patch releases and will *usually* not break + in minor releases, but when necessary minor releases may break semi-public APIs. +* Internal: These may break at any time and you really should not use them at + all. + +You should generally assume that an API is internal unless you have specific +information to the contrary. + +.. _v3.71.11: + +-------------------- +3.71.11 - 2018-09-24 +-------------------- + +This patch factors out some common code in the shrinker for iterating +over pairs of data blocks. There should be no user-visible change. + +.. _v3.71.10: + +-------------------- +3.71.10 - 2018-09-18 +-------------------- + +This patch allows :func:`~hypothesis.strategies.from_type` to handle the +empty tuple type, :obj:`typing.Tuple[()] `. + +.. _v3.71.9: + +------------------- +3.71.9 - 2018-09-17 +------------------- + +This patch updates some internal comments for :pypi:`mypy`. +There is no user-visible effect, even for Mypy users. + +.. _v3.71.8: + +------------------- +3.71.8 - 2018-09-17 +------------------- + +This patch fixes a rare bug that would cause a particular shrinker pass to +raise an IndexError, if a shrink improvement changed the underlying data +in an unexpected way. + +.. _v3.71.7: + +------------------- +3.71.7 - 2018-09-17 +------------------- + +This release fixes the broken cross-references in our docs, +and adds a CI check so we don't add new ones. + +.. _v3.71.6: + +------------------- +3.71.6 - 2018-09-16 +------------------- + +This patch fixes two bugs (:issue:`944` and :issue:`1521`), where messages +about :func:`@seed ` did not check the current verbosity +setting, and the wrong settings were active while executing +:ref:`explicit examples `. + +.. _v3.71.5: + +------------------- +3.71.5 - 2018-09-15 +------------------- + +This patch fixes a ``DeprecationWarning`` added in Python 3.8 (:issue:`1576`). + +Thanks to tirkarthi for this contribution! + +.. _v3.71.4: + +------------------- +3.71.4 - 2018-09-14 +------------------- + +This is a no-op release, which implements automatic DOI minting and code +archival of Hypothesis via `Zenodo `_. Thanks to +CERN and the EU *Horizon 2020* programme for providing this service! + +Check our :gh-file:`CITATION` file for details, or head right on over to +`doi.org/10.5281/zenodo.1412597 `_ + +.. _v3.71.3: + +------------------- +3.71.3 - 2018-09-10 +------------------- + +This release adds the test name to some deprecation warnings, +for easier debugging. + +Thanks to Sanyam Khurana for the patch! + +.. _v3.71.2: + +------------------- +3.71.2 - 2018-09-10 +------------------- + +This release makes Hypothesis's memory usage substantially smaller for tests with many +examples, by bounding the number of past examples it keeps around. + +You will not see much difference unless you are running tests with :obj:`~hypothesis.settings.max_examples` +set to well over ``1000``, but if you do have such tests then you should see memory usage mostly plateau +where previously it would have grown linearly with time. + +.. _v3.71.1: + +------------------- +3.71.1 - 2018-09-09 +------------------- + +This patch adds internal comments to some tree traversals in the core engine. +There is no user-visible change. + +.. _v3.71.0: + +------------------- +3.71.0 - 2018-09-08 +------------------- + +This release deprecates the coverage-guided testing functionality, +as it has proven brittle and does not really pull its weight. + +We intend to replace it with something more useful in the future, +but the feature in its current form does not seem to be worth the cost of using, +and whatever replaces it will likely look very different. + +.. _v3.70.4: + +------------------- +3.70.4 - 2018-09-08 +------------------- + +This patch changes the behaviour of :func:`~hypothesis.reproduce_failure` +so that blobs are only printed in quiet mode when the +:obj:`~hypothesis.settings.print_blob` setting is set to ``ALWAYS``. + +Thanks to Cameron McGill for writing this patch at the PyCon Australia sprints! + +.. _v3.70.3: + +------------------- +3.70.3 - 2018-09-03 +------------------- + +This patch removes some unnecessary code from the internals. +There is no user-visible change. + +.. _v3.70.2: + +------------------- +3.70.2 - 2018-09-03 +------------------- + +This patch fixes an internal bug where a corrupted argument to +:func:`@reproduce_failure ` could raise +the wrong type of error. Thanks again to Paweł T. Jochym, who maintains +Hypothesis on `conda-forge `_ and consistently +provides excellent bug reports including :issue:`1558`. + +.. _v3.70.1: + +------------------- +3.70.1 - 2018-09-03 +------------------- + +This patch updates hypothesis to report its version and settings when run with +pytest. (:issue:`1223`). + +Thanks to Jack Massey for this feature. + +.. _v3.70.0: + +------------------- +3.70.0 - 2018-09-01 +------------------- + +This release adds a ``fullmatch`` argument to +:func:`~hypothesis.strategies.from_regex`. When ``fullmatch=True``, the +whole example will match the regex pattern as for :func:`python:re.fullmatch`. + +Thanks to Jakub Nabaglo for writing this patch at the PyCon Australia sprints! + +.. _v3.69.12: + +-------------------- +3.69.12 - 2018-08-30 +-------------------- + +This release reverts the changes to logging handling in 3.69.11, +which broke test that use the :pypi:`pytest` ``caplog`` fixture +internally because all logging was disabled (:issue:`1546`). + +.. _v3.69.11: + +-------------------- +3.69.11 - 2018-08-29 +-------------------- + +This patch will hide all logging messages produced by test cases before the +final, minimal, failing test case (:issue:`356`). + +Thanks to Gary Donovan for writing this patch at the PyCon Australia sprints! + +.. _v3.69.10: + +-------------------- +3.69.10 - 2018-08-29 +-------------------- + +This patch fixes a bug that prevents coverage from reporting unexecuted +Python files (:issue:`1085`). + +Thanks to Gary Donovan for writing this patch at the PyCon Australia sprints! + +.. _v3.69.9: + +------------------- +3.69.9 - 2018-08-28 +------------------- + +This patch improves the packaging of the Python package by adding +``LICENSE.txt`` to the sdist (:issue:`1311`), clarifying the minimum +supported versions of :pypi:`pytz` and :pypi:`dateutil ` +(:issue:`1383`), and adds keywords to the metadata (:issue:`1520`). + +Thanks to Graham Williamson for writing this patch at the PyCon +Australia sprints! + +.. _v3.69.8: + +------------------- +3.69.8 - 2018-08-28 +------------------- + +This is an internal change which replaces pickle with json to prevent possible +security issues. + +Thanks to Vidya Rani D G for writing this patch at the PyCon Australia sprints! + +.. _v3.69.7: + +------------------- +3.69.7 - 2018-08-28 +------------------- + +This patch ensures that :func:`~hypothesis.note` prints the note for every +test case when the :obj:`~hypothesis.settings.verbosity` setting is +``Verbosity.verbose``. At normal verbosity it only prints from the final +test case. + +Thanks to Tom McDermott for writing this patch at +the PyCon Australia sprints! + +.. _v3.69.6: + +------------------- +3.69.6 - 2018-08-27 +------------------- + +This patch improves the testing of some internal caching. It should have +no user-visible effect. + +.. _v3.69.5: + +------------------- +3.69.5 - 2018-08-27 +------------------- + +This change performs a small rename and refactoring in the core engine. +There is no user-visible change. + +.. _v3.69.4: + +------------------- +3.69.4 - 2018-08-27 +------------------- + +This change improves the core engine's ability to avoid unnecessary work, +by consulting its cache of previously-tried inputs in more cases. + +.. _v3.69.3: + +------------------- +3.69.3 - 2018-08-27 +------------------- + +This patch handles passing an empty :class:`python:enum.Enum` to +:func:`~hypothesis.strategies.from_type` by returning +:func:`~hypothesis.strategies.nothing`, instead of raising an +internal :class:`python:AssertionError`. + +Thanks to Paul Amazona for writing this patch at the +PyCon Australia sprints! + +.. _v3.69.2: + +------------------- +3.69.2 - 2018-08-23 +------------------- + +This patch fixes a small mistake in an internal comment. +There is no user-visible change. + +.. _v3.69.1: + +------------------- +3.69.1 - 2018-08-21 +------------------- + +This change fixes a small bug in how the core engine consults its cache +of previously-tried inputs. There is unlikely to be any user-visible change. + +.. _v3.69.0: + +------------------- +3.69.0 - 2018-08-20 +------------------- + +This release improves argument validation for stateful testing. + +- If the target or targets of a :func:`~hypothesis.stateful.rule` are invalid, + we now raise a useful validation error rather than an internal exception. +- Passing both the ``target`` and ``targets`` arguments is deprecated - + append the ``target`` bundle to the ``targets`` tuple of bundles instead. +- Passing the name of a Bundle rather than the Bundle itself is also deprecated. + +.. _v3.68.3: + +------------------- +3.68.3 - 2018-08-20 +------------------- + +This is a docs-only patch, fixing some typos and formatting issues. + +.. _v3.68.2: + +------------------- +3.68.2 - 2018-08-19 +------------------- + +This change fixes a small bug in how the core engine caches the results of +previously-tried inputs. The effect is unlikely to be noticeable, but it might +avoid unnecesary work in some cases. + +.. _v3.68.1: + +------------------- +3.68.1 - 2018-08-18 +------------------- + +This patch documents the :func:`~hypothesis.extra.numpy.from_dtype` function, +which infers a strategy for :class:`numpy:numpy.dtype`\ s. This is used in +:func:`~hypothesis.extra.numpy.arrays`, but can also be used directly when +creating e.g. Pandas objects. + +.. _v3.68.0: + +------------------- +3.68.0 - 2018-08-15 +------------------- + +:func:`~hypothesis.extra.numpy.arrays` now checks that integer and float +values drawn from ``elements`` and ``fill`` strategies can be safely cast +to the dtype of the array, and emits a warning otherwise (:issue:`1385`). + +Elements in the resulting array could previously violate constraints on +the elements strategy due to floating-point overflow or truncation of +integers to fit smaller types. + +.. _v3.67.1: + +------------------- +3.67.1 - 2018-08-14 +------------------- + +This release contains a tiny refactoring of the internals. +There is no user-visible change. + +.. _v3.67.0: + +------------------- +3.67.0 - 2018-08-10 +------------------- + +This release adds a ``width`` argument to :func:`~hypothesis.strategies.floats`, +to generate lower-precision floating point numbers for e.g. Numpy arrays. + +The generated examples are always instances of Python's native ``float`` +type, which is 64bit, but passing ``width=32`` will ensure that all values +can be exactly represented as 32bit floats. This can be useful to avoid +overflow (to +/- infinity), and for efficiency of generation and shrinking. + +Half-precision floats (``width=16``) are also supported, but require Numpy +if you are running Python 3.5 or earlier. + +.. _v3.66.33: + +-------------------- +3.66.33 - 2018-08-10 +-------------------- + +This release fixes a bug in :func:`~hypothesis.strategies.floats`, where +setting ``allow_infinity=False`` and exactly one of ``min_value`` and +``max_value`` would allow infinite values to be generated. + +.. _v3.66.32: + +-------------------- +3.66.32 - 2018-08-09 +-------------------- + +This release adds type hints to the :func:`~hypothesis.example` and +:func:`~hypothesis.seed` decorators, and fixes the type hint on +:func:`~hypothesis.strategies.register_type_strategy`. The second argument to +:func:`~hypothesis.strategies.register_type_strategy` must either be a +``SearchStrategy``, or a callable which takes a ``type`` and returns a +``SearchStrategy``. + +.. _v3.66.31: + +-------------------- +3.66.31 - 2018-08-08 +-------------------- + +Another set of changes designed to improve the performance of shrinking on +large examples. In particular the shrinker should now spend considerably less +time running useless shrinks. + +.. _v3.66.30: + +-------------------- +3.66.30 - 2018-08-06 +-------------------- + +"Bug fixes and performance improvements". + +This release is a fairly major overhaul of the shrinker designed to improve +its behaviour on large examples, especially around stateful testing. You +should hopefully see shrinking become much faster, with little to no quality +degradation (in some cases quality may even improve). + +.. _v3.66.29: + +-------------------- +3.66.29 - 2018-08-05 +-------------------- + +This release fixes two very minor bugs in the core engine: + +* it fixes a corner case that was missing in :ref:`3.66.28 `, which + should cause shrinking to work slightly better. +* it fixes some logic for how shrinking interacts with the database that was + causing Hypothesis to be insufficiently aggressive about clearing out old + keys. + +.. _v3.66.28: + +-------------------- +3.66.28 - 2018-08-05 +-------------------- + +This release improves how Hypothesis handles reducing the size of integers' +representation. This change should mostly be invisible as it's purely about +the underlying representation and not the generated value, but it may result +in some improvements to shrink performance. + +.. _v3.66.27: + +-------------------- +3.66.27 - 2018-08-05 +-------------------- + +This release changes the order in which Hypothesis chooses parts of the test case +to shrink. For typical usage this should be a significant performance improvement on +large examples. It is unlikely to have a major impact on example quality, but where +it does change the result it should usually be an improvement. + +.. _v3.66.26: + +-------------------- +3.66.26 - 2018-08-05 +-------------------- + +This release improves the debugging information that the shrinker emits about +the operations it performs, giving better summary statistics about which +passes resulted in test executions and whether they were successful. + +.. _v3.66.25: + +-------------------- +3.66.25 - 2018-08-05 +-------------------- + +This release fixes several bugs that were introduced to the shrinker in +:ref:`3.66.24 ` which would have caused it to behave significantly +less well than advertised. With any luck you should *actually* see the promised +benefits now. + +.. _v3.66.24: + +-------------------- +3.66.24 - 2018-08-03 +-------------------- + +This release changes how Hypothesis deletes data when shrinking in order to +better handle deletion of large numbers of contiguous sequences. Most tests +should see little change, but this will hopefully provide a significant +speed up for :doc:`stateful testing `. + +.. _v3.66.23: + +-------------------- +3.66.23 - 2018-08-02 +-------------------- + +This release makes some internal changes to enable further improvements to the +shrinker. You may see some changes in the final shrunk examples, but they are +unlikely to be significant. + +.. _v3.66.22: + +-------------------- +3.66.22 - 2018-08-01 +-------------------- + +This release adds some more internal caching to the shrinker. This should cause +a significant speed up for shrinking, especially for stateful testing and +large example sizes. + +.. _v3.66.21: + +-------------------- +3.66.21 - 2018-08-01 +-------------------- + +This patch is for downstream packagers - our tests now pass under +:pypi:`pytest` 3.7.0 (released 2018-07-30). There are no changes +to the source of Hypothesis itself. + +.. _v3.66.20: + +-------------------- +3.66.20 - 2018-08-01 +-------------------- + +This release removes some functionality from the shrinker that was taking a +considerable amount of time and does not appear to be useful any more due to +a number of quality improvements in the shrinker. + +You may see some degradation in shrink quality as a result of this, but mostly +shrinking should just get much faster. + +.. _v3.66.19: + +-------------------- +3.66.19 - 2018-08-01 +-------------------- + +This release slightly changes the format of some debugging information emitted +during shrinking, and refactors some of the internal interfaces around that. + +.. _v3.66.18: + +-------------------- +3.66.18 - 2018-07-31 +-------------------- + +This release is a very small internal refactoring which should have no user +visible impact. + +.. _v3.66.17: + +-------------------- +3.66.17 - 2018-07-31 +-------------------- + +This release fixes a bug that could cause an ``IndexError`` to be raised from +inside Hypothesis during shrinking. It is likely that it was impossible to +trigger this bug in practice - it was only made visible by some currently +unreleased work. + +.. _v3.66.16: + +-------------------- +3.66.16 - 2018-07-31 +-------------------- + +This release is a very small internal refactoring which should have no user +visible impact. + +.. _v3.66.15: + +-------------------- +3.66.15 - 2018-07-31 +-------------------- + +This release makes Hypothesis's shrinking faster by removing some redundant +work that it does when minimizing values in its internal representation. + +.. _v3.66.14: + +-------------------- +3.66.14 - 2018-07-30 +-------------------- + +This release expands the deprecation of timeout from :ref:`3.16.0 ` to +also emit the deprecation warning in ``find`` or :doc:`stateful testing `. + +.. _v3.66.13: + +-------------------- +3.66.13 - 2018-07-30 +-------------------- + +This release adds an additional shrink pass that is able to reduce the size of +examples in some cases where the transformation is non-obvious. In particular +this will improve the quality of some examples which would have regressed in +:ref:`3.66.12 `. + +.. _v3.66.12: + +-------------------- +3.66.12 - 2018-07-28 +-------------------- + +This release changes how we group data together for shrinking. It should result +in improved shrinker performance, especially in stateful testing. + +.. _v3.66.11: + +-------------------- +3.66.11 - 2018-07-28 +-------------------- + +This patch modifies how which rule to run is selected during +:doc:`rule based stateful testing `. This should result in a slight +performance increase during generation and a significant performance and +quality improvement when shrinking. + +As a result of this change, some state machines which would previously have +thrown an ``InvalidDefinition`` are no longer detected as invalid. + +.. _v3.66.10: + +-------------------- +3.66.10 - 2018-07-28 +-------------------- + +This release weakens some minor functionality in the shrinker that had only +modest benefit and made its behaviour much harder to reason about. + +This is unlikely to have much user visible effect, but it is possible that in +some cases shrinking may get slightly slower. It is primarily to make it easier +to work on the shrinker and pave the way for future work. + +.. _v3.66.9: + +------------------- +3.66.9 - 2018-07-26 +------------------- + +This release improves the information that Hypothesis emits about its shrinking +when :obj:`~hypothesis.settings.verbosity` is set to debug. + +.. _v3.66.8: + +------------------- +3.66.8 - 2018-07-24 +------------------- + +This patch includes some minor fixes in the documentation, and updates +the minimum version of :pypi:`pytest` to 3.0 (released August 2016). + +.. _v3.66.7: + +------------------- +3.66.7 - 2018-07-24 +------------------- + +This release fixes a bug where difficult to shrink tests could sometimes +trigger an internal assertion error inside the shrinker. + +.. _v3.66.6: + +------------------- +3.66.6 - 2018-07-23 +------------------- + +This patch ensures that Hypothesis fully supports Python 3.7, by +upgrading :func:`~hypothesis.strategies.from_type` (:issue:`1264`) +and fixing some minor issues in our test suite (:issue:`1148`). + +.. _v3.66.5: + +------------------- +3.66.5 - 2018-07-22 +------------------- + +This patch fixes the online docs for various extras, by ensuring that +their dependencies are installed on readthedocs.io (:issue:`1326`). + +.. _v3.66.4: + +------------------- +3.66.4 - 2018-07-20 +------------------- + +This release improves the shrinker's ability to reorder examples. + +For example, consider the following test: + +.. code-block:: python + + import hypothesis.strategies as st + from hypothesis import given + + @given(st.text(), st.text()) + def test_non_equal(x, y): + assert x != y + +Previously this could have failed with either of ``x="", y="0"`` or +``x="0", y=""``. Now it should always fail with ``x="", y="0"``. + +This will allow the shrinker to produce more consistent results, especially in +cases where test cases contain some ordered collection whose actual order does +not matter. + +.. _v3.66.3: + +------------------- +3.66.3 - 2018-07-20 +------------------- + +This patch fixes inference in the :func:`~hypothesis.strategies.builds` +strategy with subtypes of :class:`python:typing.NamedTuple`, where the +``__init__`` method is not useful for introspection. We now use the +field types instead - thanks to James Uther for identifying this bug. + +.. _v3.66.2: + +------------------- +3.66.2 - 2018-07-19 +------------------- + +This release improves the shrinker's ability to handle situations where there +is an additive constraint between two values. + +For example, consider the following test: + + +.. code-block:: python + + import hypothesis.strategies as st + from hypothesis import given + + @given(st.integers(), st.integers()) + def test_does_not_exceed_100(m, n): + assert m + n < 100 + +Previously this could have failed with almost any pair ``(m, n)`` with +``0 <= m <= n`` and ``m + n == 100``. Now it should almost always fail with +``m=0, n=100``. + +This is a relatively niche specialisation, but can be useful in situations +where e.g. a bug is triggered by an integer overflow. + +.. _v3.66.1: + +------------------- +3.66.1 - 2018-07-09 +------------------- + +This patch fixes a rare bug where an incorrect percentage drawtime +could be displayed for a test, when the system clock was changed during +a test running under Python 2 (we use :func:`python:time.monotonic` +where it is available to avoid such problems). It also fixes a possible +zero-division error that can occur when the underlying C library +double-rounds an intermediate value in :func:`python:math.fsum` and +gets the least significant bit wrong. + +.. _v3.66.0: + +------------------- +3.66.0 - 2018-07-05 +------------------- + +This release improves validation of the ``alphabet`` argument to the +:func:`~hypothesis.strategies.text` strategy. The following misuses +are now deprecated, and will be an error in a future version: + +- passing an unordered collection (such as ``set('abc')``), which + violates invariants about shrinking and reproducibility +- passing an alphabet sequence with elements that are not strings +- passing an alphabet sequence with elements that are not of length one, + which violates any size constraints that may apply + +Thanks to Sushobhit for adding these warnings (:issue:`1329`). + +.. _v3.65.3: + +------------------- +3.65.3 - 2018-07-04 +------------------- + +This release fixes a mostly theoretical bug where certain usage of the internal +API could trigger an assertion error inside Hypothesis. It is unlikely that +this problem is even possible to trigger through the public API. + +.. _v3.65.2: + +------------------- +3.65.2 - 2018-07-04 +------------------- + +This release fixes dependency information for coverage. Previously Hypothesis +would allow installing :pypi:`coverage` with any version, but it only works +with coverage 4.0 or later. + +We now specify the correct metadata in our ``setup.py``, so Hypothesis will +only allow installation with compatible versions of coverage. + +.. _v3.65.1: + +------------------- +3.65.1 - 2018-07-03 +------------------- + +This patch ensures that :doc:`stateful tests ` which raise an +error from a :pypi:`pytest` helper still print the sequence of steps +taken to reach that point (:issue:`1372`). This reporting was previously +broken because the helpers inherit directly from :class:`python:BaseException`, and +therefore require special handling to catch without breaking e.g. the use +of ctrl-C to quit the test. + +.. _v3.65.0: + +------------------- +3.65.0 - 2018-06-30 +------------------- + +This release deprecates the :obj:`~hypothesis.settings.max_shrinks` setting +in favor of an internal heuristic. If you need to avoid shrinking examples, +use the :obj:`~hypothesis.settings.phases` setting instead. (:issue:`1235`) + +.. _v3.64.2: + +------------------- +3.64.2 - 2018-06-27 +------------------- + +This release fixes a bug where an internal assertion error could sometimes be +triggered while shrinking a failing test. + +.. _v3.64.1: + +------------------- +3.64.1 - 2018-06-27 +------------------- + +This patch fixes type-checking errors in our vendored pretty-printer, +which were ignored by our mypy config but visible for anyone else +(whoops). Thanks to Pi Delport for reporting :issue:`1359` so promptly. + +.. _v3.64.0: + +------------------- +3.64.0 - 2018-06-26 +------------------- + +This release adds :ref:`an interface ` +which can be used to insert a wrapper between the original test function and +:func:`@given ` (:issue:`1257`). This will be particularly +useful for test runner extensions such as :pypi:`pytest-trio`, but is +not recommended for direct use by other users of Hypothesis. + +.. _v3.63.0: + +------------------- +3.63.0 - 2018-06-26 +------------------- + +This release adds a new mechanism to infer strategies for classes +defined using :pypi:`attrs`, based on the the type, converter, or +validator of each attribute. This inference is now built in to +:func:`~hypothesis.strategies.builds` and :func:`~hypothesis.strategies.from_type`. + +On Python 2, :func:`~hypothesis.strategies.from_type` no longer generates +instances of ``int`` when passed ``long``, or vice-versa. + +.. _v3.62.0: + +------------------- +3.62.0 - 2018-06-26 +------------------- + +This release adds :PEP:`484` type hints to Hypothesis on a provisional +basis, using the comment-based syntax for Python 2 compatibility. You +can :ref:`read more about our type hints here `. + +It *also* adds the ``py.typed`` marker specified in :PEP:`561`. +After you ``pip install hypothesis``, :pypi:`mypy` 0.590 or later +will therefore type-check your use of our public interface! + +.. _v3.61.0: + +------------------- +3.61.0 - 2018-06-24 +------------------- + +This release deprecates the use of :class:`~hypothesis.settings` as a +context manager, the use of which is somewhat ambiguous. + +Users should define settings with global state or with the +:func:`@settings(...) ` decorator. + +.. _v3.60.1: + +------------------- +3.60.1 - 2018-06-20 +------------------- + +Fixed a bug in generating an instance of a Django model from a +strategy where the primary key is generated as part of the +strategy. See :ref:`details here `. + +Thanks to Tim Martin for this contribution. + +.. _v3.60.0: + +------------------- +3.60.0 - 2018-06-20 +------------------- + +This release adds the :func:`@initialize ` +decorator for stateful testing (originally discussed in :issue:`1216`). +All :func:`@initialize ` rules will be called +once each in an arbitrary order before any normal rule is called. + +.. _v3.59.3: + +------------------- +3.59.3 - 2018-06-19 +------------------- + +This is a no-op release to take into account some changes to the release +process. It should have no user visible effect. + +.. _v3.59.2: + +------------------- +3.59.2 - 2018-06-18 +------------------- + +This adds support for partially sorting examples which cannot be fully sorted. +For example, [5, 4, 3, 2, 1, 0] with a constraint that the first element needs +to be larger than the last becomes [1, 2, 3, 4, 5, 0]. + +Thanks to Luke for contributing. + +.. _v3.59.1: + +------------------- +3.59.1 - 2018-06-16 +------------------- + +This patch uses :func:`python:random.getstate` and :func:`python:random.setstate` +to restore the PRNG state after :func:`@given ` runs +deterministic tests. Without restoring state, you might have noticed problems +such as :issue:`1266`. The fix also applies to stateful testing (:issue:`702`). + +.. _v3.59.0: + +------------------- +3.59.0 - 2018-06-14 +------------------- + +This release adds the :func:`~hypothesis.strategies.emails` strategy, +which generates unicode strings representing an email address. + +Thanks to Sushobhit for moving this to the public API (:issue:`162`). + +.. _v3.58.1: + +------------------- +3.58.1 - 2018-06-13 +------------------- + +This improves the shrinker. It can now reorder examples: 3 1 2 becomes 1 2 3. + +Thanks to Luke for contributing. + +.. _v3.58.0: + +------------------- +3.58.0 - 2018-06-13 +------------------- + +This adds a new extra :py:func:`~hypothesis.extra.dateutil.timezones` strategy +that generates :pypi:`dateutil timezones `. + +Thanks to Conrad for contributing. + +.. _v3.57.0: + +------------------- +3.57.0 - 2018-05-20 +------------------- + +Using an unordered collection with the :func:`~hypothesis.strategies.permutations` +strategy has been deprecated because the order in which e.g. a set shrinks is +arbitrary. This may cause different results between runs. + +.. _v3.56.10: + +-------------------- +3.56.10 - 2018-05-16 +-------------------- + +This release makes ``hypothesis.settings.define_setting`` +a private method, which has the effect of hiding it from the +documentation. + +.. _v3.56.9: + +------------------- +3.56.9 - 2018-05-11 +------------------- + +This is another release with no functionality changes as part of changes to +Hypothesis's new release tagging scheme. + +.. _v3.56.8: + +------------------- +3.56.8 - 2018-05-10 +------------------- + +This is a release with no functionality changes that moves Hypothesis over to +a new release tagging scheme. + +.. _v3.56.7: + +------------------- +3.56.7 - 2018-05-10 +------------------- + +This release provides a performance improvement for most tests, but in +particular users of :func:`~hypothesis.strategies.sampled_from` who don't +have numpy installed should see a significant performance improvement. + +.. _v3.56.6: + +------------------- +3.56.6 - 2018-05-09 +------------------- + +This patch contains further internal work to support Mypy. +There are no user-visible changes... yet. + +.. _v3.56.5: + +------------------- +3.56.5 - 2018-04-22 +------------------- + +This patch contains some internal refactoring to run :pypi:`mypy` in CI. +There are no user-visible changes. + +.. _v3.56.4: + +------------------- +3.56.4 - 2018-04-21 +------------------- + +This release involves some very minor internal clean up and should have no +user visible effect at all. + +.. _v3.56.3: + +------------------- +3.56.3 - 2018-04-20 +------------------- + +This release fixes a problem introduced in :ref:`3.56.0 ` where +setting the hypothesis home directory (through currently undocumented +means) would no longer result in the default database location living +in the new home directory. + +.. _v3.56.2: + +------------------- +3.56.2 - 2018-04-20 +------------------- + +This release fixes a problem introduced in :ref:`3.56.0 ` where +setting :obj:`~hypothesis.settings.max_examples` to ``1`` would result in tests +failing with ``Unsatisfiable``. This problem could also occur in other harder +to trigger circumstances (e.g. by setting it to a low value, having a hard to +satisfy assumption, and disabling health checks). + +.. _v3.56.1: + +------------------- +3.56.1 - 2018-04-20 +------------------- + +This release fixes a problem that was introduced in :ref:`3.56.0 `: +Use of the ``HYPOTHESIS_VERBOSITY_LEVEL`` environment variable was, rather +than deprecated, actually broken due to being read before various setup +the deprecation path needed was done. It now works correctly (and emits a +deprecation warning). + +.. _v3.56.0: + +------------------- +3.56.0 - 2018-04-17 +------------------- + +This release deprecates several redundant or internally oriented +:class:`~hypothesis.settings`, working towards an orthogonal set of +configuration options that are widely useful *without* requiring any +knowledge of our internals (:issue:`535`). + +- Deprecated settings that no longer have any effect are no longer + shown in the ``__repr__`` unless set to a non-default value. +- :obj:`~hypothesis.settings.perform_health_check` is deprecated, as it + duplicates :obj:`~hypothesis.settings.suppress_health_check`. +- :obj:`~hypothesis.settings.max_iterations` is deprecated and disabled, + because we can usually get better behaviour from an internal heuristic + than a user-controlled setting. +- :obj:`~hypothesis.settings.min_satisfying_examples` is deprecated and + disabled, due to overlap with the + :obj:`~hypothesis.HealthCheck.filter_too_much` healthcheck + and poor interaction with :obj:`~hypothesis.settings.max_examples`. +- ``HYPOTHESIS_VERBOSITY_LEVEL`` is now deprecated. Set + :obj:`~hypothesis.settings.verbosity` through the profile system instead. +- Examples tried by :func:`~hypothesis.find` are now reported at ``debug`` + verbosity level (as well as ``verbose`` level). + +.. _v3.55.6: + +------------------- +3.55.6 - 2018-04-14 +------------------- + +This release fixes a somewhat obscure condition (:issue:`1230`) under which you +could occasionally see a failing test trigger an assertion error inside +Hypothesis instead of failing normally. + +.. _v3.55.5: + +------------------- +3.55.5 - 2018-04-14 +------------------- + +This patch fixes one possible cause of :issue:`966`. When running +Python 2 with hash randomisation, passing a :obj:`python:bytes` object +to :func:`python:random.seed` would use ``version=1``, which broke +:obj:`~hypothesis.settings.derandomize` (because the seed depended on +a randomised hash). If :obj:`~hypothesis.settings.derandomize` is +*still* nondeterministic for you, please open an issue. + +.. _v3.55.4: + +------------------- +3.55.4 - 2018-04-13 +------------------- + +This patch makes a variety of minor improvements to the documentation, +and improves a few validation messages for invalid inputs. + +.. _v3.55.3: + +------------------- +3.55.3 - 2018-04-12 +------------------- + +This release updates the URL metadata associated with the PyPI package (again). +It has no other user visible effects. + +.. _v3.55.2: + +------------------- +3.55.2 - 2018-04-11 +------------------- + +This release updates the URL metadata associated with the PyPI package. +It has no other user visible effects. + +.. _v3.55.1: + +------------------- +3.55.1 - 2018-04-06 +------------------- + +This patch relaxes constraints in our tests on the expected values returned +by the standard library function :func:`~python:math.hypot` and the internal +helper function ``cathetus``, to fix near-exact +test failures on some 32-bit systems used by downstream packagers. + +.. _v3.55.0: + +------------------- +3.55.0 - 2018-04-05 +------------------- + +This release includes several improvements to the handling of the +:obj:`~hypothesis.settings.database` setting. + +- The :obj:`~hypothesis.settings.database_file` setting was a historical + artefact, and you should just use :obj:`~hypothesis.settings.database` + directly. +- The ``HYPOTHESIS_DATABASE_FILE`` environment variable is + deprecated, in favor of :meth:`~hypothesis.settings.load_profile` and + the :obj:`~hypothesis.settings.database` setting. +- If you have not configured the example database at all and the default + location is not usable (due to e.g. permissions issues), Hypothesis + will fall back to an in-memory database. This is not persisted between + sessions, but means that the defaults work on read-only filesystems. + +.. _v3.54.0: + +------------------- +3.54.0 - 2018-04-04 +------------------- + +This release improves the :func:`~hypothesis.strategies.complex_numbers` +strategy, which now supports ``min_magnitude`` and ``max_magnitude`` +arguments, along with ``allow_nan`` and ``allow_infinity`` like for +:func:`~hypothesis.strategies.floats`. + +Thanks to J.J. Green for this feature. + +.. _v3.53.0: + +------------------- +3.53.0 - 2018-04-01 +------------------- + +This release removes support for Django 1.8, which reached end of life on +2018-04-01. You can see Django's release and support schedule +`on the Django Project website `_. + +.. _v3.52.3: + +------------------- +3.52.3 - 2018-04-01 +------------------- + +This patch fixes the :obj:`~hypothesis.settings.min_satisfying_examples` settings +documentation, by explaining that example shrinking is tracked at the level +of the underlying bytestream rather than the output value. + +The output from :func:`~hypothesis.find` in verbose mode has also been +adjusted - see :ref:`the example session ` - to avoid +duplicating lines when the example repr is constant, even if the underlying +representation has been shrunken. + +.. _v3.52.2: + +------------------- +3.52.2 - 2018-03-30 +------------------- + +This release improves the output of failures with +:ref:`rule based stateful testing ` in two ways: + +* The output from it is now usually valid Python code. +* When the same value has two different names because it belongs to two different + bundles, it will now display with the name associated with the correct bundle + for a rule argument where it is used. + +.. _v3.52.1: + +------------------- +3.52.1 - 2018-03-29 +------------------- + +This release improves the behaviour of :doc:`stateful testing ` +in two ways: + +* Previously some runs would run no steps (:issue:`376`). This should no longer + happen. +* RuleBasedStateMachine tests which used bundles extensively would often shrink + terribly. This should now be significantly improved, though there is likely + a lot more room for improvement. + +This release also involves a low level change to how ranges of integers are +handles which may result in other improvements to shrink quality in some cases. + +.. _v3.52.0: + +------------------- +3.52.0 - 2018-03-24 +------------------- + +This release deprecates use of :func:`@settings(...) ` +as a decorator, on functions or methods that are not also decorated with +:func:`@given `. You can still apply these decorators +in any order, though you should only do so once each. + +Applying :func:`@given ` twice was already deprecated, and +applying :func:`@settings(...) ` twice is deprecated in +this release and will become an error in a future version. Neither could ever +be used twice to good effect. + +Using :func:`@settings(...) ` as the sole decorator on +a test is completely pointless, so this common usage error will become an +error in a future version of Hypothesis. + +.. _v3.51.0: + +------------------- +3.51.0 - 2018-03-24 +------------------- + +This release deprecates the ``average_size`` argument to +:func:`~hypothesis.strategies.lists` and other collection strategies. +You should simply delete it wherever it was used in your tests, as it +no longer has any effect. + +In early versions of Hypothesis, the ``average_size`` argument was treated +as a hint about the distribution of examples from a strategy. Subsequent +improvements to the conceptual model and the engine for generating and +shrinking examples mean it is more effective to simply describe what +constitutes a valid example, and let our internals handle the distribution. + +.. _v3.50.3: + +------------------- +3.50.3 - 2018-03-24 +------------------- + +This patch contains some internal refactoring so that we can run +with warnings as errors in CI. + +.. _v3.50.2: + +------------------- +3.50.2 - 2018-03-20 +------------------- + +This has no user-visible changes except one slight formatting change to one docstring, to avoid a deprecation warning. + +.. _v3.50.1: + +------------------- +3.50.1 - 2018-03-20 +------------------- + +This patch fixes an internal error introduced in :ref:`3.48.0 `, where a check +for the Django test runner would expose import-time errors in Django +configuration (:issue:`1167`). + +.. _v3.50.0: + +------------------- +3.50.0 - 2018-03-19 +------------------- + +This release improves validation of numeric bounds for some strategies. + +- :func:`~hypothesis.strategies.integers` and :func:`~hypothesis.strategies.floats` + now raise ``InvalidArgument`` if passed a ``min_value`` or ``max_value`` + which is not an instance of :class:`~python:numbers.Real`, instead of + various internal errors. +- :func:`~hypothesis.strategies.floats` now converts its bounding values to + the nearest float above or below the min or max bound respectively, instead + of just casting to float. The old behaviour was incorrect in that you could + generate ``float(min_value)``, even when this was less than ``min_value`` + itself (possible with eg. fractions). +- When both bounds are provided to :func:`~hypothesis.strategies.floats` but + there are no floats in the interval, such as ``[(2**54)+1 .. (2**55)-1]``, + InvalidArgument is raised. +- :func:`~hypothesis.strategies.decimals` gives a more useful error message + if passed a string that cannot be converted to :class:`~python:decimal.Decimal` + in a context where this error is not trapped. + +Code that previously **seemed** to work may be explicitly broken if there +were no floats between ``min_value`` and ``max_value`` (only possible with +non-float bounds), or if a bound was not a :class:`~python:numbers.Real` +number but still allowed in :obj:`python:math.isnan` (some custom classes +with a ``__float__`` method). + +.. _v3.49.1: + +------------------- +3.49.1 - 2018-03-15 +------------------- + +This patch fixes our tests for Numpy dtype strategies on big-endian platforms, +where the strategy behaved correctly but the test assumed that the native byte +order was little-endian. + +There is no user impact unless you are running our test suite on big-endian +platforms. Thanks to Graham Inggs for reporting :issue:`1164`. + +.. _v3.49.0: + +------------------- +3.49.0 - 2018-03-12 +------------------- + +This release deprecates passing ``elements=None`` to collection strategies, +such as :func:`~hypothesis.strategies.lists`. + +Requiring ``lists(nothing())`` or ``builds(list)`` instead of ``lists()`` +means slightly more typing, but also improves the consistency and +discoverability of our API - as well as showing how to compose or +construct strategies in ways that still work in more complex situations. + +Passing a nonzero max_size to a collection strategy where the elements +strategy contains no values is now deprecated, and will be an error in a +future version. The equivalent with ``elements=None`` is already an error. + +.. _v3.48.1: + +------------------- +3.48.1 - 2018-03-05 +------------------- + +This patch will minimize examples that would come out non-minimal in previous versions. Thanks to Kyle Reeve for this patch. + +.. _v3.48.0: + +------------------- +3.48.0 - 2018-03-05 +------------------- + +This release improves some "unhappy paths" when using Hypothesis +with the standard library :mod:`python:unittest` module: + +- Applying :func:`@given ` to a non-test method which is + overridden from :class:`python:unittest.TestCase`, such as ``setUp``, + raises :attr:`a new health check `. + (:issue:`991`) +- Using :meth:`~python:unittest.TestCase.subTest` within a test decorated + with :func:`@given ` would leak intermediate results + when tests were run under the :mod:`python:unittest` test runner. + Individual reporting of failing subtests is now disabled during a test + using :func:`@given `. (:issue:`1071`) +- :func:`@given ` is still not a class decorator, but the + error message if you try using it on a class has been improved. + +As a related improvement, using :class:`django:django.test.TestCase` with +:func:`@given ` instead of +:class:`hypothesis.extra.django.TestCase` raises an explicit error instead +of running all examples in a single database transaction. + +.. _v3.47.0: + +------------------- +3.47.0 - 2018-03-02 +------------------- + +:obj:`~hypothesis.settings.register_profile` now accepts keyword arguments +for specific settings, and the parent settings object is now optional. +Using a ``name`` for a registered profile which is not a string was never +suggested, but it is now also deprecated and will eventually be an error. + +.. _v3.46.2: + +------------------- +3.46.2 - 2018-03-01 +------------------- + +This release removes an unnecessary branch from the code, and has no user-visible impact. + +.. _v3.46.1: + +------------------- +3.46.1 - 2018-03-01 +------------------- + +This changes only the formatting of our docstrings and should have no user-visible effects. + +.. _v3.46.0: + +------------------- +3.46.0 - 2018-02-26 +------------------- + +:func:`~hypothesis.strategies.characters` has improved docs about +what arguments are valid, and additional validation logic to raise a +clear error early (instead of e.g. silently ignoring a bad argument). +Categories may be specified as the Unicode 'general category' +(eg ``u'Nd'``), or as the 'major category' (eg ``[u'N', u'Lu']`` +is equivalent to ``[u'Nd', u'Nl', u'No', u'Lu']``). + +In previous versions, general categories were supported and all other +input was silently ignored. Now, major categories are supported in +addition to general categories (which may change the behaviour of some +existing code), and all other input is deprecated. + +.. _v3.45.5: + +------------------- +3.45.5 - 2018-02-26 +------------------- + +This patch improves strategy inference in ``hypothesis.extra.django`` +to account for some validators in addition to field type - see +:issue:`1116` for ongoing work in this space. + +Specifically, if a :class:`~django:django.db.models.CharField` or +:class:`~django:django.db.models.TextField` has an attached +:class:`~django:django.core.validators.RegexValidator`, we now use +:func:`~hypothesis.strategies.from_regex` instead of +:func:`~hypothesis.strategies.text` as the underlying strategy. +This allows us to generate examples of the default +:class:`~django:django.contrib.auth.models.User` model, closing :issue:`1112`. + +.. _v3.45.4: + +------------------- +3.45.4 - 2018-02-25 +------------------- + +This patch improves some internal debugging information, fixes +a typo in a validation error message, and expands the documentation +for new contributors. + +.. _v3.45.3: + +------------------- +3.45.3 - 2018-02-23 +------------------- + +This patch may improve example shrinking slightly for some strategies. + +.. _v3.45.2: + +------------------- +3.45.2 - 2018-02-18 +------------------- + +This release makes our docstring style more consistent, thanks to +:pypi:`flake8-docstrings`. There are no user-visible changes. + +.. _v3.45.1: + +------------------- +3.45.1 - 2018-02-17 +------------------- + +This fixes an indentation issue in docstrings for +:func:`~hypothesis.strategies.datetimes`, :func:`~hypothesis.strategies.dates`, +:func:`~hypothesis.strategies.times`, and +:func:`~hypothesis.strategies.timedeltas`. + +.. _v3.45.0: + +------------------- +3.45.0 - 2018-02-13 +------------------- + +This release fixes :func:`~hypothesis.strategies.builds` so that ``target`` +can be used as a keyword argument for passing values to the target. The target +itself can still be specified as a keyword argument, but that behavior is now +deprecated. The target should be provided as the first positional argument. + +.. _v3.44.26: + +-------------------- +3.44.26 - 2018-02-06 +-------------------- + +This release fixes some formatting issues in the Hypothesis source code. +It should have no externally visible effects. + +.. _v3.44.25: + +-------------------- +3.44.25 - 2018-02-05 +-------------------- + +This release changes the way in which Hypothesis tries to shrink the size of +examples. It probably won't have much impact, but might make shrinking faster +in some cases. It is unlikely but not impossible that it will change the +resulting examples. + +.. _v3.44.24: + +-------------------- +3.44.24 - 2018-01-27 +-------------------- + +This release fixes dependency information when installing Hypothesis +from a binary "wheel" distribution. + +- The ``install_requires`` for :pypi:`enum34` is resolved at install + time, rather than at build time (with potentially different results). +- Django has fixed their ``python_requires`` for versions 2.0.0 onward, + simplifying Python2-compatible constraints for downstream projects. + +.. _v3.44.23: + +-------------------- +3.44.23 - 2018-01-24 +-------------------- + +This release improves shrinking in a class of pathological examples that you +are probably never hitting in practice. If you *are* hitting them in practice +this should be a significant speed up in shrinking. If you are not, you are +very unlikely to notice any difference. You might see a slight slow down and/or +slightly better falsifying examples. + +.. _v3.44.22: + +-------------------- +3.44.22 - 2018-01-23 +-------------------- + +This release fixes a dependency problem. It was possible to install +Hypothesis with an old version of :pypi:`attrs`, which would throw a +``TypeError`` as soon as you tried to import hypothesis. Specifically, you +need attrs 16.0.0 or newer. + +Hypothesis will now require the correct version of attrs when installing. + +.. _v3.44.21: + +-------------------- +3.44.21 - 2018-01-22 +-------------------- + +This change adds some additional structural information that Hypothesis will +use to guide its search. + +You mostly shouldn't see much difference from this. The two most likely effects +you would notice are: + +1. Hypothesis stores slightly more examples in its database for passing tests. +2. Hypothesis *may* find new bugs that it was previously missing, but it + probably won't (this is a basic implementation of the feature that is + intended to support future work. Although it is useful on its own, it's not + *very* useful on its own). + +.. _v3.44.20: + +-------------------- +3.44.20 - 2018-01-21 +-------------------- + +This is a small refactoring release that changes how Hypothesis tracks some +information about the boundary of examples in its internal representation. + +You are unlikely to see much difference in behaviour, but memory usage and +run time may both go down slightly during normal test execution, and when +failing Hypothesis might print its failing example slightly sooner. + +.. _v3.44.19: + +-------------------- +3.44.19 - 2018-01-21 +-------------------- + +This changes how we compute the default ``average_size`` for all collection +strategies. Previously setting a ``max_size`` without setting an +``average_size`` would have the seemingly paradoxical effect of making data +generation *slower*, because it would raise the average size from its default. +Now setting ``max_size`` will either leave the default unchanged or lower it +from its default. + +If you are currently experiencing this problem, this may make your tests +substantially faster. If you are not, this will likely have no effect on you. + +.. _v3.44.18: + +-------------------- +3.44.18 - 2018-01-20 +-------------------- + +This is a small refactoring release that changes how Hypothesis detects when +the structure of data generation depends on earlier values generated (e.g. when +using :ref:`flatmap ` or :func:`~hypothesis.strategies.composite`). +It should not have any observable effect on behaviour. + +.. _v3.44.17: + +-------------------- +3.44.17 - 2018-01-15 +-------------------- + +This release fixes a typo in internal documentation, and has no user-visible impact. + +.. _v3.44.16: + +-------------------- +3.44.16 - 2018-01-13 +-------------------- + +This release improves test case reduction for recursive data structures. +Hypothesis now guarantees that whenever a strategy calls itself recursively +(usually this will happen because you are using :func:`~hypothesis.strategies.deferred`), +any recursive call may replace the top level value. e.g. given a tree structure, +Hypothesis will always try replacing it with a subtree. + +Additionally this introduces a new heuristic that may in some circumstances +significantly speed up test case reduction - Hypothesis should be better at +immediately replacing elements drawn inside another strategy with their minimal +possible value. + +.. _v3.44.15: + +-------------------- +3.44.15 - 2018-01-13 +-------------------- + +:func:`~hypothesis.strategies.from_type` can now resolve recursive types +such as binary trees (:issue:`1004`). Detection of non-type arguments has +also improved, leading to better error messages in many cases involving +:pep:`forward references <484#forward-references>`. + +.. _v3.44.14: + +-------------------- +3.44.14 - 2018-01-08 +-------------------- + +This release fixes a bug in the shrinker that prevented the optimisations in +:ref:`3.44.6 ` from working in some cases. It would not have worked correctly when +filtered examples were nested (e.g. with a set of integers in some range). + +This would not have resulted in any correctness problems, but shrinking may +have been slower than it otherwise could be. + +.. _v3.44.13: + +-------------------- +3.44.13 - 2018-01-08 +-------------------- + +This release changes the average bit length of values drawn from +:func:`~hypothesis.strategies.integers` to be much smaller. Additionally it +changes the shrinking order so that now size is considered before sign - e.g. +-1 will be preferred to +10. + +The new internal format for integers required some changes to the minimizer to +make work well, so you may also see some improvements to example quality in +unrelated areas. + +.. _v3.44.12: + +-------------------- +3.44.12 - 2018-01-07 +-------------------- + +This changes Hypothesis's internal implementation of weighted sampling. This +will affect example distribution and quality, but you shouldn't see any other +effects. + +.. _v3.44.11: + +-------------------- +3.44.11 - 2018-01-06 +-------------------- + +This is a change to some internals around how Hypothesis handles avoiding +generating duplicate examples and seeking out novel regions of the search +space. + +You are unlikely to see much difference as a result of it, but it fixes +a bug where an internal assertion could theoretically be triggered and has some +minor effects on the distribution of examples so could potentially find bugs +that have previously been missed. + +.. _v3.44.10: + +-------------------- +3.44.10 - 2018-01-06 +-------------------- + +This patch avoids creating debug statements when debugging is disabled. +Profiling suggests this is a 5-10% performance improvement (:issue:`1040`). + +.. _v3.44.9: + +------------------- +3.44.9 - 2018-01-06 +------------------- + +This patch blacklists null characters (``'\x00'``) in automatically created +strategies for Django :obj:`~django:django.db.models.CharField` and +:obj:`~django:django.db.models.TextField`, due to a database issue which +`was recently fixed upstream `_ +(Hypothesis :issue:`1045`). + +.. _v3.44.8: + +------------------- +3.44.8 - 2018-01-06 +------------------- + +This release makes the Hypothesis shrinker slightly less greedy in order to +avoid local minima - when it gets stuck, it makes a small attempt to search +around the final example it would previously have returned to find a new +starting point to shrink from. This should improve example quality in some +cases, especially ones where the test data has dependencies among parts of it +that make it difficult for Hypothesis to proceed. + +.. _v3.44.7: + +------------------- +3.44.7 - 2018-01-04 +------------------- + +This release adds support for `Django 2 +`_ in +the hypothesis-django extra. + +This release drops support for Django 1.10, as it is no longer supported by +the Django team. + +.. _v3.44.6: + +------------------- +3.44.6 - 2018-01-02 +------------------- + +This release speeds up test case reduction in many examples by being better at +detecting large shrinks it can use to discard redundant parts of its input. +This will be particularly noticeable in examples that make use of filtering +and for some integer ranges. + +.. _v3.44.5: + +------------------- +3.44.5 - 2018-01-02 +------------------- + +Happy new year! + +This is a no-op release that updates the year range on all of +the copyright headers in our source to include 2018. + +.. _v3.44.4: + +------------------- +3.44.4 - 2017-12-23 +------------------- + +This release fixes :issue:`1044`, which slowed tests by up to 6% +due to broken caching. + +.. _v3.44.3: + +------------------- +3.44.3 - 2017-12-21 +------------------- + +This release improves the shrinker in cases where examples drawn earlier can +affect how much data is drawn later (e.g. when you draw a length parameter in +a composite and then draw that many elements). Examples found in cases like +this should now be much closer to minimal. + +.. _v3.44.2: + +------------------- +3.44.2 - 2017-12-20 +------------------- + +This is a pure refactoring release which changes how Hypothesis manages its +set of examples internally. It should have no externally visible effects. + +.. _v3.44.1: + +------------------- +3.44.1 - 2017-12-18 +------------------- + +This release fixes :issue:`997`, in which under some circumstances the body of +tests run under Hypothesis would not show up when run under coverage even +though the tests were run and the code they called outside of the test file +would show up normally. + +.. _v3.44.0: + +------------------- +3.44.0 - 2017-12-17 +------------------- + +This release adds a new feature: The :func:`@reproduce_failure ` decorator, +designed to make it easy to use Hypothesis's binary format for examples to +reproduce a problem locally without having to share your example database +between machines. + +This also changes when seeds are printed: + +* They will no longer be printed for + normal falsifying examples, as there are now adequate ways of reproducing those + for all cases, so it just contributes noise. +* They will once again be printed when reusing examples from the database, as + health check failures should now be more reliable in this scenario so it will + almost always work in this case. + +This work was funded by `Smarkets `_. + +.. _v3.43.1: + +------------------- +3.43.1 - 2017-12-17 +------------------- + +This release fixes a bug with Hypothesis's database management - examples that +were found in the course of shrinking were saved in a way that indicated that +they had distinct causes, and so they would all be retried on the start of the +next test. The intended behaviour, which is now what is implemented, is that +only a bounded subset of these examples would be retried. + +.. _v3.43.0: + +------------------- +3.43.0 - 2017-12-17 +------------------- + +:exc:`~hypothesis.errors.HypothesisDeprecationWarning` now inherits from +:exc:`python:FutureWarning` instead of :exc:`python:DeprecationWarning`, +as recommended by :pep:`565` for user-facing warnings (:issue:`618`). +If you have not changed the default warnings settings, you will now see +each distinct :exc:`~hypothesis.errors.HypothesisDeprecationWarning` +instead of only the first. + +.. _v3.42.2: + +------------------- +3.42.2 - 2017-12-12 +------------------- + +This patch fixes :issue:`1017`, where instances of a list or tuple subtype +used as an argument to a strategy would be coerced to tuple. + +.. _v3.42.1: + +------------------- +3.42.1 - 2017-12-10 +------------------- + +This release has some internal cleanup, which makes reading the code +more pleasant and may shrink large examples slightly faster. + +.. _v3.42.0: + +------------------- +3.42.0 - 2017-12-09 +------------------- + +This release deprecates :ref:`faker-extra`, which was designed as a transition +strategy but does not support example shrinking or coverage-guided discovery. + +.. _v3.41.0: + +------------------- +3.41.0 - 2017-12-06 +------------------- + +:func:`~hypothesis.strategies.sampled_from` can now sample from +one-dimensional numpy ndarrays. Sampling from multi-dimensional +ndarrays still results in a deprecation warning. Thanks to Charlie +Tanksley for this patch. + +.. _v3.40.1: + +------------------- +3.40.1 - 2017-12-04 +------------------- + +This release makes two changes: + +* It makes the calculation of some of the metadata that Hypothesis uses for + shrinking occur lazily. This should speed up performance of test case + generation a bit because it no longer calculates information it doesn't need. +* It improves the shrinker for certain classes of nested examples. e.g. when + shrinking lists of lists, the shrinker is now able to concatenate two + adjacent lists together into a single list. As a result of this change, + shrinking may get somewhat slower when the minimal example found is large. + +.. _v3.40.0: + +------------------- +3.40.0 - 2017-12-02 +------------------- + +This release improves how various ways of seeding Hypothesis interact with the +example database: + +* Using the example database with :func:`~hypothesis.seed` is now deprecated. + You should set ``database=None`` if you are doing that. This will only warn + if you actually load examples from the database while using ``@seed``. +* The :attr:`~hypothesis.settings.derandomize` will behave the same way as + ``@seed``. +* Using ``--hypothesis-seed`` will disable use of the database. +* If a test used examples from the database, it will not suggest using a seed + to reproduce it, because that won't work. + +This work was funded by `Smarkets `_. + +.. _v3.39.0: + +------------------- +3.39.0 - 2017-12-01 +------------------- + +This release adds a new health check that checks if the smallest "natural" +possible example of your test case is very large - this will tend to cause +Hypothesis to generate bad examples and be quite slow. + +This work was funded by `Smarkets `_. + +.. _v3.38.9: + +------------------- +3.38.9 - 2017-11-29 +------------------- + +This is a documentation release to improve the documentation of shrinking +behaviour for Hypothesis's strategies. + +.. _v3.38.8: + +------------------- +3.38.8 - 2017-11-29 +------------------- + +This release improves the performance of +:func:`~hypothesis.strategies.characters` when using ``blacklist_characters`` +and :func:`~hypothesis.strategies.from_regex` when using negative character +classes. + +The problems this fixes were found in the course of work funded by +`Smarkets `_. + +.. _v3.38.7: + +------------------- +3.38.7 - 2017-11-29 +------------------- + +This is a patch release for :func:`~hypothesis.strategies.from_regex`, which +had a bug in handling of the :obj:`python:re.VERBOSE` flag (:issue:`992`). +Flags are now handled correctly when parsing regex. + +.. _v3.38.6: + +------------------- +3.38.6 - 2017-11-28 +------------------- + +This patch changes a few byte-string literals from double to single quotes, +thanks to an update in :pypi:`unify`. There are no user-visible changes. + +.. _v3.38.5: + +------------------- +3.38.5 - 2017-11-23 +------------------- + +This fixes the repr of strategies using lambda that are defined inside +decorators to include the lambda source. + +This would mostly have been visible when using the +:ref:`statistics ` functionality - lambdas used for e.g. filtering +would have shown up with a ```` as their body. This can still happen, +but it should happen less often now. + +.. _v3.38.4: + +------------------- +3.38.4 - 2017-11-22 +------------------- + +This release updates the reported :ref:`statistics ` so that they +show approximately what fraction of your test run time is spent in data +generation (as opposed to test execution). + +This work was funded by `Smarkets `_. + +.. _v3.38.3: + +------------------- +3.38.3 - 2017-11-21 +------------------- + +This is a documentation release, which ensures code examples are up to date +by running them as doctests in CI (:issue:`711`). + +.. _v3.38.2: + +------------------- +3.38.2 - 2017-11-21 +------------------- + +This release changes the behaviour of the :attr:`~hypothesis.settings.deadline` +setting when used with :func:`~hypothesis.strategies.data`: Time spent inside +calls to ``data.draw`` will no longer be counted towards the deadline time. + +As a side effect of some refactoring required for this work, the way flaky +tests are handled has changed slightly. You are unlikely to see much difference +from this, but some error messages will have changed. + +This work was funded by `Smarkets `_. + +.. _v3.38.1: + +------------------- +3.38.1 - 2017-11-21 +------------------- + +This patch has a variety of non-user-visible refactorings, removing various +minor warts ranging from indirect imports to typos in comments. + +.. _v3.38.0: + +------------------- +3.38.0 - 2017-11-18 +------------------- + +This release overhauls :doc:`the health check system ` +in a variety of small ways. +It adds no new features, but is nevertheless a minor release because it changes +which tests are likely to fail health checks. + +The most noticeable effect is that some tests that used to fail health checks +will now pass, and some that used to pass will fail. These should all be +improvements in accuracy. In particular: + +* New failures will usually be because they are now taking into account things + like use of :func:`~hypothesis.strategies.data` and + :func:`~hypothesis.assume` inside the test body. +* New failures *may* also be because for some classes of example the way data + generation performance was measured was artificially faster than real data + generation (for most examples that are hitting performance health checks the + opposite should be the case). +* Tests that used to fail health checks and now pass do so because the health + check system used to run in a way that was subtly different than the main + Hypothesis data generation and lacked some of its support for e.g. large + examples. + +If your data generation is especially slow, you may also see your tests get +somewhat faster, as there is no longer a separate health check phase. This will +be particularly noticeable when rerunning test failures. + +This work was funded by `Smarkets `_. + +.. _v3.37.0: + +------------------- +3.37.0 - 2017-11-12 +------------------- + +This is a deprecation release for some health check related features. + +The following are now deprecated: + +* Passing :attr:`~hypothesis.HealthCheck.exception_in_generation` to + :attr:`~hypothesis.settings.suppress_health_check`. This no longer does + anything even when passed - All errors that occur during data generation + will now be immediately reraised rather than going through the health check + mechanism. +* Passing :attr:`~hypothesis.HealthCheck.random_module` to + :attr:`~hypothesis.settings.suppress_health_check`. This hasn't done anything + for a long time, but was never explicitly deprecated. Hypothesis always seeds + the random module when running :func:`@given ` tests, so this + is no longer an error and suppressing it doesn't do anything. +* Passing non-:class:`~hypothesis.HealthCheck` values in + :attr:`~hypothesis.settings.suppress_health_check`. This was previously + allowed but never did anything useful. + +In addition, passing a non-iterable value as :attr:`~hypothesis.settings.suppress_health_check` +will now raise an error immediately (it would never have worked correctly, but +it would previously have failed later). Some validation error messages have +also been updated. + +This work was funded by `Smarkets `_. + +.. _v3.36.1: + +------------------- +3.36.1 - 2017-11-10 +------------------- + +This is a yak shaving release, mostly concerned with our own tests. + +While :func:`~python:inspect.getfullargspec` was documented as deprecated +in Python 3.5, it never actually emitted a warning. Our code to silence +this (nonexistent) warning has therefore been removed. + +We now run our tests with ``DeprecationWarning`` as an error, and made some +minor changes to our own tests as a result. This required similar upstream +updates to :pypi:`coverage` and :pypi:`execnet` (a test-time dependency via +:pypi:`pytest-xdist`). + +There is no user-visible change in Hypothesis itself, but we encourage you +to consider enabling deprecations as errors in your own tests. + +.. _v3.36.0: + +------------------- +3.36.0 - 2017-11-06 +------------------- + +This release adds a setting to the public API, and does some internal cleanup: + +- The :attr:`~hypothesis.settings.derandomize` setting is now documented (:issue:`890`) +- Removed - and disallowed - all 'bare excepts' in Hypothesis (:issue:`953`) +- Documented the :attr:`~hypothesis.settings.strict` setting as deprecated, and + updated the build so our docs always match deprecations in the code. + +.. _v3.35.0: + +------------------- +3.35.0 - 2017-11-06 +------------------- + +This minor release supports constraining :func:`~hypothesis.strategies.uuids` +to generate a particular version of :class:`~python:uuid.UUID` (:issue:`721`). + +Thanks to Dion Misic for this feature. + +.. _v3.34.1: + +------------------- +3.34.1 - 2017-11-02 +------------------- + +This patch updates the documentation to suggest +:func:`builds(callable) ` instead of +:func:`just(callable()) `. + +.. _v3.34.0: + +------------------- +3.34.0 - 2017-11-02 +------------------- + +Hypothesis now emits deprecation warnings if you apply +:func:`@given ` more than once to a target. + +Applying :func:`@given ` repeatedly wraps the target multiple +times. Each wrapper will search the space of of possible parameters separately. +This is equivalent but will be much more inefficient than doing it with a +single call to :func:`@given `. + +For example, instead of +``@given(booleans()) @given(integers())``, you could write +``@given(booleans(), integers())`` + +.. _v3.33.1: + +------------------- +3.33.1 - 2017-11-02 +------------------- + +This is a bugfix release: + +- :func:`~hypothesis.strategies.builds` would try to infer a strategy for + required positional arguments of the target from type hints, even if they + had been given to :func:`~hypothesis.strategies.builds` as positional + arguments (:issue:`946`). Now it only infers missing required arguments. +- An internal introspection function wrongly reported ``self`` as a required + argument for bound methods, which might also have affected + :func:`~hypothesis.strategies.builds`. Now it knows better. + +.. _v3.33.0: + +------------------- +3.33.0 - 2017-10-16 +------------------- + +This release supports strategy inference for more field types in Django +:func:`~hypothesis.extra.django.models.models` - you can now omit an argument for +Date, Time, Duration, Slug, IP Address, and UUID fields. (:issue:`642`) + +Strategy generation for fields with grouped choices now selects choices from +each group, instead of selecting from the group names. + +.. _v3.32.2: + +------------------- +3.32.2 - 2017-10-15 +------------------- + +This patch removes the ``mergedb`` tool, introduced in Hypothesis 1.7.1 +on an experimental basis. It has never actually worked, and the new +:doc:`Hypothesis example database ` is designed to make such a +tool unnecessary. + +.. _v3.32.1: + +------------------- +3.32.1 - 2017-10-13 +------------------- + +This patch has two improvements for strategies based on enumerations. + +- :func:`~hypothesis.strategies.from_type` now handles enumerations correctly, + delegating to :func:`~hypothesis.strategies.sampled_from`. Previously it + noted that ``Enum.__init__`` has no required arguments and therefore delegated + to :func:`~hypothesis.strategies.builds`, which would subsequently fail. +- When sampling from an :class:`python:enum.Flag`, we also generate combinations + of members. Eg for ``Flag('Permissions', 'READ, WRITE, EXECUTE')`` we can now + generate, ``Permissions.READ``, ``Permissions.READ|WRITE``, and so on. + +.. _v3.32.0: + +------------------- +3.32.0 - 2017-10-09 +------------------- + +This changes the default value of +:attr:`use_coverage=True ` to True when +running on pypy (it was already True on CPython). + +It was previously set to False because we expected it to be too slow, but +recent benchmarking shows that actually performance of the feature on pypy is +fairly acceptable - sometimes it's slower than on CPython, sometimes it's +faster, but it's generally within a factor of two either way. + +.. _v3.31.6: + +------------------- +3.31.6 - 2017-10-08 +------------------- + +This patch improves the quality of strategies inferred from Numpy dtypes: + +* Integer dtypes generated examples with the upper half of their (non-sign) bits + set to zero. The inferred strategies can now produce any representable integer. +* Fixed-width unicode- and byte-string dtypes now cap the internal example + length, which should improve example and shrink quality. +* Numpy arrays can only store fixed-size strings internally, and allow shorter + strings by right-padding them with null bytes. Inferred string strategies + no longer generate such values, as they can never be retrieved from an array. + This improves shrinking performance by skipping useless values. + +This has already been useful in Hypothesis - we found an overflow bug in our +Pandas support, and as a result :func:`~hypothesis.extra.pandas.indexes` and +:func:`~hypothesis.extra.pandas.range_indexes` now check that ``min_size`` +and ``max_size`` are at least zero. + +.. _v3.31.5: + +------------------- +3.31.5 - 2017-10-08 +------------------- + +This release fixes a performance problem in tests where +:attr:`~hypothesis.settings.use_coverage` is set to True. + +Tests experience a slow-down proportionate to the amount of code they cover. +This is still the case, but the factor is now low enough that it should be +unnoticeable. Previously it was large and became much larger in :ref:`3.30.4 `. + +.. _v3.31.4: + +------------------- +3.31.4 - 2017-10-08 +------------------- + +:func:`~hypothesis.strategies.from_type` failed with a very confusing error +if passed a :func:`~python:typing.NewType` (:issue:`901`). These psudeo-types +are now unwrapped correctly, and strategy inference works as expected. + +.. _v3.31.3: + +------------------- +3.31.3 - 2017-10-06 +------------------- + +This release makes some small optimisations to our use of coverage that should +reduce constant per-example overhead. This is probably only noticeable on +examples where the test itself is quite fast. On no-op tests that don't test +anything you may see up to a fourfold speed increase (which is still +significantly slower than without coverage). On more realistic tests the speed +up is likely to be less than that. + +.. _v3.31.2: + +------------------- +3.31.2 - 2017-09-30 +------------------- + +This release fixes some formatting and small typos/grammar issues in the +documentation, specifically the page docs/settings.rst, and the inline docs +for the various settings. + +.. _v3.31.1: + +------------------- +3.31.1 - 2017-09-30 +------------------- + +This release improves the handling of deadlines so that they act better with +the shrinking process. This fixes :issue:`892`. + +This involves two changes: + +1. The deadline is raised during the initial generation and shrinking, and then + lowered to the set value for final replay. This restricts our attention to + examples which exceed the deadline by a more significant margin, which + increases their reliability. +2. When despite the above a test still becomes flaky because it is + significantly faster on rerun than it was on its first run, the error + message is now more explicit about the nature of this problem, and includes + both the initial test run time and the new test run time. + +In addition, this release also clarifies the documentation of the deadline +setting slightly to be more explicit about where it applies. + +This work was funded by `Smarkets `_. + +.. _v3.31.0: + +------------------- +3.31.0 - 2017-09-29 +------------------- + +This release blocks installation of Hypothesis on Python 3.3, which +:PEP:`reached its end of life date on 2017-09-29 <398>`. + +This should not be of interest to anyone but downstream maintainers - +if you are affected, migrate to a secure version of Python as soon as +possible or at least seek commercial support. + +.. _v3.30.4: + +------------------- +3.30.4 - 2017-09-27 +------------------- + +This release makes several changes: + +1. It significantly improves Hypothesis's ability to use coverage information + to find interesting examples. +2. It reduces the default :attr:`~hypothesis.settings.max_examples` setting from 200 to 100. This takes + advantage of the improved algorithm meaning fewer examples are typically + needed to get the same testing and is sufficiently better at covering + interesting behaviour, and offsets some of the performance problems of + running under coverage. +3. Hypothesis will always try to start its testing with an example that is near + minimized. + +The new algorithm for 1 also makes some changes to Hypothesis's low level data +generation which apply even with coverage turned off. They generally reduce the +total amount of data generated, which should improve test performance somewhat. +Between this and 3 you should see a noticeable reduction in test runtime (how +much so depends on your tests and how much example size affects their +performance. On our benchmarks, where data generation dominates, we saw up to +a factor of two performance improvement, but it's unlikely to be that large. + +.. _v3.30.3: + +------------------- +3.30.3 - 2017-09-25 +------------------- + +This release fixes some formatting and small typos/grammar issues in the +documentation, specifically the page docs/details.rst, and some inline +docs linked from there. + +.. _v3.30.2: + +------------------- +3.30.2 - 2017-09-24 +------------------- + +This release changes Hypothesis's caching approach for functions in +``hypothesis.strategies``. Previously it would have cached extremely +aggressively and cache entries would never be evicted. Now it adopts a +least-frequently used, least recently used key invalidation policy, and is +somewhat more conservative about which strategies it caches. + +Workloads which create strategies based on dynamic values, e.g. by using +:ref:`flatmap ` or :func:`~hypothesis.strategies.composite`, +will use significantly less memory. + +.. _v3.30.1: + +------------------- +3.30.1 - 2017-09-22 +------------------- + +This release fixes a bug where when running with +:attr:`use_coverage=True ` inside an +existing running instance of coverage, Hypothesis would frequently put files +that the coveragerc excluded in the report for the enclosing coverage. + +.. _v3.30.0: + +------------------- +3.30.0 - 2017-09-20 +------------------- + +This release introduces two new features: + +* When a test fails, either with a health check failure or a falsifying example, + Hypothesis will print out a seed that led to that failure, if the test is not + already running with a fixed seed. You can then recreate that failure using either + the :func:`@seed ` decorator or (if you are running pytest) with ``--hypothesis-seed``. +* :pypi:`pytest` users can specify a seed to use for :func:`@given ` based tests by passing + the ``--hypothesis-seed`` command line argument. + +This work was funded by `Smarkets `_. + +.. _v3.29.0: + +------------------- +3.29.0 - 2017-09-19 +------------------- + +This release makes Hypothesis coverage aware. Hypothesis now runs all test +bodies under coverage, and uses this information to guide its testing. + +The :attr:`~hypothesis.settings.use_coverage` setting can be used to disable +this behaviour if you want to test code that is sensitive to coverage being +enabled (either because of performance or interaction with the trace function). + +The main benefits of this feature are: + +* Hypothesis now observes when examples it discovers cover particular lines + or branches and stores them in the database for later. +* Hypothesis will make some use of this information to guide its exploration of + the search space and improve the examples it finds (this is currently used + only very lightly and will likely improve significantly in future releases). + +This also has the following side-effects: + +* Hypothesis now has an install time dependency on the :pypi:`coverage` package. +* Tests that are already running Hypothesis under coverage will likely get + faster. +* Tests that are not running under coverage now run their test bodies under + coverage by default. + + +This feature is only partially supported under pypy. It is significantly slower +than on CPython and is turned off by default as a result, but it should still +work correctly if you want to use it. + +.. _v3.28.3: + +------------------- +3.28.3 - 2017-09-18 +------------------- + +This release is an internal change that affects how Hypothesis handles +calculating certain properties of strategies. + +The primary effect of this is that it fixes a bug where use of +:func:`~hypothesis.strategies.deferred` could sometimes trigger an internal assertion +error. However the fix for this bug involved some moderately deep changes to +how Hypothesis handles certain constructs so you may notice some additional +knock-on effects. + +In particular the way Hypothesis handles drawing data from strategies that +cannot generate any values has changed to bail out sooner than it previously +did. This may speed up certain tests, but it is unlikely to make much of a +difference in practice for tests that were not already failing with +Unsatisfiable. + +.. _v3.28.2: + +------------------- +3.28.2 - 2017-09-18 +------------------- + +This is a patch release that fixes a bug in the :mod:`hypothesis.extra.pandas` +documentation where it incorrectly referred to :func:`~hypothesis.extra.pandas.column` +instead of :func:`~hypothesis.extra.pandas.columns`. + +.. _v3.28.1: + +------------------- +3.28.1 - 2017-09-16 +------------------- + +This is a refactoring release. It moves a number of internal uses +of :func:`~python:collections.namedtuple` over to using attrs based classes, and removes a couple +of internal namedtuple classes that were no longer in use. + +It should have no user visible impact. + +.. _v3.28.0: + +------------------- +3.28.0 - 2017-09-15 +------------------- + +This release adds support for testing :pypi:`pandas` via the :ref:`hypothesis.extra.pandas ` +module. + +It also adds a dependency on :pypi:`attrs`. + +This work was funded by `Stripe `_. + +.. _v3.27.1: + +------------------- +3.27.1 - 2017-09-14 +------------------- + +This release fixes some formatting and broken cross-references in the +documentation, which includes editing docstrings - and thus a patch release. + +.. _v3.27.0: + +------------------- +3.27.0 - 2017-09-13 +------------------- + +This release introduces a :attr:`~hypothesis.settings.deadline` +setting to Hypothesis. + +When set this turns slow tests into errors. By default it is unset but will +warn if you exceed 200ms, which will become the default value in a future +release. + +This work was funded by `Smarkets `_. + +.. _v3.26.0: + +------------------- +3.26.0 - 2017-09-12 +------------------- + +Hypothesis now emits deprecation warnings if you are using the legacy +SQLite example database format, or the tool for merging them. These were +already documented as deprecated, so this doesn't change their deprecation +status, only that we warn about it. + +.. _v3.25.1: + +------------------- +3.25.1 - 2017-09-12 +------------------- + +This release fixes a bug with generating :doc:`numpy datetime and timedelta types `: +When inferring the strategy from the dtype, datetime and timedelta dtypes with +sub-second precision would always produce examples with one second resolution. +Inferring a strategy from a time dtype will now always produce example with the +same precision. + +.. _v3.25.0: + +------------------- +3.25.0 - 2017-09-12 +------------------- + +This release changes how Hypothesis shrinks and replays examples to take into +account that it can encounter new bugs while shrinking the bug it originally +found. Previously it would end up replacing the originally found bug with the +new bug and show you only that one. Now it is (often) able to recognise when +two bugs are distinct and when it finds more than one will show both. + +.. _v3.24.2: + +------------------- +3.24.2 - 2017-09-11 +------------------- + +This release removes the (purely internal and no longer useful) +``strategy_test_suite`` function and the corresponding strategytests module. + +.. _v3.24.1: + +------------------- +3.24.1 - 2017-09-06 +------------------- + +This release improves the reduction of examples involving floating point +numbers to produce more human readable examples. + +It also has some general purpose changes to the way the minimizer works +internally, which may see some improvement in quality and slow down of test +case reduction in cases that have nothing to do with floating point numbers. + +.. _v3.24.0: + +------------------- +3.24.0 - 2017-09-05 +------------------- + +Hypothesis now emits deprecation warnings if you use ``some_strategy.example()`` inside a +test function or strategy definition (this was never intended to be supported, +but is sufficiently widespread that it warrants a deprecation path). + +.. _v3.23.3: + +------------------- +3.23.3 - 2017-09-05 +------------------- + +This is a bugfix release for :func:`~hypothesis.strategies.decimals` +with the ``places`` argument. + +- No longer fails health checks (:issue:`725`, due to internal filtering) +- Specifying a ``min_value`` and ``max_value`` without any decimals with + ``places`` places between them gives a more useful error message. +- Works for any valid arguments, regardless of the decimal precision context. + +.. _v3.23.2: + +------------------- +3.23.2 - 2017-09-01 +------------------- + +This is a small refactoring release that removes a now-unused parameter to an +internal API. It shouldn't have any user visible effect. + +.. _v3.23.1: + +------------------- +3.23.1 - 2017-09-01 +------------------- + +Hypothesis no longer propagates the dynamic scope of settings into strategy +definitions. + +This release is a small change to something that was never part of the public +API and you will almost certainly not notice any effect unless you're doing +something surprising, but for example the following code will now give a +different answer in some circumstances: + +.. code-block:: python + + import hypothesis.strategies as st + from hypothesis import settings + + CURRENT_SETTINGS = st.builds(lambda: settings.default) + +(We don't actually encourage you writing code like this) + +Previously this would have generated the settings that were in effect at the +point of definition of ``CURRENT_SETTINGS``. Now it will generate the settings +that are used for the current test. + +It is very unlikely to be significant enough to be visible, but you may also +notice a small performance improvement. + +.. _v3.23.0: + +------------------- +3.23.0 - 2017-08-31 +------------------- + +This release adds a ``unique`` argument to :func:`~hypothesis.extra.numpy.arrays` +which behaves the same ways as the corresponding one for +:func:`~hypothesis.strategies.lists`, requiring all of the elements in the +generated array to be distinct. + +.. _v3.22.2: + +------------------- +3.22.2 - 2017-08-29 +------------------- + +This release fixes an issue where Hypothesis would raise a ``TypeError`` when +using the datetime-related strategies if running with ``PYTHONOPTIMIZE=2``. +This bug was introduced in :ref:`3.20.0 `. (See :issue:`822`) + +.. _v3.22.1: + +------------------- +3.22.1 - 2017-08-28 +------------------- + +Hypothesis now transparently handles problems with an internal unicode cache, +including file truncation or read-only filesystems (:issue:`767`). +Thanks to Sam Hames for the patch. + +.. _v3.22.0: + +------------------- +3.22.0 - 2017-08-26 +------------------- + +This release provides what should be a substantial performance improvement to +numpy arrays generated using :ref:`provided numpy support `, +and adds a new ``fill_value`` argument to :func:`~hypothesis.extra.numpy.arrays` +to control this behaviour. + +This work was funded by `Stripe `_. + +.. _v3.21.3: + +------------------- +3.21.3 - 2017-08-26 +------------------- + +This release fixes some extremely specific circumstances that probably have +never occurred in the wild where users of +:func:`~hypothesis.strategies.deferred` might have seen a :class:`python:RuntimeError` from +too much recursion, usually in cases where no valid example could have been +generated anyway. + +.. _v3.21.2: + +------------------- +3.21.2 - 2017-08-25 +------------------- + +This release fixes some minor bugs in argument validation: + + * :ref:`hypothesis.extra.numpy ` dtype strategies would raise an internal error + instead of an InvalidArgument exception when passed an invalid + endianness specification. + * :func:`~hypothesis.strategies.fractions` would raise an internal error instead of an InvalidArgument + if passed ``float("nan")`` as one of its bounds. + * The error message for passing ``float("nan")`` as a bound to various + strategies has been improved. + * Various bound arguments will now raise InvalidArgument in cases where + they would previously have raised an internal TypeError or + ValueError from the relevant conversion function. + * :func:`~hypothesis.strategies.streaming` would not have emitted a + deprecation warning when called with an invalid argument. + +.. _v3.21.1: + +------------------- +3.21.1 - 2017-08-24 +------------------- + +This release fixes a bug where test failures that were the result of +an :func:`@example ` would print an extra stack trace before re-raising the +exception. + +.. _v3.21.0: + +------------------- +3.21.0 - 2017-08-23 +------------------- + +This release deprecates Hypothesis's strict mode, which turned Hypothesis's +deprecation warnings into errors. Similar functionality can be achieved +by using :func:`simplefilter('error', HypothesisDeprecationWarning) `. + +.. _v3.20.0: + +------------------- +3.20.0 - 2017-08-22 +------------------- + +This release renames the relevant arguments on the +:func:`~hypothesis.strategies.datetimes`, :func:`~hypothesis.strategies.dates`, +:func:`~hypothesis.strategies.times`, and :func:`~hypothesis.strategies.timedeltas` +strategies to ``min_value`` and ``max_value``, to make them consistent with the +other strategies in the module. + +The old argument names are still supported but will emit a deprecation warning +when used explicitly as keyword arguments. Arguments passed positionally will +go to the new argument names and are not deprecated. + +.. _v3.19.3: + +------------------- +3.19.3 - 2017-08-22 +------------------- + +This release provides a major overhaul to the internals of how Hypothesis +handles shrinking. + +This should mostly be visible in terms of getting better examples for tests +which make heavy use of :func:`~hypothesis.strategies.composite`, +:func:`~hypothesis.strategies.data` or :ref:`flatmap ` where the data +drawn depends a lot on previous choices, especially where size parameters are +affected. Previously Hypothesis would have struggled to reliably produce +good examples here. Now it should do much better. Performance should also be +better for examples with a non-zero ``min_size``. + +You may see slight changes to example generation (e.g. improved example +diversity) as a result of related changes to internals, but they are unlikely +to be significant enough to notice. + +.. _v3.19.2: + +------------------- +3.19.2 - 2017-08-21 +------------------- + +This release fixes two bugs in :mod:`hypothesis.extra.numpy`: + +* :func:`~hypothesis.extra.numpy.unicode_string_dtypes` didn't work at all due + to an incorrect dtype specifier. Now it does. +* Various impossible conditions would have been accepted but would error when + they fail to produced any example. Now they raise an explicit InvalidArgument + error. + +.. _v3.19.1: + +------------------- +3.19.1 - 2017-08-21 +------------------- + +This is a bugfix release for :issue:`739`, where bounds for +:func:`~hypothesis.strategies.fractions` or floating-point +:func:`~hypothesis.strategies.decimals` were not properly converted to +integers before passing them to the integers strategy. +This excluded some values that should have been possible, and could +trigger internal errors if the bounds lay between adjacent integers. + +You can now bound :func:`~hypothesis.strategies.fractions` with two +arbitrarily close fractions. + +It is now an explicit error to supply a min_value, max_value, and +max_denominator to :func:`~hypothesis.strategies.fractions` where the value +bounds do not include a fraction with denominator at most max_denominator. + +.. _v3.19.0: + +------------------- +3.19.0 - 2017-08-20 +------------------- + +This release adds the :func:`~hypothesis.strategies.from_regex` strategy, +which generates strings that contain a match of a regular expression. + +Thanks to Maxim Kulkin for creating the +`hypothesis-regex `_ +package and then helping to upstream it! (:issue:`662`) + +.. _v3.18.5: + +------------------- +3.18.5 - 2017-08-18 +------------------- + +This is a bugfix release for :func:`~hypothesis.strategies.integers`. +Previously the strategy would hit an internal assertion if passed non-integer +bounds for ``min_value`` and ``max_value`` that had no integers between them. +The strategy now raises InvalidArgument instead. + +.. _v3.18.4: + +------------------- +3.18.4 - 2017-08-18 +------------------- + +Release to fix a bug where mocks can be used as test runners under certain +conditions. Specifically, if a mock is injected into a test via pytest +fixtures or patch decorators, and that mock is the first argument in the +list, hypothesis will think it represents self and turns the mock +into a test runner. If this happens, the affected test always passes +because the mock is executed instead of the test body. Sometimes, it +will also fail health checks. + +Fixes :issue:`491` and a section of :issue:`198`. +Thanks to Ben Peterson for this bug fix. + +.. _v3.18.3: + +------------------- +3.18.3 - 2017-08-17 +------------------- + +This release should improve the performance of some tests which +experienced a slow down as a result of the :ref:`3.13.0 ` release. + +Tests most likely to benefit from this are ones that make extensive +use of ``min_size`` parameters, but others may see some improvement +as well. + +.. _v3.18.2: + +------------------- +3.18.2 - 2017-08-16 +------------------- + +This release fixes a bug introduced in :ref:`3.18.0 `. If the arguments +``whitelist_characters`` and ``blacklist_characters`` to +:func:`~hypothesis.strategies.characters` contained overlapping elements, then an +``InvalidArgument`` exception would be raised. + +Thanks to Zac Hatfield-Dodds for reporting and fixing this. + +.. _v3.18.1: + +------------------- +3.18.1 - 2017-08-14 +------------------- + +This is a bug fix release to fix :issue:`780`, where +:func:`~hypothesis.strategies.sets` and similar would trigger health check +errors if their element strategy could only produce one element (e.g. +if it was :func:`~hypothesis.strategies.just`). + +.. _v3.18.0: + +------------------- +3.18.0 - 2017-08-13 +------------------- + +This is a feature release: + +* :func:`~hypothesis.strategies.characters` now accepts + ``whitelist_characters``, particular characters which will be added to those + it produces. (:issue:`668`) +* A bug fix for the internal function ``_union_interval_lists()``, and a rename + to ``_union_intervals()``. It now correctly handles all cases where intervals + overlap, and it always returns the result as a tuple for tuples. + +Thanks to Alex Willmer for these. + +.. _v3.17.0: + +------------------- +3.17.0 - 2017-08-07 +------------------- + +This release documents :ref:`the previously undocumented phases feature `, +making it part of the public API. It also updates how the example +database is used. Principally: + +* A ``Phases.reuse`` argument will now correctly control whether examples + from the database are run (it previously did exactly the wrong thing and + controlled whether examples would be *saved*). +* Hypothesis will no longer try to rerun *all* previously failing examples. + Instead it will replay the smallest previously failing example and a + selection of other examples that are likely to trigger any other bugs that + will found. This prevents a previous failure from dominating your tests + unnecessarily. +* As a result of the previous change, Hypothesis will be slower about clearing + out old examples from the database that are no longer failing (because it can + only clear out ones that it actually runs). + +.. _v3.16.1: + +------------------- +3.16.1 - 2017-08-07 +------------------- + +This release makes an implementation change to how Hypothesis handles certain +internal constructs. + +The main effect you should see is improvement to the behaviour and performance +of collection types, especially ones with a ``min_size`` parameter. Many cases +that would previously fail due to being unable to generate enough valid +examples will now succeed, and other cases should run slightly faster. + +.. _v3.16.0: + +------------------- +3.16.0 - 2017-08-04 +------------------- + +This release introduces a deprecation of the timeout feature. This results in +the following changes: + +* Creating a settings object with an explicit timeout will emit a deprecation + warning. +* If your test stops because it hits the timeout (and has not found a bug) then + it will emit a deprecation warning. +* There is a new value ``unlimited`` which you can import from hypothesis. + ``settings(timeout=unlimited)`` will *not* cause a deprecation warning. +* There is a new health check, ``hung_test``, which will trigger after a test + has been running for five minutes if it is not suppressed. + +.. _v3.15.0: + +------------------- +3.15.0 - 2017-08-04 +------------------- + +This release deprecates two strategies, :func:`~hypothesis.strategies.choices` and +:func:`~hypothesis.strategies.streaming`. + +Both of these are somewhat confusing to use and are entirely redundant since the +introduction of the :func:`~hypothesis.strategies.data` strategy for interactive +drawing in tests, and their use should be replaced with direct use of +:func:`~hypothesis.strategies.data` instead. + +.. _v3.14.2: + +------------------- +3.14.2 - 2017-08-03 +------------------- + +This fixes a bug where Hypothesis would not work correctly on Python 2.7 if you +had the :mod:`python:typing` module :pypi:`backport ` installed. + +.. _v3.14.1: + +------------------- +3.14.1 - 2017-08-02 +------------------- + +This raises the maximum depth at which Hypothesis starts cutting off data +generation to a more reasonable value which it is harder to hit by accident. + +This resolves (:issue:`751`), in which some examples which previously worked +would start timing out, but it will also likely improve the data generation +quality for complex data types. + +.. _v3.14.0: + +------------------- +3.14.0 - 2017-07-23 +------------------- + +Hypothesis now understands inline type annotations (:issue:`293`): + +- If the target of :func:`~hypothesis.strategies.builds` has type annotations, + a default strategy for missing required arguments is selected based on the + type. Type-based strategy selection will only override a default if you + pass :const:`hypothesis.infer` as a keyword argument. + +- If :func:`@given ` wraps a function with type annotations, + you can pass :const:`~hypothesis.infer` as a keyword argument and the + appropriate strategy will be substituted. + +- You can check what strategy will be inferred for a type with the new + :func:`~hypothesis.strategies.from_type` function. + +- :func:`~hypothesis.strategies.register_type_strategy` teaches Hypothesis + which strategy to infer for custom or unknown types. You can provide a + strategy, or for more complex cases a function which takes the type and + returns a strategy. + +.. _v3.13.1: + +------------------- +3.13.1 - 2017-07-20 +------------------- + +This is a bug fix release for :issue:`514` - Hypothesis would continue running +examples after a :class:`~python:unittest.SkipTest` exception was raised, +including printing a falsifying example. Skip exceptions from the standard +:mod:`python:unittest` module, and ``pytest``, ``nose``, or ``unittest2`` +modules now abort the test immediately without printing output. + +.. _v3.13.0: + +------------------- +3.13.0 - 2017-07-16 +------------------- + +This release has two major aspects to it: The first is the introduction of +:func:`~hypothesis.strategies.deferred`, which allows more natural definition +of recursive (including mutually recursive) strategies. + +The second is a number of engine changes designed to support this sort of +strategy better. These should have a knock-on effect of also improving the +performance of any existing strategies that currently generate a lot of data +or involve heavy nesting by reducing their typical example size. + +.. _v3.12.0: + +------------------- +3.12.0 - 2017-07-07 +------------------- + +This release makes some major internal changes to how Hypothesis represents +data internally, as a prelude to some major engine changes that should improve +data quality. There are no API changes, but it's a significant enough internal +change that a minor version bump seemed warranted. + +User facing impact should be fairly mild, but includes: + +* All existing examples in the database will probably be invalidated. Hypothesis + handles this automatically, so you don't need to do anything, but if you see + all your examples disappear that's why. +* Almost all data distributions have changed significantly. Possibly for the better, + possibly for the worse. This may result in new bugs being found, but it may + also result in Hypothesis being unable to find bugs it previously did. +* Data generation may be somewhat faster if your existing bottleneck was in + draw_bytes (which is often the case for large examples). +* Shrinking will probably be slower, possibly significantly. + +If you notice any effects you consider to be a significant regression, please +open an issue about them. + +.. _v3.11.6: + +------------------- +3.11.6 - 2017-06-19 +------------------- + +This release involves no functionality changes, but is the first to ship wheels +as well as an sdist. + +.. _v3.11.5: + +------------------- +3.11.5 - 2017-06-18 +------------------- + +This release provides a performance improvement to shrinking. For cases where +there is some non-trivial "boundary" value (e.g. the bug happens for all values +greater than some other value), shrinking should now be substantially faster. +Other types of bug will likely see improvements too. + +This may also result in some changes to the quality of the final examples - it +may sometimes be better, but is more likely to get slightly worse in some edge +cases. If you see any examples where this happens in practice, please report +them. + +.. _v3.11.4: + +------------------- +3.11.4 - 2017-06-17 +------------------- + +This is a bugfix release: Hypothesis now prints explicit examples when +running in verbose mode. (:issue:`313`) + +.. _v3.11.3: + +------------------- +3.11.3 - 2017-06-11 +------------------- + +This is a bugfix release: Hypothesis no longer emits a warning if you try to +use :func:`~hypothesis.strategies.sampled_from` with +:class:`python:collections.OrderedDict`. (:issue:`688`) + +.. _v3.11.2: + +------------------- +3.11.2 - 2017-06-10 +------------------- + +This is a documentation release. Several outdated snippets have been updated +or removed, and many cross-references are now hyperlinks. + +.. _v3.11.1: + +------------------- +3.11.1 - 2017-05-28 +------------------- + +This is a minor ergonomics release. Tracebacks shown by pytest no longer +include Hypothesis internals for test functions decorated with :func:`@given `. + +.. _v3.11.0: + +------------------- +3.11.0 - 2017-05-23 +------------------- + +This is a feature release, adding datetime-related strategies to the core strategies. + +:func:`~hypothesis.extra.pytz.timezones` allows you to sample pytz timezones from +the Olsen database. Use directly in a recipe for tz-aware datetimes, or +compose with :func:`~hypothesis.strategies.none` to allow a mix of aware and naive output. + +The new :func:`~hypothesis.strategies.dates`, :func:`~hypothesis.strategies.times`, +:func:`~hypothesis.strategies.datetimes`, and :func:`~hypothesis.strategies.timedeltas` +strategies are all constrained by objects of their type. +This means that you can generate dates bounded by a single day +(i.e. a single date), or datetimes constrained to the microsecond. + +:func:`~hypothesis.strategies.times` and :func:`~hypothesis.strategies.datetimes` +take an optional ``timezones=`` argument, which +defaults to :func:`~hypothesis.strategies.none` for naive times. You can use our extra strategy +based on pytz, or roll your own timezones strategy with dateutil or even +the standard library. + +The old ``dates``, ``times``, and ``datetimes`` strategies in +``hypothesis.extra.datetimes`` are deprecated in favor of the new +core strategies, which are more flexible and have no dependencies. + +.. _v3.10.0: + +------------------- +3.10.0 - 2017-05-22 +------------------- + +Hypothesis now uses :func:`python:inspect.getfullargspec` internally. +On Python 2, there are no visible changes. + +On Python 3 :func:`@given ` and :func:`@composite ` +now preserve :pep:`3107` annotations on the +decorated function. Keyword-only arguments are now either handled correctly +(e.g. :func:`@composite `), or caught in validation instead of silently discarded +or raising an unrelated error later (e.g. :func:`@given `). + +.. _v3.9.1: + +------------------ +3.9.1 - 2017-05-22 +------------------ + +This is a bugfix release: the default field mapping for a DateTimeField in the +Django extra now respects the ``USE_TZ`` setting when choosing a strategy. + +.. _v3.9.0: + +------------------ +3.9.0 - 2017-05-19 +------------------ + +This is feature release, expanding the capabilities of the +:func:`~hypothesis.strategies.decimals` strategy. + +* The new (optional) ``places`` argument allows you to generate decimals with + a certain number of places (e.g. cents, thousandths, satoshis). +* If allow_infinity is None, setting min_bound no longer excludes positive + infinity and setting max_value no longer excludes negative infinity. +* All of ``NaN``, ``-Nan``, ``sNaN``, and ``-sNaN`` may now be drawn if + allow_nan is True, or if allow_nan is None and min_value or max_value is None. +* min_value and max_value may be given as decimal strings, e.g. ``"1.234"``. + + +.. _v3.8.5: + +------------------ +3.8.5 - 2017-05-16 +------------------ + +Hypothesis now imports :mod:`python:sqlite3` when a SQLite database is used, rather +than at module load, improving compatibility with Python implementations +compiled without SQLite support (such as BSD or Jython). + +.. _v3.8.4: + +------------------ +3.8.4 - 2017-05-16 +------------------ + +This is a compatibility bugfix release. :func:`~hypothesis.strategies.sampled_from` +no longer raises a deprecation warning when sampling from an +:class:`python:enum.Enum`, as all enums have a reliable iteration order. + +.. _v3.8.3: + +------------------ +3.8.3 - 2017-05-09 +------------------ + +This release removes a version check for older versions of :pypi:`pytest` when using +the Hypothesis pytest plugin. The pytest plugin will now run unconditionally +on all versions of pytest. This breaks compatibility with any version of pytest +prior to 2.7.0 (which is more than two years old). + +The primary reason for this change is that the version check was a frequent +source of breakage when pytest change their versioning scheme. If you are not +working on pytest itself and are not running a very old version of it, this +release probably doesn't affect you. + +.. _v3.8.2: + +------------------ +3.8.2 - 2017-04-26 +------------------ + +This is a code reorganisation release that moves some internal test helpers +out of the main source tree so as to not have changes to them trigger releases +in future. + +.. _v3.8.1: + +------------------ +3.8.1 - 2017-04-26 +------------------ + +This is a documentation release. Almost all code examples are now doctests +checked in CI, eliminating stale examples. + +.. _v3.8.0: + +------------------ +3.8.0 - 2017-04-23 +------------------ + +This is a feature release, adding the :func:`~hypothesis.strategies.iterables` strategy, equivalent +to ``lists(...).map(iter)`` but with a much more useful repr. You can use +this strategy to check that code doesn't accidentally depend on sequence +properties such as indexing support or repeated iteration. + +.. _v3.7.4: + +------------------ +3.7.4 - 2017-04-22 +------------------ + +This patch fixes a bug in :ref:`3.7.3 `, where using +:func:`@example ` and a pytest fixture in the same test +could cause the test to fail to fill the arguments, and throw a TypeError. + +.. _v3.7.3: + +------------------ +3.7.3 - 2017-04-21 +------------------ + +This release should include no user visible changes and is purely a refactoring +release. This modularises the behaviour of the core :func:`~hypothesis.given` function, breaking +it up into smaller and more accessible parts, but its actual behaviour should +remain unchanged. + +.. _v3.7.2: + +------------------ +3.7.2 - 2017-04-21 +------------------ + +This reverts an undocumented change in :ref:`3.7.1 ` which broke installation on +debian stable: The specifier for the hypothesis[django] extra\_requires had +introduced a wild card, which was not supported on the default version of pip. + +.. _v3.7.1: + +------------------ +3.7.1 - 2017-04-21 +------------------ + +This is a bug fix and internal improvements release. + +* In particular Hypothesis now tracks a tree of where it has already explored. + This allows it to avoid some classes of duplicate examples, and significantly + improves the performance of shrinking failing examples by allowing it to + skip some shrinks that it can determine can't possibly work. +* Hypothesis will no longer seed the global random arbitrarily unless you have + asked it to using :py:meth:`~hypothesis.strategies.random_module` +* Shrinking would previously have not worked correctly in some special cases + on Python 2, and would have resulted in suboptimal examples. + +.. _v3.7.0: + +------------------ +3.7.0 - 2017-03-20 +------------------ + +This is a feature release. + +New features: + +* Rule based stateful testing now has an :func:`@invariant ` decorator that specifies + methods that are run after init and after every step, allowing you to + encode properties that should be true at all times. Thanks to Tom Prince for + this feature. +* The :func:`~hypothesis.strategies.decimals` strategy now supports ``allow_nan`` and ``allow_infinity`` flags. +* There are :ref:`significantly more strategies available for numpy `, including for + generating arbitrary data types. Thanks to Zac Hatfield Dodds for this + feature. +* When using the :func:`~hypothesis.strategies.data` strategy you can now add a label as an argument to + ``draw()``, which will be printed along with the value when an example fails. + Thanks to Peter Inglesby for this feature. + +Bug fixes: + +* Bug fix: :func:`~hypothesis.strategies.composite` now preserves functions' docstrings. +* The build is now reproducible and doesn't depend on the path you build it + from. Thanks to Chris Lamb for this feature. +* numpy strategies for the void data type did not work correctly. Thanks to + Zac Hatfield Dodds for this fix. + +There have also been a number of performance optimizations: + +* The :func:`~hypothesis.strategies.permutations` strategy is now significantly faster to use for large + lists (the underlying algorithm has gone from O(n^2) to O(n)). +* Shrinking of failing test cases should have got significantly faster in + some circumstances where it was previously struggling for a long time. +* Example generation now involves less indirection, which results in a small + speedup in some cases (small enough that you won't really notice it except in + pathological cases). + + +.. _v3.6.1: + +------------------ +3.6.1 - 2016-12-20 +------------------ + +This release fixes a dependency problem and makes some small behind the scenes +improvements. + +* The fake-factory dependency was renamed to faker. If you were depending on + it through hypothesis[django] or hypothesis[fake-factory] without pinning it + yourself then it would have failed to install properly. This release changes + it so that hypothesis[fakefactory] (which can now also be installed as + hypothesis[faker]) will install the renamed faker package instead. +* This release also removed the dependency of hypothesis[django] on + hypothesis[fakefactory] - it was only being used for emails. These now use + a custom strategy that isn't from fakefactory. As a result you should also + see performance improvements of tests which generated User objects or other + things with email fields, as well as better shrinking of email addresses. +* The distribution of code using nested calls to :func:`~hypothesis.strategies.one_of` or the ``|`` operator for + combining strategies has been improved, as branches are now flattened to give + a more uniform distribution. +* Examples using :func:`~hypothesis.strategies.composite` or ``.flatmap`` should now shrink better. In particular + this will affect things which work by first generating a length and then + generating that many items, which have historically not shrunk very well. + +.. _v3.6.0: + +------------------ +3.6.0 - 2016-10-31 +------------------ + +This release reverts Hypothesis to its old pretty printing of lambda functions +based on attempting to extract the source code rather than decompile the bytecode. +This is unfortunately slightly inferior in some cases and may result in you +occasionally seeing things like ``lambda x: `` in statistics reports and +strategy reprs. + +This removes the dependencies on uncompyle6, xdis and spark-parser. + +The reason for this is that the new functionality was based on uncompyle6, which +turns out to introduce a hidden GPLed dependency - it in turn depended on xdis, +and although the library was licensed under the MIT license, it contained some +GPL licensed source code and thus should have been released under the GPL. + +My interpretation is that Hypothesis itself was never in violation of the GPL +(because the license it is under, the Mozilla Public License v2, is fully +compatible with being included in a GPL licensed work), but I have not consulted +a lawyer on the subject. Regardless of the answer to this question, adding a +GPLed dependency will likely cause a lot of users of Hypothesis to inadvertently +be in violation of the GPL. + +As a result, if you are running Hypothesis 3.5.x you really should upgrade to +this release immediately. + +.. _v3.5.3: + +------------------ +3.5.3 - 2016-10-05 +------------------ + +This is a bug fix release. + +Bugs fixed: + +* If the same test was running concurrently in two processes and there were + examples already in the test database which no longer failed, Hypothesis + would sometimes fail with a FileNotFoundError (IOError on Python 2) because + an example it was trying to read was deleted before it was read. (:issue:`372`). +* Drawing from an :func:`~hypothesis.strategies.integers` strategy with both a min_value and a max_value + would reject too many examples needlessly. Now it repeatedly redraws until + satisfied. (:pull:`366`. Thanks to Calen Pennington for the contribution). + +.. _v3.5.2: + +------------------ +3.5.2 - 2016-09-24 +------------------ + +This is a bug fix release. + +* The Hypothesis pytest plugin broke pytest support for doctests. Now it doesn't. + +.. _v3.5.1: + +------------------ +3.5.1 - 2016-09-23 +------------------ + +This is a bug fix release. + +* Hypothesis now runs cleanly in -B and -BB modes, avoiding mixing bytes and unicode. +* :class:`python:unittest.TestCase` tests would not have shown up in the new statistics mode. Now they + do. +* Similarly, stateful tests would not have shown up in statistics and now they do. +* Statistics now print with pytest node IDs (the names you'd get in pytest verbose mode). + +.. _v3.5.0: + +------------------ +3.5.0 - 2016-09-22 +------------------ + +This is a feature release. + +* :func:`~hypothesis.strategies.fractions` and :func:`~hypothesis.strategies.decimals` strategies now support min_value and max_value + parameters. Thanks go to Anne Mulhern for the development of this feature. +* The Hypothesis pytest plugin now supports a ``--hypothesis-show-statistics`` parameter + that gives detailed statistics about the tests that were run. Huge thanks to + Jean-Louis Fuchs and Adfinis-SyGroup for funding the development of this feature. +* There is a new :func:`~hypothesis.event` function that can be used to add custom statistics. + +Additionally there have been some minor bug fixes: + +* In some cases Hypothesis should produce fewer duplicate examples (this will mostly + only affect cases with a single parameter). +* :pypi:`pytest` command line parameters are now under an option group for Hypothesis (thanks + to David Keijser for fixing this) +* Hypothesis would previously error if you used :pep:`3107` function annotations on your tests under + Python 3.4. +* The repr of many strategies using lambdas has been improved to include the lambda body + (this was previously supported in many but not all cases). + +.. _v3.4.2: + +------------------ +3.4.2 - 2016-07-13 +------------------ + +This is a bug fix release, fixing a number of problems with the settings system: + +* Test functions defined using :func:`@given ` can now be called from other threads + (:issue:`337`) +* Attempting to delete a settings property would previously have silently done + the wrong thing. Now it raises an AttributeError. +* Creating a settings object with a custom database_file parameter was silently + getting ignored and the default was being used instead. Now it's not. + +.. _v3.4.1: + +------------------ +3.4.1 - 2016-07-07 +------------------ + +This is a bug fix release for a single bug: + +* On Windows when running two Hypothesis processes in parallel (e.g. using + :pypi:`pytest-xdist`) they could race with each other and one would raise an exception + due to the non-atomic nature of file renaming on Windows and the fact that you + can't rename over an existing file. This is now fixed. + +.. _v3.4.0: + +------------------ +3.4.0 - 2016-05-27 +------------------ + +This release is entirely provided by `Lucas Wiman `_: + +Strategies constructed by :func:`~hypothesis.extra.django.models.models` +will now respect much more of Django's validations out of the box. +Wherever possible, :meth:`~django:django.db.models.Model.full_clean` should +succeed. + +In particular: + +* The max_length, blank and choices kwargs are now respected. +* Add support for DecimalField. +* If a field includes validators, the list of validators are used to filter the field strategy. + +.. _v3.3.0: + +------------------ +3.3.0 - 2016-05-27 +------------------ + +This release went wrong and is functionally equivalent to :ref:`3.2.0 `. Ignore it. + +.. _v3.2.0: + +------------------ +3.2.0 - 2016-05-19 +------------------ + +This is a small single-feature release: + +* All tests using :func:`@given ` now fix the global random seed. This removes the health + check for that. If a non-zero seed is required for the final falsifying + example, it will be reported. Otherwise Hypothesis will assume randomization + was not a significant factor for the test and be silent on the subject. If you + use :func:`~hypothesis.strategies.random_module` this will continue to work and will always + display the seed. + +.. _v3.1.3: + +------------------ +3.1.3 - 2016-05-01 +------------------ + +Single bug fix release + +* Another charmap problem. In :ref:`3.1.2 ` :func:`~hypothesis.strategies.text` and + :func:`~hypothesis.strategies.characters` would break on systems + which had ``/tmp`` mounted on a different partition than the Hypothesis storage + directory (usually in home). This fixes that. + +.. _v3.1.2: + +------------------ +3.1.2 - 2016-04-30 +------------------ + +Single bug fix release: + +* Anything which used a :func:`~hypothesis.strategies.text` or + :func:`~hypothesis.strategies.characters` strategy was broken on Windows + and I hadn't updated appveyor to use the new repository location so I didn't + notice. This is now fixed and windows support should work correctly. + +.. _v3.1.1: + +------------------ +3.1.1 - 2016-04-29 +------------------ + +Minor bug fix release. + +* Fix concurrency issue when running tests that use :func:`~hypothesis.strategies.text` from multiple + processes at once (:issue:`302`, thanks to Alex Chan). +* Improve performance of code using :func:`~hypothesis.strategies.lists` with max_size (thanks to + Cristi Cobzarenco). +* Fix install on Python 2 with ancient versions of pip so that it installs the + :pypi:`enum34` backport (thanks to Donald Stufft for telling me how to do this). +* Remove duplicated __all__ exports from hypothesis.strategies (thanks to + Piët Delport). +* Update headers to point to new repository location. +* Allow use of strategies that can't be used in :func:`~hypothesis.find` + (e.g. :func:`~hypothesis.strategies.choices`) in stateful testing. + + +.. _v3.1.0: + +------------------ +3.1.0 - 2016-03-06 +------------------ + +* Add a :func:`~hypothesis.strategies.nothing` strategy that never successfully generates values. +* :func:`~hypothesis.strategies.sampled_from` and :func:`~hypothesis.strategies.one_of` + can both now be called with an empty argument + list, in which case they also never generate any values. +* :func:`~hypothesis.strategies.one_of` may now be called with a single argument that is a collection of strategies + as well as as varargs. +* Add a :func:`~hypothesis.strategies.runner` strategy which returns the instance of the current test object + if there is one. +* 'Bundle' for RuleBasedStateMachine is now a normal(ish) strategy and can be used + as such. +* Tests using RuleBasedStateMachine should now shrink significantly better. +* Hypothesis now uses a pretty-printing library internally, compatible with IPython's + pretty printing protocol (actually using the same code). This may improve the quality + of output in some cases. +* Add a 'phases' setting that allows more fine grained control over which parts of the + process Hypothesis runs +* Add a suppress_health_check setting which allows you to turn off specific health checks + in a fine grained manner. +* Fix a bug where lists of non fixed size would always draw one more element than they + included. This mostly didn't matter, but if would cause problems with empty strategies + or ones with side effects. +* Add a mechanism to the Django model generator to allow you to explicitly request the + default value (thanks to Jeremy Thurgood for this one). + +.. _v3.0.5: + +------------------ +3.0.5 - 2016-02-25 +------------------ + +* Fix a bug where Hypothesis would now error on py.test development versions. + +.. _v3.0.4: + +------------------ +3.0.4 - 2016-02-24 +------------------ + +* Fix a bug where Hypothesis would error when running on Python 2.7.3 or + earlier because it was trying to pass a :class:`python:bytearray` object + to :func:`python:struct.unpack` (which is only supported since 2.7.4). + +.. _v3.0.3: + +------------------ +3.0.3 - 2016-02-23 +------------------ + +* Fix version parsing of py.test to work with py.test release candidates +* More general handling of the health check problem where things could fail because + of a cache miss - now one "free" example is generated before the start of the + health check run. + +.. _v3.0.2: + +------------------ +3.0.2 - 2016-02-18 +------------------ + +* Under certain circumstances, strategies involving :func:`~hypothesis.strategies.text` buried inside some + other strategy (e.g. ``text().filter(...)`` or ``recursive(text(), ...))`` would cause + a test to fail its health checks the first time it ran. This was caused by having + to compute some related data and cache it to disk. On travis or anywhere else + where the ``.hypothesis`` directory was recreated this would have caused the tests + to fail their health check on every run. This is now fixed for all the known cases, + although there could be others lurking. + +.. _v3.0.1: + +------------------ +3.0.1 - 2016-02-18 +------------------ + +* Fix a case where it was possible to trigger an "Unreachable" assertion when + running certain flaky stateful tests. +* Improve shrinking of large stateful tests by eliminating a case where it was + hard to delete early steps. +* Improve efficiency of drawing :func:`binary(min_size=n, max_size=n) ` significantly by + provide a custom implementation for fixed size blocks that can bypass a lot + of machinery. +* Set default home directory based on the current working directory at the + point Hypothesis is imported, not whenever the function first happens to be + called. + +.. _v3.0.0: + +------------------ +3.0.0 - 2016-02-17 +------------------ + +Codename: This really should have been 2.1. + +Externally this looks like a very small release. It has one small breaking change +that probably doesn't affect anyone at all (some behaviour that never really worked +correctly is now outright forbidden) but necessitated a major version bump and one +visible new feature. + +Internally this is a complete rewrite. Almost nothing other than the public API is +the same. + +New features: + +* Addition of :func:`~hypothesis.strategies.data` strategy which allows you to draw arbitrary data interactively + within the test. +* New "exploded" database format which allows you to more easily check the example + database into a source repository while supporting merging. +* Better management of how examples are saved in the database. +* Health checks will now raise as errors when they fail. It was too easy to have + the warnings be swallowed entirely. + +New limitations: + +* :func:`~hypothesis.strategies.choices` and :func:`~hypothesis.strategies.streaming` + strategies may no longer be used with :func:`~hypothesis.find`. Neither may + :func:`~hypothesis.strategies.data` (this is the change that necessitated a major version bump). + +Feature removal: + +* The ForkingTestCase executor has gone away. It may return in some more working + form at a later date. + +Performance improvements: + +* A new model which allows flatmap, composite strategies and stateful testing to + perform *much* better. They should also be more reliable. +* Filtering may in some circumstances have improved significantly. This will + help especially in cases where you have lots of values with individual filters + on them, such as lists(x.filter(...)). +* Modest performance improvements to the general test runner by avoiding expensive + operations + +In general your tests should have got faster. If they've instead got significantly +slower, I'm interested in hearing about it. + +Data distribution: + +The data distribution should have changed significantly. This may uncover bugs the +previous version missed. It may also miss bugs the previous version could have +uncovered. Hypothesis is now producing less strongly correlated data than it used +to, but the correlations are extended over more of the structure. + +Shrinking: + +Shrinking quality should have improved. In particular Hypothesis can now perform +simultaneous shrinking of separate examples within a single test (previously it +was only able to do this for elements of a single collection). In some cases +performance will have improved, in some cases it will have got worse but generally +shouldn't have by much. + +.. _v2.0.0: + +------------------ +2.0.0 - 2016-01-10 +------------------ + +Codename: A new beginning + +This release cleans up all of the legacy that accrued in the course of +Hypothesis 1.0. These are mostly things that were emitting deprecation warnings +in 1.19.0, but there were a few additional changes. + +In particular: + +* non-strategy values will no longer be converted to strategies when used in + given or find. +* FailedHealthCheck is now an error and not a warning. +* Handling of non-ascii reprs in user types have been simplified by using raw + strings in more places in Python 2. +* given no longer allows mixing positional and keyword arguments. +* given no longer works with functions with defaults. +* given no longer turns provided arguments into defaults - they will not appear + in the argspec at all. +* the basic() strategy no longer exists. +* the n_ary_tree strategy no longer exists. +* the average_list_length setting no longer exists. Note: If you're using + using recursive() this will cause you a significant slow down. You should + pass explicit average_size parameters to collections in recursive calls. +* @rule can no longer be applied to the same method twice. +* Python 2.6 and 3.3 are no longer officially supported, although in practice + they still work fine. + +This also includes two non-deprecation changes: + +* given's keyword arguments no longer have to be the rightmost arguments and + can appear anywhere in the method signature. +* The max_shrinks setting would sometimes not have been respected. + + +.. _v1.19.0: + +------------------- +1.19.0 - 2016-01-09 +------------------- + +Codename: IT COMES + +This release heralds the beginning of a new and terrible age of Hypothesis 2.0. + +It's primary purpose is some final deprecations prior to said release. The goal +is that if your code emits no warnings under this release then it will probably run +unchanged under Hypothesis 2.0 (there are some caveats to this: 2.0 will drop +support for some Python versions, and if you're using internal APIs then as usual +that may break without warning). + +It does have two new features: + +* New @seed() decorator which allows you to manually seed a test. This may be + harmlessly combined with and overrides the derandomize setting. +* settings objects may now be used as a decorator to fix those settings to a + particular @given test. + +API changes (old usage still works but is deprecated): + +* Settings has been renamed to settings (lower casing) in order to make the + decorator usage more natural. +* Functions for the storage directory that were in hypothesis.settings are now + in a new hypothesis.configuration module. + +Additional deprecations: + +* the average_list_length setting has been deprecated in favour of being + explicit. +* the basic() strategy has been deprecated as it is impossible to support + it under a Conjecture based model, which will hopefully be implemented at + some point in the 2.x series. +* the n_ary_tree strategy (which was never actually part of the public API) + has been deprecated. +* Passing settings or random as keyword arguments to given is deprecated (use + the new functionality instead) + + +Bug fixes: + +* No longer emit PendingDeprecationWarning for __iter__ and StopIteration in + streaming() values. +* When running in health check mode with non strict, don't print quite so + many errors for an exception in reify. +* When an assumption made in a test or a filter is flaky, tests will now + raise Flaky instead of UnsatisfiedAssumption. + + +.. _v1.18.1: + +----------------------------------------------------------------------- +`1.18.1 `_ - 2015-12-22 +----------------------------------------------------------------------- + +Two behind the scenes changes: + +* Hypothesis will no longer write generated code to the file system. This + will improve performance on some systems (e.g. if you're using + `PythonAnywhere `_ which is running your + code from NFS) and prevent some annoying interactions with auto-restarting + systems. +* Hypothesis will cache the creation of some strategies. This can significantly + improve performance for code that uses flatmap or composite and thus has to + instantiate strategies a lot. + +.. _v1.18.0: + +----------------------------------------------------------------------- +`1.18.0 `_ - 2015-12-21 +----------------------------------------------------------------------- + +Features: + +* Tests and find are now explicitly seeded off the global random module. This + means that if you nest one inside the other you will now get a health check + error. It also means that you can control global randomization by seeding + random. +* There is a new random_module() strategy which seeds the global random module + for you and handles things so that you don't get a health check warning if + you use it inside your tests. +* floats() now accepts two new arguments: allow\_nan and allow\_infinity. These + default to the old behaviour, but when set to False will do what the names + suggest. + +Bug fixes: + +* Fix a bug where tests that used text() on Python 3.4+ would not actually be + deterministic even when explicitly seeded or using the derandomize mode, + because generation depended on dictionary iteration order which was affected + by hash randomization. +* Fix a bug where with complicated strategies the timing of the initial health + check could affect the seeding of the subsequent test, which would also + render supposedly deterministic tests non-deterministic in some scenarios. +* In some circumstances flatmap() could get confused by two structurally + similar things it could generate and would produce a flaky test where the + first time it produced an error but the second time it produced the other + value, which was not an error. The same bug was presumably also possible in + composite(). +* flatmap() and composite() initial generation should now be moderately faster. + This will be particularly noticeable when you have many values drawn from the + same strategy in a single run, e.g. constructs like lists(s.flatmap(f)). + Shrinking performance *may* have suffered, but this didn't actually produce + an interestingly worse result in any of the standard scenarios tested. + +.. _v1.17.1: + +----------------------------------------------------------------------- +`1.17.1 `_ - 2015-12-16 +----------------------------------------------------------------------- + +A small bug fix release, which fixes the fact that the 'note' function could +not be used on tests which used the @example decorator to provide explicit +examples. + +.. _v1.17.0: + +----------------------------------------------------------------------- +`1.17.0 `_ - 2015-12-15 +----------------------------------------------------------------------- + +This is actually the same release as 1.16.1, but 1.16.1 has been pulled because +it contains the following additional change that was not intended to be in a +patch release (it's perfectly stable, but is a larger change that should have +required a minor version bump): + +* Hypothesis will now perform a series of "health checks" as part of running + your tests. These detect and warn about some common error conditions that + people often run into which wouldn't necessarily have caused the test to fail + but would cause e.g. degraded performance or confusing results. + +.. _v1.16.1: + +----------------------------------------------------------------------- +`1.16.1 `_ - 2015-12-14 +----------------------------------------------------------------------- + +Note: This release has been removed. + +A small bugfix release that allows bdists for Hypothesis to be built +under 2.7 - the compat3.py file which had Python 3 syntax wasn't intended +to be loaded under Python 2, but when building a bdist it was. In particular +this would break running setup.py test. + +.. _v1.16.0: + +----------------------------------------------------------------------- +`1.16.0 `_ - 2015-12-08 +----------------------------------------------------------------------- + +There are no public API changes in this release but it includes a behaviour +change that I wasn't comfortable putting in a patch release. + +* Functions from hypothesis.strategies will no longer raise InvalidArgument + on bad arguments. Instead the same errors will be raised when a test + using such a strategy is run. This may improve startup time in some + cases, but the main reason for it is so that errors in strategies + won't cause errors in loading, and it can interact correctly with things + like pytest.mark.skipif. +* Errors caused by accidentally invoking the legacy API are now much less + confusing, although still throw NotImplementedError. +* hypothesis.extra.django is 1.9 compatible. +* When tests are run with max_shrinks=0 this will now still rerun the test + on failure and will no longer print "Trying example:" before each run. + Additionally note() will now work correctly when used with max_shrinks=0. + +.. _v1.15.0: + +----------------------------------------------------------------------- +`1.15.0 `_ - 2015-11-24 +----------------------------------------------------------------------- + +A release with two new features. + +* A 'characters' strategy for more flexible generation of text with particular + character ranges and types, kindly contributed by `Alexander Shorin `_. +* Add support for preconditions to the rule based stateful testing. Kindly + contributed by `Christopher Armstrong `_ + + +.. _v1.14.0: + +----------------------------------------------------------------------- +`1.14.0 `_ - 2015-11-01 +----------------------------------------------------------------------- + + +New features: + +* Add 'note' function which lets you include additional information in the + final test run's output. +* Add 'choices' strategy which gives you a choice function that emulates + random.choice. +* Add 'uuid' strategy that generates UUIDs' +* Add 'shared' strategy that lets you create a strategy that just generates a + single shared value for each test run + +Bugs: + +* Using strategies of the form streaming(x.flatmap(f)) with find or in stateful + testing would have caused InvalidArgument errors when the resulting values + were used (because code that expected to only be called within a test context + would be invoked). + + +.. _v1.13.0: + +----------------------------------------------------------------------- +`1.13.0 `_ - 2015-10-29 +----------------------------------------------------------------------- + +This is quite a small release, but deprecates some public API functions +and removes some internal API functionality so gets a minor version bump. + +* All calls to the 'strategy' function are now deprecated, even ones which + pass just a SearchStrategy instance (which is still a no-op). +* Never documented hypothesis.extra entry_points mechanism has now been removed ( + it was previously how hypothesis.extra packages were loaded and has been deprecated + and unused for some time) +* Some corner cases that could previously have produced an OverflowError when simplifying + failing cases using hypothesis.extra.datetimes (or dates or times) have now been fixed. +* Hypothesis load time for first import has been significantly reduced - it used to be + around 250ms (on my SSD laptop) and now is around 100-150ms. This almost never + matters but was slightly annoying when using it in the console. +* hypothesis.strategies.randoms was previously missing from \_\_all\_\_. + +.. _v1.12.0: + +----------------------------------------------------------------------- +`1.12.0 `_ - 2015-10-18 +----------------------------------------------------------------------- + +* Significantly improved performance of creating strategies using the functions + from the hypothesis.strategies module by deferring the calculation of their + repr until it was needed. This is unlikely to have been an performance issue + for you unless you were using flatmap, composite or stateful testing, but for + some cases it could be quite a significant impact. +* A number of cases where the repr of strategies build from lambdas is improved +* Add dates() and times() strategies to hypothesis.extra.datetimes +* Add new 'profiles' mechanism to the settings system +* Deprecates mutability of Settings, both the Settings.default top level property + and individual settings. +* A Settings object may now be directly initialized from a parent Settings. +* @given should now give a better error message if you attempt to use it with a + function that uses destructuring arguments (it still won't work, but it will + error more clearly), +* A number of spelling corrections in error messages +* py.test should no longer display the intermediate modules Hypothesis generates + when running in verbose mode +* Hypothesis should now correctly handle printing objects with non-ascii reprs + on python 3 when running in a locale that cannot handle ascii printing to + stdout. +* Add a unique=True argument to lists(). This is equivalent to + unique_by=lambda x: x, but offers a more convenient syntax. + + +.. _v1.11.4: + +----------------------------------------------------------------------- +`1.11.4 `_ - 2015-09-27 +----------------------------------------------------------------------- + +* Hide modifications Hypothesis needs to make to sys.path by undoing them + after we've imported the relevant modules. This is a workaround for issues + cryptography experienced on windows. +* Slightly improved performance of drawing from sampled_from on large lists + of alternatives. +* Significantly improved performance of drawing from one_of or strategies + using \| (note this includes a lot of strategies internally - floats() + and integers() both fall into this category). There turned out to be a + massive performance regression introduced in 1.10.0 affecting these which + probably would have made tests using Hypothesis significantly slower than + they should have been. + +.. _v1.11.3: + +----------------------------------------------------------------------- +`1.11.3 `_ - 2015-09-23 +----------------------------------------------------------------------- + +* Better argument validation for datetimes() strategy - previously setting + max_year < datetime.MIN_YEAR or min_year > datetime.MAX_YEAR would not have + raised an InvalidArgument error and instead would have behaved confusingly. +* Compatibility with being run on pytest < 2.7 (achieved by disabling the + plugin). + +.. _v1.11.2: + +----------------------------------------------------------------------- +`1.11.2 `_ - 2015-09-23 +----------------------------------------------------------------------- + +Bug fixes: + +* Settings(database=my_db) would not be correctly inherited when used as a + default setting, so that newly created settings would use the database_file + setting and create an SQLite example database. +* Settings.default.database = my_db would previously have raised an error and + now works. +* Timeout could sometimes be significantly exceeded if during simplification + there were a lot of examples tried that didn't trigger the bug. +* When loading a heavily simplified example using a basic() strategy from the + database this could cause Python to trigger a recursion error. +* Remove use of deprecated API in pytest plugin so as to not emit warning + +Misc: + +* hypothesis-pytest is now part of hypothesis core. This should have no + externally visible consequences, but you should update your dependencies to + remove hypothesis-pytest and depend on only Hypothesis. +* Better repr for hypothesis.extra.datetimes() strategies. +* Add .close() method to abstract base class for Backend (it was already present + in the main implementation). + +.. _v1.11.1: + +----------------------------------------------------------------------- +`1.11.1 `_ - 2015-09-16 +----------------------------------------------------------------------- + +Bug fixes: + +* When running Hypothesis tests in parallel (e.g. using pytest-xdist) there was a race + condition caused by code generation. +* Example databases are now cached per thread so as to not use sqlite connections from + multiple threads. This should make Hypothesis now entirely thread safe. +* floats() with only min_value or max_value set would have had a very bad distribution. +* Running on 3.5, Hypothesis would have emitted deprecation warnings because of use of + inspect.getargspec + +.. _v1.11.0: + +----------------------------------------------------------------------- +`1.11.0 `_ - 2015-08-31 +----------------------------------------------------------------------- + +* text() with a non-string alphabet would have used the repr() of the the alphabet + instead of its contexts. This is obviously silly. It now works with any sequence + of things convertible to unicode strings. +* @given will now work on methods whose definitions contains no explicit positional + arguments, only varargs (:issue:`118`). + This may have some knock on effects because it means that @given no longer changes the + argspec of functions other than by adding defaults. +* Introduction of new @composite feature for more natural definition of strategies you'd + previously have used flatmap for. + +.. _v1.10.6: + +----------------------------------------------------------------------- +`1.10.6 `_ - 2015-08-26 +----------------------------------------------------------------------- + +Fix support for fixtures on Django 1.7. + +.. _v1.10.4: + +------------------- +1.10.4 - 2015-08-21 +------------------- + +Tiny bug fix release: + +* If the database_file setting is set to None, this would have resulted in + an error when running tests. Now it does the same as setting database to + None. + +.. _v1.10.3: + +----------------------------------------------------------------------- +`1.10.3 `_ - 2015-08-19 +----------------------------------------------------------------------- + +Another small bug fix release. + +* lists(elements, unique_by=some_function, min_size=n) would have raised a + ValidationError if n > Settings.default.average_list_length because it would + have wanted to use an average list length shorter than the minimum size of + the list, which is impossible. Now it instead defaults to twice the minimum + size in these circumstances. +* basic() strategy would have only ever produced at most ten distinct values + per run of the test (which is bad if you e.g. have it inside a list). This + was obviously silly. It will now produce a much better distribution of data, + both duplicated and non duplicated. + + +.. _v1.10.2: + +----------------------------------------------------------------------- +`1.10.2 `_ - 2015-08-19 +----------------------------------------------------------------------- + +This is a small bug fix release: + +* star imports from hypothesis should now work correctly. +* example quality for examples using flatmap will be better, as the way it had + previously been implemented was causing problems where Hypothesis was + erroneously labelling some examples as being duplicates. + +.. _v1.10.0: + +----------------------------------------------------------------------- +`1.10.0 `_ - 2015-08-04 +----------------------------------------------------------------------- + +This is just a bugfix and performance release, but it changes some +semi-public APIs, hence the minor version bump. + +* Significant performance improvements for strategies which are one\_of() + many branches. In particular this included recursive() strategies. This + should take the case where you use one recursive() strategy as the base + strategy of another from unusably slow (tens of seconds per generated + example) to reasonably fast. +* Better handling of just() and sampled_from() for values which have an + incorrect \_\_repr\_\_ implementation that returns non-ASCII unicode + on Python 2. +* Better performance for flatmap from changing the internal morpher API + to be significantly less general purpose. +* Introduce a new semi-public BuildContext/cleanup API. This allows + strategies to register cleanup activities that should run once the + example is complete. Note that this will interact somewhat weirdly with + find. +* Better simplification behaviour for streaming strategies. +* Don't error on lambdas which use destructuring arguments in Python 2. +* Add some better reprs for a few strategies that were missing good ones. +* The Random instances provided by randoms() are now copyable. +* Slightly more debugging information about simplify when using a debug + verbosity level. +* Support using given for functions with varargs, but not passing arguments + to it as positional. + +.. _v1.9.0: + +--------------------------------------------------------------------- +`1.9.0 `_ - 2015-07-27 +--------------------------------------------------------------------- + +Codename: The great bundling. + +This release contains two fairly major changes. + +The first is the deprecation of the hypothesis-extra mechanism. From +now on all the packages that were previously bundled under it other +than hypothesis-pytest (which is a different beast and will remain +separate). The functionality remains unchanged and you can still import +them from exactly the same location, they just are no longer separate +packages. + +The second is that this introduces a new way of building strategies +which lets you build up strategies recursively from other strategies. + +It also contains the minor change that calling .example() on a +strategy object will give you examples that are more representative of +the actual data you'll get. There used to be some logic in there to make +the examples artificially simple but this proved to be a bad idea. + +.. _v1.8.5: + +--------------------------------------------------------------------- +`1.8.5 `_ - 2015-07-24 +--------------------------------------------------------------------- + +This contains no functionality changes but fixes a mistake made with +building the previous package that would have broken installation on +Windows. + +.. _v1.8.4: + +--------------------------------------------------------------------- +`1.8.4 `_ - 2015-07-20 +--------------------------------------------------------------------- + +Bugs fixed: + +* When a call to floats() had endpoints which were not floats but merely + convertible to one (e.g. integers), these would be included in the generated + data which would cause it to generate non-floats. +* Splitting lambdas used in the definition of flatmap, map or filter over + multiple lines would break the repr, which would in turn break their usage. + + +.. _v1.8.3: + +--------------------------------------------------------------------- +`1.8.3 `_ - 2015-07-20 +--------------------------------------------------------------------- + +"Falsifying example" would not have been printed when the failure came from an +explicit example. + +.. _v1.8.2: + +--------------------------------------------------------------------- +`1.8.2 `_ - 2015-07-18 +--------------------------------------------------------------------- + +Another small bugfix release: + +* When using ForkingTestCase you would usually not get the falsifying example + printed if the process exited abnormally (e.g. due to os._exit). +* Improvements to the distribution of characters when using text() with a + default alphabet. In particular produces a better distribution of ascii and + whitespace in the alphabet. + +.. _v1.8.1: + +------------------ +1.8.1 - 2015-07-17 +------------------ + +This is a small release that contains a workaround for people who have +bad reprs returning non ascii text on Python 2.7. This is not a bug fix +for Hypothesis per se because that's not a thing that is actually supposed +to work, but Hypothesis leans more heavily on repr than is typical so it's +worth having a workaround for. + +.. _v1.8.0: + +--------------------------------------------------------------------- +`1.8.0 `_ - 2015-07-16 +--------------------------------------------------------------------- + +New features: + +* Much more sensible reprs for strategies, especially ones that come from + hypothesis.strategies. These should now have as reprs python code that + would produce the same strategy. +* lists() accepts a unique_by argument which forces the generated lists to be + only contain elements unique according to some function key (which must + return a hashable value). +* Better error messages from flaky tests to help you debug things. + +Mostly invisible implementation details that may result in finding new bugs +in your code: + +* Sets and dictionary generation should now produce a better range of results. +* floats with bounds now focus more on 'critical values', trying to produce + values at edge cases. +* flatmap should now have better simplification for complicated cases, as well + as generally being (I hope) more reliable. + +Bug fixes: + +* You could not previously use assume() if you were using the forking executor. + + +.. _v1.7.2: + +--------------------------------------------------------------------- +`1.7.2 `_ - 2015-07-10 +--------------------------------------------------------------------- + +This is purely a bug fix release: + +* When using floats() with stale data in the database you could sometimes get + values in your tests that did not respect min_value or max_value. +* When getting a Flaky error from an unreliable test it would have incorrectly + displayed the example that caused it. +* 2.6 dependency on backports was incorrectly specified. This would only have + caused you problems if you were building a universal wheel from Hypothesis, + which is not how Hypothesis ships, so unless you're explicitly building wheels + for your dependencies and support Python 2.6 plus a later version of Python + this probably would never have affected you. +* If you use flatmap in a way that the strategy on the right hand side depends + sensitively on the left hand side you may have occasionally seen Flaky errors + caused by producing unreliable examples when minimizing a bug. This use case + may still be somewhat fraught to be honest. This code is due a major rearchitecture + for 1.8, but in the meantime this release fixes the only source of this error that + I'm aware of. + +.. _v1.7.1: + +--------------------------------------------------------------------- +`1.7.1 `_ - 2015-06-29 +--------------------------------------------------------------------- + +Codename: There is no 1.7.0. + +A slight technical hitch with a premature upload means there's was a yanked +1.7.0 release. Oops. + +The major feature of this release is Python 2.6 support. Thanks to Jeff Meadows +for doing most of the work there. + +Other minor features + +* strategies now has a permutations() function which returns a strategy + yielding permutations of values from a given collection. +* if you have a flaky test it will print the exception that it last saw before + failing with Flaky, even if you do not have verbose reporting on. +* Slightly experimental git merge script available as "python -m + hypothesis.tools.mergedbs". Instructions on how to use it in the docstring + of that file. + +Bug fixes: + +* Better performance from use of filter. In particular tests which involve large + numbers of heavily filtered strategies should perform a lot better. +* floats() with a negative min_value would not have worked correctly (worryingly, + it would have just silently failed to run any examples). This is now fixed. +* tests using sampled\_from would error if the number of sampled elements was smaller + than min\_satisfying\_examples. + + +.. _v1.6.2: + +------------------ +1.6.2 - 2015-06-08 +------------------ + +This is just a few small bug fixes: + +* Size bounds were not validated for values for a binary() strategy when + reading examples from the database. +* sampled\_from is now in __all__ in hypothesis.strategies +* floats no longer consider negative integers to be simpler than positive + non-integers +* Small floating point intervals now correctly count members, so if you have a + floating point interval so narrow there are only a handful of values in it, + this will no longer cause an error when Hypothesis runs out of values. + +.. _v1.6.1: + +------------------ +1.6.1 - 2015-05-21 +------------------ + +This is a small patch release that fixes a bug where 1.6.0 broke the use +of flatmap with the deprecated API and assumed the passed in function returned +a SearchStrategy instance rather than converting it to a strategy. + +.. _v1.6.0: + +--------------------------------------------------------------------- +`1.6.0 `_ - 2015-05-21 +--------------------------------------------------------------------- + + +This is a smallish release designed to fix a number of bugs and smooth out +some weird behaviours. + +* Fix a critical bug in flatmap where it would reuse old strategies. If all + your flatmap code was pure you're fine. If it's not, I'm surprised it's + working at all. In particular if you want to use flatmap with django models, + you desperately need to upgrade to this version. +* flatmap simplification performance should now be better in some cases where + it previously had to redo work. +* Fix for a bug where invalid unicode data with surrogates could be generated + during simplification (it was already filtered out during actual generation). +* The Hypothesis database is now keyed off the name of the test instead of the + type of data. This makes much more sense now with the new strategies API and + is generally more robust. This means you will lose old examples on upgrade. +* The database will now not delete values which fail to deserialize correctly, + just skip them. This is to handle cases where multiple incompatible strategies + share the same key. +* find now also saves and loads values from the database, keyed off a hash of the + function you're finding from. +* Stateful tests now serialize and load values from the database. They should have + before, really. This was a bug. +* Passing a different verbosity level into a test would not have worked entirely + correctly, leaving off some messages. This is now fixed. +* Fix a bug where derandomized tests with unicode characters in the function + body would error on Python 2.7. + + +.. _v1.5.0: + +--------------------------------------------------------------------- +`1.5.0 `_ - 2015-05-14 +--------------------------------------------------------------------- + + +Codename: Strategic withdrawal. + +The purpose of this release is a radical simplification of the API for building +strategies. Instead of the old approach of @strategy.extend and things that +get converted to strategies, you just build strategies directly. + +The old method of defining strategies will still work until Hypothesis 2.0, +because it's a major breaking change, but will now emit deprecation warnings. + +The new API is also a lot more powerful as the functions for defining strategies +give you a lot of dials to turn. See :doc:`the updated data section ` for +details. + +Other changes: + + * Mixing keyword and positional arguments in a call to @given is deprecated as well. + * There is a new setting called 'strict'. When set to True, Hypothesis will raise + warnings instead of merely printing them. Turning it on by default is inadvisable because + it means that Hypothesis minor releases can break your code, but it may be useful for + making sure you catch all uses of deprecated APIs. + * max_examples in settings is now interpreted as meaning the maximum number + of unique (ish) examples satisfying assumptions. A new setting max_iterations + which defaults to a larger value has the old interpretation. + * Example generation should be significantly faster due to a new faster parameter + selection algorithm. This will mostly show up for simple data types - for complex + ones the parameter selection is almost certainly dominated. + * Simplification has some new heuristics that will tend to cut down on cases + where it could previously take a very long time. + * timeout would previously not have been respected in cases where there were a lot + of duplicate examples. You probably wouldn't have previously noticed this because + max_examples counted duplicates, so this was very hard to hit in a way that mattered. + * A number of internal simplifications to the SearchStrategy API. + * You can now access the current Hypothesis version as hypothesis.__version__. + * A top level function is provided for running the stateful tests without the + TestCase infrastructure. + +.. _v1.4.0: + +--------------------------------------------------------------------- +`1.4.0 `_ - 2015-05-04 +--------------------------------------------------------------------- + +Codename: What a state. + +The *big* feature of this release is the new and slightly experimental +stateful testing API. You can read more about that in :doc:`the +appropriate section `. + +Two minor features the were driven out in the course of developing this: + +* You can now set settings.max_shrinks to limit the number of times + Hypothesis will try to shrink arguments to your test. If this is set to + <= 0 then Hypothesis will not rerun your test and will just raise the + failure directly. Note that due to technical limitations if max_shrinks + is <= 0 then Hypothesis will print *every* example it calls your test + with rather than just the failing one. Note also that I don't consider + settings max_shrinks to zero a sensible way to run your tests and it + should really be considered a debug feature. +* There is a new debug level of verbosity which is even *more* verbose than + verbose. You probably don't want this. + +Breakage of semi-public SearchStrategy API: + +* It is now a required invariant of SearchStrategy that if u simplifies to + v then it is not the case that strictly_simpler(u, v). i.e. simplifying + should not *increase* the complexity even though it is not required to + decrease it. Enforcing this invariant lead to finding some bugs where + simplifying of integers, floats and sets was suboptimal. +* Integers in basic data are now required to fit into 64 bits. As a result + python integer types are now serialized as strings, and some types have + stopped using quite so needlessly large random seeds. + +Hypothesis Stateful testing was then turned upon Hypothesis itself, which lead +to an amazing number of minor bugs being found in Hypothesis itself. + +Bugs fixed (most but not all from the result of stateful testing) include: + +* Serialization of streaming examples was flaky in a way that you would + probably never notice: If you generate a template, simplify it, serialize + it, deserialize it, serialize it again and then deserialize it you would + get the original stream instead of the simplified one. +* If you reduced max_examples below the number of examples already saved in + the database, you would have got a ValueError. Additionally, if you had + more than max_examples in the database all of them would have been + considered. +* @given will no longer count duplicate examples (which it never called + your function with) towards max_examples. This may result in your tests + running slower, but that's probably just because they're trying more + examples. +* General improvements to example search which should result in better + performance and higher quality examples. In particular parameters which + have a history of producing useless results will be more aggressively + culled. This is useful both because it decreases the chance of useless + examples and also because it's much faster to not check parameters which + we were unlikely to ever pick! +* integers_from and lists of types with only one value (e.g. [None]) would + previously have had a very high duplication rate so you were probably + only getting a handful of examples. They now have a much lower + duplication rate, as well as the improvements to search making this + less of a problem in the first place. +* You would sometimes see simplification taking significantly longer than + your defined timeout. This would happen because timeout was only being + checked after each *successful* simplification, so if Hypothesis was + spending a lot of time unsuccessfully simplifying things it wouldn't + stop in time. The timeout is now applied for unsuccessful simplifications + too. +* In Python 2.7, integers_from strategies would have failed during + simplification with an OverflowError if their starting point was at or + near to the maximum size of a 64-bit integer. +* flatmap and map would have failed if called with a function without a + __name__ attribute. +* If max_examples was less than min_satisfying_examples this would always + error. Now min_satisfying_examples is capped to max_examples. Note that + if you have assumptions to satisfy here this will still cause an error. + +Some minor quality improvements: + +* Lists of streams, flatmapped strategies and basic strategies should now + now have slightly better simplification. + +.. _v1.3.0: + +--------------------------------------------------------------------- +`1.3.0 `_ - 2015-05-22 +--------------------------------------------------------------------- + +New features: + +* New verbosity level API for printing intermediate results and exceptions. +* New specifier for strings generated from a specified alphabet. +* Better error messages for tests that are failing because of a lack of enough + examples. + +Bug fixes: + +* Fix error where use of ForkingTestCase would sometimes result in too many + open files. +* Fix error where saving a failing example that used flatmap could error. +* Implement simplification for sampled_from, which apparently never supported + it previously. Oops. + + +General improvements: + +* Better range of examples when using one_of or sampled_from. +* Fix some pathological performance issues when simplifying lists of complex + values. +* Fix some pathological performance issues when simplifying examples that + require unicode strings with high codepoints. +* Random will now simplify to more readable examples. + + +.. _v1.2.1: + +--------------------------------------------------------------------- +`1.2.1 `_ - 2015-04-16 +--------------------------------------------------------------------- + +A small patch release for a bug in the new executors feature. Tests which require +doing something to their result in order to fail would have instead reported as +flaky. + +.. _v1.2.0: + +--------------------------------------------------------------------- +`1.2.0 `_ - 2015-04-15 +--------------------------------------------------------------------- + +Codename: Finders keepers. + +A bunch of new features and improvements. + +* Provide a mechanism for customizing how your tests are executed. +* Provide a test runner that forks before running each example. This allows + better support for testing native code which might trigger a segfault or a C + level assertion failure. +* Support for using Hypothesis to find examples directly rather than as just as + a test runner. +* New streaming type which lets you generate infinite lazily loaded streams of + data - perfect for if you need a number of examples but don't know how many. +* Better support for large integer ranges. You can now use integers_in_range + with ranges of basically any size. Previously large ranges would have eaten + up all your memory and taken forever. +* Integers produce a wider range of data than before - previously they would + only rarely produce integers which didn't fit into a machine word. Now it's + much more common. This percolates to other numeric types which build on + integers. +* Better validation of arguments to @given. Some situations that would + previously have caused silently wrong behaviour will now raise an error. +* Include +/- sys.float_info.max in the set of floating point edge cases that + Hypothesis specifically tries. +* Fix some bugs in floating point ranges which happen when given + +/- sys.float_info.max as one of the endpoints... (really any two floats that + are sufficiently far apart so that x, y are finite but y - x is infinite). + This would have resulted in generating infinite values instead of ones inside + the range. + +.. _v1.1.1: + +--------------------------------------------------------------------- +`1.1.1 `_ - 2015-04-07 +--------------------------------------------------------------------- + +Codename: Nothing to see here + +This is just a patch release put out because it fixed some internal bugs that would +block the Django integration release but did not actually affect anything anyone could +previously have been using. It also contained a minor quality fix for floats that +I'd happened to have finished in time. + +* Fix some internal bugs with object lifecycle management that were impossible to + hit with the previously released versions but broke hypothesis-django. +* Bias floating point numbers somewhat less aggressively towards very small numbers + + +.. _v1.1.0: + +--------------------------------------------------------------------- +`1.1.0 `_ - 2015-04-06 +--------------------------------------------------------------------- + +Codename: No-one mention the M word. + +* Unicode strings are more strongly biased towards ascii characters. Previously they + would generate all over the space. This is mostly so that people who try to + shape their unicode strings with assume() have less of a bad time. +* A number of fixes to data deserialization code that could theoretically have + caused mysterious bugs when using an old version of a Hypothesis example + database with a newer version. To the best of my knowledge a change that could + have triggered this bug has never actually been seen in the wild. Certainly + no-one ever reported a bug of this nature. +* Out of the box support for Decimal and Fraction. +* new dictionary specifier for dictionaries with variable keys. +* Significantly faster and higher quality simplification, especially for + collections of data. +* New filter() and flatmap() methods on Strategy for better ways of building + strategies out of other strategies. +* New BasicStrategy class which allows you to define your own strategies from + scratch without needing an existing matching strategy or being exposed to the + full horror or non-public nature of the SearchStrategy interface. + + +.. _v1.0.0: + +--------------------------------------------------------------------- +`1.0.0 `_ - 2015-03-27 +--------------------------------------------------------------------- + +Codename: Blast-off! + +There are no code changes in this release. This is precisely the 0.9.2 release +with some updated documentation. + +.. _v0.9.2: + +------------------ +0.9.2 - 2015-03-26 +------------------ + +Codename: T-1 days. + +* floats_in_range would not actually have produced floats_in_range unless that + range happened to be (0, 1). Fix this. + +.. _v0.9.1: + +------------------ +0.9.1 - 2015-03-25 +------------------ + +Codename: T-2 days. + +* Fix a bug where if you defined a strategy using map on a lambda then the results would not be saved in the database. +* Significant performance improvements when simplifying examples using lists, strings or bounded integer ranges. + +.. _v0.9.0: + +------------------ +0.9.0 - 2015-03-23 +------------------ + +Codename: The final countdown + +This release could also be called 1.0-RC1. + +It contains a teeny tiny bugfix, but the real point of this release is to declare +feature freeze. There will be zero functionality changes between 0.9.0 and 1.0 unless +something goes really really wrong. No new features will be added, no breaking API changes +will occur, etc. This is the final shakedown before I declare Hypothesis stable and ready +to use and throw a party to celebrate. + +Bug bounty for any bugs found between now and 1.0: I will buy you a drink (alcoholic, +caffeinated, or otherwise) and shake your hand should we ever find ourselves in the +same city at the same time. + +The one tiny bugfix: + +* Under pypy, databases would fail to close correctly when garbage collected, leading to a memory leak and a confusing error message if you were repeatedly creating databases and not closing them. It is very unlikely you were doing this and the chances of you ever having noticed this bug are very low. + +.. _v0.7.2: + +------------------ +0.7.2 - 2015-03-22 +------------------ + +Codename: Hygienic macros or bust + +* You can now name an argument to @given 'f' and it won't break (:issue:`38`) +* strategy_test_suite is now named strategy_test_suite as the documentation claims and not in fact strategy_test_suitee +* Settings objects can now be used as a context manager to temporarily override the default values inside their context. + + +.. _v0.7.1: + +------------------ +0.7.1 - 2015-03-21 +------------------ + +Codename: Point releases go faster + +* Better string generation by parametrizing by a limited alphabet +* Faster string simplification - previously if simplifying a string with high range unicode characters it would try every unicode character smaller than that. This was pretty pointless. Now it stops after it's a short range (it can still reach smaller ones through recursive calls because of other simplifying operations). +* Faster list simplification by first trying a binary chop down the middle +* Simultaneous simplification of identical elements in a list. So if a bug only triggers when you have duplicates but you drew e.g. [-17, -17], this will now simplify to [0, 0]. + + +.. _v0.7.0,: + +------------------- +0.7.0, - 2015-03-20 +------------------- + +Codename: Starting to look suspiciously real + +This is probably the last minor release prior to 1.0. It consists of stability +improvements, a few usability things designed to make Hypothesis easier to try +out, and filing off some final rough edges from the API. + +* Significant speed and memory usage improvements +* Add an example() method to strategy objects to give an example of the sort of data that the strategy generates. +* Remove .descriptor attribute of strategies +* Rename descriptor_test_suite to strategy_test_suite +* Rename the few remaining uses of descriptor to specifier (descriptor already has a defined meaning in Python) + + +.. _v0.6.0: + +--------------------------------------------------------- +0.6.0 - 2015-03-13 +--------------------------------------------------------- + +Codename: I'm sorry, were you using that API? + +This is primarily a "simplify all the weird bits of the API" release. As a result there are a lot of breaking changes. If +you just use @given with core types then you're probably fine. + +In particular: + +* Stateful testing has been removed from the API +* The way the database is used has been rendered less useful (sorry). The feature for reassembling values saved from other + tests doesn't currently work. This will probably be brought back in post 1.0. +* SpecificationMapper is no longer a thing. Instead there is an ExtMethod called strategy which you extend to specify how + to convert other types to strategies. +* Settings are now extensible so you can add your own for configuring a strategy +* MappedSearchStrategy no longer needs an unpack method +* Basically all the SearchStrategy internals have changed massively. If you implemented SearchStrategy directly rather than + using MappedSearchStrategy talk to me about fixing it. +* Change to the way extra packages work. You now specify the package. This + must have a load() method. Additionally any modules in the package will be + loaded in under hypothesis.extra + +Bug fixes: + +* Fix for a bug where calling falsify on a lambda with a non-ascii character + in its body would error. + +Hypothesis Extra: + +hypothesis-fakefactory\: An extension for using faker data in hypothesis. Depends + on fake-factory. + +.. _v0.5.0: + +------------------ +0.5.0 - 2015-02-10 +------------------ + +Codename: Read all about it. + +Core hypothesis: + +* Add support back in for pypy and python 3.2 +* @given functions can now be invoked with some arguments explicitly provided. If all arguments that hypothesis would have provided are passed in then no falsification is run. +* Related to the above, this means that you can now use pytest fixtures and mark.parametrize with Hypothesis without either interfering with the other. +* Breaking change: @given no longer works for functions with varargs (varkwargs are fine). This might be added back in at a later date. +* Windows is now fully supported. A limited version (just the tests with none of the extras) of the test suite is run on windows with each commit so it is now a first class citizen of the Hypothesis world. +* Fix a bug for fuzzy equality of equal complex numbers with different reprs (this can happen when one coordinate is zero). This shouldn't affect users - that feature isn't used anywhere public facing. +* Fix generation of floats on windows and 32-bit builds of python. I was using some struct.pack logic that only worked on certain word sizes. +* When a test times out and hasn't produced enough examples this now raises a Timeout subclass of Unfalsifiable. +* Small search spaces are better supported. Previously something like a @given(bool, bool) would have failed because it couldn't find enough examples. Hypothesis is now aware of the fact that these are small search spaces and will not error in this case. +* Improvements to parameter search in the case of hard to satisfy assume. Hypothesis will now spend less time exploring parameters that are unlikely to provide anything useful. +* Increase chance of generating "nasty" floats +* Fix a bug that would have caused unicode warnings if you had a sampled_from that was mixing unicode and byte strings. +* Added a standard test suite that you can use to validate a custom strategy you've defined is working correctly. + +Hypothesis extra: + +First off, introducing Hypothesis extra packages! + +These are packages that are separated out from core Hypothesis because they have one or more dependencies. Every +hypothesis-extra package is pinned to a specific point release of Hypothesis and will have some version requirements +on its dependency. They use entry_points so you will usually not need to explicitly import them, just have them installed +on the path. + +This release introduces two of them: + +hypothesis-datetime: + +Does what it says on the tin: Generates datetimes for Hypothesis. Just install the package and datetime support will start +working. + +Depends on pytz for timezone support + +hypothesis-pytest: + +A very rudimentary pytest plugin. All it does right now is hook the display of falsifying examples into pytest reporting. + +Depends on pytest. + + +.. _v0.4.3: + +------------------ +0.4.3 - 2015-02-05 +------------------ + +Codename: TIL narrow Python builds are a thing + +This just fixes the one bug. + +* Apparently there is such a thing as a "narrow python build" and OS X ships with these by default + for python 2.7. These are builds where you only have two bytes worth of unicode. As a result, + generating unicode was completely broken on OS X. Fix this by only generating unicode codepoints + in the range supported by the system. + + +.. _v0.4.2: + +------------------ +0.4.2 - 2015-02-04 +------------------ + +Codename: O(dear) + +This is purely a bugfix release: + +* Provide sensible external hashing for all core types. This will significantly improve + performance of tracking seen examples which happens in literally every falsification + run. For Hypothesis fixing this cut 40% off the runtime of the test suite. The behaviour + is quadratic in the number of examples so if you're running the default configuration + this will be less extreme (Hypothesis's test suite runs at a higher number of examples + than default), but you should still see a significant improvement. +* Fix a bug in formatting of complex numbers where the string could get incorrectly truncated. + + +.. _v0.4.1: + +------------------ +0.4.1 - 2015-02-03 +------------------ + +Codename: Cruel and unusual edge cases + +This release is mostly about better test case generation. + +Enhancements: + +* Has a cool release name +* text_type (str in python 3, unicode in python 2) example generation now + actually produces interesting unicode instead of boring ascii strings. +* floating point numbers are generated over a much wider range, with particular + attention paid to generating nasty numbers - nan, infinity, large and small + values, etc. +* examples can be generated using pieces of examples previously saved in the + database. This allows interesting behaviour that has previously been discovered + to be propagated to other examples. +* improved parameter exploration algorithm which should allow it to more reliably + hit interesting edge cases. +* Timeout can now be disabled entirely by setting it to any value <= 0. + + +Bug fixes: + +* The descriptor on a OneOfStrategy could be wrong if you had descriptors which + were equal but should not be coalesced. e.g. a strategy for one_of((frozenset({int}), {int})) + would have reported its descriptor as {int}. This is unlikely to have caused you + any problems +* If you had strategies that could produce NaN (which float previously couldn't but + e.g. a Just(float('nan')) could) then this would have sent hypothesis into an infinite + loop that would have only been terminated when it hit the timeout. +* Given elements that can take a long time to minimize, minimization of floats or tuples + could be quadratic or worse in the that value. You should now see much better performance + for simplification, albeit at some cost in quality. + +Other: + +* A lot of internals have been been rewritten. This shouldn't affect you at all, but + it opens the way for certain of hypothesis's oddities to be a lot more extensible by + users. Whether this is a good thing may be up for debate... + + +.. _v0.4.0: + +------------------ +0.4.0 - 2015-01-21 +------------------ + +FLAGSHIP FEATURE: Hypothesis now persists examples for later use. It stores +data in a local SQLite database and will reuse it for all tests of the same +type. + +LICENSING CHANGE: Hypothesis is now released under the Mozilla Public License +2.0. This applies to all versions from 0.4.0 onwards until further notice. +The previous license remains applicable to all code prior to 0.4.0. + +Enhancements: + +* Printing of failing examples. I was finding that the pytest runner was not + doing a good job of displaying these, and that Hypothesis itself could do + much better. +* Drop dependency on six for cross-version compatibility. It was easy + enough to write the shim for the small set of features that we care about + and this lets us avoid a moderately complex dependency. +* Some improvements to statistical distribution of selecting from small (<= + 3 elements) +* Improvements to parameter selection for finding examples. + +Bugs fixed: + +* could_have_produced for lists, dicts and other collections would not have + examined the elements and thus when using a union of different types of + list this could result in Hypothesis getting confused and passing a value + to the wrong strategy. This could potentially result in exceptions being + thrown from within simplification. +* sampled_from would not work correctly on a single element list. +* Hypothesis could get *very* confused by values which are + equal despite having different types being used in descriptors. Hypothesis + now has its own more specific version of equality it uses for descriptors + and tracking. It is always more fine grained than Python equality: Things + considered != are not considered equal by hypothesis, but some things that + are considered == are distinguished. If your test suite uses both frozenset + and set tests this bug is probably affecting you. + +.. _v0.3.2: + +------------------ +0.3.2 - 2015-01-16 +------------------ + +* Fix a bug where if you specified floats_in_range with integer arguments + Hypothesis would error in example simplification. +* Improve the statistical distribution of the floats you get for the + floats_in_range strategy. I'm not sure whether this will affect users in + practice but it took my tests for various conditions from flaky to rock + solid so it at the very least improves discovery of the artificial cases + I'm looking for. +* Improved repr() for strategies and RandomWithSeed instances. +* Add detection for flaky test cases where hypothesis managed to find an + example which breaks it but on the final invocation of the test it does + not raise an error. This will typically happen with too much recursion + errors but could conceivably happen in other circumstances too. +* Provide a "derandomized" mode. This allows you to run hypothesis with + zero real randomization, making your build nice and deterministic. The + tests run with a seed calculated from the function they're testing so you + should still get a good distribution of test cases. +* Add a mechanism for more conveniently defining tests which just sample + from some collection. +* Fix for a really subtle bug deep in the internals of the strategy table. + In some circumstances if you were to define instance strategies for both + a parent class and one or more of its subclasses you would under some + circumstances get the strategy for the wrong superclass of an instance. + It is very unlikely anyone has ever encountered this in the wild, but it + is conceivably possible given that a mix of namedtuple and tuple are used + fairly extensively inside hypothesis which do exhibit this pattern of + strategy. + + +.. _v0.3.1: + +------------------ +0.3.1 - 2015-01-13 +------------------ + +* Support for generation of frozenset and Random values +* Correct handling of the case where a called function mutates it argument. + This involved introducing a notion of a strategies knowing how to copy + their argument. The default method should be entirely acceptable and the + worst case is that it will continue to have the old behaviour if you + don't mark your strategy as mutable, so this shouldn't break anything. +* Fix for a bug where some strategies did not correctly implement + could_have_produced. It is very unlikely that any of these would have + been seen in the wild, and the consequences if they had been would have + been minor. +* Re-export the @given decorator from the main hypothesis namespace. It's + still available at the old location too. +* Minor performance optimisation for simplifying long lists. + + +.. _v0.3.0: + +------------------ +0.3.0 - 2015-01-12 +------------------ + +* Complete redesign of the data generation system. Extreme breaking change + for anyone who was previously writing their own SearchStrategy + implementations. These will not work any more and you'll need to modify + them. +* New settings system allowing more global and modular control of Verifier + behaviour. +* Decouple SearchStrategy from the StrategyTable. This leads to much more + composable code which is a lot easier to understand. +* A significant amount of internal API renaming and moving. This may also + break your code. +* Expanded available descriptors, allowing for generating integers or + floats in a specific range. +* Significantly more robust. A very large number of small bug fixes, none + of which anyone is likely to have ever noticed. +* Deprecation of support for pypy and python 3 prior to 3.3. 3.3 and 3.4. + Supported versions are 2.7.x, 3.3.x, 3.4.x. I expect all of these to + remain officially supported for a very long time. I would not be + surprised to add pypy support back in later but I'm not going to do so + until I know someone cares about it. In the meantime it will probably + still work. + + +.. _v0.2.2: + +------------------ +0.2.2 - 2015-01-08 +------------------ + +* Fix an embarrassing complete failure of the installer caused by my being + bad at version control + + +.. _v0.2.1: + +------------------ +0.2.1 - 2015-01-07 +------------------ + +* Fix a bug in the new stateful testing feature where you could make + __init__ a @requires method. Simplification would not always work if the + prune method was able to successfully shrink the test. + + +.. _v0.2.0: + +------------------ +0.2.0 - 2015-01-07 +------------------ + +* It's aliiive. +* Improve python 3 support using six. +* Distinguish between byte and unicode types. +* Fix issues where FloatStrategy could raise. +* Allow stateful testing to request constructor args. +* Fix for issue where test annotations would timeout based on when the + module was loaded instead of when the test started + + +.. _v0.1.4: + +------------------ +0.1.4 - 2013-12-14 +------------------ + +* Make verification runs time bounded with a configurable timeout + + +.. _v0.1.3: + +------------------ +0.1.3 - 2013-05-03 +------------------ + +* Bugfix: Stateful testing behaved incorrectly with subclassing. +* Complex number support +* support for recursive strategies +* different error for hypotheses with unsatisfiable assumptions + +.. _v0.1.2: + +------------------ +0.1.2 - 2013-03-24 +------------------ + +* Bugfix: Stateful testing was not minimizing correctly and could + throw exceptions. +* Better support for recursive strategies. +* Support for named tuples. +* Much faster integer generation. + + +.. _v0.1.1: + +------------------ +0.1.1 - 2013-03-24 +------------------ + +* Python 3.x support via 2to3. +* Use new style classes (oops). + + +.. _v0.1.0: + +------------------ +0.1.0 - 2013-03-23 +------------------ + +* Introduce stateful testing. +* Massive rewrite of internals to add flags and strategies. + + +.. _v0.0.5: + +------------------ +0.0.5 - 2013-03-13 +------------------ + +* No changes except trying to fix packaging + +.. _v0.0.4: + +------------------ +0.0.4 - 2013-03-13 +------------------ + +* No changes except that I checked in a failing test case for 0.0.3 + so had to replace the release. Doh + +.. _v0.0.3: + +------------------ +0.0.3 - 2013-03-13 +------------------ + +* Improved a few internals. +* Opened up creating generators from instances as a general API. +* Test integration. + +.. _v0.0.2: + +------------------ +0.0.2 - 2013-03-12 +------------------ + +* Starting to tighten up on the internals. +* Change API to allow more flexibility in configuration. +* More testing. + +.. _v0.0.1: + +------------------ +0.0.1 - 2013-03-10 +------------------ + +* Initial release. +* Basic working prototype. Demonstrates idea, probably shouldn't be used. diff -Nru python-hypothesis-3.44.1/hypothesis-python/docs/community.rst python-hypothesis-3.71.11/hypothesis-python/docs/community.rst --- python-hypothesis-3.44.1/hypothesis-python/docs/community.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/docs/community.rst 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,35 @@ +========= +Community +========= + +The Hypothesis community is small for the moment but is full of excellent people +who can answer your questions and help you out. Please do join us. + +The two major places for community discussion are: + +* `The mailing list `_. +* An IRC channel, #hypothesis on freenode, which is more active than the mailing list. + +Feel free to use these to ask for help, provide feedback, or discuss anything remotely +Hypothesis related at all. + +Please note that `the Hypothesis code of conduct `_ +applies in all Hypothesis community spaces. + +If you would like to cite Hypothesis, please consider `our sugested citation +`_. + +If you like repo badges, we suggest the following badge, which you can add +with reStructuredText or Markdown, respectively: + +.. image:: https://img.shields.io/badge/hypothesis-tested-brightgreen.svg + +.. code:: restructuredtext + + .. image:: https://img.shields.io/badge/hypothesis-tested-brightgreen.svg + :alt: Tested with Hypothesis + :target: https://hypothesis.readthedocs.io + +.. code:: md + + [![Tested with Hypothesis](https://img.shields.io/badge/hypothesis-tested-brightgreen.svg)](https://hypothesis.readthedocs.io/) diff -Nru python-hypothesis-3.44.1/hypothesis-python/docs/conf.py python-hypothesis-3.71.11/hypothesis-python/docs/conf.py --- python-hypothesis-3.44.1/hypothesis-python/docs/conf.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/docs/conf.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,143 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +# -*- coding: utf-8 -*- + +from __future__ import division, print_function, absolute_import + +import os +import sys +import datetime + +sys.path.append( + os.path.join(os.path.dirname(__file__), '..', 'src') +) + + +autodoc_member_order = 'bysource' + +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.doctest', + 'sphinx.ext.extlinks', + 'sphinx.ext.viewcode', + 'sphinx.ext.intersphinx', +] + +templates_path = ['_templates'] + +source_suffix = '.rst' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'Hypothesis' +copyright = u'2013-%s, David R. MacIver' % datetime.datetime.utcnow().year +author = u'David R. MacIver' + +_d = {} +with open(os.path.join(os.path.dirname(__file__), '..', 'src', + 'hypothesis', 'version.py')) as f: + exec(f.read(), _d) + version = _d['__version__'] + release = _d['__version__'] + +language = None + +exclude_patterns = ['_build'] + +pygments_style = 'sphinx' + +todo_include_todos = False + +intersphinx_mapping = { + 'python': ('https://docs.python.org/3/', None), + 'numpy': ('https://docs.scipy.org/doc/numpy/', None), + 'pandas': ('https://pandas.pydata.org/pandas-docs/stable/', None), + 'pytest': ('https://docs.pytest.org/en/stable/', None), + 'django': ('https://django.readthedocs.io/en/stable/', None), + 'attrs': ('http://www.attrs.org/en/stable/', None), +} + +autodoc_mock_imports = ['pandas'] + +doctest_global_setup = ''' +# Some standard imports +from hypothesis import * +from hypothesis.strategies import * +# Run deterministically, and don't save examples +import random +_random_state = random.getstate() +random.seed(0) +doctest_settings = settings(database=None, derandomize=True) +settings.register_profile('doctests', doctest_settings) +settings.load_profile('doctests') +# Never show deprecated behaviour in code examples +import warnings +warnings.filterwarnings('error', category=DeprecationWarning) +''' + +doctest_global_cleanup = ''' +random.setstate(_random_state) +''' + +# This config value must be a dictionary of external sites, mapping unique +# short alias names to a base URL and a prefix. +# See http://sphinx-doc.org/ext/extlinks.html +_repo = 'https://github.com/HypothesisWorks/hypothesis/' +extlinks = { + 'commit': (_repo + 'commit/%s', 'commit '), + 'gh-file': (_repo + 'blob/master/%s', ''), + 'gh-link': (_repo + '%s', ''), + 'issue': (_repo + 'issues/%s', 'issue #'), + 'pull': (_repo + 'pull/%s', 'pull request #'), + 'pypi': ('https://pypi.org/project/%s', ''), +} + +# -- Options for HTML output ---------------------------------------------- + +if os.environ.get('READTHEDOCS', None) != 'True': + # only import and set the theme if we're building docs locally + import sphinx_rtd_theme + html_theme = 'sphinx_rtd_theme' + html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] + +html_static_path = ['_static'] + +htmlhelp_basename = 'Hypothesisdoc' + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { +} + +latex_documents = [ + (master_doc, 'Hypothesis.tex', u'Hypothesis Documentation', + u'David R. MacIver', 'manual'), +] + +man_pages = [ + (master_doc, 'hypothesis', u'Hypothesis Documentation', + [author], 1) +] + +texinfo_documents = [ + (master_doc, 'Hypothesis', u'Hypothesis Documentation', + author, 'Hypothesis', 'Advanced property-based testing for Python.', + 'Miscellaneous'), +] diff -Nru python-hypothesis-3.44.1/hypothesis-python/docs/database.rst python-hypothesis-3.71.11/hypothesis-python/docs/database.rst --- python-hypothesis-3.44.1/hypothesis-python/docs/database.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/docs/database.rst 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,73 @@ +=============================== +The Hypothesis Example Database +=============================== + +When Hypothesis finds a bug it stores enough information in its database to reproduce it. This +enables you to have a classic testing workflow of find a bug, fix a bug, and be confident that +this is actually doing the right thing because Hypothesis will start by retrying the examples that +broke things last time. + +----------- +Limitations +----------- + +The database is best thought of as a cache that you never need to invalidate: Information may be +lost when you upgrade a Hypothesis version or change your test, so you shouldn't rely on it for +correctness - if there's an example you want to ensure occurs each time then :ref:`there's a feature for +including them in your source code ` - but it helps the development +workflow considerably by making sure that the examples you've just found are reproduced. + +The database also records examples that excercise less-used parts of your +code, so the database may update even when no failing examples were found. + +-------------- +File locations +-------------- + +The default storage format is as a fairly opaque directory structure. Each test +corresponds to a directory, and each example to a file within that directory. +The standard location for it is ``.hypothesis/examples`` in your current working +directory. You can override this by setting the +:obj:`~hypothesis.settings.database` setting. + +There is also a legacy sqlite3 based format. This is mostly still supported for +compatibility reasons, and support will be dropped in some future version of +Hypothesis. If you use a database file name ending in .db, .sqlite or .sqlite3 +that format will be used instead. + +If you have not configured a database and the default location is unusable +(e.g. because you do not have read/write permission), Hypothesis will issue +a warning and then fall back to an in-memory database. + +-------------------------------------------- +Upgrading Hypothesis and changing your tests +-------------------------------------------- + +The design of the Hypothesis database is such that you can put arbitrary data in the database +and not get wrong behaviour. When you upgrade Hypothesis, old data *might* be invalidated, but +this should happen transparently. It should never be the case that e.g. changing the strategy +that generates an argument sometimes gives you data from the old strategy. + +----------------------------- +Sharing your example database +----------------------------- + +.. note:: + If specific examples are important for correctness you should use the + :func:`@example ` decorator, as the example database may discard entries due to + changes in your code or dependencies. For most users, we therefore + recommend using the example database locally and possibly persisting it + between CI builds, but not tracking it under version control. + +The examples database can be shared simply by checking the directory into +version control, for example with the following ``.gitignore``:: + + # Ignore files cached by Hypothesis... + .hypothesis/* + # except for the examples directory + !.hypothesis/examples/ + +Like everything under ``.hypothesis/``, the examples directory will be +transparently created on demand. Unlike the other subdirectories, +``examples/`` is designed to handle merges, deletes, etc if you just add the +directory into git, mercurial, or any similar version control system. diff -Nru python-hypothesis-3.44.1/hypothesis-python/docs/data.rst python-hypothesis-3.71.11/hypothesis-python/docs/data.rst --- python-hypothesis-3.44.1/hypothesis-python/docs/data.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/docs/data.rst 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,344 @@ +============================= +What you can generate and how +============================= + +*Most things should be easy to generate and everything should be possible.* + +To support this principle Hypothesis provides strategies for most built-in +types with arguments to constrain or adjust the output, as well as higher-order +strategies that can be composed to generate more complex types. + +This document is a guide to what strategies are available for generating data +and how to build them. Strategies have a variety of other important internal +features, such as how they simplify, but the data they can generate is the only +public part of their API. + +Functions for building strategies are all available in the hypothesis.strategies +module. The salient functions from it are as follows: + +.. automodule:: hypothesis.strategies + :members: + +.. _shrinking: + +~~~~~~~~~ +Shrinking +~~~~~~~~~ + +When using strategies it is worth thinking about how the data *shrinks*. +Shrinking is the process by which Hypothesis tries to produce human readable +examples when it finds a failure - it takes a complex example and turns it +into a simpler one. + +Each strategy defines an order in which it shrinks - you won't usually need to +care about this much, but it can be worth being aware of as it can affect what +the best way to write your own strategies is. + +The exact shrinking behaviour is not a guaranteed part of the API, but it +doesn't change that often and when it does it's usually because we think the +new way produces nicer examples. + +Possibly the most important one to be aware of is +:func:`~hypothesis.strategies.one_of`, which has a preference for values +produced by strategies earlier in its argument list. Most of the others should +largely "do the right thing" without you having to think about it. + + +~~~~~~~~~~~~~~~~~~~ +Adapting strategies +~~~~~~~~~~~~~~~~~~~ + +Often it is the case that a strategy doesn't produce exactly what you want it +to and you need to adapt it. Sometimes you can do this in the test, but this +hurts reuse because you then have to repeat the adaption in every test. + +Hypothesis gives you ways to build strategies from other strategies given +functions for transforming the data. + +------- +Mapping +------- + +``map`` is probably the easiest and most useful of these to use. If you have a +strategy ``s`` and a function ``f``, then an example ``s.map(f).example()`` is +``f(s.example())``, i.e. we draw an example from ``s`` and then apply ``f`` to it. + +e.g.: + +.. doctest:: + + >>> lists(integers()).map(sorted).example() + [-25527, -24245, -23118, -93, -70, -7, 0, 39, 40, 65, 88, 112, 6189, 9480, 19469, 27256, 32526, 1566924430] + +Note that many things that you might use mapping for can also be done with +:func:`~hypothesis.strategies.builds`. + +.. _filtering: + +--------- +Filtering +--------- + +``filter`` lets you reject some examples. ``s.filter(f).example()`` is some +example of ``s`` such that ``f(example)`` is truthy. + +.. doctest:: + + >>> integers().filter(lambda x: x > 11).example() + 26126 + >>> integers().filter(lambda x: x > 11).example() + 23324 + +It's important to note that ``filter`` isn't magic and if your condition is too +hard to satisfy then this can fail: + +.. doctest:: + + >>> integers().filter(lambda x: False).example() + Traceback (most recent call last): + ... + hypothesis.errors.NoExamples: Could not find any valid examples in 20 tries + +In general you should try to use ``filter`` only to avoid corner cases that you +don't want rather than attempting to cut out a large chunk of the search space. + +A technique that often works well here is to use map to first transform the data +and then use ``filter`` to remove things that didn't work out. So for example if +you wanted pairs of integers (x,y) such that x < y you could do the following: + + +.. doctest:: + + >>> tuples(integers(), integers()).map(sorted).filter(lambda x: x[0] < x[1]).example() + [-8543729478746591815, 3760495307320535691] + +.. _flatmap: + +---------------------------- +Chaining strategies together +---------------------------- + +Finally there is ``flatmap``. ``flatmap`` draws an example, then turns that +example into a strategy, then draws an example from *that* strategy. + +It may not be obvious why you want this at first, but it turns out to be +quite useful because it lets you generate different types of data with +relationships to each other. + +For example suppose we wanted to generate a list of lists of the same +length: + +.. code-block:: pycon + + >>> rectangle_lists = integers(min_value=0, max_value=10).flatmap( + ... lambda n: lists(lists(integers(), min_size=n, max_size=n))) + >>> find(rectangle_lists, lambda x: True) + [] + >>> find(rectangle_lists, lambda x: len(x) >= 10) + [[], [], [], [], [], [], [], [], [], []] + >>> find(rectangle_lists, lambda t: len(t) >= 3 and len(t[0]) >= 3) + [[0, 0, 0], [0, 0, 0], [0, 0, 0]] + >>> find(rectangle_lists, lambda t: sum(len(s) for s in t) >= 10) + [[0], [0], [0], [0], [0], [0], [0], [0], [0], [0]] + +In this example we first choose a length for our tuples, then we build a +strategy which generates lists containing lists precisely of that length. The +finds show what simple examples for this look like. + +Most of the time you probably don't want ``flatmap``, but unlike ``filter`` and +``map`` which are just conveniences for things you could just do in your tests, +``flatmap`` allows genuinely new data generation that you wouldn't otherwise be +able to easily do. + +(If you know Haskell: Yes, this is more or less a monadic bind. If you don't +know Haskell, ignore everything in these parentheses. You do not need to +understand anything about monads to use this, or anything else in Hypothesis). + + +-------------- +Recursive data +-------------- + +Sometimes the data you want to generate has a recursive definition. e.g. if you +wanted to generate JSON data, valid JSON is: + +1. Any float, any boolean, any unicode string. +2. Any list of valid JSON data +3. Any dictionary mapping unicode strings to valid JSON data. + +The problem is that you cannot call a strategy recursively and expect it to not just +blow up and eat all your memory. The other problem here is that not all unicode strings +display consistently on different machines, so we'll restrict them in our doctest. + +The way Hypothesis handles this is with the :py:func:`recursive` function +which you pass in a base case and a function that, given a strategy for your data type, +returns a new strategy for it. So for example: + +.. doctest:: + + >>> from string import printable; from pprint import pprint + >>> json = recursive(none() | booleans() | floats() | text(printable), + ... lambda children: lists(children) | dictionaries(text(printable), children)) + >>> pprint(json.example()) + ['dy', + [None, True, 6.297399055778002e+16, False], + {'a{h\\:694K~{mY>a1yA:#CmDYb': None}, + '\\kP!4', + {'#1J1': '', + 'cx.': None, + "jv'A?qyp_sB\n$62g": [], + 'qgnP': [False, -inf, 'la)']}, + [], + {}] + >>> pprint(json.example()) + {'': None, + '(Rt)': 1.192092896e-07, + ',': [], + '6': 2.2250738585072014e-308, + 'HA=/': [], + 'YU]gy8': inf, + 'l': None, + 'nK': False} + >>> pprint(json.example()) + [] + +That is, we start with our leaf data and then we augment it by allowing lists and dictionaries of anything we can generate as JSON data. + +The size control of this works by limiting the maximum number of values that can be drawn from the base strategy. So for example if +we wanted to only generate really small JSON we could do this as: + + +.. doctest:: + + >>> small_lists = recursive(booleans(), lists, max_leaves=5) + >>> small_lists.example() + [False] + >>> small_lists.example() + True + >>> small_lists.example() + [] + +.. _composite-strategies: + +~~~~~~~~~~~~~~~~~~~~ +Composite strategies +~~~~~~~~~~~~~~~~~~~~ + +The :func:`@composite ` decorator lets +you combine other strategies in more or less +arbitrary ways. It's probably the main thing you'll want to use for +complicated custom strategies. + +The composite decorator works by converting a function that returns one +example into a function that returns a strategy that produces such +examples - which you can pass to :func:`@given `, modify +with ``.map`` or ``.filter``, and generally use like any other strategy. + +It does this by giving you a special function ``draw`` as the first +argument, which can be used just like the corresponding method of the +:func:`~hypothesis.strategies.data` strategy within a test. In fact, +the implementation is almost the same - but defining a strategy with +:func:`@composite ` makes code reuse +easier, and usually improves the display of failing examples. + +For example, the following gives you a list and an index into it: + +.. doctest:: + + >>> @composite + ... def list_and_index(draw, elements=integers()): + ... xs = draw(lists(elements, min_size=1)) + ... i = draw(integers(min_value=0, max_value=len(xs) - 1)) + ... return (xs, i) + +``draw(s)`` is a function that should be thought of as returning ``s.example()``, +except that the result is reproducible and will minimize correctly. The +decorated function has the initial argument removed from the list, but will +accept all the others in the expected order. Defaults are preserved. + +.. doctest:: + + >>> list_and_index() + list_and_index() + >>> list_and_index().example() + ([-21904], 0) + + >>> list_and_index(booleans()) + list_and_index(elements=booleans()) + >>> list_and_index(booleans()).example() + ([True], 0) + +Note that the repr will work exactly like it does for all the built-in +strategies: it will be a function that you can call to get the strategy in +question, with values provided only if they do not match the defaults. + +You can use :func:`assume ` inside composite functions: + +.. code-block:: python + + @composite + def distinct_strings_with_common_characters(draw): + x = draw(text(), min_size=1) + y = draw(text(alphabet=x)) + assume(x != y) + return (x, y) + +This works as :func:`assume ` normally would, filtering out any examples for which the +passed in argument is falsey. + + +.. _interactive-draw: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Drawing interactively in tests +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +There is also the :func:`~hypothesis.strategies.data` strategy, which gives you a means of using +strategies interactively. Rather than having to specify everything up front in +:func:`@given ` you can draw from strategies in the body of your test: + +.. code-block:: python + + @given(data()) + def test_draw_sequentially(data): + x = data.draw(integers()) + y = data.draw(integers(min_value=x)) + assert x < y + +If the test fails, each draw will be printed with the falsifying example. e.g. +the above is wrong (it has a boundary condition error), so will print: + +.. code-block:: pycon + + Falsifying example: test_draw_sequentially(data=data(...)) + Draw 1: 0 + Draw 2: 0 + +As you can see, data drawn this way is simplified as usual. + +Test functions using the :func:`~hypothesis.strategies.data` strategy do not support explicit +:func:`@example(...) `\ s. In this case, the best option is usually to construct +your data with :func:`@composite ` or the explicit example, and unpack this within +the body of the test. + +Optionally, you can provide a label to identify values generated by each call +to ``data.draw()``. These labels can be used to identify values in the output +of a falsifying example. + +For instance: + +.. code-block:: python + + @given(data()) + def test_draw_sequentially(data): + x = data.draw(integers(), label='First number') + y = data.draw(integers(min_value=x), label='Second number') + assert x < y + +will produce the output: + +.. code-block:: pycon + + Falsifying example: test_draw_sequentially(data=data(...)) + Draw 1 (First number): 0 + Draw 2 (Second number): 0 diff -Nru python-hypothesis-3.44.1/hypothesis-python/docs/details.rst python-hypothesis-3.71.11/hypothesis-python/docs/details.rst --- python-hypothesis-3.44.1/hypothesis-python/docs/details.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/docs/details.rst 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,666 @@ +============================= +Details and advanced features +============================= + +This is an account of slightly less common Hypothesis features that you don't need +to get started but will nevertheless make your life easier. + + +---------------------- +Additional test output +---------------------- + +Normally the output of a failing test will look something like: + +.. code:: + + Falsifying example: test_a_thing(x=1, y="foo") + +With the ``repr`` of each keyword argument being printed. + +Sometimes this isn't enough, either because you have values with a ``repr`` that +isn't very descriptive or because you need to see the output of some +intermediate steps of your test. That's where the ``note`` function comes in: + +.. autofunction:: hypothesis.note + +.. doctest:: + + >>> from hypothesis import given, note, strategies as st + >>> @given(st.lists(st.integers()), st.randoms()) + ... def test_shuffle_is_noop(ls, r): + ... ls2 = list(ls) + ... r.shuffle(ls2) + ... note("Shuffle: %r" % (ls2)) + ... assert ls == ls2 + ... + >>> try: + ... test_shuffle_is_noop() + ... except AssertionError: + ... print('ls != ls2') + Falsifying example: test_shuffle_is_noop(ls=[0, 0, 1], r=RandomWithSeed(0)) + Shuffle: [0, 1, 0] + ls != ls2 + +The note is printed in the final run of the test in order to include any +additional information you might need in your test. + + +.. _statistics: + +--------------- +Test Statistics +--------------- + +If you are using :pypi:`pytest` you can see a number of statistics about the executed tests +by passing the command line argument ``--hypothesis-show-statistics``. This will include +some general statistics about the test: + +For example if you ran the following with ``--hypothesis-show-statistics``: + +.. code-block:: python + + from hypothesis import given, strategies as st + + @given(st.integers()) + def test_integers(i): + pass + + +You would see: + +.. code-block:: none + + test_integers: + + - 100 passing examples, 0 failing examples, 0 invalid examples + - Typical runtimes: ~ 1ms + - Fraction of time spent in data generation: ~ 12% + - Stopped because settings.max_examples=100 + +The final "Stopped because" line is particularly important to note: It tells you the +setting value that determined when the test should stop trying new examples. This +can be useful for understanding the behaviour of your tests. Ideally you'd always want +this to be :obj:`~hypothesis.settings.max_examples`. + +In some cases (such as filtered and recursive strategies) you will see events mentioned +which describe some aspect of the data generation: + +.. code-block:: python + + from hypothesis import given, strategies as st + + @given(st.integers().filter(lambda x: x % 2 == 0)) + def test_even_integers(i): + pass + +You would see something like: + +.. code-block:: none + + test_even_integers: + + - 100 passing examples, 0 failing examples, 36 invalid examples + - Typical runtimes: 0-1 ms + - Fraction of time spent in data generation: ~ 16% + - Stopped because settings.max_examples=100 + - Events: + * 80.88%, Retried draw from integers().filter(lambda x: ) to satisfy filter + * 26.47%, Aborted test because unable to satisfy integers().filter(lambda x: ) + +You can also mark custom events in a test using the ``event`` function: + +.. autofunction:: hypothesis.event + +.. code:: python + + from hypothesis import given, event, strategies as st + + @given(st.integers().filter(lambda x: x % 2 == 0)) + def test_even_integers(i): + event("i mod 3 = %d" % (i % 3,)) + + +You will then see output like: + +.. code-block:: none + + test_even_integers: + + - 100 passing examples, 0 failing examples, 38 invalid examples + - Typical runtimes: 0-1 ms + - Fraction of time spent in data generation: ~ 16% + - Stopped because settings.max_examples=100 + - Events: + * 80.43%, Retried draw from integers().filter(lambda x: ) to satisfy filter + * 31.88%, i mod 3 = 0 + * 27.54%, Aborted test because unable to satisfy integers().filter(lambda x: ) + * 21.74%, i mod 3 = 1 + * 18.84%, i mod 3 = 2 + +Arguments to ``event`` can be any hashable type, but two events will be considered the same +if they are the same when converted to a string with :obj:`python:str`. + +------------------ +Making assumptions +------------------ + +Sometimes Hypothesis doesn't give you exactly the right sort of data you want - it's +mostly of the right shape, but some examples won't work and you don't want to care about +them. You *can* just ignore these by aborting the test early, but this runs the risk of +accidentally testing a lot less than you think you are. Also it would be nice to spend +less time on bad examples - if you're running 100 examples per test (the default) and +it turns out 70 of those examples don't match your needs, that's a lot of wasted time. + +.. autofunction:: hypothesis.assume + +For example suppose you had the following test: + + +.. code:: python + + @given(floats()) + def test_negation_is_self_inverse(x): + assert x == -(-x) + + +Running this gives us: + +.. code:: + + Falsifying example: test_negation_is_self_inverse(x=float('nan')) + AssertionError + +This is annoying. We know about NaN and don't really care about it, but as soon as Hypothesis +finds a NaN example it will get distracted by that and tell us about it. Also the test will +fail and we want it to pass. + +So lets block off this particular example: + +.. code:: python + + from math import isnan + + @given(floats()) + def test_negation_is_self_inverse_for_non_nan(x): + assume(not isnan(x)) + assert x == -(-x) + +And this passes without a problem. + +In order to avoid the easy trap where you assume a lot more than you intended, Hypothesis +will fail a test when it can't find enough examples passing the assumption. + +If we'd written: + +.. code:: python + + @given(floats()) + def test_negation_is_self_inverse_for_non_nan(x): + assume(False) + assert x == -(-x) + +Then on running we'd have got the exception: + +.. code:: + + Unsatisfiable: Unable to satisfy assumptions of hypothesis test_negation_is_self_inverse_for_non_nan. Only 0 examples considered satisfied assumptions + +~~~~~~~~~~~~~~~~~~~ +How good is assume? +~~~~~~~~~~~~~~~~~~~ + +Hypothesis has an adaptive exploration strategy to try to avoid things which falsify +assumptions, which should generally result in it still being able to find examples in +hard to find situations. + +Suppose we had the following: + + +.. code:: python + + @given(lists(integers())) + def test_sum_is_positive(xs): + assert sum(xs) > 0 + +Unsurprisingly this fails and gives the falsifying example ``[]``. + +Adding ``assume(xs)`` to this removes the trivial empty example and gives us ``[0]``. + +Adding ``assume(all(x > 0 for x in xs))`` and it passes: the sum of a list of +positive integers is positive. + +The reason that this should be surprising is not that it doesn't find a +counter-example, but that it finds enough examples at all. + +In order to make sure something interesting is happening, suppose we wanted to +try this for long lists. e.g. suppose we added an ``assume(len(xs) > 10)`` to it. +This should basically never find an example: a naive strategy would find fewer +than one in a thousand examples, because if each element of the list is +negative with probability one-half, you'd have to have ten of these go the right +way by chance. In the default configuration Hypothesis gives up long before +it's tried 1000 examples (by default it tries 200). + +Here's what happens if we try to run this: + + +.. code:: python + + @given(lists(integers())) + def test_sum_is_positive(xs): + assume(len(xs) > 10) + assume(all(x > 0 for x in xs)) + print(xs) + assert sum(xs) > 0 + + In: test_sum_is_positive() + [17, 12, 7, 13, 11, 3, 6, 9, 8, 11, 47, 27, 1, 31, 1] + [6, 2, 29, 30, 25, 34, 19, 15, 50, 16, 10, 3, 16] + [25, 17, 9, 19, 15, 2, 2, 4, 22, 10, 10, 27, 3, 1, 14, 17, 13, 8, 16, 9, 2... + [17, 65, 78, 1, 8, 29, 2, 79, 28, 18, 39] + [13, 26, 8, 3, 4, 76, 6, 14, 20, 27, 21, 32, 14, 42, 9, 24, 33, 9, 5, 15, ... + [2, 1, 2, 2, 3, 10, 12, 11, 21, 11, 1, 16] + +As you can see, Hypothesis doesn't find *many* examples here, but it finds some - enough to +keep it happy. + +In general if you *can* shape your strategies better to your tests you should - for example +:py:func:`integers(1, 1000) ` is a lot better than +``assume(1 <= x <= 1000)``, but ``assume`` will take you a long way if you can't. + +--------------------- +Defining strategies +--------------------- + +The type of object that is used to explore the examples given to your test +function is called a :class:`~hypothesis.strategies.SearchStrategy`. +These are created using the functions +exposed in the :mod:`hypothesis.strategies` module. + +Many of these strategies expose a variety of arguments you can use to customize +generation. For example for integers you can specify ``min`` and ``max`` values of +integers you want. +If you want to see exactly what a strategy produces you can ask for an example: + +.. doctest:: + + >>> integers(min_value=0, max_value=10).example() + 1 + +Many strategies are built out of other strategies. For example, if you want +to define a tuple you need to say what goes in each element: + +.. doctest:: + + >>> from hypothesis.strategies import tuples + >>> tuples(integers(), integers()).example() + (-24597, 12566) + +Further details are :doc:`available in a separate document `. + +------------------------------------ +The gory details of given parameters +------------------------------------ + +.. autofunction:: hypothesis.given + +The :func:`@given ` decorator may be used to specify +which arguments of a function should be parametrized over. You can use +either positional or keyword arguments, but not a mixture of both. + +For example all of the following are valid uses: + +.. code:: python + + @given(integers(), integers()) + def a(x, y): + pass + + @given(integers()) + def b(x, y): + pass + + @given(y=integers()) + def c(x, y): + pass + + @given(x=integers()) + def d(x, y): + pass + + @given(x=integers(), y=integers()) + def e(x, **kwargs): + pass + + @given(x=integers(), y=integers()) + def f(x, *args, **kwargs): + pass + + + class SomeTest(TestCase): + @given(integers()) + def test_a_thing(self, x): + pass + +The following are not: + +.. code:: python + + @given(integers(), integers(), integers()) + def g(x, y): + pass + + @given(integers()) + def h(x, *args): + pass + + @given(integers(), x=integers()) + def i(x, y): + pass + + @given() + def j(x, y): + pass + + +The rules for determining what are valid uses of ``given`` are as follows: + +1. You may pass any keyword argument to ``given``. +2. Positional arguments to ``given`` are equivalent to the rightmost named + arguments for the test function. +3. Positional arguments may not be used if the underlying test function has + varargs, arbitrary keywords, or keyword-only arguments. +4. Functions tested with ``given`` may not have any defaults. + +The reason for the "rightmost named arguments" behaviour is so that +using :func:`@given ` with instance methods works: ``self`` +will be passed to the function as normal and not be parametrized over. + +The function returned by given has all the same arguments as the original +test, minus those that are filled in by :func:`@given `. + + +.. _custom-function-execution: + +------------------------- +Custom function execution +------------------------- + +Hypothesis provides you with a hook that lets you control how it runs +examples. + +This lets you do things like set up and tear down around each example, run +examples in a subprocess, transform coroutine tests into normal tests, etc. +For example, :class:`~hypothesis.extra.django.TransactionTestCase` in the +Django extra runs each example in a separate database transaction. + +The way this works is by introducing the concept of an executor. An executor +is essentially a function that takes a block of code and run it. The default +executor is: + +.. code:: python + + def default_executor(function): + return function() + +You define executors by defining a method ``execute_example`` on a class. Any +test methods on that class with :func:`@given ` used on them will use +``self.execute_example`` as an executor with which to run tests. For example, +the following executor runs all its code twice: + +.. code:: python + + from unittest import TestCase + + class TestTryReallyHard(TestCase): + @given(integers()) + def test_something(self, i): + perform_some_unreliable_operation(i) + + def execute_example(self, f): + f() + return f() + +Note: The functions you use in map, etc. will run *inside* the executor. i.e. +they will not be called until you invoke the function passed to ``execute_example``. + +An executor must be able to handle being passed a function which returns None, +otherwise it won't be able to run normal test cases. So for example the following +executor is invalid: + +.. code:: python + + from unittest import TestCase + + class TestRunTwice(TestCase): + def execute_example(self, f): + return f()() + +and should be rewritten as: + +.. code:: python + + from unittest import TestCase + + class TestRunTwice(TestCase): + def execute_example(self, f): + result = f() + if callable(result): + result = result() + return result + + +An alternative hook is provided for use by test runner extensions such as +:pypi:`pytest-trio`, which cannot use the ``execute_example`` method. +This is **not** recommended for end-users - it is better to write a complete +test function directly, perhaps by using a decorator to perform the same +transformation before applying :func:`@given `. + +.. code:: python + + @given(x=integers()) + @pytest.mark.trio + async def test(x): + ... + # Illustrative code, inside the pytest-trio plugin + test.hypothesis.inner_test = lambda x: trio.run(test, x) + +For authors of test runners however, assigning to the ``inner_test`` attribute +of the ``hypothesis`` attribute of the test will replace the interior test. + +.. note:: + The new ``inner_test`` must accept and pass through all the ``*args`` + and ``**kwargs`` expected by the original test. + +If the end user has also specified a custom executor using the +``execute_example`` method, it - and all other execution-time logic - will +be applied to the *new* inner test assigned by the test runner. + + +------------------------------- +Using Hypothesis to find values +------------------------------- + +You can use Hypothesis's data exploration features to find values satisfying +some predicate. This is generally useful for exploring custom strategies +defined with :func:`@composite `, or +experimenting with conditions for filtering data. + +.. autofunction:: hypothesis.find + +.. doctest:: + + >>> from hypothesis import find + >>> from hypothesis.strategies import sets, lists, integers + >>> find(lists(integers()), lambda x: sum(x) >= 10) + [10] + >>> find(lists(integers()), lambda x: sum(x) >= 10 and len(x) >= 3) + [0, 0, 10] + >>> find(sets(integers()), lambda x: sum(x) >= 10 and len(x) >= 3) + {0, 1, 9} + +The first argument to :func:`~hypothesis.find` describes data in the usual way for an argument to +:func:`~hypothesis.given`, and supports :doc:`all the same data types `. The second is a +predicate it must satisfy. + +Of course not all conditions are satisfiable. If you ask Hypothesis for an +example to a condition that is always false it will raise an error: + +.. doctest:: + + >>> find(integers(), lambda x: False) + Traceback (most recent call last): + ... + hypothesis.errors.NoSuchExample: No examples of condition lambda x: + +(The ``lambda x: unknown`` is because Hypothesis can't retrieve the source code +of lambdas from the interactive python console. It gives a better error message +most of the time which contains the actual condition) + + +.. _type-inference: + +------------------- +Inferred Strategies +------------------- + +In some cases, Hypothesis can work out what to do when you omit arguments. +This is based on introspection, *not* magic, and therefore has well-defined +limits. + +:func:`~hypothesis.strategies.builds` will check the signature of the +``target`` (using :func:`~python:inspect.getfullargspec`). +If there are required arguments with type annotations and +no strategy was passed to :func:`~hypothesis.strategies.builds`, +:func:`~hypothesis.strategies.from_type` is used to fill them in. +You can also pass the special value :const:`hypothesis.infer` as a keyword +argument, to force this inference for arguments with a default value. + +.. doctest:: + + >>> def func(a: int, b: str): + ... return [a, b] + >>> builds(func).example() + [-6993, ''] + +.. data:: hypothesis.infer + +:func:`@given ` does not perform any implicit inference +for required arguments, as this would break compatibility with pytest fixtures. +:const:`~hypothesis.infer` can be used as a keyword argument to explicitly +fill in an argument from its type annotation. + +.. code:: python + + @given(a=infer) + def test(a: int): pass + # is equivalent to + @given(a=integers()) + def test(a): pass + +~~~~~~~~~~~ +Limitations +~~~~~~~~~~~ + +:pep:`3107` type annotations are not supported on Python 2, and Hypothesis +does not inspect :pep:`484` type comments at runtime. While +:func:`~hypothesis.strategies.from_type` will work as usual, inference in +:func:`~hypothesis.strategies.builds` and :func:`@given ` +will only work if you manually create the ``__annotations__`` attribute +(e.g. by using ``@annotations(...)`` and ``@returns(...)`` decorators). +The :mod:`python:typing` module is fully supported on Python 2 if you have +the backport installed. + +The :mod:`python:typing` module is provisional and has a number of internal +changes between Python 3.5.0 and 3.6.1, including at minor versions. These +are all supported on a best-effort basis, but you may encounter problems with +an old version of the module. Please report them to us, and consider +updating to a newer version of Python as a workaround. + + +.. _our-type-hints: + +------------------------------ +Type Annotations in Hypothesis +------------------------------ + +If you install Hypothesis and use :pypi:`mypy` 0.590+, or another +:PEP:`561`-compatible tool, the type checker should automatically pick +up our type hints. + +.. note:: + Hypothesis' type hints may make breaking changes between minor releases. + + Upstream tools and conventions about type hints remain in flux - for + example the :mod:`python:typing` module itself is provisional, and Mypy + has not yet reached version 1.0 - and we plan to support the latest + version of this ecosystem, as well as older versions where practical. + + We may also find more precise ways to describe the type of various + interfaces, or change their type and runtime behaviour togther in a way + which is otherwise backwards-compatible. We often omit type hints for + deprecated features or arguments, as an additional form of warning. + +There are known issues inferring the type of examples generated by +:func:`~hypothesis.strategies.deferred`, :func:`~hypothesis.strategies.recursive`, +:func:`~hypothesis.strategies.one_of`, :func:`~hypothesis.strategies.dictionaries`, +and :func:`~hypothesis.strategies.fixed_dictionaries`. +We will fix these, and require correspondingly newer versions of Mypy for type +hinting, as the ecosystem improves. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Writing downstream type hints +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Projects that :doc:`provide Hypothesis strategies ` and use +type hints may wish to annotate their strategies too. This *is* a +supported use-case, again on a best-effort provisional basis. For example: + +.. code:: python + + def foo_strategy() -> SearchStrategy[Foo]: ... + +.. class:: hypothesis.strategies.SearchStrategy + +:class:`~hypothesis.strategies.SearchStrategy` is the type of all strategy +objects. It is a generic type, and covariant in the type of the examples +it creates. For example: + +- ``integers()`` is of type ``SearchStrategy[int]``. +- ``lists(integers())`` is of type ``SearchStrategy[List[int]]``. +- ``SearchStrategy[Dog]`` is a subtype of ``SearchStrategy[Animal]`` + if ``Dog`` is a subtype of ``Animal`` (as seems likely). + +.. warning:: + :class:`~hypothesis.strategies.SearchStrategy` **should only be used + in type hints.** Please do not inherit from, compare to, or otherwise + use it in any way outside of type hints. The only supported way to + construct objects of this type is to use the functions provided by the + :mod:`hypothesis.strategies` module! + + +.. _pytest-plugin: + +---------------------------- +The Hypothesis pytest Plugin +---------------------------- + +Hypothesis includes a tiny plugin to improve integration with :pypi:`pytest`, +which is activated by default (but does not affect other test runners). +It aims to improve the integration between Hypothesis and Pytest by +providing extra information and convenient access to config options. + +- ``pytest --hypothesis-show-statistics`` can be used to + :ref:`display test and data generation statistics `. +- ``pytest --hypothesis-profile=`` can be used to + :ref:`load a settings profile `. +- ``pytest --hypothesis-seed=`` can be used to + :ref:`reproduce a failure with a particular seed `. + +Finally, all tests that are defined with Hypothesis automatically have +``@pytest.mark.hypothesis`` applied to them. See :ref:`here for information +on working with markers `. + +.. note:: + Pytest will load the plugin automatically if Hypothesis is installed. + You don't need to do anything at all to use it. diff -Nru python-hypothesis-3.44.1/hypothesis-python/docs/development.rst python-hypothesis-3.71.11/hypothesis-python/docs/development.rst --- python-hypothesis-3.44.1/hypothesis-python/docs/development.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/docs/development.rst 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,53 @@ +============================== +Ongoing Hypothesis Development +============================== + +Hypothesis development is managed by me, `David R. MacIver `_. +I am the primary author of Hypothesis. + +*However*, I no longer do unpaid feature development on Hypothesis. My roles as leader of the project are: + +1. Helping other people do feature development on Hypothesis +2. Fixing bugs and other code health issues +3. Improving documentation +4. General release management work +5. Planning the general roadmap of the project +6. Doing sponsored development on tasks that are too large or in depth for other people to take on + +So all new features must either be sponsored or implemented by someone else. +That being said, the maintenance team takes an active role in shepherding pull requests and +helping people write a new feature (see :gh-file:`CONTRIBUTING.rst` for +details and :pull:`154` for an example of how the process goes). This isn't +"patches welcome", it's "we will help you write a patch". + + +.. _release-policy: + +Release Policy +============== + +Hypothesis releases follow `semantic versioning `_. + +We maintain backwards-compatibility wherever possible, and use deprecation +warnings to mark features that have been superseded by a newer alternative. +If you want to detect this, you can +:mod:`upgrade warnings to errors in the usual ways `. + +We use continuous deployment to ensure that you can always use our newest and +shiniest features - every change to the source tree is automatically built and +published on PyPI as soon as it's merged onto master, after code review and +passing our extensive test suite. + + +Project Roadmap +=============== + +Hypothesis does not have a long-term release plan. However some visibility +into our plans for future :doc:`compatibility ` may be useful: + +- We value compatibility, and maintain it as far as practical. This generally + excludes things which are end-of-life upstream, or have an unstable API. +- We would like to drop Python 2 support when it reaches end of life in + 2020. Ongoing support is likely to depend on commercial funding. +- We intend to support PyPy3 as soon as it supports a recent enough version of + Python 3. See :issue:`602`. diff -Nru python-hypothesis-3.44.1/hypothesis-python/docs/django.rst python-hypothesis-3.71.11/hypothesis-python/docs/django.rst --- python-hypothesis-3.44.1/hypothesis-python/docs/django.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/docs/django.rst 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,185 @@ +.. _hypothesis-django: + +=========================== +Hypothesis for Django users +=========================== + +Hypothesis offers a number of features specific for Django testing, available +in the ``hypothesis[django]`` :doc:`extra `. This is tested +against each supported series with mainstream or extended support - +if you're still getting security patches, you can test with Hypothesis. + +.. class:: hypothesis.extra.django.TestCase + +Using it is quite straightforward: All you need to do is subclass +:class:`hypothesis.extra.django.TestCase` or +:class:`hypothesis.extra.django.TransactionTestCase` +and you can use :func:`@given ` as normal, +and the transactions will be per example +rather than per test function as they would be if you used :func:`@given ` with a normal +django test suite (this is important because your test function will be called +multiple times and you don't want them to interfere with each other). Test cases +on these classes that do not use +:func:`@given ` will be run as normal. + +.. class:: hypothesis.extra.django.TransactionTestCase + +We recommend avoiding :class:`~hypothesis.extra.django.TransactionTestCase` +unless you really have to run each test case in a database transaction. +Because Hypothesis runs this in a loop, the performance problems it normally has +are significantly exacerbated and your tests will be really slow. +If you are using :class:`~hypothesis.extra.django.TransactionTestCase`, +you may need to use ``@settings(suppress_health_check=[HealthCheck.too_slow])`` +to avoid :doc:`errors due to slow example generation `. + +Having set up a test class, you can now pass :func:`@given ` +a strategy for Django models: + +.. autofunction:: hypothesis.extra.django.models.models + +For example, using `the trivial django project we have for testing +`_: + +.. code-block:: python + + >>> from hypothesis.extra.django.models import models + >>> from toystore.models import Customer + >>> c = models(Customer).example() + >>> c + + >>> c.email + 'jaime.urbina@gmail.com' + >>> c.name + '\U00109d3d\U000e07be\U000165f8\U0003fabf\U000c12cd\U000f1910\U00059f12\U000519b0\U0003fabf\U000f1910\U000423fb\U000423fb\U00059f12\U000e07be\U000c12cd\U000e07be\U000519b0\U000165f8\U0003fabf\U0007bc31' + >>> c.age + -873375803 + +Hypothesis has just created this with whatever the relevant type of data is. + +Obviously the customer's age is implausible, which is only possible because +we have not used (eg) :class:`~django:django.core.validators.MinValueValidator` +to set the valid range for this field (or used a +:class:`~django:django.db.models.PositiveSmallIntegerField`, which would only +need a maximum value validator). + +If you *do* have validators attached, Hypothesis will only generate examples +that pass validation. Sometimes that will mean that we fail a +:class:`~hypothesis.HealthCheck` because of the filtering, so let's explicitly +pass a strategy to skip validation at the strategy level: + +.. note:: + Inference from validators will be much more powerful when :issue:`1116` + is implemented, but there will always be some edge cases that require you + to pass an explicit strategy. + +.. code-block:: python + + >>> from hypothesis.strategies import integers + >>> c = models(Customer, age=integers(min_value=0, max_value=120)).example() + >>> c + + >>> c.age + 5 + +--------------- +Tips and tricks +--------------- + +Custom field types +================== + +If you have a custom Django field type you can register it with Hypothesis's +model deriving functionality by registering a default strategy for it: + +.. code-block:: python + + >>> from toystore.models import CustomishField, Customish + >>> models(Customish).example() + hypothesis.errors.InvalidArgument: Missing arguments for mandatory field + customish for model Customish + >>> from hypothesis.extra.django.models import add_default_field_mapping + >>> from hypothesis.strategies import just + >>> add_default_field_mapping(CustomishField, just("hi")) + >>> x = models(Customish).example() + >>> x.customish + 'hi' + +Note that this mapping is on exact type. Subtypes will not inherit it. + + +Generating child models +======================= + +For the moment there's no explicit support in hypothesis-django for generating +dependent models. i.e. a Company model will generate no Shops. However if you +want to generate some dependent models as well, you can emulate this by using +the *flatmap* function as follows: + +.. code:: python + + from hypothesis.strategies import lists, just + + def generate_with_shops(company): + return lists(models(Shop, company=just(company))).map(lambda _: company) + + company_with_shops_strategy = models(Company).flatmap(generate_with_shops) + +Lets unpack what this is doing: + +The way flatmap works is that we draw a value from the original strategy, then +apply a function to it which gives us a new strategy. We then draw a value from +*that* strategy. So in this case we're first drawing a company, and then we're +drawing a list of shops belonging to that company: The *just* strategy is a +strategy such that drawing it always produces the individual value, so +``models(Shop, company=just(company))`` is a strategy that generates a Shop belonging +to the original company. + +So the following code would give us a list of shops all belonging to the same +company: + +.. code:: python + + models(Company).flatmap(lambda c: lists(models(Shop, company=just(c)))) + +The only difference from this and the above is that we want the company, not +the shops. This is where the inner map comes in. We build the list of shops +and then throw it away, instead returning the company we started for. This +works because the models that Hypothesis generates are saved in the database, +so we're essentially running the inner strategy purely for the side effect of +creating those children in the database. + + +Using default field values +========================== + +Hypothesis ignores field defaults and always tries to generate values, even if +it doesn't know how to. You can tell it to use the default value for a field +instead of generating one by passing ``fieldname=default_value`` to +``models()``: + +.. code:: python + + >>> from toystore.models import DefaultCustomish + >>> models(DefaultCustomish).example() + hypothesis.errors.InvalidArgument: Missing arguments for mandatory field + customish for model DefaultCustomish + >>> from hypothesis.extra.django.models import default_value + >>> x = models(DefaultCustomish, customish=default_value).example() + >>> x.customish + 'b' + +.. _django-generating-primary-key: + +Generating primary key values +============================= + +If your model includes a custom primary key that you want to generate +using a strategy (rather than a default auto-increment primary key) +then Hypothesis has to deal with the possibility of a duplicate +primary key. + +If a model strategy generates a value for the primary key field, +Hypothesis will create the model instance with +:meth:`~django:django.db.models.query.QuerySet.update_or_create`, +overwriting any existing instance in the database for this test case +with the same primary key. diff -Nru python-hypothesis-3.44.1/hypothesis-python/docs/endorsements.rst python-hypothesis-3.71.11/hypothesis-python/docs/endorsements.rst --- python-hypothesis-3.44.1/hypothesis-python/docs/endorsements.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/docs/endorsements.rst 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,221 @@ +============ +Testimonials +============ + +This is a page for listing people who are using Hypothesis and how excited they +are about that. If that's you and your name is not on the list, `this file is in +Git `_ +and I'd love it if you sent me a pull request to fix that. + +--------------------------------------------------------------------------------------- +`Stripe `_ +--------------------------------------------------------------------------------------- + +At Stripe we use Hypothesis to test every piece of our machine +learning model training pipeline (powered by scikit). Before we +migrated, our tests were filled with hand-crafted pandas Dataframes +that weren't representative at all of our actual very complex +data. Because we needed to craft examples for each test, we took the +easy way out and lived with extremely low test coverage. + +Hypothesis changed all that. Once we had our strategies for generating +Dataframes of features it became trivial to slightly customize each +strategy for new tests. Our coverage is now close to 90%. + +Full-stop, property-based testing is profoundly more powerful - and +has caught or prevented far more bugs - than our old style of +example-based testing. + +--------------------------------------------------------------------------------------- +Kristian Glass - Director of Technology at `LaterPay GmbH `_ +--------------------------------------------------------------------------------------- + +Hypothesis has been brilliant for expanding the coverage of our test cases, +and also for making them much easier to read and understand, +so we're sure we're testing the things we want in the way we want. + +----------------------------------------------- +`Seth Morton `_ +----------------------------------------------- + +When I first heard about Hypothesis, I knew I had to include it in my two +open-source Python libraries, `natsort `_ +and `fastnumbers `_ . Quite frankly, +I was a little appalled at the number of bugs and "holes" I found in the code. I can +now say with confidence that my libraries are more robust to "the wild." In +addition, Hypothesis gave me the confidence to expand these libraries to fully +support Unicode input, which I never would have had the stomach for without such +thorough testing capabilities. Thanks! + +------------------------------------------- +`Sixty North `_ +------------------------------------------- + +At Sixty North we use Hypothesis for testing +`Segpy `_ an open source Python library for +shifting data between Python data structures and SEG Y files which contain +geophysical data from the seismic reflection surveys used in oil and gas +exploration. + +This is our first experience of property-based testing – as opposed to example-based +testing. Not only are our tests more powerful, they are also much better +explanations of what we expect of the production code. In fact, the tests are much +closer to being specifications. Hypothesis has located real defects in our code +which went undetected by traditional test cases, simply because Hypothesis is more +relentlessly devious about test case generation than us mere humans! We found +Hypothesis particularly beneficial for Segpy because SEG Y is an antiquated format +that uses legacy text encodings (EBCDIC) and even a legacy floating point format +we implemented from scratch in Python. + +Hypothesis is sure to find a place in most of our future Python codebases and many +existing ones too. + +------------------------------------------- +`mulkieran `_ +------------------------------------------- + +Just found out about this excellent QuickCheck for Python implementation and +ran up a few tests for my `bytesize `_ +package last night. Refuted a few hypotheses in the process. + +Looking forward to using it with a bunch of other projects as well. + +----------------------------------------------- +`Adam Johnson `_ +----------------------------------------------- + +I have written a small library to serialize ``dict``\s to MariaDB's dynamic +columns binary format, +`mariadb-dyncol `_. When I first +developed it, I thought I had tested it really well - there were hundreds of +test cases, some of them even taken from MariaDB's test suite itself. I was +ready to release. + +Lucky for me, I tried Hypothesis with David at the PyCon UK sprints. Wow! It +found bug after bug after bug. Even after a first release, I thought of a way +to make the tests do more validation, which revealed a further round of bugs! +Most impressively, Hypothesis found a complicated off-by-one error in a +condition with 4095 versus 4096 bytes of data - something that I would never +have found. + +Long live Hypothesis! (Or at least, property-based testing). + +------------------------------------------- +`Josh Bronson `_ +------------------------------------------- + +Adopting Hypothesis improved `bidict `_'s +test coverage and significantly increased our ability to make changes to +the code with confidence that correct behavior would be preserved. +Thank you, David, for the great testing tool. + +-------------------------------------------- +`Cory Benfield `_ +-------------------------------------------- + +Hypothesis is the single most powerful tool in my toolbox for working with +algorithmic code, or any software that produces predictable output from a wide +range of sources. When using it with +`Priority `_, Hypothesis consistently found +errors in my assumptions and extremely subtle bugs that would have taken months +of real-world use to locate. In some cases, Hypothesis found subtle deviations +from the correct output of the algorithm that may never have been noticed at +all. + +When it comes to validating the correctness of your tools, nothing comes close +to the thoroughness and power of Hypothesis. + +------------------------------------------ +`Jon Moore `_ +------------------------------------------ + +One extremely satisfied user here. Hypothesis is a really solid implementation +of property-based testing, adapted well to Python, and with good features +such as failure-case shrinkers. I first used it on a project where we needed +to verify that a vendor's Python and non-Python implementations of an algorithm +matched, and it found about a dozen cases that previous example-based testing +and code inspections had not. Since then I've been evangelizing for it at our firm. + +-------------------------------------------- +`Russel Winder `_ +-------------------------------------------- + +I am using Hypothesis as an integral part of my Python workshops. Testing is an integral part of Python +programming and whilst unittest and, better, py.test can handle example-based testing, property-based +testing is increasingly far more important than example-base testing, and Hypothesis fits the bill. + +--------------------------------------------- +`Wellfire Interactive `_ +--------------------------------------------- + +We've been using Hypothesis in a variety of client projects, from testing +Django-related functionality to domain-specific calculations. It both speeds +up and simplifies the testing process since there's so much less tedious and +error-prone work to do in identifying edge cases. Test coverage is nice but +test depth is even nicer, and it's much easier to get meaningful test depth +using Hypothesis. + +-------------------------------------------------- +`Cody Kochmann `_ +-------------------------------------------------- + +Hypothesis is being used as the engine for random object generation with my +open source function fuzzer +`battle_tested `_ +which maps all behaviors of a function allowing you to minimize the chance of +unexpected crashes when running code in production. + +With how efficient Hypothesis is at generating the edge cases that cause +unexpected behavior occur, +`battle_tested `_ +is able to map out the entire behavior of most functions in less than a few +seconds. + +Hypothesis truly is a masterpiece. I can't thank you enough for building it. + + +--------------------------------------------------- +`Merchise Autrement `_ +--------------------------------------------------- + +Just minutes after our first use of hypothesis `we uncovered a subtle bug`__ +in one of our most used library. Since then, we have increasingly used +hypothesis to improve the quality of our testing in libraries and applications +as well. + +__ https://github.com/merchise/xoutil/commit/0a4a0f529812fed363efb653f3ade2d2bc203945 + +---------------------------------------------- +`Florian Kromer `_ +---------------------------------------------- + +At `Roboception GmbH `_ I use Hypothesis to +implement fully automated stateless and stateful reliability tests for the +`3D sensor rc_visard `_ and +`robotic software components `_ . + +Thank you very much for creating the (probably) most powerful property-based +testing framework. + +------------------------------------------- +`Reposit Power `_ +------------------------------------------- + +With a micro-service architecture, testing between services is made easy using Hypothesis +in integration testing. Ensuring everything is running smoothly is vital to help maintain +a secure network of Virtual Power Plants. + +It allows us to find potential bugs and edge cases with relative ease +and minimal overhead. As our architecture relies on services communicating effectively, Hypothesis +allows us to strictly test for the kind of data which moves around our services, particularly +our backend Python applications. + + +------------------------------------------- +`Your name goes here `_ +------------------------------------------- + +I know there are many more, because I keep finding out about new people I'd never +even heard of using Hypothesis. If you're looking to way to give back to a tool you +love, adding your name here only takes a moment and would really help a lot. As per +instructions at the top, just send me a pull request and I'll add you to the list. diff -Nru python-hypothesis-3.44.1/hypothesis-python/docs/examples.rst python-hypothesis-3.71.11/hypothesis-python/docs/examples.rst --- python-hypothesis-3.44.1/hypothesis-python/docs/examples.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/docs/examples.rst 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,464 @@ +================== +Some more examples +================== + +This is a collection of examples of how to use Hypothesis in interesting ways. +It's small for now but will grow over time. + +All of these examples are designed to be run under `py.test`_ (`nose`_ should probably +work too). + +---------------------------------- +How not to sort by a partial order +---------------------------------- + +The following is an example that's been extracted and simplified from a real +bug that occurred in an earlier version of Hypothesis. The real bug was a lot +harder to find. + +Suppose we've got the following type: + +.. code:: python + + class Node(object): + def __init__(self, label, value): + self.label = label + self.value = tuple(value) + + def __repr__(self): + return "Node(%r, %r)" % (self.label, self.value) + + def sorts_before(self, other): + if len(self.value) >= len(other.value): + return False + return other.value[:len(self.value)] == self.value + + +Each node is a label and a sequence of some data, and we have the relationship +sorts_before meaning the data of the left is an initial segment of the right. +So e.g. a node with value ``[1, 2]`` will sort before a node with value ``[1, 2, 3]``, +but neither of ``[1, 2]`` nor ``[1, 3]`` will sort before the other. + +We have a list of nodes, and we want to topologically sort them with respect to +this ordering. That is, we want to arrange the list so that if ``x.sorts_before(y)`` +then x appears earlier in the list than y. We naively think that the easiest way +to do this is to extend the partial order defined here to a total order by +breaking ties arbitrarily and then using a normal sorting algorithm. So we +define the following code: + +.. code:: python + + from functools import total_ordering + + + @total_ordering + class TopoKey(object): + def __init__(self, node): + self.value = node + + def __lt__(self, other): + if self.value.sorts_before(other.value): + return True + if other.value.sorts_before(self.value): + return False + + return self.value.label < other.value.label + + + def sort_nodes(xs): + xs.sort(key=TopoKey) + +This takes the order defined by ``sorts_before`` and extends it by breaking ties by +comparing the node labels. + +But now we want to test that it works. + +First we write a function to verify that our desired outcome holds: + +.. code:: python + + def is_prefix_sorted(xs): + for i in range(len(xs)): + for j in range(i+1, len(xs)): + if xs[j].sorts_before(xs[i]): + return False + return True + +This will return false if it ever finds a pair in the wrong order and +return true otherwise. + +Given this function, what we want to do with Hypothesis is assert that for all +sequences of nodes, the result of calling ``sort_nodes`` on it is sorted. + +First we need to define a strategy for Node: + +.. code:: python + + from hypothesis import settings, strategies + import hypothesis.strategies as s + + NodeStrategy = s.builds( + Node, + s.integers(), + s.lists(s.booleans(), average_size=5, max_size=10)) + +We want to generate *short* lists of values so that there's a decent chance of +one being a prefix of the other (this is also why the choice of bool as the +elements). We then define a strategy which builds a node out of an integer and +one of those short lists of booleans. + +We can now write a test: + +.. code:: python + + from hypothesis import given + + @given(s.lists(NodeStrategy)) + def test_sorting_nodes_is_prefix_sorted(xs): + sort_nodes(xs) + assert is_prefix_sorted(xs) + +this immediately fails with the following example: + +.. code:: python + + [Node(0, (False, True)), Node(0, (True,)), Node(0, (False,))] + + +The reason for this is that because False is not a prefix of (True, True) nor vice +versa, sorting things the first two nodes are equal because they have equal labels. +This makes the whole order non-transitive and produces basically nonsense results. + +But this is pretty unsatisfying. It only works because they have the same label. Perhaps +we actually wanted our labels to be unique. Lets change the test to do that. + +.. code:: python + + def deduplicate_nodes_by_label(nodes): + table = {node.label: node for node in nodes} + return list(table.values()) + +We define a function to deduplicate nodes by labels, and can now map that over a strategy +for lists of nodes to give us a strategy for lists of nodes with unique labels: + +.. code:: python + + @given(s.lists(NodeStrategy).map(deduplicate_nodes_by_label)) + def test_sorting_nodes_is_prefix_sorted(xs): + sort_nodes(xs) + assert is_prefix_sorted(xs) + +Hypothesis quickly gives us an example of this *still* being wrong: + +.. code:: python + + [Node(0, (False,)), Node(-1, (True,)), Node(-2, (False, False))]) + + +Now this is a more interesting example. None of the nodes will sort equal. What is +happening here is that the first node is strictly less than the last node because +(False,) is a prefix of (False, False). This is in turn strictly less than the middle +node because neither is a prefix of the other and -2 < -1. The middle node is then +less than the first node because -1 < 0. + +So, convinced that our implementation is broken, we write a better one: + +.. code:: python + + def sort_nodes(xs): + for i in hrange(1, len(xs)): + j = i - 1 + while j >= 0: + if xs[j].sorts_before(xs[j+1]): + break + xs[j], xs[j+1] = xs[j+1], xs[j] + j -= 1 + +This is just insertion sort slightly modified - we swap a node backwards until swapping +it further would violate the order constraints. The reason this works is because our +order is a partial order already (this wouldn't produce a valid result for a general +topological sorting - you need the transitivity). + +We now run our test again and it passes, telling us that this time we've successfully +managed to sort some nodes without getting it completely wrong. Go us. + +-------------------- +Time zone arithmetic +-------------------- + +This is an example of some tests for :pypi:`pytz` which check that various timezone +conversions behave as you would expect them to. These tests should all pass, +and are mostly a demonstration of some useful sorts of thing to test with +Hypothesis, and how the :func:`~hypothesis.strategies.datetimes` strategy works. + +.. doctest:: + + >>> from datetime import timedelta + >>> from hypothesis.extra.pytz import timezones + >>> from hypothesis.strategies import datetimes + + >>> # The datetimes strategy is naive by default, so tell it to use timezones + >>> aware_datetimes = datetimes(timezones=timezones()) + + >>> @given(aware_datetimes, timezones(), timezones()) + ... def test_convert_via_intermediary(dt, tz1, tz2): + ... """Test that converting between timezones is not affected + ... by a detour via another timezone. + ... """ + ... assert dt.astimezone(tz1).astimezone(tz2) == dt.astimezone(tz2) + + >>> @given(aware_datetimes, timezones()) + ... def test_convert_to_and_fro(dt, tz2): + ... """If we convert to a new timezone and back to the old one + ... this should leave the result unchanged. + ... """ + ... tz1 = dt.tzinfo + ... assert dt == dt.astimezone(tz2).astimezone(tz1) + + >>> @given(aware_datetimes, timezones()) + ... def test_adding_an_hour_commutes(dt, tz): + ... """When converting between timezones it shouldn't matter + ... if we add an hour here or add an hour there. + ... """ + ... an_hour = timedelta(hours=1) + ... assert (dt + an_hour).astimezone(tz) == dt.astimezone(tz) + an_hour + + >>> @given(aware_datetimes, timezones()) + ... def test_adding_a_day_commutes(dt, tz): + ... """When converting between timezones it shouldn't matter + ... if we add a day here or add a day there. + ... """ + ... a_day = timedelta(days=1) + ... assert (dt + a_day).astimezone(tz) == dt.astimezone(tz) + a_day + + >>> # And we can check that our tests pass + >>> test_convert_via_intermediary() + >>> test_convert_to_and_fro() + >>> test_adding_an_hour_commutes() + >>> test_adding_a_day_commutes() + +------------------- +Condorcet's Paradox +------------------- + +A classic paradox in voting theory, called Condorcet's paradox, is that +majority preferences are not transitive. That is, there is a population +and a set of three candidates A, B and C such that the majority of the +population prefer A to B, B to C and C to A. + +Wouldn't it be neat if we could use Hypothesis to provide an example of this? + +Well as you can probably guess from the presence of this section, we can! This +is slightly surprising because it's not really obvious how we would generate an +election given the types that Hypothesis knows about. + +The trick here turns out to be twofold: + +1. We can generate a type that is *much larger* than an election, extract an election out of that, and rely on minimization to throw away all the extraneous detail. +2. We can use assume and rely on Hypothesis's adaptive exploration to focus on the examples that turn out to generate interesting elections + +Without further ado, here is the code: + +.. code:: python + + from hypothesis import given, assume + from hypothesis.strategies import integers, lists + from collections import Counter + + + def candidates(votes): + return {candidate for vote in votes for candidate in vote} + + + def build_election(votes): + """ + Given a list of lists we extract an election out of this. We do this + in two phases: + + 1. First of all we work out the full set of candidates present in all + votes and throw away any votes that do not have that whole set. + 2. We then take each vote and make it unique, keeping only the first + instance of any candidate. + + This gives us a list of total orderings of some set. It will usually + be a lot smaller than the starting list, but that's OK. + """ + all_candidates = candidates(votes) + votes = list(filter(lambda v: set(v) == all_candidates, votes)) + if not votes: + return [] + rebuilt_votes = [] + for vote in votes: + rv = [] + for v in vote: + if v not in rv: + rv.append(v) + assert len(rv) == len(all_candidates) + rebuilt_votes.append(rv) + return rebuilt_votes + + + @given(lists(lists(integers(min_value=1, max_value=5)))) + def test_elections_are_transitive(election): + election = build_election(election) + # Small elections are unlikely to be interesting + assume(len(election) >= 3) + all_candidates = candidates(election) + # Elections with fewer than three candidates certainly can't exhibit + # intransitivity + assume(len(all_candidates) >= 3) + + # Now we check if the election is transitive + + # First calculate the pairwise counts of how many prefer each candidate + # to the other + counts = Counter() + for vote in election: + for i in range(len(vote)): + for j in range(i+1, len(vote)): + counts[(vote[i], vote[j])] += 1 + + # Now look at which pairs of candidates one has a majority over the + # other and store that. + graph = {} + all_candidates = candidates(election) + for i in all_candidates: + for j in all_candidates: + if counts[(i, j)] > counts[(j, i)]: + graph.setdefault(i, set()).add(j) + + # Now for each triple assert that it is transitive. + for x in all_candidates: + for y in graph.get(x, ()): + for z in graph.get(y, ()): + assert x not in graph.get(z, ()) + +The example Hypothesis gives me on my first run (your mileage may of course +vary) is: + +.. code:: python + + [[3, 1, 4], [4, 3, 1], [1, 4, 3]] + +Which does indeed do the job: The majority (votes 0 and 1) prefer 3 to 1, the +majority (votes 0 and 2) prefer 1 to 4 and the majority (votes 1 and 2) prefer +4 to 3. This is in fact basically the canonical example of the voting paradox, +modulo variations on the names of candidates. + +------------------- +Fuzzing an HTTP API +------------------- + +Hypothesis's support for testing HTTP services is somewhat nascent. There are +plans for some fully featured things around this, but right now they're +probably quite far down the line. + +But you can do a lot yourself without any explicit support! Here's a script +I wrote to throw arbitrary data against the API for an entirely fictitious service +called Waspfinder (this is only lightly obfuscated and you can easily figure +out who I'm actually talking about, but I don't want you to run this code and +hammer their API without their permission). + +All this does is use Hypothesis to generate arbitrary JSON data matching the +format their API asks for and check for 500 errors. More advanced tests which +then use the result and go on to do other things are definitely also possible. +The :pypi:`swagger-conformance` package provides an excellent example of this! + +.. code:: python + + import unittest + from hypothesis import given, assume, settings, strategies as st + from collections import namedtuple + import requests + import os + import random + import time + import math + + # These tests will be quite slow because we have to talk to an external + # service. Also we'll put in a sleep between calls so as to not hammer it. + # As a result we reduce the number of test cases and turn off the timeout. + settings.default.max_examples = 100 + settings.default.timeout = -1 + + Goal = namedtuple("Goal", ("slug",)) + + + # We just pass in our API credentials via environment variables. + waspfinder_token = os.getenv('WASPFINDER_TOKEN') + waspfinder_user = os.getenv('WASPFINDER_USER') + assert waspfinder_token is not None + assert waspfinder_user is not None + + GoalData = st.fixed_dictionaries({ + 'title': st.text(), + 'goal_type': st.sampled_from([ + "hustler", "biker", "gainer", "fatloser", "inboxer", + "drinker", "custom"]), + 'goaldate': st.one_of(st.none(), st.floats()), + 'goalval': st.one_of(st.none(), st.floats()), + 'rate': st.one_of(st.none(), st.floats()), + 'initval': st.floats(), + 'panic': st.floats(), + 'secret': st.booleans(), + 'datapublic': st.booleans(), + }) + + + needs2 = ['goaldate', 'goalval', 'rate'] + + + class WaspfinderTest(unittest.TestCase): + + @given(GoalData) + def test_create_goal_dry_run(self, data): + # We want slug to be unique for each run so that multiple test runs + # don't interfere with each other. If for some reason some slugs trigger + # an error and others don't we'll get a Flaky error, but that's OK. + slug = hex(random.getrandbits(32))[2:] + + # Use assume to guide us through validation we know about, otherwise + # we'll spend a lot of time generating boring examples. + + # Title must not be empty + assume(data["title"]) + + # Exactly two of these values should be not None. The other will be + # inferred by the API. + + assume(len([1 for k in needs2 if data[k] is not None]) == 2) + for v in data.values(): + if isinstance(v, float): + assume(not math.isnan(v)) + data["slug"] = slug + + # The API nicely supports a dry run option, which means we don't have + # to worry about the user account being spammed with lots of fake goals + # Otherwise we would have to make sure we cleaned up after ourselves + # in this test. + data["dryrun"] = True + data["auth_token"] = waspfinder_token + for d, v in data.items(): + if v is None: + data[d] = "null" + else: + data[d] = str(v) + result = requests.post( + "https://waspfinder.example.com/api/v1/users/" + "%s/goals.json" % (waspfinder_user,), data=data) + + # Lets not hammer the API too badly. This will of course make the + # tests even slower than they otherwise would have been, but that's + # life. + time.sleep(1.0) + + # For the moment all we're testing is that this doesn't generate an + # internal error. If we didn't use the dry run option we could have + # then tried doing more with the result, but this is a good start. + self.assertNotEqual(result.status_code, 500) + + if __name__ == '__main__': + unittest.main() + +.. _py.test: https://docs.pytest.org/en/latest/ +.. _nose: https://nose.readthedocs.io/en/latest/ diff -Nru python-hypothesis-3.44.1/hypothesis-python/docs/extras.rst python-hypothesis-3.71.11/hypothesis-python/docs/extras.rst --- python-hypothesis-3.44.1/hypothesis-python/docs/extras.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/docs/extras.rst 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,107 @@ +=================== +Additional packages +=================== + +Hypothesis itself does not have any dependencies, but there are some packages that +need additional things installed in order to work. + +You can install these dependencies using the setuptools extra feature as e.g. +``pip install hypothesis[django]``. This will check installation of compatible versions. + +You can also just install hypothesis into a project using them, ignore the version +constraints, and hope for the best. + +In general "Which version is Hypothesis compatible with?" is a hard question to answer +and even harder to regularly test. Hypothesis is always tested against the latest +compatible version and each package will note the expected compatibility range. If +you run into a bug with any of these please specify the dependency version. + +There are separate pages for :doc:`django` and :doc:`numpy`. + +-------------------- +hypothesis[pytz] +-------------------- + +.. automodule:: hypothesis.extra.pytz + :members: + + +-------------------- +hypothesis[dateutil] +-------------------- + +.. automodule:: hypothesis.extra.dateutil + :members: + + +-------------------- +hypothesis[datetime] +-------------------- + +.. automodule:: hypothesis.extra.datetime + :members: + + +.. _faker-extra: + +----------------------- +hypothesis[fakefactory] +----------------------- + +.. note:: + This extra package is deprecated. We strongly recommend using native + Hypothesis strategies, which are more effective at both finding and + shrinking failing examples for your tests. + + The :func:`~hypothesis.strategies.from_regex`, :func:`~hypothesis.strategies.emails`, + :func:`~hypothesis.strategies.text` (with some specific alphabet), and + :func:`~hypothesis.strategies.sampled_from` strategies may be particularly + useful. + +:pypi:`Faker` (previously :pypi:`fake-factory`) is a Python package that +generates fake data for you. It's great for bootstraping your database, +creating good-looking XML documents, stress-testing a database, or anonymizing +production data. However, it's not designed for automated testing - data from +Hypothesis looks less realistic, but produces minimal bug-triggering examples +and uses coverage information to check more cases. + +``hypothesis.extra.fakefactory`` lets you use Faker generators to parametrize +Hypothesis tests. This was only ever meant to ease your transition to +Hypothesis, but we've improved Hypothesis enough since then that we no longer +recommend using Faker for automated tests under any circumstances. + +hypothesis.extra.fakefactory defines a function fake_factory which returns a +strategy for producing text data from any Faker provider. + +So for example the following will parametrize a test by an email address: + +.. code-block:: pycon + + >>> fake_factory('email').example() + 'tnader@prosacco.info' + + >>> fake_factory('name').example() + 'Zbyněk Černý CSc.' + +You can explicitly specify the locale (otherwise it uses any of the available +locales), either as a single locale or as several: + +.. code-block:: pycon + + >>> fake_factory('name', locale='en_GB').example() + 'Antione Gerlach' + >>> fake_factory('name', locales=['en_GB', 'cs_CZ']).example() + 'Miloš Šťastný' + >>> fake_factory('name', locales=['en_GB', 'cs_CZ']).example() + 'Harm Sanford' + +You can use custom Faker providers via the ``providers`` argument: + +.. code-block:: pycon + + >>> from faker.providers import BaseProvider + >>> class KittenProvider(BaseProvider): + ... def meows(self): + ... return 'meow %d' % (self.random_number(digits=10),) + >>> fake_factory('meows', providers=[KittenProvider]).example() + 'meow 9139348419' diff -Nru python-hypothesis-3.44.1/hypothesis-python/docs/healthchecks.rst python-hypothesis-3.71.11/hypothesis-python/docs/healthchecks.rst --- python-hypothesis-3.44.1/hypothesis-python/docs/healthchecks.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/docs/healthchecks.rst 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,45 @@ +============= +Health checks +============= + +Hypothesis tries to detect common mistakes and things that will cause difficulty +at run time in the form of a number of 'health checks'. + +These include detecting and warning about: + +* Strategies with very slow data generation +* Strategies which filter out too much +* Recursive strategies which branch too much +* Tests that are unlikely to complete in a reasonable amount of time. + +If any of these scenarios are detected, Hypothesis will emit a warning about them. + +The general goal of these health checks is to warn you about things that you are doing that might +appear to work but will either cause Hypothesis to not work correctly or to perform badly. + +To selectively disable health checks, use the +:obj:`~hypothesis.settings.suppress_health_check` setting. +The argument for this parameter is a list with elements drawn from any of +the class-level attributes of the HealthCheck class. +Using a value of ``HealthCheck.all()`` will disable all health checks. + +.. module:: hypothesis +.. autoclass:: HealthCheck + :undoc-members: + :inherited-members: + + +------------ +Deprecations +------------ + +We also use a range of custom exception and warning types, so you can see +exactly where an error came from - or turn only our warnings into errors. + +.. autoclass:: hypothesis.errors.HypothesisDeprecationWarning + +Deprecated features will be continue to emit warnings for at least six +months, and then be removed in the following major release. +Note however that not all warnings are subject to this grace period; +sometimes we strengthen validation by adding a warning and these may +become errors immediately at a major release. diff -Nru python-hypothesis-3.44.1/hypothesis-python/docs/index.rst python-hypothesis-3.71.11/hypothesis-python/docs/index.rst --- python-hypothesis-3.44.1/hypothesis-python/docs/index.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/docs/index.rst 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,80 @@ +====================== +Welcome to Hypothesis! +====================== + +`Hypothesis `_ is a Python library for +creating unit tests which are simpler to write and more powerful when run, +finding edge cases in your code you wouldn't have thought to look for. It is +stable, powerful and easy to add to any existing test suite. + +It works by letting you write tests that assert that something should be true +for every case, not just the ones you happen to think of. + +Think of a normal unit test as being something like the following: + +1. Set up some data. +2. Perform some operations on the data. +3. Assert something about the result. + +Hypothesis lets you write tests which instead look like this: + +1. For all data matching some specification. +2. Perform some operations on the data. +3. Assert something about the result. + +This is often called property based testing, and was popularised by the +Haskell library `Quickcheck `_. + +It works by generating arbitrary data matching your specification and checking +that your guarantee still holds in that case. If it finds an example where it doesn't, +it takes that example and cuts it down to size, simplifying it until it finds a +much smaller example that still causes the problem. It then saves that example +for later, so that once it has found a problem with your code it will not forget +it in the future. + +Writing tests of this form usually consists of deciding on guarantees that +your code should make - properties that should always hold true, +regardless of what the world throws at you. Examples of such guarantees +might be: + +* Your code shouldn't throw an exception, or should only throw a particular type of exception (this works particularly well if you have a lot of internal assertions). +* If you delete an object, it is no longer visible. +* If you serialize and then deserialize a value, then you get the same value back. + +Now you know the basics of what Hypothesis does, the rest of this +documentation will take you through how and why. It's divided into a +number of sections, which you can see in the sidebar (or the +menu at the top if you're on mobile), but you probably want to begin with +the :doc:`Quick start guide `, which will give you a worked +example of how to use Hypothesis and a detailed outline +of the things you need to know to begin testing your code with it, or +check out some of the +`introductory articles `_. + + +.. toctree:: + :maxdepth: 1 + :hidden: + + quickstart + details + settings + data + extras + django + numpy + healthchecks + database + stateful + supported + examples + community + manifesto + endorsements + usage + strategies + changes + development + support + packaging + reproducing diff -Nru python-hypothesis-3.44.1/hypothesis-python/docs/manifesto.rst python-hypothesis-3.71.11/hypothesis-python/docs/manifesto.rst --- python-hypothesis-3.44.1/hypothesis-python/docs/manifesto.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/docs/manifesto.rst 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,60 @@ +========================= +The Purpose of Hypothesis +========================= + +What is Hypothesis for? + +From the perspective of a user, the purpose of Hypothesis is to make it easier for +you to write better tests. + +From my perspective as the author, that is of course also a purpose of Hypothesis, +but (if you will permit me to indulge in a touch of megalomania for a moment), the +larger purpose of Hypothesis is to drag the world kicking and screaming into a new +and terrifying age of high quality software. + +Software is, as they say, eating the world. Software is also `terrible`_. It's buggy, +insecure and generally poorly thought out. This combination is clearly a recipe for +disaster. + +And the state of software testing is even worse. Although it's fairly uncontroversial +at this point that you *should* be testing your code, can you really say with a straight +face that most projects you've worked on are adequately tested? + +A lot of the problem here is that it's too hard to write good tests. Your tests encode +exactly the same assumptions and fallacies that you had when you wrote the code, so they +miss exactly the same bugs that you missed when you wrote the code. + +Meanwhile, there are all sorts of tools for making testing better that are basically +unused. The original Quickcheck is from *1999* and the majority of developers have +not even heard of it, let alone used it. There are a bunch of half-baked implementations +for most languages, but very few of them are worth using. + +The goal of Hypothesis is to bring advanced testing techniques to the masses, and to +provide an implementation that is so high quality that it is easier to use them than +it is not to use them. Where I can, I will beg, borrow and steal every good idea +I can find that someone has had to make software testing better. Where I can't, I will +invent new ones. + +Quickcheck is the start, but I also plan to integrate ideas from fuzz testing (a +planned future feature is to use coverage information to drive example selection, and +the example saving database is already inspired by the workflows people use for fuzz +testing), and am open to and actively seeking out other suggestions and ideas. + +The plan is to treat the social problem of people not using these ideas as a bug to +which there is a technical solution: Does property-based testing not match your workflow? +That's a bug, let's fix it by figuring out how to integrate Hypothesis into it. +Too hard to generate custom data for your application? That's a bug. Let's fix it by +figuring out how to make it easier, or how to take something you're already using to +specify your data and derive a generator from that automatically. Find the explanations +of these advanced ideas hopelessly obtuse and hard to follow? That's a bug. Let's provide +you with an easy API that lets you test your code better without a PhD in software +verification. + +Grand ambitions, I know, and I expect ultimately the reality will be somewhat less +grand, but so far in about three months of development, Hypothesis has become the most +solid implementation of Quickcheck ever seen in a mainstream language (as long as we don't +count Scala as mainstream yet), and at the same time managed to +significantly push forward the state of the art, so I think there's +reason to be optimistic. + +.. _terrible: https://www.youtube.com/watch?v=csyL9EC0S0c diff -Nru python-hypothesis-3.44.1/hypothesis-python/docs/numpy.rst python-hypothesis-3.71.11/hypothesis-python/docs/numpy.rst --- python-hypothesis-3.44.1/hypothesis-python/docs/numpy.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/docs/numpy.rst 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,54 @@ +=================================== +Hypothesis for the Scientific Stack +=================================== + +.. _hypothesis-numpy: + +----- +numpy +----- + +Hypothesis offers a number of strategies for `NumPy `_ testing, +available in the ``hypothesis[numpy]`` :doc:`extra `. +It lives in the ``hypothesis.extra.numpy`` package. + +The centerpiece is the :func:`~hypothesis.extra.numpy.arrays` strategy, which generates arrays with +any dtype, shape, and contents you can specify or give a strategy for. +To make this as useful as possible, strategies are provided to generate array +shapes and generate all kinds of fixed-size or compound dtypes. + + +.. automodule:: hypothesis.extra.numpy + :members: + :exclude-members: ArrayStrategy + +.. _hypothesis-pandas: + +------ +pandas +------ + +Hypothesis provides strategies for several of the core pandas data types: +:class:`pandas.Index`, :class:`pandas.Series` and :class:`pandas.DataFrame`. + +The general approach taken by the pandas module is that there are multiple +strategies for generating indexes, and all of the other strategies take the +number of entries they contain from their index strategy (with sensible defaults). +So e.g. a Series is specified by specifying its :class:`numpy.dtype` (and/or +a strategy for generating elements for it). + +.. automodule:: hypothesis.extra.pandas + :members: + +~~~~~~~~~~~~~~~~~~ +Supported Versions +~~~~~~~~~~~~~~~~~~ + +There is quite a lot of variation between pandas versions. We only +commit to supporting the latest version of pandas, but older minor versions are +supported on a "best effort" basis. Hypothesis is currently tested against +and confirmed working with Pandas 0.19, 0.20, 0.21, 0.22, and 0.23. + +Releases that are not the latest patch release of their minor version are not +tested or officially supported, but will probably also work unless you hit a +pandas bug. diff -Nru python-hypothesis-3.44.1/hypothesis-python/docs/packaging.rst python-hypothesis-3.71.11/hypothesis-python/docs/packaging.rst --- python-hypothesis-3.44.1/hypothesis-python/docs/packaging.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/docs/packaging.rst 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,104 @@ +==================== +Packaging Guidelines +==================== + +Downstream packagers often want to package Hypothesis. Here are some guidelines. + +The primary guideline is this: If you are not prepared to keep up with the Hypothesis release schedule, +don't. You will annoy me and are doing your users a disservice. + +Hypothesis has a very frequent release schedule. It's rare that it goes a week without a release, +and there are often multiple releases in a given week. + +If you *are* prepared to keep up with this schedule, you might find the rest of this document useful. + +---------------- +Release tarballs +---------------- + +These are available from :gh-link:`the GitHub releases page `. The +tarballs on pypi are intended for installation from a Python tool such as pip and should not +be considered complete releases. Requests to include additional files in them will not be granted. Their absence +is not a bug. + + +------------ +Dependencies +------------ + +~~~~~~~~~~~~~~~ +Python versions +~~~~~~~~~~~~~~~ + +Hypothesis is designed to work with a range of Python versions. Currently supported are: + +* pypy-2.6.1 (earlier versions of pypy *may* work) +* CPython 2.7.x +* CPython 3.4.x +* CPython 3.5.x +* CPython 3.6.x +* CPython 3.7.x + +If you feel the need to have separate Python 3 and Python 2 packages you can, but Hypothesis works unmodified +on either. + +~~~~~~~~~~~~~~~~~~~~~~ +Other Python libraries +~~~~~~~~~~~~~~~~~~~~~~ + +Hypothesis has *mandatory* dependencies on the following libraries: + +* :pypi:`attrs` +* :pypi:`coverage` +* :pypi:`enum34` is required on Python 2.7 + +Hypothesis has *optional* dependencies on the following libraries: + +* :pypi:`pytz` (almost any version should work) +* :pypi:`Faker`, version 0.7 or later +* `Django `_, all supported versions +* :pypi:`numpy`, 1.10 or later (earlier versions will probably work fine) +* :pypi:`pandas`, 1.19 or later +* :pypi:`pytest` (3.0 or greater). This is a mandatory dependency for testing Hypothesis itself but optional for users. + +The way this works when installing Hypothesis normally is that these features become available if the relevant +library is installed. + +------------------ +Testing Hypothesis +------------------ + +If you want to test Hypothesis as part of your packaging you will probably not want to use the mechanisms +Hypothesis itself uses for running its tests, because it has a lot of logic for installing and testing against +different versions of Python. + +The tests must be run with py.test. A version more recent than 2.8.0 is strongly encouraged, but it may work +with earlier versions (however py.test specific logic is disabled before 2.8.0). + +Tests are organised into a number of top level subdirectories of the tests/ directory. + +* cover: This is a small, reasonably fast, collection of tests designed to give 100% coverage of all but a select + subset of the files when run under Python 3. +* nocover: This is a much slower collection of tests that should not be run under coverage for performance reasons. +* py2: Tests that can only be run under Python 2 +* py3: Tests that can only be run under Python 3 +* datetime: This tests the subset of Hypothesis that depends on pytz +* fakefactory: This tests the subset of Hypothesis that depends on fakefactory. +* django: This tests the subset of Hypothesis that depends on django + + +An example invocation for running the coverage subset of these tests: + +.. code-block:: bash + + pip install -e . + pip install pytest # you will probably want to use your own packaging here + python -m pytest tests/cover + +-------- +Examples +-------- + +* `arch linux `_ +* `fedora `_ +* `gentoo `_ diff -Nru python-hypothesis-3.44.1/hypothesis-python/docs/quickstart.rst python-hypothesis-3.71.11/hypothesis-python/docs/quickstart.rst --- python-hypothesis-3.44.1/hypothesis-python/docs/quickstart.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/docs/quickstart.rst 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,291 @@ +================= +Quick start guide +================= + +This document should talk you through everything you need to get started with +Hypothesis. + +---------- +An example +---------- + +Suppose we've written a `run length encoding +`_ system and we want to test +it out. + +We have the following code which I took straight from the +`Rosetta Code `_ wiki (OK, I +removed some commented out code and fixed the formatting, but there are no +functional modifications): + + +.. code:: python + + def encode(input_string): + count = 1 + prev = '' + lst = [] + for character in input_string: + if character != prev: + if prev: + entry = (prev, count) + lst.append(entry) + count = 1 + prev = character + else: + count += 1 + else: + entry = (character, count) + lst.append(entry) + return lst + + + def decode(lst): + q = '' + for character, count in lst: + q += character * count + return q + + +We want to write a test for this that will check some invariant of these +functions. + +The invariant one tends to try when you've got this sort of encoding / +decoding is that if you encode something and then decode it then you get the same +value back. + +Lets see how you'd do that with Hypothesis: + + +.. code:: python + + from hypothesis import given + from hypothesis.strategies import text + + @given(text()) + def test_decode_inverts_encode(s): + assert decode(encode(s)) == s + +(For this example we'll just let pytest discover and run the test. We'll cover +other ways you could have run it later). + +The text function returns what Hypothesis calls a search strategy. An object +with methods that describe how to generate and simplify certain kinds of +values. The :func:`@given ` decorator then takes our test +function and turns it into a +parametrized one which, when called, will run the test function over a wide +range of matching data from that strategy. + +Anyway, this test immediately finds a bug in the code: + +.. code:: + + Falsifying example: test_decode_inverts_encode(s='') + + UnboundLocalError: local variable 'character' referenced before assignment + +Hypothesis correctly points out that this code is simply wrong if called on +an empty string. + +If we fix that by just adding the following code to the beginning of the function +then Hypothesis tells us the code is correct (by doing nothing as you'd expect +a passing test to). + +.. code:: python + + + if not input_string: + return [] + +If we wanted to make sure this example was always checked we could add it in +explicitly by using the :func:`@example ` decorator: + +.. code:: python + + from hypothesis import given, example + from hypothesis.strategies import text + + @given(text()) + @example('') + def test_decode_inverts_encode(s): + assert decode(encode(s)) == s + +This can be useful to show other developers (or your future self) what kinds +of data are valid inputs, or to ensure that particular edge cases such as +``""`` are tested every time. It's also great for regression tests because +although Hypothesis will :doc:`remember failing examples `, +we don't recommend distributing that database. + +It's also worth noting that both example and given support keyword arguments as +well as positional. The following would have worked just as well: + +.. code:: python + + @given(s=text()) + @example(s='') + def test_decode_inverts_encode(s): + assert decode(encode(s)) == s + +Suppose we had a more interesting bug and forgot to reset the count +each time. Say we missed a line in our ``encode`` method: + +.. code:: python + + def encode(input_string): + count = 1 + prev = '' + lst = [] + for character in input_string: + if character != prev: + if prev: + entry = (prev, count) + lst.append(entry) + # count = 1 # Missing reset operation + prev = character + else: + count += 1 + else: + entry = (character, count) + lst.append(entry) + return lst + +Hypothesis quickly informs us of the following example: + +.. code:: + + Falsifying example: test_decode_inverts_encode(s='001') + +Note that the example provided is really quite simple. Hypothesis doesn't just +find *any* counter-example to your tests, it knows how to simplify the examples +it finds to produce small easy to understand ones. In this case, two identical +values are enough to set the count to a number different from one, followed by +another distinct value which should have reset the count but in this case +didn't. + +The examples Hypothesis provides are valid Python code you can run. Any +arguments that you explicitly provide when calling the function are not +generated by Hypothesis, and if you explicitly provide *all* the arguments +Hypothesis will just call the underlying function once rather than +running it multiple times. + +---------- +Installing +---------- + +Hypothesis is :pypi:`available on pypi as "hypothesis" `. You can install it with: + +.. code:: bash + + pip install hypothesis + +You can install the dependencies for :doc:`optional extensions ` with +e.g. ``pip install hypothesis[pandas,django]``. + +If you want to install directly from the source code (e.g. because you want to +make changes and install the changed version), check out the instructions in +:gh-file:`CONTRIBUTING.rst`. + +------------- +Running tests +------------- + +In our example above we just let pytest discover and run our tests, but we could +also have run it explicitly ourselves: + +.. code:: python + + if __name__ == '__main__': + test_decode_inverts_encode() + +We could also have done this as a :class:`python:unittest.TestCase`: + +.. code:: python + + import unittest + + class TestEncoding(unittest.TestCase): + @given(text()) + def test_decode_inverts_encode(self, s): + self.assertEqual(decode(encode(s)), s) + + if __name__ == '__main__': + unittest.main() + +A detail: This works because Hypothesis ignores any arguments it hasn't been +told to provide (positional arguments start from the right), so the self +argument to the test is simply ignored and works as normal. This also means +that Hypothesis will play nicely with other ways of parameterizing tests. e.g +it works fine if you use pytest fixtures for some arguments and Hypothesis for +others. + +------------- +Writing tests +------------- + +A test in Hypothesis consists of two parts: A function that looks like a normal +test in your test framework of choice but with some additional arguments, and +a :func:`@given ` decorator that specifies +how to provide those arguments. + +Here are some other examples of how you could use that: + + +.. code:: python + + from hypothesis import given + import hypothesis.strategies as st + + @given(st.integers(), st.integers()) + def test_ints_are_commutative(x, y): + assert x + y == y + x + + @given(x=st.integers(), y=st.integers()) + def test_ints_cancel(x, y): + assert (x + y) - y == x + + @given(st.lists(st.integers())) + def test_reversing_twice_gives_same_list(xs): + # This will generate lists of arbitrary length (usually between 0 and + # 100 elements) whose elements are integers. + ys = list(xs) + ys.reverse() + ys.reverse() + assert xs == ys + + @given(st.tuples(st.booleans(), st.text())) + def test_look_tuples_work_too(t): + # A tuple is generated as the one you provided, with the corresponding + # types in those positions. + assert len(t) == 2 + assert isinstance(t[0], bool) + assert isinstance(t[1], str) + + +Note that as we saw in the above example you can pass arguments to :func:`@given ` +either as positional or as keywords. + +-------------- +Where to start +-------------- + +You should now know enough of the basics to write some tests for your code +using Hypothesis. The best way to learn is by doing, so go have a try. + +If you're stuck for ideas for how to use this sort of test for your code, here +are some good starting points: + +1. Try just calling functions with appropriate arbitrary data and see if they + crash. You may be surprised how often this works. e.g. note that the first + bug we found in the encoding example didn't even get as far as our + assertion: It crashed because it couldn't handle the data we gave it, not + because it did the wrong thing. +2. Look for duplication in your tests. Are there any cases where you're testing + the same thing with multiple different examples? Can you generalise that to + a single test using Hypothesis? +3. `This piece is designed for an F# implementation + `_, but + is still very good advice which you may find helps give you good ideas for + using Hypothesis. + +If you have any trouble getting started, don't feel shy about +:doc:`asking for help `. diff -Nru python-hypothesis-3.44.1/hypothesis-python/docs/reproducing.rst python-hypothesis-3.71.11/hypothesis-python/docs/reproducing.rst --- python-hypothesis-3.44.1/hypothesis-python/docs/reproducing.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/docs/reproducing.rst 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,131 @@ +==================== +Reproducing Failures +==================== + +One of the things that is often concerning for people using randomized testing +is the question of how to reproduce failing test cases. + +.. note:: + It is better to think about the data Hypothesis generates as being + *arbitrary*, rather than *random*. We deliberately generate any valid + data that seems likely to cause errors, so you shouldn't rely on any + expected distribution of or relationships between generated data. + You can read about "swarm testing" and "coverage guided fuzzing" if + you're interested, because you don't need to know for Hypothesis! + +Fortunately Hypothesis has a number of features to support reproducing test failures. The one you +will use most commonly when developing locally is :doc:`the example database `, +which means that you shouldn't have to think about the problem at all for local +use - test failures will just automatically reproduce without you having to do +anything. + +The example database is perfectly suitable for sharing between machines, but +there currently aren't very good work flows for that, so Hypothesis provides a +number of ways to make examples reproducible by adding them to the source code +of your tests. This is particularly useful when e.g. you are trying to run an +example that has failed on your CI, or otherwise share them between machines. + +.. _providing-explicit-examples: + +--------------------------- +Providing explicit examples +--------------------------- + +You can explicitly ask Hypothesis to try a particular example, using + +.. autofunction:: hypothesis.example + +Hypothesis will run all examples you've asked for first. If any of them fail it +will not go on to look for more examples. + +It doesn't matter whether you put the example decorator before or after given. +Any permutation of the decorators in the above will do the same thing. + +Note that examples can be positional or keyword based. If they're positional then +they will be filled in from the right when calling, so either of the following +styles will work as expected: + +.. code:: python + + @given(text()) + @example("Hello world") + @example(x="Some very long string") + def test_some_code(x): + assert True + + from unittest import TestCase + + class TestThings(TestCase): + @given(text()) + @example("Hello world") + @example(x="Some very long string") + def test_some_code(self, x): + assert True + +As with ``@given``, it is not permitted for a single example to be a mix of +positional and keyword arguments. +Either are fine, and you can use one in one example and the other in another +example if for some reason you really want to, but a single example must be +consistent. + +.. _reproducing-with-seed: + +------------------------------------- +Reproducing a test run with ``@seed`` +------------------------------------- + +.. autofunction:: hypothesis.seed + +When a test fails unexpectedly, usually due to a health check failure, +Hypothesis will print out a seed that led to that failure, if the test is not +already running with a fixed seed. You can then recreate that failure using either +the ``@seed`` decorator or (if you are running :pypi:`pytest`) with +``--hypothesis-seed``. + +.. _reproduce_failure: + +------------------------------------------------------- +Reproducing an example with with ``@reproduce_failure`` +------------------------------------------------------- + +Hypothesis has an opaque binary representation that it uses for all examples it +generates. This representation is not intended to be stable across versions or +with respect to changes in the test, but can be used to to reproduce failures +with the ``@reproduce_example`` decorator. + +.. autofunction:: hypothesis.reproduce_failure + +The intent is that you should never write this decorator by hand, but it is +instead provided by Hypothesis. +When a test fails with a falsifying example, Hypothesis may print out a +suggestion to use ``@reproduce_failure`` on the test to recreate the problem +as follows: + +.. doctest:: + + >>> from hypothesis import settings, given, PrintSettings + >>> import hypothesis.strategies as st + >>> @given(st.floats()) + ... @settings(print_blob=PrintSettings.ALWAYS) + ... def test(f): + ... assert f == f + ... + >>> try: + ... test() + ... except AssertionError: + ... pass + Falsifying example: test(f=nan) + + You can reproduce this example by temporarily adding @reproduce_failure(..., b'AAAA//AAAAAAAAEA') as a decorator on your test case + +Adding the suggested decorator to the test should reproduce the failure (as +long as everything else is the same - changing the versions of Python or +anything else involved, might of course affect the behaviour of the test! Note +that changing the version of Hypothesis will result in a different error - +each ``@reproduce_failure`` invocation is specific to a Hypothesis version). + +When to do this is controlled by the :attr:`~hypothesis.settings.print_blob` +setting, which may be one of the following values: + +.. autoclass:: hypothesis.PrintSettings + :members: diff -Nru python-hypothesis-3.44.1/hypothesis-python/docs/settings.rst python-hypothesis-3.71.11/hypothesis-python/docs/settings.rst --- python-hypothesis-3.44.1/hypothesis-python/docs/settings.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/docs/settings.rst 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,269 @@ +======== +Settings +======== + +Hypothesis tries to have good defaults for its behaviour, but sometimes that's +not enough and you need to tweak it. + +The mechanism for doing this is the :class:`~hypothesis.settings` object. +You can set up a :func:`@given ` based test to use this using a settings +decorator: + +:func:`@given ` invocation is as follows: + +.. code:: python + + from hypothesis import given, settings + + @given(integers()) + @settings(max_examples=500) + def test_this_thoroughly(x): + pass + +This uses a :class:`~hypothesis.settings` object which causes the test to receive a much larger +set of examples than normal. + +This may be applied either before or after the given and the results are +the same. The following is exactly equivalent: + + +.. code:: python + + from hypothesis import given, settings + + @settings(max_examples=500) + @given(integers()) + def test_this_thoroughly(x): + pass + +------------------ +Available settings +------------------ + +.. autoclass:: hypothesis.settings + :members: + :exclude-members: register_profile, get_profile, load_profile + +.. _phases: + +~~~~~~~~~~~~~~~~~~~~~ +Controlling What Runs +~~~~~~~~~~~~~~~~~~~~~ + +Hypothesis divides tests into four logically distinct phases: + +1. Running explicit examples :ref:`provided with the @example decorator `. +2. Rerunning a selection of previously failing examples to reproduce a previously seen error +3. Generating new examples. +4. Attempting to shrink an example found in phases 2 or 3 to a more manageable + one (explicit examples cannot be shrunk). + +The phases setting provides you with fine grained control over which of these run, +with each phase corresponding to a value on the :class:`~hypothesis.Phase` enum: + +.. class:: hypothesis.Phase + +1. ``Phase.explicit`` controls whether explicit examples are run. +2. ``Phase.reuse`` controls whether previous examples will be reused. +3. ``Phase.generate`` controls whether new examples will be generated. +4. ``Phase.shrink`` controls whether examples will be shrunk. + +The phases argument accepts a collection with any subset of these. e.g. +``settings(phases=[Phase.generate, Phase.shrink])`` will generate new examples +and shrink them, but will not run explicit examples or reuse previous failures, +while ``settings(phases=[Phase.explicit])`` will only run the explicit +examples. + +.. _verbose-output: + +~~~~~~~~~~~~~~~~~~~~~~~~~~ +Seeing intermediate result +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To see what's going on while Hypothesis runs your tests, you can turn +up the verbosity setting. This works with both :func:`~hypothesis.find` +and :func:`@given `. + +.. doctest:: + + >>> from hypothesis import find, settings, Verbosity + >>> from hypothesis.strategies import lists, integers + >>> find(lists(integers()), any, settings=settings(verbosity=Verbosity.verbose)) + Tried non-satisfying example [] + Found satisfying example [-1198601713, -67, 116, -29578] + Shrunk example to [-1198601713, -67, 0, -29578] + Shrunk example to [-1198601713, -67, 0, -138] + Shrunk example to [-1198601600, -67, 0, -138] + Shrunk example to [-1191228800, -67, 0, -138] + Shrunk example to [-8435072, -67, 0, -138] + Shrunk example to [-8435072, 0, 0, -138] + Shrunk example to [-8421504, 0, 0, -138] + Shrunk example to [-8421504, 0, 0, -128] + Shrunk example to [-8421504, 0, 0] + Shrunk example to [-8421504, 0] + Shrunk example to [-8421504] + Shrunk example to [-32896] + Shrunk example to [-128] + Shrunk example to [64] + Shrunk example to [32] + Shrunk example to [16] + Shrunk example to [8] + Shrunk example to [4] + Shrunk example to [3] + Shrunk example to [2] + Shrunk example to [1] + [1] + +The four levels are quiet, normal, verbose and debug. normal is the default, +while in quiet mode Hypothesis will not print anything out, not even the final +falsifying example. debug is basically verbose but a bit more so. You probably +don't want it. + +If you are using :pypi:`pytest`, you may also need to +:doc:`disable output capturing for passing tests `. + +------------------------- +Building settings objects +------------------------- + +Settings can be created by calling :class:`~hypothesis.settings` with any of the available settings +values. Any absent ones will be set to defaults: + +.. doctest:: + + >>> from hypothesis import settings + >>> settings().max_examples + 100 + >>> settings(max_examples=10).max_examples + 10 + +You can also pass a 'parent' settings object as the first argument, +and any settings you do not specify as keyword arguments will be +copied from the parent settings: + +.. doctest:: + + >>> parent = settings(max_examples=10) + >>> child = settings(parent, deadline=200) + >>> parent.max_examples == child.max_examples == 10 + True + >>> parent.deadline + not_set + >>> child.deadline + 200 + +---------------- +Default settings +---------------- + +At any given point in your program there is a current default settings, +available as ``settings.default``. As well as being a settings object in its own +right, all newly created settings objects which are not explicitly based off +another settings are based off the default, so will inherit any values that are +not explicitly set from it. + +You can change the defaults by using profiles. + +.. _settings_profiles: + +~~~~~~~~~~~~~~~~~ +settings Profiles +~~~~~~~~~~~~~~~~~ + +Depending on your environment you may want different default settings. +For example: during development you may want to lower the number of examples +to speed up the tests. However, in a CI environment you may want more examples +so you are more likely to find bugs. + +Hypothesis allows you to define different settings profiles. These profiles +can be loaded at any time. + +.. autoclass:: hypothesis.settings + :members: register_profile, get_profile, load_profile + +Loading a profile changes the default settings but will not change the behavior +of tests that explicitly change the settings. + +.. doctest:: + + >>> from hypothesis import settings + >>> settings.register_profile("ci", max_examples=1000) + >>> settings().max_examples + 100 + >>> settings.load_profile("ci") + >>> settings().max_examples + 1000 + +Instead of loading the profile and overriding the defaults you can retrieve profiles for +specific tests. + +.. doctest:: + + >>> with settings.get_profile("ci"): + ... print(settings().max_examples) + ... + 1000 + +Optionally, you may define the environment variable to load a profile for you. +This is the suggested pattern for running your tests on CI. +The code below should run in a `conftest.py` or any setup/initialization section of your test suite. +If this variable is not defined the Hypothesis defined defaults will be loaded. + +.. doctest:: + + >>> import os + >>> from hypothesis import settings, Verbosity + >>> settings.register_profile("ci", max_examples=1000) + >>> settings.register_profile("dev", max_examples=10) + >>> settings.register_profile("debug", max_examples=10, verbosity=Verbosity.verbose) + >>> settings.load_profile(os.getenv(u'HYPOTHESIS_PROFILE', 'default')) + +If you are using the hypothesis pytest plugin and your profiles are registered +by your conftest you can load one with the command line option ``--hypothesis-profile``. + +.. code:: bash + + $ pytest tests --hypothesis-profile + + +~~~~~~~~ +Timeouts +~~~~~~~~ + +The timeout functionality of Hypothesis is being deprecated, and will +eventually be removed. For the moment, the timeout setting can still be set +and the old default timeout of one minute remains. + +If you want to future proof your code you can get +the future behaviour by setting it to the value ``hypothesis.unlimited``. + +.. code:: python + + from hypothesis import given, settings, unlimited + from hypothesis import strategies as st + + @settings(timeout=unlimited) + @given(st.integers()) + def test_something_slow(i): + ... + +This will cause your code to run until it hits the normal Hypothesis example +limits, regardless of how long it takes. ``timeout=unlimited`` will remain a +valid setting after the timeout functionality has been deprecated (but will +then have its own deprecation cycle). + +There is however now a timing related health check which is designed to catch +tests that run for ages by accident. If you really want your test to run +forever, the following code will enable that: + +.. code:: python + + from hypothesis import given, settings, unlimited, HealthCheck + from hypothesis import strategies as st + + @settings(timeout=unlimited, suppress_health_check=[ + HealthCheck.hung_test + ]) + @given(st.integers()) + def test_something_slow(i): + ... diff -Nru python-hypothesis-3.44.1/hypothesis-python/docs/stateful.rst python-hypothesis-3.71.11/hypothesis-python/docs/stateful.rst --- python-hypothesis-3.44.1/hypothesis-python/docs/stateful.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/docs/stateful.rst 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,387 @@ +================ +Stateful testing +================ + +With :func:`@given `, your tests are still something that +you mostly write yourself, with Hypothesis providing some data. +With Hypothesis's *stateful testing*, Hypothesis instead tries to generate +not just data but entire tests. You specify a number of primitive +actions that can be combined together, and then Hypothesis will +try to find sequences of those actions that result in a failure. + +.. note:: + + This style of testing is often called *model-based testing*, but in Hypothesis + is called *stateful testing* (mostly for historical reasons - the original + implementation of this idea in Hypothesis was more closely based on + `ScalaCheck's stateful testing `_ + where the name is more apt). + Both of these names are somewhat misleading: You don't really need any sort of + formal model of your code to use this, and it can be just as useful for pure APIs + that don't involve any state as it is for stateful ones. + + It's perhaps best to not take the name of this sort of testing too seriously. + Regardless of what you call it, it is a powerful form of testing which is useful + for most non-trivial APIs. + +Hypothesis has two stateful testing APIs: A high level one, providing what +we call *rule based state machines*, and a low level one, providing what we call +*generic state machines*. + +You probably want to use the rule based state machines - they provide a high +level API for describing the sort of actions you want to perform, based on a +structured representation of actions. However the generic state machines are +more flexible, and are particularly useful if you want the set of currently +possible actions to depend primarily on external state. + +.. _rulebasedstateful: + +------------------------- +Rule based state machines +------------------------- + +Rule based state machines are the ones you're most likely to want to use. +They're significantly more user friendly and should be good enough for most +things you'd want to do. + +The two main ingredients of a rule based state machine are rules and bundles. + +A rule is very similar to a normal ``@given`` based test in that it takes +values drawn from strategies and passes them to a user defined test function. +The key difference is that where ``@given`` based tests must be independent, +rules can be chained together - a single test run may involve multiple rule +invocations, which may interact in various ways. + +A Bundle is a named collection of generated values that can be reused by other +operations in the test. +They are populated with the results of rules, and may be used as arguments to +rules, allowing data to flow from one rule to another, and rules to work on +the results of previous computations or actions. + +The following rule based state machine example is a simplified version of a +test for Hypothesis's example database implementation. An example database +maps keys to sets of values, and in this test we compare one implementation of +it to a simplified in memory model of its behaviour, which just stores the same +values in a Python ``dict``. The test then runs operations against both the +real database and the in-memory representation of it and looks for discrepancies +in their behaviour. + +.. code:: python + + import shutil + import tempfile + + from collections import defaultdict + import hypothesis.strategies as st + from hypothesis.database import DirectoryBasedExampleDatabase + from hypothesis.stateful import Bundle, RuleBasedStateMachine, rule + + + class DatabaseComparison(RuleBasedStateMachine): + def __init__(self): + super(DatabaseComparison, self).__init__() + self.tempd = tempfile.mkdtemp() + self.database = DirectoryBasedExampleDatabase(self.tempd) + self.model = defaultdict(set) + + keys = Bundle('keys') + values = Bundle('values') + + @rule(target=keys, k=st.binary()) + def k(self, k): + return k + + @rule(target=values, v=st.binary()) + def v(self, v): + return v + + @rule(k=keys, v=values) + def save(self, k, v): + self.model[k].add(v) + self.database.save(k, v) + + @rule(k=keys, v=values) + def delete(self, k, v): + self.model[k].discard(v) + self.database.delete(k, v) + + @rule(k=keys) + def values_agree(self, k): + assert set(self.database.fetch(k)) == self.model[k] + + def teardown(self): + shutil.rmtree(self.tempd) + + + TestDBComparison = DatabaseComparison.TestCase + +In this we declare two bundles - one for keys, and one for values. +We have two trivial rules which just populate them with data (``k`` and ``v``), +and three non-trivial rules: +``save`` saves a value under a key and ``delete`` removes a value from a key, +in both cases also updating the model of what *should* be in the database. +``values_agree`` then checks that the contents of the database agrees with the +model for a particular key. + +We can then integrate this into our test suite by getting a unittest TestCase +from it: + +.. code:: python + + TestTrees = DatabaseComparison.TestCase + + # Or just run with pytest's unittest support + if __name__ == '__main__': + unittest.main() + +This test currently passes, but if we comment out the line where we call ``self.model[k].discard(v)``, +we would see the following output when run under pytest: + +:: + + AssertionError: assert set() == {b''} + + ------------ Hypothesis ------------ + + state = DatabaseComparison() + v1 = state.k(k=b'') + v2 = state.v(v=v1) + state.save(k=v1, v=v2) + state.delete(k=v1, v=v2) + state.values_agree(k=v1) + state.teardown() + +Note how it's printed out a very short program that will demonstrate the +problem. The output from a rule based state machine should generally be pretty +close to Python code - if you have custom ``repr`` implementations that don't +return valid Python then it might not be, but most of the time you should just +be able to copy and paste the code into a test to reproduce it. + +You can control the detailed behaviour with a settings object on the TestCase +(this is a normal hypothesis settings object using the defaults at the time +the TestCase class was first referenced). For example if you wanted to run +fewer examples with larger programs you could change the settings to: + +.. code:: python + + DatabaseComparison.settings = settings(max_examples=50, stateful_step_count=100) + +Which doubles the number of steps each program runs and halves the number of +test cases that will be run. + +----- +Rules +----- + +As said earlier, rules are the most common feature used in RuleBasedStateMachine. +They are defined by applying the :func:`~hypothesis.stateful.rule` decorator +on a function. +Note that RuleBasedStateMachine must have at least one rule defined and that +a single function cannot be used to define multiple rules (this to avoid having +multiple rules doing the same things). +Due to the stateful execution method, rules generally cannot take arguments +from other sources such as fixtures or ``pytest.mark.parametrize`` - consider +providing them via a strategy such as :func:`~hypothesis.strategies.sampled_from` +instead. + +.. autofunction:: hypothesis.stateful.rule + +----------- +Initializes +----------- + +Initializes are a special case of rules that are guaranteed to be run at most +once at the beginning of a run (i.e. before any normal rule is called). +Note if multiple initialize rules are defined, they may be called in any order, +and that order will vary from run to run. + +Initializes are typically useful to populate bundles: + +.. autofunction:: hypothesis.stateful.initialize + +.. code:: python + + import hypothesis.strategies as st + from hypothesis.stateful import RuleBasedStateMachine, Bundle, rule, initialize + + name_strategy = st.text(min_size=1).filter(lambda x: "/" not in x) + + class NumberModifier(RuleBasedStateMachine): + + folders = Bundle('folders') + files = Bundle('files') + + @initialize(target=folders) + def init_folders(self): + return '/' + + @rule(target=folders, name=name_strategy) + def create_folder(self, parent, name): + return '%s/%s' % (parent, name) + + @rule(target=files, name=name_strategy) + def create_file(self, parent, name): + return '%s/%s' % (parent, name) + + +------------- +Preconditions +------------- + +While it's possible to use :func:`~hypothesis.assume` in RuleBasedStateMachine rules, if you +use it in only a few rules you can quickly run into a situation where few or +none of your rules pass their assumptions. Thus, Hypothesis provides a +:func:`~hypothesis.stateful.precondition` decorator to avoid this problem. The :func:`~hypothesis.stateful.precondition` +decorator is used on ``rule``-decorated functions, and must be given a function +that returns True or False based on the RuleBasedStateMachine instance. + +.. autofunction:: hypothesis.stateful.precondition + +.. code:: python + + from hypothesis.stateful import RuleBasedStateMachine, rule, precondition + + class NumberModifier(RuleBasedStateMachine): + + num = 0 + + @rule() + def add_one(self): + self.num += 1 + + @precondition(lambda self: self.num != 0) + @rule() + def divide_with_one(self): + self.num = 1 / self.num + + +By using :func:`~hypothesis.stateful.precondition` here instead of :func:`~hypothesis.assume`, Hypothesis can filter the +inapplicable rules before running them. This makes it much more likely that a +useful sequence of steps will be generated. + +Note that currently preconditions can't access bundles; if you need to use +preconditions, you should store relevant data on the instance instead. + +---------- +Invariants +---------- + +Often there are invariants that you want to ensure are met after every step in +a process. It would be possible to add these as rules that are run, but they +would be run zero or multiple times between other rules. Hypothesis provides a +decorator that marks a function to be run after every step. + +.. autofunction:: hypothesis.stateful.invariant + +.. code:: python + + from hypothesis.stateful import RuleBasedStateMachine, rule, invariant + + class NumberModifier(RuleBasedStateMachine): + + num = 0 + + @rule() + def add_two(self): + self.num += 2 + if self.num > 50: + self.num += 1 + + @invariant() + def divide_with_one(self): + assert self.num % 2 == 0 + + NumberTest = NumberModifier.TestCase + +Invariants can also have :func:`~hypothesis.stateful.precondition`\ s applied to them, in which case +they will only be run if the precondition function returns true. + +Note that currently invariants can't access bundles; if you need to use +invariants, you should store relevant data on the instance instead. + +---------------------- +Generic state machines +---------------------- + +The class :class:`~hypothesis.stateful.GenericStateMachine` is the underlying machinery of stateful testing +in Hypothesis. Chances are you will want to use the rule based stateful testing +for most things, but the generic state machine functionality can be useful e.g. if +you want to test things where the set of actions to be taken is more closely +tied to the state of the system you are testing. + +.. module:: hypothesis.stateful +.. autoclass:: GenericStateMachine + :members: steps, execute_step, check_invariants, teardown + +For example, here we use stateful testing as a sort of link checker, to test +`hypothesis.works `_ for broken links or links that +use HTTP instead of HTTPS. + +.. code:: python + + from hypothesis.stateful import GenericStateMachine + import hypothesis.strategies as st + from requests_html import HTMLSession + + + class LinkChecker(GenericStateMachine): + def __init__(self): + super(LinkChecker, self).__init__() + self.session = HTMLSession() + self.result = None + + def steps(self): + if self.result is None: + # Always start on the home page + return st.just("https://hypothesis.works/") + else: + return st.sampled_from([ + l + for l in self.result.html.absolute_links + # Don't try to crawl to other people's sites + if l.startswith("https://hypothesis.works") and + # Avoid Cloudflare's bot protection. We are a bot but we don't + # care about the info it's hiding. + '/cdn-cgi/' not in l + ]) + + def execute_step(self, step): + self.result = self.session.get(step) + + assert self.result.status_code == 200 + + for l in self.result.html.absolute_links: + # All links should be HTTPS + assert "http://hypothesis.works" not in l + + + TestLinks = LinkChecker.TestCase + +Running this (at the time of writing this documentation) produced the following +output: + +:: + + AssertionError: assert 'http://hypothesis.works' not in 'http://hypoth...test-fixtures/' + 'http://hypothesis.works' is contained here: + http://hypothesis.works/articles/hypothesis-pytest-fixtures/ + ? +++++++++++++++++++++++ + + ------------ Hypothesis ------------ + + Step #1: 'https://hypothesis.works/' + Step #2: 'https://hypothesis.works/articles/' + + +------------------------- +More fine grained control +------------------------- + +If you want to bypass the TestCase infrastructure you can invoke these +manually. The stateful module exposes the function run_state_machine_as_test, +which takes an arbitrary function returning a GenericStateMachine and an +optional settings parameter and does the same as the class based runTest +provided. + +In particular this may be useful if you wish to pass parameters to a custom +__init__ in your subclass. diff -Nru python-hypothesis-3.44.1/hypothesis-python/docs/strategies.rst python-hypothesis-3.71.11/hypothesis-python/docs/strategies.rst --- python-hypothesis-3.44.1/hypothesis-python/docs/strategies.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/docs/strategies.rst 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,87 @@ +============================= +Projects extending Hypothesis +============================= + +Hypothesis has been eagerly used and extended by the open source community. +This page lists extensions and applications; you can find more or newer +packages by `searching PyPI `_ or +`libraries.io `_. + +If there's something missing which you think should be here, let us know! + +.. note:: + Being listed on this page does not imply that the Hypothesis + maintainers endorse a package. + +------------------- +External Strategies +------------------- + +Some packages provide strategies directly: + +* :pypi:`hypothesis-fspaths` - strategy to generate filesystem paths. +* :pypi:`hypothesis-geojson` - strategy to generate `GeoJson `_. +* :pypi:`hs-dbus-signature` - strategy to generate arbitrary + `D-Bus signatures `_. +* :pypi:`hypothesis_sqlalchemy` - strategies to generate :pypi:`SQLAlchemy` objects. +* :pypi:`hypothesis-ros` - strategies to generate messages and parameters for the `Robot Operating System `_. +* :pypi:`hypothesis-csv` - strategy to generate CSV files. + +Others provide a function to infer a strategy from some other schema: + +* :pypi:`lollipop-hypothesis` - infer strategies from :pypi:`lollipop` schemas. +* :pypi:`hypothesis-drf` - infer strategies from a :pypi:`djangorestframework` serialiser. +* :pypi:`hypothesis-mongoengine` - infer strategies from a :pypi:`mongoengine` model. +* :pypi:`hypothesis-pb` - infer strategies from `Protocol Buffer + `_ schemas. + + +----------------- +Other Cool Things +----------------- + +:pypi:`swagger-conformance` is powered by Hypothesis and :pypi:`pyswagger`. +Based on a `Swagger specification `_, it can build and +run an entire test suite to check that the implementation matches the spec. +The command-line version can test apps written in any language, simply by +passing the file or URL path to the schema to check! + +`Trio `_ is an async framework with "an obsessive +focus on usability and correctness", so naturally it works with Hypothesis! +:pypi:`pytest-trio` includes :ref:`a custom hook ` +that allows ``@given(...)`` to work with Trio-style async test functions, and +:pypi:`hypothesis-trio` includes stateful testing extensions to support +concurrent programs. + +:pypi:`libarchimedes` makes it easy to use Hypothesis in +`the Hy language `_, a Lisp embedded in Python. + +:pypi:`battle_tested` is a fuzzing tool that will show you how your code can +fail - by trying all kinds of inputs and reporting whatever happens. + +:pypi:`pytest-subtesthack` functions as a workaround for :issue:`377`. + + +-------------------- +Writing an Extension +-------------------- + +*See* :gh-file:`CONTRIBUTING.rst` *for more information.* + +New strategies can be added to Hypothesis, or published as an external package +on PyPI - either is fine for most strategies. If in doubt, ask! + +It's generally much easier to get things working outside, because there's more +freedom to experiment and fewer requirements in stability and API style. We're +happy to review and help with external packages as well as pull requests! + +If you're thinking about writing an extension, please name it +``hypothesis-{something}`` - a standard prefix makes the community more +visible and searching for extensions easier. + +On the other hand, being inside gets you access to some deeper implementation +features (if you need them) and better long-term guarantees about maintenance. +We particularly encourage pull requests for new composable primitives that +make implementing other strategies easier, or for widely used types in the +standard library. Strategies for other things are also welcome; anything with +external dependencies just goes in hypothesis.extra. diff -Nru python-hypothesis-3.44.1/hypothesis-python/docs/supported.rst python-hypothesis-3.71.11/hypothesis-python/docs/supported.rst --- python-hypothesis-3.44.1/hypothesis-python/docs/supported.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/docs/supported.rst 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,98 @@ +============= +Compatibility +============= + +Hypothesis does its level best to be compatible with everything you could +possibly need it to be compatible with. Generally you should just try it and +expect it to work. If it doesn't, you can be surprised and check this document +for the details. + +--------------- +Python versions +--------------- + +Hypothesis is supported and tested on CPython 2.7 and CPython 3.4+. + +Hypothesis also supports PyPy2, and will support PyPy3 when there is a stable +release supporting Python 3.4+. Hypothesis does not currently work on Jython, +though it probably could (:issue:`174`). IronPython might work but hasn't been +tested. 32-bit and narrow builds should work, though this is currently only +tested on Windows. + +In general Hypothesis does not officially support anything except the latest +patch release of any version of Python it supports. Earlier releases should work +and bugs in them will get fixed if reported, but they're not tested in CI and +no guarantees are made. + +----------------- +Operating systems +----------------- + +In theory Hypothesis should work anywhere that Python does. In practice it is +only known to work and regularly tested on OS X, Windows and Linux, and you may +experience issues running it elsewhere. + +If you're using something else and it doesn't work, do get in touch and I'll try +to help, but unless you can come up with a way for me to run a CI server on that +operating system it probably won't stay fixed due to the inevitable march of time. + +------------------ +Testing frameworks +------------------ + +In general Hypothesis goes to quite a lot of effort to generate things that +look like normal Python test functions that behave as closely to the originals +as possible, so it should work sensibly out of the box with every test framework. + +If your testing relies on doing something other than calling a function and seeing +if it raises an exception then it probably *won't* work out of the box. In particular +things like tests which return generators and expect you to do something with them +(e.g. nose's yield based tests) will not work. Use a decorator or similar to wrap the +test to take this form, or ask the framework maintainer to support our +:ref:`hooks for inserting such a wrapper later `. + +In terms of what's actually *known* to work: + + * Hypothesis integrates as smoothly with py.test and unittest as we can make it, + and this is verified as part of the CI. + Note however that :func:`@given ` should only be used on + tests, not :class:`python:unittest.TestCase` setup or teardown methods. + * :pypi:`pytest` fixtures work in the usual way for tests that have been decorated + with :func:`@given ` - just avoid passing a strategy for + each argument that will be supplied by a fixture. However, each fixture + will run once for the whole function, not once per example. Decorating a + fixture function is meaningless. + * Nose works fine with hypothesis, and this is tested as part of the CI. yield based + tests simply won't work. + * Integration with Django's testing requires use of the :ref:`hypothesis-django` package. + The issue is that in Django's tests' normal mode of execution it will reset the + database once per test rather than once per example, which is not what you want. + * Coverage works out of the box with Hypothesis - we use it to guide example + selection for user code, and Hypothesis has 100% branch coverage in its own tests. + +----------------- +Optional Packages +----------------- + +The supported versions of optional packages, for strategies in ``hypothesis.extra``, +are listed in the documentation for that extra. Our general goal is to support +all versions that are supported upstream. + +------------------------ +Regularly verifying this +------------------------ + +Everything mentioned above as explicitly supported is checked on every commit +with `Travis `_, +`Appveyor `_, and +`CircleCI `_. +Our continous delivery pipeline runs all of these checks before publishing +each release, so when we say they're supported we really mean it. + +------------------- +Hypothesis versions +------------------- + +Backwards compatibility is better than backporting fixes, so we use +:ref:`semantic versioning ` and only support the most recent +version of Hypothesis. See :doc:`support` for more information. diff -Nru python-hypothesis-3.44.1/hypothesis-python/docs/support.rst python-hypothesis-3.71.11/hypothesis-python/docs/support.rst --- python-hypothesis-3.44.1/hypothesis-python/docs/support.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/docs/support.rst 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,20 @@ +================ +Help and Support +================ + +For questions you are happy to ask in public, the :doc:`Hypothesis community ` is a +friendly place where I or others will be more than happy to help you out. You're also welcome to +ask questions on Stack Overflow. If you do, please tag them with +`'python-hypothesis' `_ so someone +sees them. + +For bugs and enhancements, please file an issue on the :issue:`GitHub issue tracker <>`. +Note that as per the :doc:`development policy `, enhancements will probably not get +implemented unless you're willing to pay for development or implement them yourself (with assistance from me). Bugs +will tend to get fixed reasonably promptly, though it is of course on a best effort basis. + +To see the versions of Python, optional dependencies, test runners, and operating systems Hypothesis +supports (meaning incompatibility is treated as a bug), see :doc:`supported`. + +If you need to ask questions privately or want more of a guarantee of bugs being fixed promptly, please contact me on +hypothesis-support@drmaciver.com to talk about availability of support contracts. diff -Nru python-hypothesis-3.44.1/hypothesis-python/docs/usage.rst python-hypothesis-3.71.11/hypothesis-python/docs/usage.rst --- python-hypothesis-3.44.1/hypothesis-python/docs/usage.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/docs/usage.rst 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,54 @@ +===================================== +Open Source Projects using Hypothesis +===================================== + +The following is a non-exhaustive list of open source projects I know are +using Hypothesis. If you're aware of any others please add them to the list! +The only inclusion criterion right now is that if it's a Python library +then it should be available on pypi. + +You can find hundreds more from `the Hypothesis page at libraries.io +`_, and over a thousand +`on GitHub `_. + +* `aur `_ +* `argon2_cffi `_ +* `attrs `_ +* `axelrod `_ +* `bidict `_ +* `binaryornot `_ +* `brotlipy `_ +* :pypi:`chardet` +* `cmph-cffi `_ +* `cryptography `_ +* `dbus-signature-pyparsing `_ +* `fastnumbers `_ +* `flocker `_ +* `flownetpy `_ +* `funsize `_ +* `fusion-index `_ +* `hyper-h2 `_ +* `into-dbus-python `_ +* `justbases `_ +* `justbytes `_ +* `loris `_ +* `mariadb-dyncol `_ +* `mercurial `_ +* `natsort `_ +* `pretext `_ +* `priority `_ +* `PyCEbox `_ +* `PyPy `_ +* `pyrsistent `_ +* `python-humble-utils `_ +* `pyudev `_ +* `qutebrowser `_ +* `RubyMarshal `_ +* `Segpy `_ +* `simoa `_ +* `srt `_ +* `tchannel `_ +* `vdirsyncer `_ +* `wcag-contrast-ratio `_ +* `yacluster `_ +* `yturl `_ diff -Nru python-hypothesis-3.44.1/hypothesis-python/examples/README.rst python-hypothesis-3.71.11/hypothesis-python/examples/README.rst --- python-hypothesis-3.44.1/hypothesis-python/examples/README.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/examples/README.rst 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,10 @@ +============================ +Examples of Hypothesis usage +============================ + +This is a directory for examples of using Hypothesis that show case its +features or demonstrate a useful way of testing something. + +Right now it's a bit small and fairly algorithmically focused. Pull requests to +add more examples would be *greatly* appreciated, especially ones using e.g. +the Django integration or testing something "Businessy". diff -Nru python-hypothesis-3.44.1/hypothesis-python/examples/test_binary_search.py python-hypothesis-3.71.11/hypothesis-python/examples/test_binary_search.py --- python-hypothesis-3.44.1/hypothesis-python/examples/test_binary_search.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/examples/test_binary_search.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,138 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +"""This file demonstrates testing a binary search. + +It's a useful example because the result of the binary search is so clearly +determined by the invariants it must satisfy, so we can simply test for those +invariants. + +It also demonstrates the useful testing technique of testing how the answer +should change (or not) in response to movements in the underlying data. +""" + +from __future__ import division, print_function, absolute_import + +import hypothesis.strategies as st +from hypothesis import given + + +def binary_search(ls, v): + """Take a list ls and a value v such that ls is sorted and v is comparable + with the elements of ls. + + Return an index i such that 0 <= i <= len(v) with the properties: + + 1. ls.insert(i, v) is sorted + 2. ls.insert(j, v) is not sorted for j < i + """ + # Without this check we will get an index error on the next line when the + # list is empty. + if not ls: + return 0 + + # Without this check we will miss the case where the insertion point should + # be zero: The invariant we maintain in the next section is that lo is + # always strictly lower than the insertion point. + if v <= ls[0]: + return 0 + + # Invariant: There is no insertion point i with i <= lo + lo = 0 + + # Invariant: There is an insertion point i with i <= hi + hi = len(ls) + while lo + 1 < hi: + mid = (lo + hi) // 2 + if v > ls[mid]: + # Inserting v anywhere below mid would result in an unsorted list + # because it's > the value at mid. Therefore mid is a valid new lo + lo = mid + # Uncommenting the following lines will cause this to return a valid + # insertion point which is not always minimal. + # elif v == ls[mid]: + # return mid + else: + # Either v == ls[mid] in which case mid is a valid insertion point + # or v < ls[mid], in which case all valid insertion points must be + # < hi. Either way, mid is a valid new hi. + hi = mid + assert lo + 1 == hi + # We now know that there is a valid insertion point <= hi and there is no + # valid insertion point < hi because hi - 1 is lo. Therefore hi is the + # answer we were seeking + return hi + + +def is_sorted(ls): + """Is this list sorted?""" + for i in range(len(ls) - 1): + if ls[i] > ls[i + 1]: + return False + return True + + +Values = st.integers() + +# We generate arbitrary lists and turn this into generating sorting lists +# by just sorting them. +SortedLists = st.lists(Values).map(sorted) + +# We could also do it this way, but that would be a bad idea: +# SortedLists = st.lists(Values).filter(is_sorted) +# The problem is that Hypothesis will only generate long sorted lists with very +# low probability, so we are much better off post-processing values into the +# form we want than filtering them out. + + +@given(ls=SortedLists, v=Values) +def test_insert_is_sorted(ls, v): + """We test the first invariant: binary_search should return an index such + that inserting the value provided at that index would result in a sorted + set.""" + ls.insert(binary_search(ls, v), v) + assert is_sorted(ls) + + +@given(ls=SortedLists, v=Values) +def test_is_minimal(ls, v): + """We test the second invariant: binary_search should return an index such + that no smaller index is a valid insertion point for v.""" + for i in range(binary_search(ls, v)): + ls2 = list(ls) + ls2.insert(i, v) + assert not is_sorted(ls2) + + +@given(ls=SortedLists, v=Values) +def test_inserts_into_same_place_twice(ls, v): + """In this we test a *consequence* of the second invariant: When we insert + a value into a list twice, the insertion point should be the same both + times. This is because we know that v is > the previous element and == the + next element. + + In theory if the former passes, this should always pass. In practice, + failures are detected by this test with much higher probability because it + deliberately puts the data into a shape that is likely to trigger a + failure. + + This is an instance of a good general category of test: Testing how the + function moves in responses to changes in the underlying data. + """ + i = binary_search(ls, v) + ls.insert(i, v) + assert binary_search(ls, v) == i diff -Nru python-hypothesis-3.44.1/hypothesis-python/examples/test_rle.py python-hypothesis-3.71.11/hypothesis-python/examples/test_rle.py --- python-hypothesis-3.44.1/hypothesis-python/examples/test_rle.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/examples/test_rle.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,103 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +"""This example demonstrates testing a run length encoding scheme. That is, we +take a sequence and represent it by a shorter sequence where each 'run' of +consecutive equal elements is represented as a single element plus a count. So +e.g. + +[1, 1, 1, 1, 2, 1] is represented as [[1, 4], [2, 1], [1, 1]] + +This demonstrates the useful decode(encode(x)) == x invariant that is often +a fruitful source of testing with Hypothesis. + +It also has an example of testing invariants in response to changes in the +underlying data. +""" + +from __future__ import division, print_function, absolute_import + +import hypothesis.strategies as st +from hypothesis import given, assume + + +def run_length_encode(seq): + """Encode a sequence as a new run-length encoded sequence.""" + if not seq: + return [] + # By starting off the count at zero we simplify the iteration logic + # slightly. + result = [[seq[0], 0]] + for s in seq: + if ( + # If you uncomment this line this branch will be skipped and we'll + # always append a new run of length 1. Note which tests fail. + # False and + s == result[-1][0] + # Try uncommenting this line and see what problems occur: + # and result[-1][-1] < 2 + ): + result[-1][1] += 1 + else: + result.append([s, 1]) + return result + + +def run_length_decode(seq): + """Take a previously encoded sequence and reconstruct the original from + it.""" + result = [] + for s, i in seq: + for _ in range(i): + result.append(s) + return result + + +# We use lists of a type that should have a relatively high duplication rate, +# otherwise we'd almost never get any runs. +Lists = st.lists(st.integers(0, 10)) + + +@given(Lists) +def test_decodes_to_starting_sequence(ls): + """If we encode a sequence and then decode the result, we should get the + original sequence back. + + Otherwise we've done something very wrong. + """ + assert run_length_decode(run_length_encode(ls)) == ls + + +@given(Lists, st.data()) +def test_duplicating_an_element_does_not_increase_length(ls, data): + """The previous test could be passed by simply returning the input sequence + so we need something that tests the compression property of our encoding. + + In this test we deliberately introduce or extend a run and assert + that this does not increase the length of our encoding, because they + should be part of the same run in the final result. + """ + # We use assume to get a valid index into the list. We could also have used + # e.g. flatmap, but this is relatively straightforward and will tend to + # perform better. + assume(ls) + i = data.draw(st.integers(0, len(ls) - 1)) + ls2 = list(ls) + # duplicating the value at i right next to it guarantees they are part of + # the same run in the resulting compression. + ls2.insert(i, ls2[i]) + assert len(run_length_encode(ls2)) == len(run_length_encode(ls)) diff -Nru python-hypothesis-3.44.1/hypothesis-python/LICENSE.txt python-hypothesis-3.71.11/hypothesis-python/LICENSE.txt --- python-hypothesis-3.44.1/hypothesis-python/LICENSE.txt 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/LICENSE.txt 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,382 @@ +Copyright (c) 2013, David R. MacIver + +All code in this repository except where explicitly noted otherwise is released +under the Mozilla Public License v 2.0. You can obtain a copy at http://mozilla.org/MPL/2.0/. + +Some code in this repository comes from other projects. Where applicable, the +original copyright and license are noted and any modifications made are released +dual licensed with the original license. + +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff -Nru python-hypothesis-3.44.1/hypothesis-python/MANIFEST.in python-hypothesis-3.71.11/hypothesis-python/MANIFEST.in --- python-hypothesis-3.44.1/hypothesis-python/MANIFEST.in 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/MANIFEST.in 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,2 @@ +# Include the license file +include LICENSE.txt diff -Nru python-hypothesis-3.44.1/hypothesis-python/README.rst python-hypothesis-3.71.11/hypothesis-python/README.rst --- python-hypothesis-3.44.1/hypothesis-python/README.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/README.rst 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,59 @@ +========== +Hypothesis +========== + +Hypothesis is an advanced testing library for Python. It lets you write tests which +are parametrized by a source of examples, and then generates simple and comprehensible +examples that make your tests fail. This lets you find more bugs in your code with less +work. + +e.g. + +.. code-block:: python + + @given(st.lists( + st.floats(allow_nan=False, allow_infinity=False), min_size=1)) + def test_mean(xs): + assert min(xs) <= mean(xs) <= max(xs) + +.. code-block:: + + Falsifying example: test_mean( + xs=[1.7976321109618856e+308, 6.102390043022755e+303] + ) + +Hypothesis is extremely practical and advances the state of the art of +unit testing by some way. It's easy to use, stable, and powerful. If +you're not using Hypothesis to test your project then you're missing out. + +------------------------ +Quick Start/Installation +------------------------ +If you just want to get started: + +.. code-block:: + + pip install hypothesis + + +----------------- +Links of interest +----------------- + +The main Hypothesis site is at `hypothesis.works `_, and contains a lot +of good introductory and explanatory material. + +Extensive documentation and examples of usage are `available at readthedocs `_. + +If you want to talk to people about using Hypothesis, `we have both an IRC channel +and a mailing list `_. + +If you want to receive occasional updates about Hypothesis, including useful tips and tricks, there's a +`TinyLetter mailing list to sign up for them `_. + +If you want to contribute to Hypothesis, `instructions are here `_. + +If you want to hear from people who are already using Hypothesis, some of them `have written +about it `_. + +If you want to create a downstream package of Hypothesis, please read `these guidelines for packagers `_. diff -Nru python-hypothesis-3.44.1/hypothesis-python/scripts/basic-test.sh python-hypothesis-3.71.11/hypothesis-python/scripts/basic-test.sh --- python-hypothesis-3.44.1/hypothesis-python/scripts/basic-test.sh 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/scripts/basic-test.sh 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,65 @@ +#!/bin/bash +set -e -o xtrace + +HERE="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +cd "$HERE/.." + +python -c ' +import os +for k, v in sorted(dict(os.environ).items()): + print("%s=%s" % (k, v)) +' + +pip install . + + +PYTEST="python -m pytest -n2" + +$PYTEST --runpytest=subprocess tests/pytest + +# Run some tests without docstrings or assertions, to catch bugs +# like issue #822 in one of the test decorators. See also #1541. +PYTHONOPTIMIZE=2 $PYTEST tests/cover/test_testdecorators.py + +pip install ".[pytz, dateutil]" +$PYTEST tests/datetime/ +pip uninstall -y pytz python-dateutil + +if [ "$(python -c 'import sys; print(sys.version_info[0] == 2)')" = "True" ] ; then + $PYTEST "tests/py2" +else + $PYTEST "tests/py3" +fi + +# We run a reduced set of tests on the macOS CI so that it runs in vaguely +# reasonable time. +if [ "$CIRCLECI" = true ]; then + echo Skipping the rest of the test suite on CircleCI. + exit 0 +fi + +if [ "$(python -c 'import sys; print(sys.version_info[:2] in ((2, 7), (3, 6)))')" = "False" ] ; then + exit 0 +fi + +$PYTEST tests/nocover/ + +# fake-factory doesn't have a correct universal wheel +pip install --no-binary :all: faker +$PYTEST tests/fakefactory/ +pip uninstall -y faker + +if [ "$(python -c 'import platform; print(platform.python_implementation())')" != "PyPy" ]; then + pip install .[django] + HYPOTHESIS_DJANGO_USETZ=TRUE python -m tests.django.manage test tests.django + HYPOTHESIS_DJANGO_USETZ=FALSE python -m tests.django.manage test tests.django + pip uninstall -y django pytz + + pip install numpy + $PYTEST tests/numpy + + pip install pandas + $PYTEST tests/pandas + + pip uninstall -y numpy pandas +fi diff -Nru python-hypothesis-3.44.1/hypothesis-python/scripts/unicodechecker.py python-hypothesis-3.71.11/hypothesis-python/scripts/unicodechecker.py --- python-hypothesis-3.44.1/hypothesis-python/scripts/unicodechecker.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/scripts/unicodechecker.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,63 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import os +import sys +import inspect +import warnings +from tempfile import mkdtemp + +import unicodenazi +from hypothesis import settings, unlimited +from hypothesis.errors import HypothesisDeprecationWarning +from hypothesis.configuration import set_hypothesis_home_dir + +warnings.filterwarnings('error', category=UnicodeWarning) +warnings.filterwarnings('error', category=HypothesisDeprecationWarning) +unicodenazi.enable() + + +set_hypothesis_home_dir(mkdtemp()) + +assert isinstance(settings, type) + +settings.register_profile( + 'default', settings(timeout=unlimited) +) +settings.load_profile('default') + + +TESTS = [ + 'test_testdecorators', +] + +sys.path.append(os.path.join('tests', 'cover')) + + +def main(): + for t in TESTS: + module = __import__(t) + for k, v in sorted(module.__dict__.items(), key=lambda x: x[0]): + if k.startswith('test_') and inspect.isfunction(v): + print(k) + v() + + +if __name__ == '__main__': + main() diff -Nru python-hypothesis-3.44.1/hypothesis-python/scripts/validate_branch_check.py python-hypothesis-3.71.11/hypothesis-python/scripts/validate_branch_check.py --- python-hypothesis-3.44.1/hypothesis-python/scripts/validate_branch_check.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/scripts/validate_branch_check.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,64 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import sys +import json +from collections import defaultdict + +if __name__ == '__main__': + with open('branch-check') as i: + data = [ + json.loads(l) for l in i + ] + + checks = defaultdict(set) + + for d in data: + checks[d['name']].add(d['value']) + + always_true = [] + always_false = [] + + for c, vs in sorted(checks.items()): + if len(vs) < 2: + v = list(vs)[0] + assert v in (False, True) + if v: + always_true.append(c) + else: + always_false.append(c) + + failure = always_true or always_false + + if failure: + print('Some branches were not properly covered.') + print() + + if always_true: + print('The following were always True:') + print() + for c in always_true: + print(' * %s' % (c,)) + if always_false: + print('The following were always False:') + print() + for c in always_false: + print(' * %s' % (c,)) + if failure: + sys.exit(1) diff -Nru python-hypothesis-3.44.1/hypothesis-python/setup.cfg python-hypothesis-3.71.11/hypothesis-python/setup.cfg --- python-hypothesis-3.44.1/hypothesis-python/setup.cfg 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/setup.cfg 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,3 @@ +[metadata] +# This includes the license file in the wheel. +license_file = LICENSE.txt diff -Nru python-hypothesis-3.44.1/hypothesis-python/setup.py python-hypothesis-3.71.11/hypothesis-python/setup.py --- python-hypothesis-3.44.1/hypothesis-python/setup.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/setup.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,124 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import os +import sys +import warnings + +import setuptools + + +def local_file(name): + return os.path.relpath(os.path.join(os.path.dirname(__file__), name)) + + +SOURCE = local_file('src') +README = local_file('README.rst') + +setuptools_version = tuple(map(int, setuptools.__version__.split('.')[:2])) + +if setuptools_version < (36, 2): + # Warning only - very bad if uploading bdist but fine if installing sdist. + warnings.warn( + 'This version of setuptools is too old to correctly store ' + 'conditional dependencies in binary wheels. For more info, see: ' + 'https://hynek.me/articles/conditional-python-dependencies/' + ) + + +# Assignment to placate pyflakes. The actual version is from the exec that +# follows. +__version__ = None + +with open(local_file('src/hypothesis/version.py')) as o: + exec(o.read()) + +assert __version__ is not None + + +extras = { + 'datetime': ['pytz>=2014.1'], + 'pytz': ['pytz>=2014.1'], + 'dateutil': ['python-dateutil>=1.4'], + 'fakefactory': ['Faker>=0.7'], + 'numpy': ['numpy>=1.9.0'], + 'pytest': ['pytest>=3.0'], + # We only support Django versions with upstream support - see + # https://www.djangoproject.com/download/#supported-versions + 'django': ['pytz', 'django>=1.11'], +} + +extras['faker'] = extras['fakefactory'] +extras['all'] = sorted(sum(extras.values(), [])) + + +install_requires = ['attrs>=16.0.0'] +# Using an environment marker on enum34 makes the dependency condition +# independent of the build environemnt, which is important for wheels. +# https://www.python.org/dev/peps/pep-0345/#environment-markers +if sys.version_info[0] < 3 and setuptools_version < (8, 0): + # Except really old systems, where we give up and install unconditionally + install_requires.append('enum34') +else: + install_requires.append('enum34; python_version=="2.7"') + + +setuptools.setup( + name='hypothesis', + version=__version__, + author='David R. MacIver', + author_email='david@drmaciver.com', + packages=setuptools.find_packages(SOURCE), + package_dir={'': SOURCE}, + package_data={'hypothesis': ['py.typed']}, + url=( + 'https://github.com/HypothesisWorks/hypothesis/' + 'tree/master/hypothesis-python' + ), + license='MPL v2', + description='A library for property based testing', + zip_safe=False, + extras_require=extras, + install_requires=install_requires, + python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*', + classifiers=[ + 'Development Status :: 5 - Production/Stable', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)', + 'Operating System :: Unix', + 'Operating System :: POSIX', + 'Operating System :: Microsoft :: Windows', + 'Programming Language :: Python', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: Implementation :: CPython', + 'Programming Language :: Python :: Implementation :: PyPy', + 'Topic :: Software Development :: Testing', + 'Framework :: Pytest', + ], + entry_points={ + 'pytest11': ['hypothesispytest = hypothesis.extra.pytestplugin'], + }, + long_description=open(README).read(), + keywords='python testing fuzzing property-based-testing', +) diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/configuration.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/configuration.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/configuration.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/configuration.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,57 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import os + +__hypothesis_home_directory_default = os.path.join(os.getcwd(), '.hypothesis') + +__hypothesis_home_directory = None + + +def set_hypothesis_home_dir(directory): + global __hypothesis_home_directory + __hypothesis_home_directory = directory + + +def mkdir_p(path): + try: + os.makedirs(path) + except OSError: + pass + + +def hypothesis_home_dir(): + global __hypothesis_home_directory + if not __hypothesis_home_directory: + __hypothesis_home_directory = os.getenv( + 'HYPOTHESIS_STORAGE_DIRECTORY') + if not __hypothesis_home_directory: + __hypothesis_home_directory = __hypothesis_home_directory_default + mkdir_p(__hypothesis_home_directory) + return __hypothesis_home_directory + + +def storage_directory(*names): + path = os.path.join(hypothesis_home_dir(), *names) + mkdir_p(path) + return path + + +def tmpdir(): + return storage_directory('tmp') diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/control.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/control.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/control.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/control.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,136 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import traceback + +from hypothesis import Verbosity, settings +from hypothesis.errors import CleanupFailed, InvalidArgument, \ + UnsatisfiedAssumption +from hypothesis.reporting import report +from hypothesis.utils.dynamicvariables import DynamicVariable + +if False: + from typing import Any, AnyStr # noqa + + +def reject(): + raise UnsatisfiedAssumption() + + +def assume(condition): + # type: (Any) -> bool + """Calling ``assume`` is like an :ref:`assert ` that marks + the example as bad, rather than failing the test. + + This allows you to specify properties that you *assume* will be + true, and let Hypothesis try to avoid similar examples in future. + """ + if not condition: + raise UnsatisfiedAssumption() + return True + + +_current_build_context = DynamicVariable(None) + + +def current_build_context(): + context = _current_build_context.value + if context is None: + raise InvalidArgument( + u'No build context registered') + return context + + +class BuildContext(object): + + def __init__(self, data, is_final=False, close_on_capture=True): + self.data = data + self.tasks = [] + self.is_final = is_final + self.close_on_capture = close_on_capture + self.close_on_del = False + self.notes = [] + + def __enter__(self): + self.assign_variable = _current_build_context.with_value(self) + self.assign_variable.__enter__() + return self + + def __exit__(self, exc_type, exc_value, tb): + self.assign_variable.__exit__(exc_type, exc_value, tb) + if self.close() and exc_type is None: + raise CleanupFailed() + + def local(self): + return _current_build_context.with_value(self) + + def close(self): + any_failed = False + for task in self.tasks: + try: + task() + except BaseException: + any_failed = True + report(traceback.format_exc()) + return any_failed + + +def cleanup(teardown): + """Register a function to be called when the current test has finished + executing. Any exceptions thrown in teardown will be printed but not + rethrown. + + Inside a test this isn't very interesting, because you can just use + a finally block, but note that you can use this inside map, flatmap, + etc. in order to e.g. insist that a value is closed at the end. + """ + context = _current_build_context.value + if context is None: + raise InvalidArgument( + u'Cannot register cleanup outside of build context') + context.tasks.append(teardown) + + +def note(value): + # type: (AnyStr) -> None + """Report this value in the final execution.""" + context = _current_build_context.value + if context is None: + raise InvalidArgument( + 'Cannot make notes outside of a test') + context.notes.append(value) + if context.is_final or settings.default.verbosity >= Verbosity.verbose: + report(value) + + +def event(value): + # type: (AnyStr) -> None + """Record an event that occurred this test. Statistics on number of test + runs with each event will be reported at the end if you run Hypothesis in + statistics reporting mode. + + Events should be strings or convertible to them. + """ + context = _current_build_context.value + if context is None: + raise InvalidArgument( + 'Cannot make record events outside of a test') + + if context.data is not None: + context.data.note_event(value) diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/core.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/core.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/core.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/core.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,1051 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +"""This module provides the core primitives of Hypothesis, such as given.""" + + +from __future__ import division, print_function, absolute_import + +import os +import ast +import sys +import zlib +import base64 +import random as rnd_module +import inspect +import warnings +import traceback +import contextlib +from random import Random +from unittest import TestCase + +import attr + +import hypothesis.strategies as st +from hypothesis.errors import Flaky, Timeout, NoSuchExample, \ + Unsatisfiable, DidNotReproduce, InvalidArgument, DeadlineExceeded, \ + MultipleFailures, FailedHealthCheck, HypothesisWarning, \ + UnsatisfiedAssumption, HypothesisDeprecationWarning +from hypothesis.control import BuildContext +from hypothesis.version import __version__ +from hypothesis._settings import Phase, Verbosity, HealthCheck, \ + PrintSettings +from hypothesis._settings import settings as Settings +from hypothesis._settings import local_settings, note_deprecation +from hypothesis.executors import new_style_executor +from hypothesis.reporting import report, verbose_report, current_verbosity +from hypothesis.statistics import note_engine_for_statistics +from hypothesis.internal.compat import ceil, hbytes, qualname, \ + str_to_bytes, benchmark_time, get_type_hints, getfullargspec, \ + int_from_bytes, bad_django_TestCase +from hypothesis.internal.entropy import deterministic_PRNG +from hypothesis.utils.conventions import infer, not_set +from hypothesis.internal.escalation import \ + escalate_hypothesis_internal_error +from hypothesis.internal.reflection import is_mock, proxies, nicerepr, \ + arg_string, impersonate, function_digest, fully_qualified_name, \ + define_function_signature, convert_positional_arguments, \ + get_pretty_function_description +from hypothesis.internal.healthcheck import fail_health_check +from hypothesis.internal.conjecture.data import StopTest, ConjectureData +from hypothesis.searchstrategy.strategies import SearchStrategy +from hypothesis.internal.conjecture.engine import ExitReason, \ + ConjectureRunner, sort_key + +if False: + from typing import ( # noqa + Any, Dict, Callable, Hashable, Optional, Union, TypeVar, + ) + from hypothesis.utils.conventions import InferType # noqa + + TestFunc = TypeVar('TestFunc', bound=Callable) + + +running_under_pytest = False +global_force_seed = None + + +def new_random(): + return rnd_module.Random(rnd_module.getrandbits(128)) + + +@attr.s() +class Example(object): + args = attr.ib() + kwargs = attr.ib() + + +def example(*args, **kwargs): + # type: (*Any, **Any) -> Callable[[TestFunc], TestFunc] + """A decorator which ensures a specific example is always tested.""" + if args and kwargs: + raise InvalidArgument( + 'Cannot mix positional and keyword arguments for examples' + ) + if not (args or kwargs): + raise InvalidArgument( + 'An example must provide at least one argument' + ) + + def accept(test): + if not hasattr(test, 'hypothesis_explicit_examples'): + test.hypothesis_explicit_examples = [] + test.hypothesis_explicit_examples.append(Example(tuple(args), kwargs)) + return test + return accept + + +def seed(seed): + # type: (Hashable) -> Callable[[TestFunc], TestFunc] + """seed: Start the test execution from a specific seed. + + May be any hashable object. No exact meaning for seed is provided + other than that for a fixed seed value Hypothesis will try the same + actions (insofar as it can given external sources of non- + determinism. e.g. timing and hash randomization). + + Overrides the derandomize setting, which is designed to enable + deterministic builds rather than reproducing observed failures. + + """ + def accept(test): + test._hypothesis_internal_use_seed = seed + return test + return accept + + +def reproduce_failure(version, blob): + """Run the example that corresponds to this data blob in order to reproduce + a failure. + + A test with this decorator *always* runs only one example and always fails. + If the provided example does not cause a failure, or is in some way invalid + for this test, then this will fail with a DidNotReproduce error. + + This decorator is not intended to be a permanent addition to your test + suite. It's simply some code you can add to ease reproduction of a problem + in the event that you don't have access to the test database. Because of + this, *no* compatibility guarantees are made between different versions of + Hypothesis - its API may change arbitrarily from version to version. + """ + def accept(test): + test._hypothesis_internal_use_reproduce_failure = (version, blob) + return test + return accept + + +def encode_failure(buffer): + buffer = bytes(buffer) + compressed = zlib.compress(buffer) + if len(compressed) < len(buffer): + buffer = b'\1' + compressed + else: + buffer = b'\0' + buffer + return base64.b64encode(buffer) + + +def decode_failure(blob): + try: + buffer = base64.b64decode(blob) + except Exception: + raise InvalidArgument('Invalid base64 encoded string: %r' % (blob,)) + prefix = buffer[:1] + if prefix == b'\0': + return buffer[1:] + elif prefix == b'\1': + try: + return zlib.decompress(buffer[1:]) + except zlib.error: + raise InvalidArgument( + 'Invalid zlib compression for blob %r' % (blob,) + ) + else: + raise InvalidArgument( + 'Could not decode blob %r: Invalid start byte %r' % ( + blob, prefix + )) + + +class WithRunner(SearchStrategy): + + def __init__(self, base, runner): + assert runner is not None + self.base = base + self.runner = runner + + def do_draw(self, data): + data.hypothesis_runner = self.runner + return self.base.do_draw(data) + + +def is_invalid_test( + name, original_argspec, generator_arguments, generator_kwargs +): + def invalid(message): + def wrapped_test(*arguments, **kwargs): + raise InvalidArgument(message) + return wrapped_test + + if not (generator_arguments or generator_kwargs): + return invalid( + 'given must be called with at least one argument') + + if generator_arguments and any([original_argspec.varargs, + original_argspec.varkw, + original_argspec.kwonlyargs]): + return invalid( + 'positional arguments to @given are not supported with varargs, ' + 'varkeywords, or keyword-only arguments' + ) + + if len(generator_arguments) > len(original_argspec.args): + return invalid(( + 'Too many positional arguments for %s() (got %d but' + ' expected at most %d') % ( + name, len(generator_arguments), + len(original_argspec.args))) + + if infer in generator_arguments: + return invalid('infer was passed as a positional argument to @given, ' + 'but may only be passed as a keyword argument') + + if generator_arguments and generator_kwargs: + return invalid( + 'cannot mix positional and keyword arguments to @given' + ) + extra_kwargs = [ + k for k in generator_kwargs + if k not in original_argspec.args + original_argspec.kwonlyargs + ] + if extra_kwargs and not original_argspec.varkw: + return invalid( + '%s() got an unexpected keyword argument %r' % ( + name, + extra_kwargs[0] + )) + for a in original_argspec.args: + if isinstance(a, list): # pragma: no cover + return invalid(( + 'Cannot decorate function %s() because it has ' + 'destructuring arguments') % ( + name, + )) + if original_argspec.defaults or original_argspec.kwonlydefaults: + return invalid('Cannot apply @given to a function with defaults.') + missing = [repr(kw) for kw in original_argspec.kwonlyargs + if kw not in generator_kwargs] + if missing: + raise InvalidArgument('Missing required kwarg{}: {}'.format( + 's' if len(missing) > 1 else '', ', '.join(missing))) + + +def execute_explicit_examples( + test_runner, test, wrapped_test, settings, arguments, kwargs +): + original_argspec = getfullargspec(test) + + for example in reversed(getattr( + wrapped_test, 'hypothesis_explicit_examples', () + )): + example_kwargs = dict(original_argspec.kwonlydefaults or {}) + if example.args: + if len(example.args) > len(original_argspec.args): + raise InvalidArgument( + 'example has too many arguments for test. ' + 'Expected at most %d but got %d' % ( + len(original_argspec.args), len(example.args))) + example_kwargs.update(dict(zip( + original_argspec.args[-len(example.args):], + example.args + ))) + else: + example_kwargs.update(example.kwargs) + if Phase.explicit not in settings.phases: + continue + example_kwargs.update(kwargs) + # Note: Test may mutate arguments and we can't rerun explicit + # examples, so we have to calculate the failure message at this + # point rather than than later. + example_string = '%s(%s)' % ( + test.__name__, arg_string(test, arguments, example_kwargs) + ) + with local_settings(settings): + try: + with BuildContext(None) as b: + verbose_report('Trying example: ' + example_string) + test_runner( + None, lambda data: test(*arguments, **example_kwargs) + ) + except BaseException: + report('Falsifying example: ' + example_string) + for n in b.notes: + report(n) + raise + + +def get_random_for_wrapped_test(test, wrapped_test): + settings = wrapped_test._hypothesis_internal_use_settings + wrapped_test._hypothesis_internal_use_generated_seed = None + + if wrapped_test._hypothesis_internal_use_seed is not None: + return Random( + wrapped_test._hypothesis_internal_use_seed) + elif settings.derandomize: + return Random(int_from_bytes(function_digest(test))) + elif global_force_seed is not None: + return Random(global_force_seed) + else: + seed = rnd_module.getrandbits(128) + wrapped_test._hypothesis_internal_use_generated_seed = seed + return Random(seed) + + +def process_arguments_to_given( + wrapped_test, arguments, kwargs, generator_arguments, generator_kwargs, + argspec, test, settings +): + selfy = None + arguments, kwargs = convert_positional_arguments( + wrapped_test, arguments, kwargs) + + # If the test function is a method of some kind, the bound object + # will be the first named argument if there are any, otherwise the + # first vararg (if any). + if argspec.args: + selfy = kwargs.get(argspec.args[0]) + elif arguments: + selfy = arguments[0] + + # Ensure that we don't mistake mocks for self here. + # This can cause the mock to be used as the test runner. + if is_mock(selfy): + selfy = None + + test_runner = new_style_executor(selfy) + + arguments = tuple(arguments) + + search_strategy = st.tuples( + st.just(arguments), + st.fixed_dictionaries(generator_kwargs).map( + lambda args: dict(args, **kwargs) + ) + ) + + if selfy is not None: + search_strategy = WithRunner(search_strategy, selfy) + + search_strategy.validate() + + return arguments, kwargs, test_runner, search_strategy + + +def skip_exceptions_to_reraise(): + """Return a tuple of exceptions meaning 'skip this test', to re-raise. + + This is intended to cover most common test runners; if you would + like another to be added please open an issue or pull request. + """ + import unittest + # This is a set because nose may simply re-export unittest.SkipTest + exceptions = set([unittest.SkipTest]) + + try: # pragma: no cover + from unittest2 import SkipTest + exceptions.add(SkipTest) + except ImportError: + pass + + try: # pragma: no cover + from pytest.runner import Skipped + exceptions.add(Skipped) + except ImportError: + pass + + try: # pragma: no cover + from nose import SkipTest as NoseSkipTest + exceptions.add(NoseSkipTest) + except ImportError: + pass + + return tuple(sorted(exceptions, key=str)) + + +EXCEPTIONS_TO_RERAISE = skip_exceptions_to_reraise() + + +def failure_exceptions_to_catch(): + """Return a tuple of exceptions meaning 'this test has failed', to catch. + + This is intended to cover most common test runners; if you would + like another to be added please open an issue or pull request. + """ + exceptions = [Exception] + try: # pragma: no cover + from _pytest.outcomes import Failed + exceptions.append(Failed) + except ImportError: + pass + return tuple(exceptions) + + +EXCEPTIONS_TO_FAIL = failure_exceptions_to_catch() + + +def new_given_argspec(original_argspec, generator_kwargs): + """Make an updated argspec for the wrapped test.""" + new_args = [a for a in original_argspec.args if a not in generator_kwargs] + new_kwonlyargs = [a for a in original_argspec.kwonlyargs + if a not in generator_kwargs] + annots = {k: v for k, v in original_argspec.annotations.items() + if k in new_args + new_kwonlyargs} + annots['return'] = None + return original_argspec._replace( + args=new_args, kwonlyargs=new_kwonlyargs, annotations=annots) + + +ROOT = os.path.dirname(__file__) + +STDLIB = os.path.dirname(os.__file__) + + +class StateForActualGivenExecution(object): + + def __init__( + self, test_runner, search_strategy, test, settings, random, had_seed + ): + self.test_runner = test_runner + self.search_strategy = search_strategy + self.settings = settings + self.last_exception = None + self.falsifying_examples = () + self.__was_flaky = False + self.random = random + self.__warned_deadline = False + self.__test_runtime = None + self.__had_seed = had_seed + + self.test = test + + self.files_to_propagate = set() + self.failed_normally = False + + self.used_examples_from_database = False + + def execute( + self, data, + print_example=False, + is_final=False, + expected_failure=None, collect=False, + ): + text_repr = [None] + if self.settings.deadline is None: + test = self.test + else: + @proxies(self.test) + def test(*args, **kwargs): + self.__test_runtime = None + initial_draws = len(data.draw_times) + start = benchmark_time() + result = self.test(*args, **kwargs) + finish = benchmark_time() + internal_draw_time = sum(data.draw_times[initial_draws:]) + runtime = (finish - start - internal_draw_time) * 1000 + self.__test_runtime = runtime + if self.settings.deadline is not_set: + if ( + not self.__warned_deadline and + runtime >= 200 + ): + self.__warned_deadline = True + note_deprecation(( + 'Test: %s took %.2fms to run. In future the ' + 'default deadline setting will be 200ms, which ' + 'will make this an error. You can set deadline to ' + 'an explicit value of e.g. %d to turn tests ' + 'slower than this into an error, or you can set ' + 'it to None to disable this check entirely.') % ( + self.test.__name__, runtime, + ceil(runtime / 100) * 100, + )) + else: + current_deadline = self.settings.deadline + if not is_final: + current_deadline *= 1.25 + if runtime >= current_deadline: + raise DeadlineExceeded(runtime, self.settings.deadline) + return result + + def run(data): + if not hasattr(data, 'can_reproduce_example_from_repr'): + data.can_reproduce_example_from_repr = True + with local_settings(self.settings): + with BuildContext(data, is_final=is_final): + with deterministic_PRNG(): + args, kwargs = data.draw(self.search_strategy) + if expected_failure is not None: + text_repr[0] = arg_string(test, args, kwargs) + + if print_example: + example = '%s(%s)' % ( + test.__name__, arg_string(test, args, kwargs)) + try: + ast.parse(example) + except SyntaxError: + data.can_reproduce_example_from_repr = False + report('Falsifying example: %s' % (example,)) + elif current_verbosity() >= Verbosity.verbose: + report( + lambda: 'Trying example: %s(%s)' % ( + test.__name__, arg_string(test, args, kwargs))) + + with deterministic_PRNG(): + return test(*args, **kwargs) + + result = self.test_runner(data, run) + if expected_failure is not None: + exception, traceback = expected_failure + if ( + isinstance( + exception, + DeadlineExceeded + ) and self.__test_runtime is not None + ): + report(( + 'Unreliable test timings! On an initial run, this ' + 'test took %.2fms, which exceeded the deadline of ' + '%.2fms, but on a subsequent run it took %.2f ms, ' + 'which did not. If you expect this sort of ' + 'variability in your test timings, consider turning ' + 'deadlines off for this test by setting deadline=None.' + ) % ( + exception.runtime, + self.settings.deadline, self.__test_runtime + )) + else: + report( + 'Failed to reproduce exception. Expected: \n' + + traceback, + ) + self.__flaky(( + 'Hypothesis %s(%s) produces unreliable results: Falsified' + ' on the first call but did not on a subsequent one' + ) % (test.__name__, text_repr[0],)) + return result + + def evaluate_test_data(self, data): + try: + result = self.execute(data) + if result is not None: + fail_health_check(self.settings, ( + 'Tests run under @given should return None, but ' + '%s returned %r instead.' + ) % (self.test.__name__, result), HealthCheck.return_value) + return False + except UnsatisfiedAssumption: + data.mark_invalid() + except ( + HypothesisDeprecationWarning, FailedHealthCheck, + StopTest, + ) + EXCEPTIONS_TO_RERAISE: + raise + except Exception as e: + escalate_hypothesis_internal_error() + data.__expected_traceback = traceback.format_exc() + data.__expected_exception = e + verbose_report(data.__expected_traceback) + + error_class, _, tb = sys.exc_info() + + origin = traceback.extract_tb(tb)[-1] + filename = origin[0] + lineno = origin[1] + data.mark_interesting((error_class, filename, lineno)) + + def run(self): + # Tell pytest to omit the body of this function from tracebacks + __tracebackhide__ = True + if global_force_seed is None: + database_key = str_to_bytes(fully_qualified_name(self.test)) + else: + database_key = None + self.start_time = benchmark_time() + runner = ConjectureRunner( + self.evaluate_test_data, + settings=self.settings, random=self.random, + database_key=database_key, + ) + try: + runner.run() + finally: + self.used_examples_from_database = \ + runner.used_examples_from_database + note_engine_for_statistics(runner) + run_time = benchmark_time() - self.start_time + + self.used_examples_from_database = runner.used_examples_from_database + + if runner.used_examples_from_database: + if self.settings.derandomize: + note_deprecation(( + 'In future derandomize will imply database=None, but your ' + 'test: %s is currently using examples from the database. ' + 'To get the future behaviour, update your settings to ' + 'include database=None.') % (self.test.__name__, ) + ) + if self.__had_seed: + note_deprecation(( + 'In future use of @seed will imply database=None in your ' + 'settings, but your test: %s is currently using examples ' + 'from the database. To get the future behaviour, update ' + 'your settings for this test to include database=None.') + % (self.test.__name__,) + ) + + timed_out = runner.exit_reason == ExitReason.timeout + if runner.call_count == 0: + return + if runner.interesting_examples: + self.falsifying_examples = sorted( + [d for d in runner.interesting_examples.values()], + key=lambda d: sort_key(d.buffer), reverse=True + ) + else: + if runner.valid_examples == 0: + if timed_out: + raise Timeout(( + 'Ran out of time before finding a satisfying ' + 'example for %s. Only found %d examples in %.2fs.' + ) % ( + get_pretty_function_description(self.test), + runner.valid_examples, run_time + )) + else: + raise Unsatisfiable( + 'Unable to satisfy assumptions of hypothesis %s.' % + (get_pretty_function_description(self.test),) + ) + + if not self.falsifying_examples: + return + + self.failed_normally = True + + flaky = 0 + + for falsifying_example in self.falsifying_examples: + ran_example = ConjectureData.for_buffer(falsifying_example.buffer) + self.__was_flaky = False + assert falsifying_example.__expected_exception is not None + try: + self.execute( + ran_example, + print_example=True, is_final=True, + expected_failure=( + falsifying_example.__expected_exception, + falsifying_example.__expected_traceback, + ) + ) + except (UnsatisfiedAssumption, StopTest): + report(traceback.format_exc()) + self.__flaky( + 'Unreliable assumption: An example which satisfied ' + 'assumptions on the first run now fails it.' + ) + except BaseException: + if len(self.falsifying_examples) <= 1: + raise + report(traceback.format_exc()) + finally: # pragma: no cover + # This section is in fact entirely covered by the tests in + # test_reproduce_failure, but it seems to trigger a lovely set + # of coverage bugs: The branches show up as uncovered (despite + # definitely being covered - you can add an assert False else + # branch to verify this and see it fail - and additionally the + # second branch still complains about lack of coverage even if + # you add a pragma: no cover to it! + # See https://bitbucket.org/ned/coveragepy/issues/623/ + if self.settings.print_blob is not PrintSettings.NEVER: + failure_blob = encode_failure(falsifying_example.buffer) + # Have to use the example we actually ran, not the original + # falsifying example! Otherwise we won't catch problems + # where the repr of the generated example doesn't parse. + can_use_repr = ran_example.can_reproduce_example_from_repr + if ( + self.settings.print_blob is PrintSettings.ALWAYS or ( + self.settings.print_blob is PrintSettings.INFER and + self.settings.verbosity >= Verbosity.normal and + not can_use_repr and + len(failure_blob) < 200 + ) + ): + report(( + '\n' + 'You can reproduce this example by temporarily ' + 'adding @reproduce_failure(%r, %r) as a decorator ' + 'on your test case') % ( + __version__, failure_blob,)) + if self.__was_flaky: + flaky += 1 + + # If we only have one example then we should have raised an error or + # flaky prior to this point. + assert len(self.falsifying_examples) > 1 + + if flaky > 0: + raise Flaky(( + 'Hypothesis found %d distinct failures, but %d of them ' + 'exhibited some sort of flaky behaviour.') % ( + len(self.falsifying_examples), flaky)) + else: + raise MultipleFailures(( + 'Hypothesis found %d distinct failures.') % ( + len(self.falsifying_examples,))) + + def __flaky(self, message): + if len(self.falsifying_examples) <= 1: + raise Flaky(message) + else: + self.__was_flaky = True + report('Flaky example! ' + message) + + +@contextlib.contextmanager +def fake_subTest(self, msg=None, **__): + """Monkeypatch for `unittest.TestCase.subTest` during `@given`. + + If we don't patch this out, each failing example is reported as a + seperate failing test by the unittest test runner, which is + obviously incorrect. We therefore replace it for the duration with + this version. + """ + warnings.warn( + 'subTest per-example reporting interacts badly with Hypothesis ' + 'trying hundreds of examples, so we disable it for the duration of ' + 'any test that uses `@given`.', HypothesisWarning, stacklevel=2 + ) + yield + + +@attr.s() +class HypothesisHandle(object): + """This object is provided as the .hypothesis attribute on @given tests. + + Downstream users can reassign its attributes to insert custom logic into + the execution of each case, for example by converting an async into a + sync function. + + This must be an attribute of an attribute, because reassignment of a + first-level attribute would not be visible to Hypothesis if the function + had been decorated before the assignment. + + See https://github.com/HypothesisWorks/hypothesis/issues/1257 for more + information. + """ + + inner_test = attr.ib() + + +def given( + *given_arguments, # type: Union[SearchStrategy, InferType] + **given_kwargs # type: Union[SearchStrategy, InferType] +): + # type: (...) -> Callable[[Callable[..., None]], Callable[..., None]] + """A decorator for turning a test function that accepts arguments into a + randomized test. + + This is the main entry point to Hypothesis. + """ + def run_test_with_generator(test): + if hasattr(test, '_hypothesis_internal_test_function_without_warning'): + # Pull out the original test function to avoid the warning we + # stuck in about using @settings without @given. + test = test._hypothesis_internal_test_function_without_warning + if inspect.isclass(test): + # Provide a meaningful error to users, instead of exceptions from + # internals that assume we're dealing with a function. + raise InvalidArgument('@given cannot be applied to a class.') + generator_arguments = tuple(given_arguments) + generator_kwargs = dict(given_kwargs) + + original_argspec = getfullargspec(test) + + check_invalid = is_invalid_test( + test.__name__, original_argspec, + generator_arguments, generator_kwargs) + + if check_invalid is not None: + return check_invalid + + for name, strategy in zip(reversed(original_argspec.args), + reversed(generator_arguments)): + generator_kwargs[name] = strategy + + argspec = new_given_argspec(original_argspec, generator_kwargs) + + @impersonate(test) + @define_function_signature( + test.__name__, test.__doc__, argspec + ) + def wrapped_test(*arguments, **kwargs): + # Tell pytest to omit the body of this function from tracebacks + __tracebackhide__ = True + + test = wrapped_test.hypothesis.inner_test + + if getattr(test, 'is_hypothesis_test', False): + note_deprecation(( + 'You have applied @given to test: %s more than once. In ' + 'future this will be an error. Applying @given twice ' + 'wraps the test twice, which can be extremely slow. A ' + 'similar effect can be gained by combining the arguments ' + 'of the two calls to given. For example, instead of ' + '@given(booleans()) @given(integers()), you could write ' + '@given(booleans(), integers())') % (test.__name__, ) + ) + + settings = wrapped_test._hypothesis_internal_use_settings + + random = get_random_for_wrapped_test(test, wrapped_test) + + if infer in generator_kwargs.values(): + hints = get_type_hints(test) + for name in [name for name, value in generator_kwargs.items() + if value is infer]: + if name not in hints: + raise InvalidArgument( + 'passed %s=infer for %s, but %s has no type annotation' + % (name, test.__name__, name)) + generator_kwargs[name] = st.from_type(hints[name]) + + processed_args = process_arguments_to_given( + wrapped_test, arguments, kwargs, generator_arguments, + generator_kwargs, argspec, test, settings + ) + arguments, kwargs, test_runner, search_strategy = processed_args + + runner = getattr(search_strategy, 'runner', None) + if isinstance(runner, TestCase) and test.__name__ in dir(TestCase): + msg = ('You have applied @given to the method %s, which is ' + 'used by the unittest runner but is not itself a test.' + ' This is not useful in any way.' % test.__name__) + fail_health_check(settings, msg, HealthCheck.not_a_test_method) + if bad_django_TestCase(runner): # pragma: no cover + # Covered by the Django tests, but not the pytest coverage task + raise InvalidArgument( + 'You have applied @given to a method on %s, but this ' + 'class does not inherit from the supported versions in ' + '`hypothesis.extra.django`. Use the Hypothesis variants ' + 'to ensure that each example is run in a separate ' + 'database transaction.' % qualname(type(runner)) + ) + + state = StateForActualGivenExecution( + test_runner, search_strategy, test, settings, random, + had_seed=wrapped_test._hypothesis_internal_use_seed + ) + + reproduce_failure = \ + wrapped_test._hypothesis_internal_use_reproduce_failure + + if reproduce_failure is not None: + expected_version, failure = reproduce_failure + if expected_version != __version__: + raise InvalidArgument(( + 'Attempting to reproduce a failure from a different ' + 'version of Hypothesis. This failure is from %s, but ' + 'you are currently running %r. Please change your ' + 'Hypothesis version to a matching one.' + ) % (expected_version, __version__)) + try: + state.execute(ConjectureData.for_buffer( + decode_failure(failure)), + print_example=True, is_final=True, + ) + raise DidNotReproduce( + 'Expected the test to raise an error, but it ' + 'completed successfully.' + ) + except StopTest: + raise DidNotReproduce( + 'The shape of the test data has changed in some way ' + 'from where this blob was defined. Are you sure ' + "you're running the same test?" + ) + except UnsatisfiedAssumption: + raise DidNotReproduce( + 'The test data failed to satisfy an assumption in the ' + 'test. Have you added it since this blob was ' + 'generated?' + ) + + execute_explicit_examples( + test_runner, test, wrapped_test, settings, arguments, kwargs + ) + + if settings.max_examples <= 0: + return + + if not ( + Phase.reuse in settings.phases or + Phase.generate in settings.phases + ): + return + + try: + if isinstance(runner, TestCase) and hasattr(runner, 'subTest'): + subTest = runner.subTest + try: + setattr(runner, 'subTest', fake_subTest) + state.run() + finally: + setattr(runner, 'subTest', subTest) + else: + state.run() + except BaseException: + generated_seed = \ + wrapped_test._hypothesis_internal_use_generated_seed + if generated_seed is not None and not state.failed_normally: + with local_settings(settings): + if running_under_pytest: + report( + 'You can add @seed(%(seed)d) to this test or ' + 'run pytest with --hypothesis-seed=%(seed)d ' + 'to reproduce this failure.' % { + 'seed': generated_seed}) + else: + report( + 'You can add @seed(%d) to this test to ' + 'reproduce this failure.' % (generated_seed,)) + raise + + for attrib in dir(test): + if not (attrib.startswith('_') or hasattr(wrapped_test, attrib)): + setattr(wrapped_test, attrib, getattr(test, attrib)) + wrapped_test.is_hypothesis_test = True + if hasattr(test, '_hypothesis_internal_settings_applied'): + # Used to check if @settings is applied twice. + wrapped_test._hypothesis_internal_settings_applied = True + wrapped_test._hypothesis_internal_use_seed = getattr( + test, '_hypothesis_internal_use_seed', None + ) + wrapped_test._hypothesis_internal_use_settings = getattr( + test, '_hypothesis_internal_use_settings', None + ) or Settings.default + wrapped_test._hypothesis_internal_use_reproduce_failure = getattr( + test, '_hypothesis_internal_use_reproduce_failure', None + ) + wrapped_test.hypothesis = HypothesisHandle(test) + return wrapped_test + return run_test_with_generator + + +def find( + specifier, # type: SearchStrategy + condition, # type: Callable[[Any], bool] + settings=None, # type: Settings + random=None, # type: Any + database_key=None, # type: bytes +): + # type: (...) -> Any + """Returns the minimal example from the given strategy ``specifier`` that + matches the predicate function ``condition``.""" + if settings is None: + settings = Settings(max_examples=2000) + settings = Settings(settings, suppress_health_check=HealthCheck.all()) + + if database_key is None and settings.database is not None: + database_key = function_digest(condition) + + if not isinstance(specifier, SearchStrategy): + raise InvalidArgument( + 'Expected SearchStrategy but got %r of type %s' % ( + specifier, type(specifier).__name__ + )) + specifier.validate() + + search = specifier + + random = random or new_random() + successful_examples = [0] + last_data = [None] + last_repr = [None] + + def template_condition(data): + with BuildContext(data): + try: + data.is_find = True + with deterministic_PRNG(): + result = data.draw(search) + data.note(result) + success = condition(result) + except UnsatisfiedAssumption: + data.mark_invalid() + + if success: + successful_examples[0] += 1 + + if settings.verbosity >= Verbosity.verbose: + if not successful_examples[0]: + report( + u'Tried non-satisfying example %s' % (nicerepr(result),)) + elif success: + if successful_examples[0] == 1: + last_repr[0] = nicerepr(result) + report(u'Found satisfying example %s' % (last_repr[0],)) + last_data[0] = data + elif ( + sort_key(hbytes(data.buffer)) < + sort_key(last_data[0].buffer) + ) and nicerepr(result) != last_repr[0]: + last_repr[0] = nicerepr(result) + report(u'Shrunk example to %s' % (last_repr[0],)) + last_data[0] = data + if success and not data.frozen: + data.mark_interesting() + start = benchmark_time() + runner = ConjectureRunner( + template_condition, settings=settings, random=random, + database_key=database_key, + ) + runner.run() + note_engine_for_statistics(runner) + run_time = benchmark_time() - start + if runner.interesting_examples: + data = ConjectureData.for_buffer( + list(runner.interesting_examples.values())[0].buffer) + with BuildContext(data): + with deterministic_PRNG(): + return data.draw(search) + if runner.valid_examples == 0 and ( + runner.exit_reason != ExitReason.finished + ): + if settings.timeout > 0 and run_time > settings.timeout: + raise Timeout(( # pragma: no cover + 'Ran out of time before finding enough valid examples for ' + '%s. Only %d valid examples found in %.2f seconds.' + ) % ( + get_pretty_function_description(condition), + runner.valid_examples, run_time)) + + else: + raise Unsatisfiable( + 'Unable to satisfy assumptions of %s.' % + (get_pretty_function_description(condition),) + ) + + raise NoSuchExample(get_pretty_function_description(condition)) diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/database.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/database.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/database.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/database.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,335 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import os +import re +import binascii +import warnings +import threading +from hashlib import sha1 +from contextlib import contextmanager + +from hypothesis.errors import HypothesisWarning +from hypothesis._settings import note_deprecation +from hypothesis.configuration import storage_directory +from hypothesis.internal.compat import FileNotFoundError, hbytes, \ + b64decode, b64encode +from hypothesis.utils.conventions import not_set + +sqlite3 = None +SQLITE_PATH = re.compile(r"\.\(db|sqlite|sqlite3\)$") + + +def _db_for_path(path=None): + if path is not_set: + path = os.getenv('HYPOTHESIS_DATABASE_FILE') + if path is not None: # pragma: no cover + # Note: we should retain an explicit deprecation warning for a + # further period after this is removed, to ease debugging for + # anyone migrating to a new version. + note_deprecation( + 'The $HYPOTHESIS_DATABASE_FILE environment variable is ' + 'deprecated, and will be ignored by a future version of ' + 'Hypothesis. Configure your database location via a ' + 'settings profile instead.' + ) + return _db_for_path(path) + # Note: storage_directory attempts to create the dir in question, so + # if os.access fails there *must* be a fatal permissions issue. + path = storage_directory('examples') + if os.access(path, os.R_OK | os.W_OK | os.X_OK): + return _db_for_path(path) + else: # pragma: no cover + warnings.warn(HypothesisWarning( + 'The database setting is not configured, and the default ' + 'location is unusable - falling back to an in-memory ' + 'database for this session. path=%r' % (path,) + )) + return InMemoryExampleDatabase() + if path in (None, ':memory:'): + return InMemoryExampleDatabase() + path = str(path) + if os.path.isdir(path): + return DirectoryBasedExampleDatabase(path) + if os.path.exists(path): + return SQLiteExampleDatabase(path) + if SQLITE_PATH.search(path): + return SQLiteExampleDatabase(path) + else: + return DirectoryBasedExampleDatabase(path) + + +class EDMeta(type): + + def __call__(self, *args, **kwargs): + if self is ExampleDatabase: + return _db_for_path(*args, **kwargs) + return super(EDMeta, self).__call__(*args, **kwargs) + + +class ExampleDatabase( + EDMeta('ExampleDatabase', (object,), {}) # type: ignore +): + """Interface class for storage systems. + + A key -> multiple distinct values mapping. + + Keys and values are binary data. + """ + + def save(self, key, value): + """Save ``value`` under ``key``. + + If this value is already present for this key, silently do + nothing + """ + raise NotImplementedError('%s.save' % (type(self).__name__)) + + def delete(self, key, value): + """Remove this value from this key. + + If this value is not present, silently do nothing. + """ + raise NotImplementedError('%s.delete' % (type(self).__name__)) + + def move(self, src, dest, value): + """Move value from key src to key dest. Equivalent to delete(src, + value) followed by save(src, value) but may have a more efficient + implementation. + + Note that value will be inserted at dest regardless of whether + it is currently present at src. + """ + if src == dest: + self.save(src, value) + return + self.delete(src, value) + self.save(dest, value) + + def fetch(self, key): + """Return all values matching this key.""" + raise NotImplementedError('%s.fetch' % (type(self).__name__)) + + def close(self): + """Clear up any resources associated with this database.""" + raise NotImplementedError('%s.close' % (type(self).__name__)) + + +class InMemoryExampleDatabase(ExampleDatabase): + + def __init__(self): + self.data = {} + + def __repr__(self): + return 'InMemoryExampleDatabase(%r)' % (self.data,) + + def fetch(self, key): + for v in self.data.get(key, ()): + yield v + + def save(self, key, value): + self.data.setdefault(key, set()).add(hbytes(value)) + + def delete(self, key, value): + self.data.get(key, set()).discard(hbytes(value)) + + def close(self): + pass + + +class SQLiteExampleDatabase(ExampleDatabase): + + def __init__(self, path=u':memory:'): + self.path = path + self.db_created = False + self.current_connection = threading.local() + global sqlite3 + import sqlite3 + + if path == u':memory:': + note_deprecation( + 'The SQLite database backend has been deprecated. ' + 'Use InMemoryExampleDatabase or set database_file=":memory:" ' + 'instead.' + ) + else: + note_deprecation( + 'The SQLite database backend has been deprecated. ' + 'Set database_file to some path name not ending in .db, ' + '.sqlite or .sqlite3 to get the new directory based database ' + 'backend instead.' + ) + + def connection(self): + if not hasattr(self.current_connection, 'connection'): + self.current_connection.connection = sqlite3.connect(self.path) + return self.current_connection.connection + + def close(self): + if hasattr(self.current_connection, 'connection'): + try: + self.connection().close() + finally: + del self.current_connection.connection + + def __repr__(self): + return u'%s(%s)' % (self.__class__.__name__, self.path) + + @contextmanager + def cursor(self): + conn = self.connection() + cursor = conn.cursor() + try: + try: + yield cursor + finally: + cursor.close() + except BaseException: + conn.rollback() + raise + else: + conn.commit() + + def save(self, key, value): + self.create_db_if_needed() + with self.cursor() as cursor: + try: + cursor.execute(""" + insert into hypothesis_data_mapping(key, value) + values(?, ?) + """, (b64encode(key), b64encode(value))) + except sqlite3.IntegrityError: + pass + + def delete(self, key, value): + self.create_db_if_needed() + with self.cursor() as cursor: + cursor.execute(""" + delete from hypothesis_data_mapping + where key = ? and value = ? + """, (b64encode(key), b64encode(value))) + + def fetch(self, key): + self.create_db_if_needed() + with self.cursor() as cursor: + cursor.execute(""" + select value from hypothesis_data_mapping + where key = ? + """, (b64encode(key),)) + for (value,) in cursor: + try: + yield b64decode(value) + except (binascii.Error, TypeError): + pass + + def create_db_if_needed(self): + if self.db_created: + return + with self.cursor() as cursor: + cursor.execute(""" + create table if not exists hypothesis_data_mapping( + key text, + value text, + unique(key, value) + ) + """) + self.db_created = True + + +def mkdirp(path): + try: + os.makedirs(path) + except OSError: + pass + return path + + +def _hash(key): + return sha1(key).hexdigest()[:16] + + +class DirectoryBasedExampleDatabase(ExampleDatabase): + + def __init__(self, path): + self.path = path + self.keypaths = {} + + def __repr__(self): + return 'DirectoryBasedExampleDatabase(%r)' % (self.path,) + + def close(self): + pass + + def _key_path(self, key): + try: + return self.keypaths[key] + except KeyError: + pass + directory = os.path.join(self.path, _hash(key)) + mkdirp(directory) + self.keypaths[key] = directory + return directory + + def _value_path(self, key, value): + return os.path.join( + self._key_path(key), + sha1(value).hexdigest()[:16] + ) + + def fetch(self, key): + kp = self._key_path(key) + for path in os.listdir(kp): + try: + with open(os.path.join(kp, path), 'rb') as i: + yield hbytes(i.read()) + except FileNotFoundError: + pass + + def save(self, key, value): + path = self._value_path(key, value) + if not os.path.exists(path): + suffix = binascii.hexlify(os.urandom(16)) + if not isinstance(suffix, str): # pragma: no branch + # On Python 3, binascii.hexlify returns bytes + suffix = suffix.decode('ascii') + tmpname = path + '.' + suffix + with open(tmpname, 'wb') as o: + o.write(value) + try: + os.rename(tmpname, path) + except OSError: # pragma: no cover + os.unlink(tmpname) + assert not os.path.exists(tmpname) + + def move(self, src, dest, value): + if src == dest: + self.save(src, value) + return + try: + os.rename( + self._value_path(src, value), self._value_path(dest, value)) + except OSError: + self.delete(src, value) + self.save(dest, value) + + def delete(self, key, value): + try: + os.unlink(self._value_path(key, value)) + except OSError: + pass diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/errors.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/errors.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/errors.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/errors.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,202 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + + +class HypothesisException(Exception): + """Generic parent class for exceptions thrown by Hypothesis.""" + + +class CleanupFailed(HypothesisException): + """At least one cleanup task failed and no other exception was raised.""" + + +class UnsatisfiedAssumption(HypothesisException): + """An internal error raised by assume. + + If you're seeing this error something has gone wrong. + """ + + +class BadTemplateDraw(HypothesisException): + """An internal error raised when something unfortunate happened during + template generation and you should restart the draw, preferably with a new + parameter. + + This is not an error condition internally, but if you ever see this + in your code it's probably a Hypothesis bug + """ + + +class NoSuchExample(HypothesisException): + """The condition we have been asked to satisfy appears to be always false. + + This does not guarantee that no example exists, only that we were + unable to find one. + """ + + def __init__(self, condition_string, extra=''): + super(NoSuchExample, self).__init__( + 'No examples found of condition %s%s' % ( + condition_string, extra) + ) + + +class DefinitelyNoSuchExample(NoSuchExample): # pragma: no cover + """Hypothesis used to be able to detect exhaustive coverage of a search + space and no longer can. + + This exception remains for compatibility reasons for now but can + never actually be thrown. + """ + + +class NoExamples(HypothesisException): + """Raised when example() is called on a strategy but we cannot find any + examples after enough tries that we really should have been able to if this + was ever going to work.""" + + +class Unsatisfiable(HypothesisException): + """We ran out of time or examples before we could find enough examples + which satisfy the assumptions of this hypothesis. + + This could be because the function is too slow. If so, try upping + the timeout. It could also be because the function is using assume + in a way that is too hard to satisfy. If so, try writing a custom + strategy or using a better starting point (e.g if you are requiring + a list has unique values you could instead filter out all duplicate + values from the list) + """ + + +class Flaky(HypothesisException): + """This function appears to fail non-deterministically: We have seen it + fail when passed this example at least once, but a subsequent invocation + did not fail. + + Common causes for this problem are: + 1. The function depends on external state. e.g. it uses an external + random number generator. Try to make a version that passes all the + relevant state in from Hypothesis. + 2. The function is suffering from too much recursion and its failure + depends sensitively on where it's been called from. + 3. The function is timing sensitive and can fail or pass depending on + how long it takes. Try breaking it up into smaller functions which + don't do that and testing those instead. + """ + + +class Timeout(Unsatisfiable): + """We were unable to find enough examples that satisfied the preconditions + of this hypothesis in the amount of time allotted to us.""" + + +class WrongFormat(HypothesisException, ValueError): + """An exception indicating you have attempted to serialize a value that + does not match the type described by this format.""" + + +class BadData(HypothesisException, ValueError): + """The data that we got out of the database does not seem to match the data + we could have put into the database given this schema.""" + + +class InvalidArgument(HypothesisException, TypeError): + """Used to indicate that the arguments to a Hypothesis function were in + some manner incorrect.""" + + +class ResolutionFailed(InvalidArgument): + """Hypothesis had to resolve a type to a strategy, but this failed. + + Type inference is best-effort, so this only happens when an + annotation exists but could not be resolved for a required argument + to the target of ``builds()``, or where the user passed ``infer``. + """ + + +class InvalidState(HypothesisException): + """The system is not in a state where you were allowed to do that.""" + + +class InvalidDefinition(HypothesisException, TypeError): + """Used to indicate that a class definition was not well put together and + has something wrong with it.""" + + +class AbnormalExit(HypothesisException): + """Raised when a test running in a child process exits without returning or + raising an exception.""" + + +class FailedHealthCheck(HypothesisException, Warning): + """Raised when a test fails a preliminary healthcheck that occurs before + execution.""" + + def __init__(self, message, check): + super(FailedHealthCheck, self).__init__(message) + self.health_check = check + + +class HypothesisWarning(HypothesisException, Warning): + """A generic warning issued by Hypothesis.""" + + +class HypothesisDeprecationWarning(HypothesisWarning, FutureWarning): + """A deprecation warning issued by Hypothesis. + + Actually inherits from FutureWarning, because DeprecationWarning is + hidden by the default warnings filter. + + You can configure the Python :mod:`python:warnings` to handle these + warnings differently to others, either turning them into errors or + suppressing them entirely. Obviously we would prefer the former! + """ + + +class Frozen(HypothesisException): + """Raised when a mutation method has been called on a ConjectureData object + after freeze() has been called.""" + + +class MultipleFailures(HypothesisException): + """Indicates that Hypothesis found more than one distinct bug when testing + your code.""" + + +class DeadlineExceeded(HypothesisException): + """Raised when an individual test body has taken too long to run.""" + + def __init__(self, runtime, deadline): + super(DeadlineExceeded, self).__init__(( + 'Test took %.2fms, which exceeds the deadline of ' + '%.2fms') % (runtime, deadline)) + self.runtime = runtime + self.deadline = deadline + + +class StopTest(BaseException): + + def __init__(self, testcounter): + super(StopTest, self).__init__(repr(testcounter)) + self.testcounter = testcounter + + +class DidNotReproduce(HypothesisException): + pass diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/executors.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/executors.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/executors.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/executors.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,79 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + + +def default_executor(function): # pragma: nocover + raise NotImplementedError() # We don't actually use this any more + + +def setup_teardown_executor(setup, teardown): + setup = setup or (lambda: None) + teardown = teardown or (lambda ex: None) + + def execute(function): + token = None + try: + token = setup() + return function() + finally: + teardown(token) + return execute + + +def executor(runner): + try: + return runner.execute_example + except AttributeError: + pass + + if ( + hasattr(runner, 'setup_example') or + hasattr(runner, 'teardown_example') + ): + return setup_teardown_executor( + getattr(runner, 'setup_example', None), + getattr(runner, 'teardown_example', None), + ) + + return default_executor + + +def default_new_style_executor(data, function): + return function(data) + + +class ConjectureRunner(object): + + def hypothesis_execute_example_with_data(self, data, function): + return function(data) + + +def new_style_executor(runner): + if runner is None: + return default_new_style_executor + if isinstance(runner, ConjectureRunner): + return runner.hypothesis_execute_example_with_data + + old_school = executor(runner) + if old_school is default_executor: + return default_new_style_executor + else: + return lambda data, function: old_school( + lambda: function(data) + ) diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/extra/datetime.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/extra/datetime.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/extra/datetime.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/extra/datetime.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,112 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +"""This module provides deprecated time and date related strategies. + +It depends on the ``pytz`` package, which is stable enough that almost any +version should be compatible - most updates are for the timezone database. +""" + +from __future__ import division, print_function, absolute_import + +import datetime as dt + +import pytz + +import hypothesis.strategies as st +from hypothesis.errors import InvalidArgument +from hypothesis._settings import note_deprecation +from hypothesis.extra.pytz import timezones as timezones_strategy + +__all__ = ['datetimes', 'dates', 'times'] + + +def tz_args_strat(allow_naive, tz_list, name): + if tz_list is None: + tz_strat = timezones_strategy() + else: + tz_strat = st.sampled_from([ + tz if isinstance(tz, dt.tzinfo) else pytz.timezone(tz) + for tz in tz_list + ]) + if allow_naive or (allow_naive is None and tz_strat.is_empty): + tz_strat = st.none() | tz_strat + if tz_strat.is_empty: + raise InvalidArgument( + 'Cannot create non-naive %s with no timezones allowed.' % name) + return tz_strat + + +def convert_year_bound(val, default): + if val is None: + return default + try: + return default.replace(val) + except ValueError: + raise InvalidArgument('Invalid year=%r' % (val,)) + + +@st.defines_strategy +def datetimes(allow_naive=None, timezones=None, min_year=None, max_year=None): + """Return a strategy for generating datetimes. + + .. deprecated:: 3.9.0 + use :py:func:`hypothesis.strategies.datetimes` instead. + + allow_naive=True will cause the values to sometimes be naive. + timezones is the set of permissible timezones. If set to an empty + collection all datetimes will be naive. If set to None all timezones + available via pytz will be used. + + All generated datetimes will be between min_year and max_year, inclusive. + """ + note_deprecation('Use hypothesis.strategies.datetimes, which supports ' + 'full-precision bounds and has a simpler API.') + min_dt = convert_year_bound(min_year, dt.datetime.min) + max_dt = convert_year_bound(max_year, dt.datetime.max) + tzs = tz_args_strat(allow_naive, timezones, 'datetimes') + return st.datetimes(min_dt, max_dt, tzs) + + +@st.defines_strategy +def dates(min_year=None, max_year=None): + """Return a strategy for generating dates. + + .. deprecated:: 3.9.0 + use :py:func:`hypothesis.strategies.dates` instead. + + All generated dates will be between min_year and max_year, inclusive. + """ + note_deprecation('Use hypothesis.strategies.dates, which supports bounds ' + 'given as date objects for single-day resolution.') + return st.dates(convert_year_bound(min_year, dt.date.min), + convert_year_bound(max_year, dt.date.max)) + + +@st.defines_strategy +def times(allow_naive=None, timezones=None): + """Return a strategy for generating times. + + .. deprecated:: 3.9.0 + use :py:func:`hypothesis.strategies.times` instead. + + The allow_naive and timezones arguments act the same as the datetimes + strategy above. + """ + note_deprecation('Use hypothesis.strategies.times, which supports ' + 'min_time and max_time arguments.') + return st.times(timezones=tz_args_strat(allow_naive, timezones, 'times')) diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/extra/dateutil.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/extra/dateutil.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/extra/dateutil.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/extra/dateutil.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,58 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +"""This module provides ``dateutil`` timezones. + +You can use this strategy to make +:py:func:`hypothesis.strategies.datetimes` and +:py:func:`hypothesis.strategies.times` produce timezone-aware values. +""" + +from __future__ import division, print_function, absolute_import + +import datetime as dt + +from dateutil import tz, zoneinfo # type: ignore + +import hypothesis.strategies as st + +__all__ = ['timezones'] + + +@st.cacheable +@st.defines_strategy +def timezones(): + # type: () -> st.SearchStrategy[dt.tzinfo] + """Any timezone in dateutil. + + This strategy minimises to UTC, or the timezone with the smallest offset + from UTC as of 2000-01-01, and is designed for use with + :py:func:`~hypothesis.strategies.datetimes`. + + Note that the timezones generated by the strategy may vary depending on the + configuration of your machine. See the dateutil documentation for more + information. + """ + reference_date = dt.datetime(2000, 1, 1) + tz_names = zoneinfo.get_zonefile_instance().zones + + all_timezones = [tz.UTC] # type: ignore + all_timezones += sorted( + [tz.gettz(t) for t in tz_names], + key=lambda zone: abs(zone.utcoffset(reference_date)) + ) + return st.sampled_from(all_timezones) diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/extra/django/__init__.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/extra/django/__init__.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/extra/django/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/extra/django/__init__.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,44 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +import unittest + +import django.test as dt + + +class HypothesisTestCase(object): + + def setup_example(self): + self._pre_setup() + + def teardown_example(self, example): + self._post_teardown() + + def __call__(self, result=None): + testMethod = getattr(self, self._testMethodName) + if getattr(testMethod, u'is_hypothesis_test', False): + return unittest.TestCase.__call__(self, result) + else: + return dt.SimpleTestCase.__call__(self, result) + + +class TestCase(HypothesisTestCase, dt.TestCase): + pass + + +class TransactionTestCase(HypothesisTestCase, dt.TransactionTestCase): + pass diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/extra/django/models.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/extra/django/models.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/extra/django/models.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/extra/django/models.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,240 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import re +import string +from decimal import Decimal +from datetime import timedelta + +import django.db.models as dm +from django.db import IntegrityError +from django.conf import settings as django_settings +from django.core import validators +from django.core.exceptions import ValidationError + +import hypothesis.strategies as st +from hypothesis import reject +from hypothesis.errors import InvalidArgument +from hypothesis.extra.pytz import timezones +from hypothesis.strategies import emails +from hypothesis.provisional import ip4_addr_strings, ip6_addr_strings +from hypothesis.utils.conventions import DefaultValueType + +if False: + from datetime import tzinfo # noqa + from typing import Any, Type, Optional, List, Text, Callable, Union # noqa + + +def get_tz_strat(): + # type: () -> st.SearchStrategy[Optional[tzinfo]] + if getattr(django_settings, 'USE_TZ', False): + return timezones() + return st.none() + + +__default_field_mappings = None + + +def field_mappings(): + global __default_field_mappings + + if __default_field_mappings is None: + # Sized fields are handled in _get_strategy_for_field() + # URL fields are not yet handled + __default_field_mappings = { + dm.SmallIntegerField: st.integers(-32768, 32767), + dm.IntegerField: st.integers(-2147483648, 2147483647), + dm.BigIntegerField: + st.integers(-9223372036854775808, 9223372036854775807), + dm.PositiveIntegerField: st.integers(0, 2147483647), + dm.PositiveSmallIntegerField: st.integers(0, 32767), + dm.BinaryField: st.binary(), + dm.BooleanField: st.booleans(), + dm.DateField: st.dates(), + dm.DateTimeField: st.datetimes(timezones=get_tz_strat()), + dm.DurationField: st.timedeltas(), + dm.EmailField: emails(), + dm.FloatField: st.floats(), + dm.NullBooleanField: st.one_of(st.none(), st.booleans()), + dm.TimeField: st.times(timezones=get_tz_strat()), + dm.UUIDField: st.uuids(), + } + + # SQLite does not support timezone-aware times, or timedeltas that + # don't fit in six bytes of microseconds, so we override those + db = getattr(django_settings, 'DATABASES', {}).get('default', {}) + if db.get('ENGINE', '').endswith('.sqlite3'): # pragma: no branch + sqlite_delta = timedelta(microseconds=2 ** 47 - 1) + __default_field_mappings.update({ + dm.TimeField: st.times(), + dm.DurationField: st.timedeltas(-sqlite_delta, sqlite_delta), + }) + + return __default_field_mappings + + +def add_default_field_mapping(field_type, strategy): + # type: (Type[dm.Field], st.SearchStrategy[Any]) -> None + field_mappings()[field_type] = strategy + + +default_value = DefaultValueType(u'default_value') + + +def validator_to_filter(f): + # type: (Type[dm.Field]) -> Callable[[Any], bool] + """Converts the field run_validators method to something suitable for use + in filter.""" + def validate(value): + try: + f.run_validators(value) + return True + except ValidationError: + return False + + return validate + + +def _get_strategy_for_field(f): + # type: (Type[dm.Field]) -> st.SearchStrategy[Any] + if f.choices: + choices = [] # type: list + for value, name_or_optgroup in f.choices: + if isinstance(name_or_optgroup, (list, tuple)): + choices.extend(key for key, _ in name_or_optgroup) + else: + choices.append(value) + if isinstance(f, (dm.CharField, dm.TextField)) and f.blank: + choices.insert(0, u'') + strategy = st.sampled_from(choices) + elif type(f) == dm.SlugField: + strategy = st.text(alphabet=string.ascii_letters + string.digits, + min_size=(None if f.blank else 1), + max_size=f.max_length) + elif type(f) == dm.GenericIPAddressField: + lookup = {'both': ip4_addr_strings() | ip6_addr_strings(), + 'ipv4': ip4_addr_strings(), 'ipv6': ip6_addr_strings()} + strategy = lookup[f.protocol.lower()] + elif type(f) in (dm.TextField, dm.CharField): + strategy = st.text( + alphabet=st.characters(blacklist_characters=u'\x00', + blacklist_categories=('Cs',)), + min_size=(None if f.blank else 1), + max_size=f.max_length, + ) + # We can infer a vastly more precise strategy by considering the + # validators as well as the field type. This is a minimal proof of + # concept, but we intend to leverage the idea much more heavily soon. + # See https://github.com/HypothesisWorks/hypothesis-python/issues/1116 + re_validators = [ + v for v in f.validators + if isinstance(v, validators.RegexValidator) and not v.inverse_match + ] + if re_validators: + regexes = [re.compile(v.regex, v.flags) if isinstance(v.regex, str) + else v.regex for v in re_validators] + # This strategy generates according to one of the regexes, and + # filters using the others. It can therefore learn to generate + # from the most restrictive and filter with permissive patterns. + # Not maximally efficient, but it makes pathological cases rarer. + # If you want a challenge: extend https://qntm.org/greenery to + # compute intersections of the full Python regex language. + strategy = st.one_of(*[st.from_regex(r) for r in regexes]) + elif type(f) == dm.DecimalField: + bound = Decimal(10 ** f.max_digits - 1) / (10 ** f.decimal_places) + strategy = st.decimals(min_value=-bound, max_value=bound, + places=f.decimal_places) + else: + strategy = field_mappings().get(type(f), st.nothing()) + if f.validators: + strategy = strategy.filter(validator_to_filter(f)) + if f.null: + strategy = st.one_of(st.none(), strategy) + return strategy + + +def models( + model, # type: Type[dm.Model] + **field_strategies # type: Union[st.SearchStrategy[Any], DefaultValueType] +): + # type: (...) -> st.SearchStrategy[Any] + """Return a strategy for examples of ``model``. + + .. warning:: + Hypothesis creates saved models. This will run inside your testing + transaction when using the test runner, but if you use the dev console + this will leave debris in your database. + + ``model`` must be an subclass of :class:`~django:django.db.models.Model`. + Strategies for fields may be passed as keyword arguments, for example + ``is_staff=st.just(False)``. + + Hypothesis can often infer a strategy based the field type and validators + - for best results, make sure your validators are derived from Django's + and therefore have the known types and attributes. + Passing a keyword argument skips inference for that field; pass a strategy + or pass ``hypothesis.extra.django.models.default_value`` to skip + inference for that field. + + Foreign keys are not automatically derived. If they're nullable they will + default to always being null, otherwise you always have to specify them. + For example, examples of a Shop type with a foreign key to Company could + be generated with:: + + shop_strategy = models(Shop, company=models(Company)) + """ + result = {} + for k, v in field_strategies.items(): + if not isinstance(v, DefaultValueType): + result[k] = v + missed = [] # type: List[Text] + for f in model._meta.concrete_fields: + if not (f.name in field_strategies or isinstance(f, dm.AutoField)): + result[f.name] = _get_strategy_for_field(f) + if result[f.name].is_empty: + missed.append(f.name) + if missed: + raise InvalidArgument( + u'Missing arguments for mandatory field%s %s for model %s' + % (u's' if missed else u'', u', '.join(missed), model.__name__)) + + for field in result: + if model._meta.get_field(field).primary_key: + # The primary key is generated as part of the strategy. We + # want to find any existing row with this primary key and + # overwrite its contents. + kwargs = {field: result.pop(field)} + kwargs['defaults'] = st.fixed_dictionaries(result) + return _models_impl( + st.builds(model.objects.update_or_create, **kwargs) + ) + + # The primary key is not generated as part of the strategy, so we + # just match against any row that has the same value for all + # fields. + return _models_impl(st.builds(model.objects.get_or_create, **result)) + + +@st.composite +def _models_impl(draw, strat): + """Handle the nasty part of drawing a value for models()""" + try: + return draw(strat)[0] + except IntegrityError: + reject() diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/extra/fakefactory.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/extra/fakefactory.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/extra/fakefactory.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/extra/fakefactory.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,105 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import random as globalrandom +from random import Random + +import faker +from faker.factory import AVAILABLE_LOCALES + +from hypothesis._settings import note_deprecation +from hypothesis.internal.compat import text_type +from hypothesis.internal.reflection import check_valid_identifier +from hypothesis.searchstrategy.strategies import SearchStrategy + + +def fake_factory(source, locale=None, locales=None, providers=()): + note_deprecation( + 'hypothesis.extra.fakefactory has been deprecated, because it does ' + 'not support example discovery or shrinking. Consider using a lower-' + 'level strategy (such as st.text()) instead.' + ) + check_valid_identifier(source) + if source[0] == u'_': + raise ValueError(u'Bad source name %s' % (source,)) + + if locale is not None and locales is not None: + raise ValueError(u'Cannot specify both single and multiple locales') + if locale: + locales = (locale,) + elif locales: + locales = tuple(locales) + else: + locales = None + for l in (locales or ()): + if l not in AVAILABLE_LOCALES: + raise ValueError(u'Unsupported locale %r' % (l,)) + + def supports_source(locale): + test_faker = faker.Faker(locale) + for provider in providers: + test_faker.add_provider(provider) + return hasattr(test_faker, source) + + if locales is None: + locales = list(filter(supports_source, AVAILABLE_LOCALES)) + if not locales: + raise ValueError(u'No such source %r' % (source,)) + else: + for l in locales: + if not supports_source(locale): + raise ValueError(u'Unsupported source %s for locale %s' % ( + source, l + )) + return FakeFactoryStrategy(source, providers, locales) + + +class FakeFactoryStrategy(SearchStrategy): + + def __init__(self, source, providers, locales): + self.source = source + self.providers = tuple(providers) + self.locales = tuple(locales) + self.factories = {} + + def do_draw(self, data): + seed = data.draw_bytes(4) + random = Random(bytes(seed)) + return self.gen_example(random) + + def factory_for(self, locale): + try: + return self.factories[locale] + except KeyError: + pass + factory = faker.Faker(locale=locale) + self.factories[locale] = factory + for p in self.providers: + factory.add_provider(p) + return factory + + def gen_example(self, random): + factory = self.factory_for(random.choice(self.locales)) + original = globalrandom.getstate() + seed = random.getrandbits(128) + try: + factory.seed(seed) + return text_type(getattr(factory, self.source)()) + finally: + globalrandom.setstate(original) diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/extra/__init__.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/extra/__init__.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/extra/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/extra/__init__.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,16 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/extra/numpy.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/extra/numpy.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/extra/numpy.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/extra/numpy.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,588 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import math + +import numpy as np + +import hypothesis.strategies as st +import hypothesis.internal.conjecture.utils as cu +from hypothesis import Verbosity +from hypothesis.errors import InvalidArgument +from hypothesis._settings import note_deprecation +from hypothesis.reporting import current_verbosity +from hypothesis.searchstrategy import SearchStrategy +from hypothesis.internal.compat import hrange, text_type +from hypothesis.internal.coverage import check_function +from hypothesis.internal.reflection import proxies +from hypothesis.internal.validation import check_type + +if False: + from typing import Any, Union, Sequence, Tuple # noqa + from hypothesis.searchstrategy.strategies import T # noqa + +TIME_RESOLUTIONS = tuple('Y M D h m s ms us ns ps fs as'.split()) + + +@st.defines_strategy_with_reusable_values +def from_dtype(dtype): + # type: (np.dtype) -> st.SearchStrategy[Any] + """Creates a strategy which can generate any value of the given dtype.""" + check_type(np.dtype, dtype, 'dtype') + # Compound datatypes, eg 'f4,f4,f4' + if dtype.names is not None: + # mapping np.void.type over a strategy is nonsense, so return now. + return st.tuples( + *[from_dtype(dtype.fields[name][0]) for name in dtype.names]) + + # Subarray datatypes, eg '(2, 3)i4' + if dtype.subdtype is not None: + subtype, shape = dtype.subdtype + return arrays(subtype, shape) + + # Scalar datatypes + if dtype.kind == u'b': + result = st.booleans() # type: SearchStrategy[Any] + elif dtype.kind == u'f': + if dtype.itemsize == 2: + result = st.floats(width=16) + elif dtype.itemsize == 4: + result = st.floats(width=32) + else: + result = st.floats() + elif dtype.kind == u'c': + if dtype.itemsize == 8: + float32 = st.floats(width=32) + result = st.builds(complex, float32, float32) + else: + result = st.complex_numbers() + elif dtype.kind in (u'S', u'a'): + # Numpy strings are null-terminated; only allow round-trippable values. + # `itemsize == 0` means 'fixed length determined at array creation' + result = st.binary(max_size=dtype.itemsize or None + ).filter(lambda b: b[-1:] != b'\0') + elif dtype.kind == u'u': + result = st.integers(min_value=0, + max_value=2 ** (8 * dtype.itemsize) - 1) + elif dtype.kind == u'i': + overflow = 2 ** (8 * dtype.itemsize - 1) + result = st.integers(min_value=-overflow, max_value=overflow - 1) + elif dtype.kind == u'U': + # Encoded in UTF-32 (four bytes/codepoint) and null-terminated + result = st.text(max_size=(dtype.itemsize or 0) // 4 or None + ).filter(lambda b: b[-1:] != u'\0') + elif dtype.kind in (u'm', u'M'): + if '[' in dtype.str: + res = st.just(dtype.str.split('[')[-1][:-1]) + else: + res = st.sampled_from(TIME_RESOLUTIONS) + result = st.builds(dtype.type, st.integers(-2**63, 2**63 - 1), res) + else: + raise InvalidArgument(u'No strategy inference for {}'.format(dtype)) + return result.map(dtype.type) + + +@check_function +def check_argument(condition, fail_message, *f_args, **f_kwargs): + if not condition: + raise InvalidArgument(fail_message.format(*f_args, **f_kwargs)) + + +@check_function +def order_check(name, floor, small, large): + check_argument( + floor <= small, u'min_{name} must be at least {} but was {}', + floor, small, name=name + ) + check_argument( + small <= large, u'min_{name}={} is larger than max_{name}={}', + small, large, name=name + ) + + +class ArrayStrategy(SearchStrategy): + + def __init__(self, element_strategy, shape, dtype, fill, unique): + self.shape = tuple(shape) + self.fill = fill + check_argument(shape, + u'Array shape must have at least one dimension, ' + u'provided shape was {}', shape) + check_argument(all(isinstance(s, int) for s in shape), + u'Array shape must be integer in each dimension, ' + u'provided shape was {}', shape) + self.array_size = int(np.prod(shape)) + self.dtype = dtype + self.element_strategy = element_strategy + self.unique = unique + + # Used by self.insert_element to check that the value can be stored + # in the array without e.g. overflowing. See issue #1385. + if dtype.kind in (u'i', u'u'): + self.check_cast = lambda x: np.can_cast(x, self.dtype, 'safe') + elif dtype.kind == u'f' and dtype.itemsize == 2: + max_f2 = (2. - 2 ** -10) * 2 ** 15 + self.check_cast = lambda x: \ + (not np.isfinite(x)) or (-max_f2 <= x <= max_f2) + elif dtype.kind == u'f' and dtype.itemsize == 4: + max_f4 = (2. - 2 ** -23) * 2 ** 127 + self.check_cast = lambda x: \ + (not np.isfinite(x)) or (-max_f4 <= x <= max_f4) + else: + self.check_cast = lambda x: True + + def set_element(self, data, result, idx, strategy=None): + strategy = strategy or self.element_strategy + val = data.draw(strategy) + if self._report_overflow and not self.check_cast(val): + note_deprecation( + 'Generated array element %r from %r cannot be represented as ' + 'dtype %r without overflow or underflow. Consider using a ' + 'more precise strategy, as this will be an error in a future ' + 'version of Hypothesis.' % (val, strategy, self.dtype) + ) + # Because the message includes the value of the generated element, + # it would be easy to spam users with thousands of warnings. + # We therefore only warn once per draw, unless in verbose mode. + self._report_overflow = current_verbosity() >= Verbosity.verbose + result[idx] = val + + def do_draw(self, data): + if 0 in self.shape: + return np.zeros(dtype=self.dtype, shape=self.shape) + + # Reset this flag for each test case to emit warnings from set_element + self._report_overflow = True + + # This could legitimately be a np.empty, but the performance gains for + # that would be so marginal that there's really not much point risking + # undefined behaviour shenanigans. + result = np.zeros(shape=self.array_size, dtype=self.dtype) + + if self.fill.is_empty: + # We have no fill value (either because the user explicitly + # disabled it or because the default behaviour was used and our + # elements strategy does not produce reusable values), so we must + # generate a fully dense array with a freshly drawn value for each + # entry. + if self.unique: + seen = set() + elements = cu.many( + data, + min_size=self.array_size, max_size=self.array_size, + average_size=self.array_size + ) + i = 0 + while elements.more(): + # We assign first because this means we check for + # uniqueness after numpy has converted it to the relevant + # type for us. Because we don't increment the counter on + # a duplicate we will overwrite it on the next draw. + self.set_element(data, result, i) + if result[i] not in seen: + seen.add(result[i]) + i += 1 + else: + elements.reject() + else: + for i in hrange(len(result)): + self.set_element(data, result, i) + else: + # We draw numpy arrays as "sparse with an offset". We draw a + # collection of index assignments within the array and assign + # fresh values from our elements strategy to those indices. If at + # the end we have not assigned every element then we draw a single + # value from our fill strategy and use that to populate the + # remaining positions with that strategy. + + elements = cu.many( + data, + min_size=0, max_size=self.array_size, + # sqrt isn't chosen for any particularly principled reason. It + # just grows reasonably quickly but sublinearly, and for small + # arrays it represents a decent fraction of the array size. + average_size=math.sqrt(self.array_size), + ) + + needs_fill = np.full(self.array_size, True) + seen = set() + + while elements.more(): + i = cu.integer_range(data, 0, self.array_size - 1) + if not needs_fill[i]: + elements.reject() + continue + self.set_element(data, result, i) + if self.unique: + if result[i] in seen: + elements.reject() + continue + else: + seen.add(result[i]) + needs_fill[i] = False + if needs_fill.any(): + # We didn't fill all of the indices in the early loop, so we + # put a fill value into the rest. + + # We have to do this hilarious little song and dance to work + # around numpy's special handling of iterable values. If the + # value here were e.g. a tuple then neither array creation + # nor putmask would do the right thing. But by creating an + # array of size one and then assigning the fill value as a + # single element, we both get an array with the right value in + # it and putmask will do the right thing by repeating the + # values of the array across the mask. + one_element = np.zeros(shape=1, dtype=self.dtype) + self.set_element(data, one_element, 0, self.fill) + fill_value = one_element[0] + if self.unique: + try: + is_nan = np.isnan(fill_value) + except TypeError: + is_nan = False + + if not is_nan: + raise InvalidArgument( + 'Cannot fill unique array with non-NaN ' + 'value %r' % (fill_value,)) + + np.putmask(result, needs_fill, one_element) + + return result.reshape(self.shape) + + +@check_function +def fill_for(elements, unique, fill, name=''): + if fill is None: + if unique or not elements.has_reusable_values: + fill = st.nothing() + else: + fill = elements + else: + st.check_strategy(fill, '%s.fill' % (name,) if name else 'fill') + return fill + + +@st.composite +def arrays( + draw, # type: Any + dtype, # type: Any + shape, # type: Union[int, Sequence[int]] + elements=None, # type: st.SearchStrategy[Any] + fill=None, # type: st.SearchStrategy[Any] + unique=False, # type: bool +): + # type: (...) -> st.SearchStrategy[np.ndarray] + r"""Returns a strategy for generating :class:`numpy:numpy.ndarray`\ s. + + * ``dtype`` may be any valid input to + :class:`numpy.dtype ` (this includes + :class:`~numpy:numpy.dtype` objects), or a strategy that generates such + values. + * ``shape`` may be an integer >= 0, a tuple of length >= 0 of such + integers, or a strategy that generates such values. + * ``elements`` is a strategy for generating values to put in the array. + If it is None a suitable value will be inferred based on the dtype, + which may give any legal value (including eg ``NaN`` for floats). + If you have more specific requirements, you should supply your own + elements strategy. + * ``fill`` is a strategy that may be used to generate a single background + value for the array. If None, a suitable default will be inferred + based on the other arguments. If set to + :func:`~hypothesis.strategies.nothing` then filling + behaviour will be disabled entirely and every element will be generated + independently. + * ``unique`` specifies if the elements of the array should all be + distinct from one another. Note that in this case multiple NaN values + may still be allowed. If fill is also set, the only valid values for + it to return are NaN values (anything for which :obj:`numpy:numpy.isnan` + returns True. So e.g. for complex numbers (nan+1j) is also a valid fill). + Note that if unique is set to True the generated values must be hashable. + + Arrays of specified ``dtype`` and ``shape`` are generated for example + like this: + + .. code-block:: pycon + + >>> import numpy as np + >>> arrays(np.int8, (2, 3)).example() + array([[-8, 6, 3], + [-6, 4, 6]], dtype=int8) + + - See :doc:`What you can generate and how `. + + .. code-block:: pycon + + >>> import numpy as np + >>> from hypothesis.strategies import floats + >>> arrays(np.float, 3, elements=floats(0, 1)).example() + array([ 0.88974794, 0.77387938, 0.1977879 ]) + + Array values are generated in two parts: + + 1. Some subset of the coordinates of the array are populated with a value + drawn from the elements strategy (or its inferred form). + 2. If any coordinates were not assigned in the previous step, a single + value is drawn from the fill strategy and is assigned to all remaining + places. + + You can set fill to :func:`~hypothesis.strategies.nothing` if you want to + disable this behaviour and draw a value for every element. + + If fill is set to None then it will attempt to infer the correct behaviour + automatically: If unique is True, no filling will occur by default. + Otherwise, if it looks safe to reuse the values of elements across + multiple coordinates (this will be the case for any inferred strategy, and + for most of the builtins, but is not the case for mutable values or + strategies built with flatmap, map, composite, etc) then it will use the + elements strategy as the fill, else it will default to having no fill. + + Having a fill helps Hypothesis craft high quality examples, but its + main importance is when the array generated is large: Hypothesis is + primarily designed around testing small examples. If you have arrays with + hundreds or more elements, having a fill value is essential if you want + your tests to run in reasonable time. + """ + if isinstance(dtype, SearchStrategy): + dtype = draw(dtype) + dtype = np.dtype(dtype) + if elements is None: + elements = from_dtype(dtype) + if isinstance(shape, SearchStrategy): + shape = draw(shape) + if isinstance(shape, int): + shape = (shape,) + shape = tuple(shape) + if not shape: + if dtype.kind != u'O': + return draw(elements) + fill = fill_for( + elements=elements, unique=unique, fill=fill + ) + return draw(ArrayStrategy(elements, shape, dtype, fill, unique)) + + +@st.defines_strategy +def array_shapes(min_dims=1, max_dims=3, min_side=1, max_side=10): + # type: (int, int, int, int) -> st.SearchStrategy[Tuple[int, ...]] + """Return a strategy for array shapes (tuples of int >= 1).""" + order_check('dims', 1, min_dims, max_dims) + order_check('side', 1, min_side, max_side) + return st.lists(st.integers(min_side, max_side), + min_size=min_dims, max_size=max_dims).map(tuple) + + +@st.defines_strategy +def scalar_dtypes(): + # type: () -> st.SearchStrategy[np.dtype] + """Return a strategy that can return any non-flexible scalar dtype.""" + return st.one_of(boolean_dtypes(), + integer_dtypes(), unsigned_integer_dtypes(), + floating_dtypes(), complex_number_dtypes(), + datetime64_dtypes(), timedelta64_dtypes()) + + +def defines_dtype_strategy(strat): + # type: (T) -> T + @st.defines_strategy + @proxies(strat) + def inner(*args, **kwargs): + return strat(*args, **kwargs).map(np.dtype) + return inner + + +@defines_dtype_strategy +def boolean_dtypes(): + # type: () -> st.SearchStrategy[np.dtype] + return st.just('?') + + +def dtype_factory(kind, sizes, valid_sizes, endianness): + # Utility function, shared logic for most integer and string types + valid_endian = ('?', '<', '=', '>') + check_argument(endianness in valid_endian, + u'Unknown endianness: was {}, must be in {}', + endianness, valid_endian) + if valid_sizes is not None: + if isinstance(sizes, int): + sizes = (sizes,) + check_argument(sizes, 'Dtype must have at least one possible size.') + check_argument(all(s in valid_sizes for s in sizes), + u'Invalid sizes: was {} must be an item or sequence ' + u'in {}', sizes, valid_sizes) + if all(isinstance(s, int) for s in sizes): + sizes = sorted(set(s // 8 for s in sizes)) + strat = st.sampled_from(sizes) + if '{}' not in kind: + kind += '{}' + if endianness == '?': + return strat.map(('<' + kind).format) | strat.map(('>' + kind).format) + return strat.map((endianness + kind).format) + + +@defines_dtype_strategy +def unsigned_integer_dtypes(endianness='?', sizes=(8, 16, 32, 64)): + # type: (str, Sequence[int]) -> st.SearchStrategy[np.dtype] + """Return a strategy for unsigned integer dtypes. + + endianness may be ``<`` for little-endian, ``>`` for big-endian, + ``=`` for native byte order, or ``?`` to allow either byte order. + This argument only applies to dtypes of more than one byte. + + sizes must be a collection of integer sizes in bits. The default + (8, 16, 32, 64) covers the full range of sizes. + """ + return dtype_factory('u', sizes, (8, 16, 32, 64), endianness) + + +@defines_dtype_strategy +def integer_dtypes(endianness='?', sizes=(8, 16, 32, 64)): + # type: (str, Sequence[int]) -> st.SearchStrategy[np.dtype] + """Return a strategy for signed integer dtypes. + + endianness and sizes are treated as for + :func:`unsigned_integer_dtypes`. + """ + return dtype_factory('i', sizes, (8, 16, 32, 64), endianness) + + +@defines_dtype_strategy +def floating_dtypes(endianness='?', sizes=(16, 32, 64)): + # type: (str, Sequence[int]) -> st.SearchStrategy[np.dtype] + """Return a strategy for floating-point dtypes. + + sizes is the size in bits of floating-point number. Some machines support + 96- or 128-bit floats, but these are not generated by default. + + Larger floats (96 and 128 bit real parts) are not supported on all + platforms and therefore disabled by default. To generate these dtypes, + include these values in the sizes argument. + """ + return dtype_factory('f', sizes, (16, 32, 64, 96, 128), endianness) + + +@defines_dtype_strategy +def complex_number_dtypes(endianness='?', sizes=(64, 128)): + # type: (str, Sequence[int]) -> st.SearchStrategy[np.dtype] + """Return a strategy for complex-number dtypes. + + sizes is the total size in bits of a complex number, which consists + of two floats. Complex halfs (a 16-bit real part) are not supported + by numpy and will not be generated by this strategy. + """ + return dtype_factory('c', sizes, (64, 128, 192, 256), endianness) + + +@check_function +def validate_time_slice(max_period, min_period): + check_argument(max_period in TIME_RESOLUTIONS, + u'max_period {} must be a valid resolution in {}', + max_period, TIME_RESOLUTIONS) + check_argument(min_period in TIME_RESOLUTIONS, + u'min_period {} must be a valid resolution in {}', + min_period, TIME_RESOLUTIONS) + start = TIME_RESOLUTIONS.index(max_period) + end = TIME_RESOLUTIONS.index(min_period) + 1 + check_argument(start < end, + u'max_period {} must be earlier in sequence {} than ' + u'min_period {}', max_period, TIME_RESOLUTIONS, min_period) + return TIME_RESOLUTIONS[start:end] + + +@defines_dtype_strategy +def datetime64_dtypes(max_period='Y', min_period='ns', endianness='?'): + # type: (str, str, str) -> st.SearchStrategy[np.dtype] + """Return a strategy for datetime64 dtypes, with various precisions from + year to attosecond.""" + return dtype_factory('datetime64[{}]', + validate_time_slice(max_period, min_period), + TIME_RESOLUTIONS, endianness) + + +@defines_dtype_strategy +def timedelta64_dtypes(max_period='Y', min_period='ns', endianness='?'): + # type: (str, str, str) -> st.SearchStrategy[np.dtype] + """Return a strategy for timedelta64 dtypes, with various precisions from + year to attosecond.""" + return dtype_factory('timedelta64[{}]', + validate_time_slice(max_period, min_period), + TIME_RESOLUTIONS, endianness) + + +@defines_dtype_strategy +def byte_string_dtypes(endianness='?', min_len=0, max_len=16): + # type: (str, int, int) -> st.SearchStrategy[np.dtype] + """Return a strategy for generating bytestring dtypes, of various lengths + and byteorder.""" + order_check('len', 0, min_len, max_len) + return dtype_factory('S', list(range(min_len, max_len + 1)), + None, endianness) + + +@defines_dtype_strategy +def unicode_string_dtypes(endianness='?', min_len=0, max_len=16): + # type: (str, int, int) -> st.SearchStrategy[np.dtype] + """Return a strategy for generating unicode string dtypes, of various + lengths and byteorder.""" + order_check('len', 0, min_len, max_len) + return dtype_factory('U', list(range(min_len, max_len + 1)), + None, endianness) + + +@defines_dtype_strategy +def array_dtypes( + subtype_strategy=scalar_dtypes(), # type: st.SearchStrategy[np.dtype] + min_size=1, # type: int + max_size=5, # type: int + allow_subarrays=False, # type: bool +): + # type: (...) -> st.SearchStrategy[np.dtype] + """Return a strategy for generating array (compound) dtypes, with members + drawn from the given subtype strategy.""" + order_check('size', 0, min_size, max_size) + native_strings = st.text() # type: SearchStrategy[Any] + if text_type is not str: # pragma: no cover + native_strings = st.binary() + elements = st.tuples(native_strings, subtype_strategy) + if allow_subarrays: + elements |= st.tuples(native_strings, subtype_strategy, + array_shapes(max_dims=2, max_side=2)) + return st.lists(elements=elements, min_size=min_size, max_size=max_size, + unique_by=lambda d: d[0]) + + +@st.defines_strategy +def nested_dtypes( + subtype_strategy=scalar_dtypes(), # type: st.SearchStrategy[np.dtype] + max_leaves=10, # type: int + max_itemsize=None, # type: int +): + # type: (...) -> st.SearchStrategy[np.dtype] + """Return the most-general dtype strategy. + + Elements drawn from this strategy may be simple (from the + subtype_strategy), or several such values drawn from + :func:`array_dtypes` with ``allow_subarrays=True``. Subdtypes in an + array dtype may be nested to any depth, subject to the max_leaves + argument. + """ + return st.recursive(subtype_strategy, + lambda x: array_dtypes(x, allow_subarrays=True), + max_leaves).filter( + lambda d: max_itemsize is None or d.itemsize <= max_itemsize) diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/extra/pandas/impl.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/extra/pandas/impl.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/extra/pandas/impl.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/extra/pandas/impl.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,662 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from copy import copy +from collections import Iterable, OrderedDict + +import attr +import numpy as np + +import pandas +import hypothesis.strategies as st +import hypothesis.extra.numpy as npst +import hypothesis.internal.conjecture.utils as cu +from hypothesis.errors import InvalidArgument +from hypothesis.control import reject +from hypothesis.strategies import check_strategy +from hypothesis.internal.compat import hrange +from hypothesis.internal.coverage import check, check_function +from hypothesis.internal.validation import check_type, try_convert, \ + check_valid_size, check_valid_interval + +try: + from pandas.api.types import is_categorical_dtype +except ImportError: # pragma: no cover + def is_categorical_dtype(dt): + if isinstance(dt, np.dtype): + return False + return dt == 'category' + +if False: + from typing import Any, Union, Sequence, Set # noqa + from hypothesis.searchstrategy.strategies import Ex # noqa + + +def dtype_for_elements_strategy(s): + return st.shared( + s.map(lambda x: pandas.Series([x]).dtype), + key=('hypothesis.extra.pandas.dtype_for_elements_strategy', s), + ) + + +def infer_dtype_if_necessary(dtype, values, elements, draw): + if dtype is None and not values: + return draw(dtype_for_elements_strategy(elements)) + return dtype + + +@check_function +def elements_and_dtype(elements, dtype, source=None): + + if source is None: + prefix = '' + else: + prefix = '%s.' % (source,) + + if elements is not None: + check_strategy(elements, '%selements' % (prefix,)) + else: + with check('dtype is not None'): + if dtype is None: + raise InvalidArgument(( + 'At least one of %(prefix)selements or %(prefix)sdtype ' + 'must be provided.') % {'prefix': prefix}) + + with check('is_categorical_dtype'): + if is_categorical_dtype(dtype): + raise InvalidArgument( + '%sdtype is categorical, which is currently unsupported' % ( + prefix, + )) + + dtype = try_convert(np.dtype, dtype, 'dtype') + + if elements is None: + elements = npst.from_dtype(dtype) + elif dtype is not None: + def convert_element(value): + name = 'draw(%selements)' % (prefix,) + try: + return np.array([value], dtype=dtype)[0] + except TypeError: + raise InvalidArgument( + 'Cannot convert %s=%r of type %s to dtype %s' % ( + name, value, type(value).__name__, dtype.str + ) + ) + except ValueError: + raise InvalidArgument( + 'Cannot convert %s=%r to type %s' % ( + name, value, dtype.str, + ) + ) + elements = elements.map(convert_element) + assert elements is not None + + return elements, dtype + + +class ValueIndexStrategy(st.SearchStrategy): + def __init__(self, elements, dtype, min_size, max_size, unique): + super(ValueIndexStrategy, self).__init__() + self.elements = elements + self.dtype = dtype + self.min_size = min_size + self.max_size = max_size + self.unique = unique + + def do_draw(self, data): + result = [] + seen = set() + + iterator = cu.many( + data, min_size=self.min_size, max_size=self.max_size, + average_size=(self.min_size + self.max_size) / 2 + ) + + while iterator.more(): + elt = data.draw(self.elements) + + if self.unique: + if elt in seen: + iterator.reject() + continue + seen.add(elt) + result.append(elt) + + dtype = infer_dtype_if_necessary( + dtype=self.dtype, values=result, elements=self.elements, + draw=data.draw + ) + return pandas.Index(result, dtype=dtype, tupleize_cols=False) + + +DEFAULT_MAX_SIZE = 10 + + +@st.cacheable +@st.defines_strategy +def range_indexes(min_size=0, max_size=None): + # type: (int, int) -> st.SearchStrategy[pandas.RangeIndex] + """Provides a strategy which generates an :class:`~pandas.Index` whose + values are 0, 1, ..., n for some n. + + Arguments: + + * min_size is the smallest number of elements the index can have. + * max_size is the largest number of elements the index can have. If None + it will default to some suitable value based on min_size. + """ + check_valid_size(min_size, 'min_size') + check_valid_size(max_size, 'max_size') + if max_size is None: + max_size = min([min_size + DEFAULT_MAX_SIZE, 2 ** 63 - 1]) + check_valid_interval(min_size, max_size, 'min_size', 'max_size') + return st.integers(min_size, max_size).map(pandas.RangeIndex) + + +@st.cacheable +@st.defines_strategy +def indexes( + elements=None, # type: st.SearchStrategy[Ex] + dtype=None, # type: Any + min_size=0, # type: int + max_size=None, # type: int + unique=True, # type: bool +): + """Provides a strategy for producing a :class:`pandas.Index`. + + Arguments: + + * elements is a strategy which will be used to generate the individual + values of the index. If None, it will be inferred from the dtype. Note: + even if the elements strategy produces tuples, the generated value + will not be a MultiIndex, but instead be a normal index whose elements + are tuples. + * dtype is the dtype of the resulting index. If None, it will be inferred + from the elements strategy. At least one of dtype or elements must be + provided. + * min_size is the minimum number of elements in the index. + * max_size is the maximum number of elements in the index. If None then it + will default to a suitable small size. If you want larger indexes you + should pass a max_size explicitly. + * unique specifies whether all of the elements in the resulting index + should be distinct. + """ + check_valid_size(min_size, 'min_size') + check_valid_size(max_size, 'max_size') + check_valid_interval(min_size, max_size, 'min_size', 'max_size') + check_type(bool, unique, 'unique') + + elements, dtype = elements_and_dtype(elements, dtype) + + if max_size is None: + max_size = min_size + DEFAULT_MAX_SIZE + return ValueIndexStrategy( + elements, dtype, min_size, max_size, unique) + + +@st.defines_strategy +def series( + elements=None, # type: st.SearchStrategy[Ex] + dtype=None, # type: Any + index=None, # type: st.SearchStrategy[Union[Sequence, pandas.Index]] + fill=None, # type: st.SearchStrategy[Ex] + unique=False, # type: bool +): + # type: (...) -> st.SearchStrategy[pandas.Series] + """Provides a strategy for producing a :class:`pandas.Series`. + + Arguments: + + * elements: a strategy that will be used to generate the individual + values in the series. If None, we will attempt to infer a suitable + default from the dtype. + + * dtype: the dtype of the resulting series and may be any value + that can be passed to :class:`numpy.dtype`. If None, will use + pandas's standard behaviour to infer it from the type of the elements + values. Note that if the type of values that comes out of your + elements strategy varies, then so will the resulting dtype of the + series. + + * index: If not None, a strategy for generating indexes for the + resulting Series. This can generate either :class:`pandas.Index` + objects or any sequence of values (which will be passed to the + Index constructor). + + You will probably find it most convenient to use the + :func:`~hypothesis.extra.pandas.indexes` or + :func:`~hypothesis.extra.pandas.range_indexes` function to produce + values for this argument. + + Usage: + + .. code-block:: pycon + + >>> series(dtype=int).example() + 0 -2001747478 + 1 1153062837 + """ + if index is None: + index = range_indexes() + else: + check_strategy(index) + + elements, dtype = elements_and_dtype(elements, dtype) + index_strategy = index + + @st.composite + def result(draw): + index = draw(index_strategy) + + if len(index) > 0: + if dtype is not None: + result_data = draw(npst.arrays( + dtype=dtype, elements=elements, shape=len(index), + fill=fill, unique=unique, + )) + else: + result_data = list(draw(npst.arrays( + dtype=object, elements=elements, shape=len(index), + fill=fill, unique=unique, + ))) + + return pandas.Series( + result_data, index=index, dtype=dtype + ) + else: + return pandas.Series( + (), index=index, + dtype=dtype if dtype is not None else draw( + dtype_for_elements_strategy(elements))) + + return result() + + +@attr.s(slots=True) +class column(object): + """Data object for describing a column in a DataFrame. + + Arguments: + + * name: the column name, or None to default to the column position. Must + be hashable, but can otherwise be any value supported as a pandas column + name. + * elements: the strategy for generating values in this column, or None + to infer it from the dtype. + * dtype: the dtype of the column, or None to infer it from the element + strategy. At least one of dtype or elements must be provided. + * fill: A default value for elements of the column. See + :func:`~hypothesis.extra.numpy.arrays` for a full explanation. + * unique: If all values in this column should be distinct. + """ + + name = attr.ib(default=None) + elements = attr.ib(default=None) + dtype = attr.ib(default=None) + fill = attr.ib(default=None) + unique = attr.ib(default=False) + + +def columns( + names_or_number, # type: Union[int, Sequence[str]] + dtype=None, # type: Any + elements=None, # type: st.SearchStrategy[Ex] + fill=None, # type: st.SearchStrategy[Ex] + unique=False, # type: bool +): + """A convenience function for producing a list of :class:`column` objects + of the same general shape. + + The names_or_number argument is either a sequence of values, the + elements of which will be used as the name for individual column + objects, or a number, in which case that many unnamed columns will + be created. All other arguments are passed through verbatim to + create the columns. + """ + if isinstance(names_or_number, (int, float)): + names = [None] * names_or_number # type: list + else: + names = list(names_or_number) + return [ + column( + name=n, dtype=dtype, elements=elements, fill=fill, unique=unique + ) for n in names + ] + + +@st.defines_strategy +def data_frames( + columns=None, # type: Sequence[column] + rows=None, # type: st.SearchStrategy[Union[dict, Sequence[Any]]] + index=None, # type: st.SearchStrategy[Ex] +): + # type: (...) -> st.SearchStrategy[pandas.DataFrame] + """Provides a strategy for producing a :class:`pandas.DataFrame`. + + Arguments: + + * columns: An iterable of :class:`column` objects describing the shape + of the generated DataFrame. + + * rows: A strategy for generating a row object. Should generate + either dicts mapping column names to values or a sequence mapping + column position to the value in that position (note that unlike the + :class:`pandas.DataFrame` constructor, single values are not allowed + here. Passing e.g. an integer is an error, even if there is only one + column). + + At least one of rows and columns must be provided. If both are + provided then the generated rows will be validated against the + columns and an error will be raised if they don't match. + + Caveats on using rows: + + * In general you should prefer using columns to rows, and only use + rows if the columns interface is insufficiently flexible to + describe what you need - you will get better performance and + example quality that way. + * If you provide rows and not columns, then the shape and dtype of + the resulting DataFrame may vary. e.g. if you have a mix of int + and float in the values for one column in your row entries, the + column will sometimes have an integral dtype and sometimes a float. + + * index: If not None, a strategy for generating indexes for the + resulting DataFrame. This can generate either :class:`pandas.Index` + objects or any sequence of values (which will be passed to the + Index constructor). + + You will probably find it most convenient to use the + :func:`~hypothesis.extra.pandas.indexes` or + :func:`~hypothesis.extra.pandas.range_indexes` function to produce + values for this argument. + + Usage: + + The expected usage pattern is that you use :class:`column` and + :func:`columns` to specify a fixed shape of the DataFrame you want as + follows. For example the following gives a two column data frame: + + .. code-block:: pycon + + >>> from hypothesis.extra.pandas import column, data_frames + >>> data_frames([ + ... column('A', dtype=int), column('B', dtype=float)]).example() + A B + 0 2021915903 1.793898e+232 + 1 1146643993 inf + 2 -2096165693 1.000000e+07 + + If you want the values in different columns to interact in some way you + can use the rows argument. For example the following gives a two column + DataFrame where the value in the first column is always at most the value + in the second: + + .. code-block:: pycon + + >>> from hypothesis.extra.pandas import column, data_frames + >>> import hypothesis.strategies as st + >>> data_frames( + ... rows=st.tuples(st.floats(allow_nan=False), + ... st.floats(allow_nan=False)).map(sorted) + ... ).example() + 0 1 + 0 -3.402823e+38 9.007199e+15 + 1 -1.562796e-298 5.000000e-01 + + You can also combine the two: + + .. code-block:: pycon + + >>> from hypothesis.extra.pandas import columns, data_frames + >>> import hypothesis.strategies as st + >>> data_frames( + ... columns=columns(["lo", "hi"], dtype=float), + ... rows=st.tuples(st.floats(allow_nan=False), + ... st.floats(allow_nan=False)).map(sorted) + ... ).example() + lo hi + 0 9.314723e-49 4.353037e+45 + 1 -9.999900e-01 1.000000e+07 + 2 -2.152861e+134 -1.069317e-73 + + (Note that the column dtype must still be specified and will not be + inferred from the rows. This restriction may be lifted in future). + + Combining rows and columns has the following behaviour: + + * The column names and dtypes will be used. + * If the column is required to be unique, this will be enforced. + * Any values missing from the generated rows will be provided using the + column's fill. + * Any values in the row not present in the column specification (if + dicts are passed, if there are keys with no corresponding column name, + if sequences are passed if there are too many items) will result in + InvalidArgument being raised. + """ + if index is None: + index = range_indexes() + else: + check_strategy(index) + + index_strategy = index + + if columns is None: + if rows is None: + raise InvalidArgument( + 'At least one of rows and columns must be provided' + ) + else: + @st.composite + def rows_only(draw): + index = draw(index_strategy) + + @check_function + def row(): + result = draw(rows) + check_type(Iterable, result, 'draw(row)') + return result + + if len(index) > 0: + return pandas.DataFrame( + [row() for _ in index], + index=index + ) + else: + # If we haven't drawn any rows we need to draw one row and + # then discard it so that we get a consistent shape for the + # DataFrame. + base = pandas.DataFrame([row()]) + return base.drop(0) + return rows_only() + + assert columns is not None + cols = try_convert(tuple, columns, 'columns') # type: Sequence[column] + + rewritten_columns = [] + column_names = set() # type: Set[str] + + for i, c in enumerate(cols): + check_type(column, c, 'columns[%d]' % (i,)) + + c = copy(c) + if c.name is None: + label = 'columns[%d]' % (i,) + c.name = i + else: + label = c.name + try: + hash(c.name) + except TypeError: + raise InvalidArgument( + 'Column names must be hashable, but columns[%d].name was ' + '%r of type %s, which cannot be hashed.' % ( + i, c.name, type(c.name).__name__,)) + + if c.name in column_names: + raise InvalidArgument( + 'duplicate definition of column name %r' % (c.name,)) + + column_names.add(c.name) + + c.elements, c.dtype = elements_and_dtype( + c.elements, c.dtype, label + ) + + if c.dtype is None and rows is not None: + raise InvalidArgument( + 'Must specify a dtype for all columns when combining rows with' + ' columns.' + ) + + c.fill = npst.fill_for( + fill=c.fill, elements=c.elements, unique=c.unique, + name=label + ) + + rewritten_columns.append(c) + + if rows is None: + @st.composite + def just_draw_columns(draw): + index = draw(index_strategy) + local_index_strategy = st.just(index) + + data = OrderedDict((c.name, None) for c in rewritten_columns) + + # Depending on how the columns are going to be generated we group + # them differently to get better shrinking. For columns with fill + # enabled, the elements can be shrunk independently of the size, + # so we can just shrink by shrinking the index then shrinking the + # length and are generally much more free to move data around. + + # For columns with no filling the problem is harder, and drawing + # them like that would result in rows being very far apart from + # each other in the underlying data stream, which gets in the way + # of shrinking. So what we do is reorder and draw those columns + # row wise, so that the values of each row are next to each other. + # This makes life easier for the shrinker when deleting blocks of + # data. + columns_without_fill = [ + c for c in rewritten_columns if c.fill.is_empty] + + if columns_without_fill: + for c in columns_without_fill: + data[c.name] = pandas.Series( + np.zeros(shape=len(index), dtype=c.dtype), + index=index, + ) + seen = { + c.name: set() for c in columns_without_fill if c.unique} + + for i in hrange(len(index)): + for c in columns_without_fill: + if c.unique: + for _ in range(5): + value = draw(c.elements) + if value not in seen[c.name]: + seen[c.name].add(value) + break + else: + reject() + else: + value = draw(c.elements) + data[c.name][i] = value + + for c in rewritten_columns: + if not c.fill.is_empty: + data[c.name] = draw(series( + index=local_index_strategy, dtype=c.dtype, + elements=c.elements, fill=c.fill, unique=c.unique)) + + return pandas.DataFrame(data, index=index) + return just_draw_columns() + else: + @st.composite + def assign_rows(draw): + index = draw(index_strategy) + + result = pandas.DataFrame(OrderedDict( + (c.name, pandas.Series( + np.zeros(dtype=c.dtype, shape=len(index)), dtype=c.dtype)) + for c in rewritten_columns + ), index=index) + + fills = {} + + any_unique = any(c.unique for c in rewritten_columns) + + if any_unique: + all_seen = [ + set() if c.unique else None for c in rewritten_columns] + while all_seen[-1] is None: + all_seen.pop() + + for row_index in hrange(len(index)): + for _ in hrange(5): + original_row = draw(rows) + row = original_row + if isinstance(row, dict): + as_list = [None] * len(rewritten_columns) + for i, c in enumerate(rewritten_columns): + try: + as_list[i] = row[c.name] + except KeyError: + try: + as_list[i] = fills[i] + except KeyError: + fills[i] = draw(c.fill) + as_list[i] = fills[i] + for k in row: + if k not in column_names: + raise InvalidArgument(( + 'Row %r contains column %r not in ' + 'columns %r)' % ( + row, k, [ + c.name for c in rewritten_columns + ]))) + row = as_list + if any_unique: + has_duplicate = False + for seen, value in zip(all_seen, row): + if seen is None: + continue + if value in seen: + has_duplicate = True + break + seen.add(value) + if has_duplicate: + continue + row = list(try_convert(tuple, row, 'draw(rows)')) + + if len(row) > len(rewritten_columns): + raise InvalidArgument(( + 'Row %r contains too many entries. Has %d but ' + 'expected at most %d') % ( + original_row, len(row), len(rewritten_columns) + )) + while len(row) < len(rewritten_columns): + row.append(draw(rewritten_columns[len(row)].fill)) + result.iloc[row_index] = row + break + else: + reject() + return result + return assign_rows() diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/extra/pandas/__init__.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/extra/pandas/__init__.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/extra/pandas/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/extra/pandas/__init__.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,28 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from hypothesis.extra.pandas.impl import series, data_frames, column, columns,\ + indexes, range_indexes + +__all__ = [ + 'indexes', 'range_indexes', + 'series', + 'column', 'columns', + 'data_frames', +] diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/extra/pytestplugin.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/extra/pytestplugin.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/extra/pytestplugin.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/extra/pytestplugin.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,170 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import pytest + +from hypothesis import core, settings +from hypothesis.reporting import default as default_reporter +from hypothesis.reporting import with_reporter +from hypothesis.statistics import collector +from hypothesis.internal.compat import OrderedDict, text_type +from hypothesis.internal.detection import is_hypothesis_test + +LOAD_PROFILE_OPTION = '--hypothesis-profile' +PRINT_STATISTICS_OPTION = '--hypothesis-show-statistics' +SEED_OPTION = '--hypothesis-seed' + + +class StoringReporter(object): + + def __init__(self, config): + self.config = config + self.results = [] + + def __call__(self, msg): + if self.config.getoption('capture', 'fd') == 'no': + default_reporter(msg) + if not isinstance(msg, text_type): + msg = repr(msg) + self.results.append(msg) + + +def pytest_addoption(parser): + group = parser.getgroup('hypothesis', 'Hypothesis') + group.addoption( + LOAD_PROFILE_OPTION, + action='store', + help='Load in a registered hypothesis.settings profile' + ) + group.addoption( + PRINT_STATISTICS_OPTION, + action='store_true', + help='Configure when statistics are printed', + default=False + ) + group.addoption( + SEED_OPTION, + action='store', + help='Set a seed to use for all Hypothesis tests' + ) + + +def pytest_report_header(config): + profile = config.getoption(LOAD_PROFILE_OPTION) + if not profile: + profile = 'default' + settings_str = settings.get_profile(profile).show_changed() + if settings_str != '': + settings_str = ' -> %s' % (settings_str) + return 'hypothesis profile %r%s' % (profile, settings_str) + + +def pytest_configure(config): + core.running_under_pytest = True + profile = config.getoption(LOAD_PROFILE_OPTION) + if profile: + settings.load_profile(profile) + seed = config.getoption(SEED_OPTION) + if seed is not None: + try: + seed = int(seed) + except ValueError: + pass + core.global_force_seed = seed + config.addinivalue_line( + 'markers', + 'hypothesis: Tests which use hypothesis.') + + +gathered_statistics = OrderedDict() # type: dict + + +@pytest.mark.hookwrapper +def pytest_runtest_call(item): + if not (hasattr(item, 'obj') and is_hypothesis_test(item.obj)): + yield + else: + store = StoringReporter(item.config) + + def note_statistics(stats): + gathered_statistics[item.nodeid] = stats + + with collector.with_value(note_statistics): + with with_reporter(store): + yield + if store.results: + item.hypothesis_report_information = list(store.results) + + +@pytest.mark.hookwrapper +def pytest_runtest_makereport(item, call): + report = (yield).get_result() + if hasattr(item, 'hypothesis_report_information'): + report.sections.append(( + 'Hypothesis', + '\n'.join(item.hypothesis_report_information) + )) + + +def pytest_terminal_summary(terminalreporter): + if not terminalreporter.config.getoption(PRINT_STATISTICS_OPTION): + return + terminalreporter.section('Hypothesis Statistics') + for name, statistics in gathered_statistics.items(): + terminalreporter.write_line(name + ':') + terminalreporter.write_line('') + + if not statistics.has_runs: + terminalreporter.write_line(' - Test was never run') + continue + + terminalreporter.write_line(( + ' - %d passing examples, %d failing examples,' + ' %d invalid examples') % ( + statistics.passing_examples, statistics.failing_examples, + statistics.invalid_examples, + )) + terminalreporter.write_line( + ' - Typical runtimes: %s' % (statistics.runtimes,) + ) + terminalreporter.write_line( + ' - Fraction of time spent in data generation: %s' % ( + statistics.draw_time_percentage,)) + terminalreporter.write_line( + ' - Stopped because %s' % (statistics.exit_reason,) + ) + if statistics.events: + terminalreporter.write_line(' - Events:') + for event in statistics.events: + terminalreporter.write_line( + ' * %s' % (event,) + ) + terminalreporter.write_line('') + + +def pytest_collection_modifyitems(items): + for item in items: + if not isinstance(item, pytest.Function): + continue + if getattr(item.function, 'is_hypothesis_test', False): + item.add_marker('hypothesis') + + +def load(): + pass diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/extra/pytz.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/extra/pytz.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/extra/pytz.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/extra/pytz.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,58 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +"""This module provides ``pytz`` timezones. + +You can use this strategy to make +:py:func:`hypothesis.strategies.datetimes` and +:py:func:`hypothesis.strategies.times` produce timezone-aware values. +""" + +from __future__ import division, print_function, absolute_import + +import datetime as dt + +import pytz + +import hypothesis.strategies as st + +__all__ = ['timezones'] + + +@st.cacheable +@st.defines_strategy +def timezones(): + # type: () -> st.SearchStrategy[dt.tzinfo] + """Any timezone in the Olsen database, as a pytz tzinfo object. + + This strategy minimises to UTC, or the smallest possible fixed + offset, and is designed for use with + :py:func:`hypothesis.strategies.datetimes`. + """ + all_timezones = [pytz.timezone(tz) for tz in pytz.all_timezones] + # Some timezones have always had a constant offset from UTC. This makes + # them simpler than timezones with daylight savings, and the smaller the + # absolute offset the simpler they are. Of course, UTC is even simpler! + static = [pytz.UTC] # type: list + static += sorted( + (t for t in all_timezones + if isinstance(t, pytz.tzfile.StaticTzInfo)), # type: ignore + key=lambda tz: abs(tz.utcoffset(dt.datetime(2000, 1, 1))) + ) + # Timezones which have changed UTC offset; best ordered by name. + dynamic = [tz for tz in all_timezones if tz not in static] + return st.sampled_from(static + dynamic) diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/__init__.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/__init__.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/__init__.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,54 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +"""Hypothesis is a library for writing unit tests which are parametrized by +some source of data. + +It verifies your code against a wide range of input and minimizes any +failing examples it finds. +""" + + +from hypothesis._settings import settings, Verbosity, Phase, HealthCheck, \ + unlimited +from hypothesis.version import __version_info__, __version__ +from hypothesis.control import assume, note, reject, event +from hypothesis.core import given, find, example, seed, reproduce_failure, \ + PrintSettings +from hypothesis.utils.conventions import infer + + +__all__ = [ + 'settings', + 'Verbosity', + 'HealthCheck', + 'Phase', + 'PrintSettings', + 'assume', + 'reject', + 'seed', + 'given', + 'unlimited', + 'reproduce_failure', + 'find', + 'example', + 'note', + 'event', + 'infer', + '__version__', + '__version_info__', +] diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/cache.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/cache.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/cache.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/cache.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,221 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import attr + + +@attr.s(slots=True) +class Entry(object): + key = attr.ib() + value = attr.ib() + score = attr.ib() + + +class GenericCache(object): + """Generic supertype for cache implementations. + + Defines a dict-like mapping with a maximum size, where as well as mapping + to a value, each key also maps to a score. When a write would cause the + dict to exceed its maximum size, it first evicts the existing key with + the smallest score, then adds the new key to the map. + + A key has the following lifecycle: + + 1. key is written for the first time, the key is given the score + self.new_entry(key, value) + 2. whenever an existing key is read or written, self.on_access(key, value, + score) is called. This returns a new score for the key. + 3. When a key is evicted, self.on_evict(key, value, score) is called. + + The cache will be in a valid state in all of these cases. + + Implementations are expected to implement new_entry and optionally + on_access and on_evict to implement a specific scoring strategy. + """ + + __slots__ = ('keys_to_indices', 'data', 'max_size') + + def __init__(self, max_size): + self.max_size = max_size + + # Implementation: We store a binary heap of Entry objects in self.data, + # with the heap property requiring that a parent's score is <= that of + # its children. keys_to_index then maps keys to their index in the + # heap. We keep these two in sync automatically - the heap is never + # reordered without updating the index. + self.keys_to_indices = {} + self.data = [] + + def __len__(self): + assert len(self.keys_to_indices) == len(self.data) + return len(self.data) + + def __getitem__(self, key): + i = self.keys_to_indices[key] + result = self.data[i] + self.on_access(result.key, result.value, result.score) + self.__balance(i) + return result.value + + def __setitem__(self, key, value): + if self.max_size == 0: + return + evicted = None + try: + i = self.keys_to_indices[key] + except KeyError: + entry = Entry(key, value, self.new_entry(key, value)) + if len(self.data) >= self.max_size: + evicted = self.data[0] + del self.keys_to_indices[evicted.key] + i = 0 + self.data[0] = entry + else: + i = len(self.data) + self.data.append(entry) + self.keys_to_indices[key] = i + else: + entry = self.data[i] + assert entry.key == key + entry.value = value + entry.score = self.on_access(entry.key, entry.value, entry.score) + + self.__balance(i) + + if evicted is not None: + if self.data[0] is not entry: + assert evicted.score <= self.data[0].score + self.on_evict(evicted.key, evicted.value, evicted.score) + + def clear(self): + del self.data[:] + self.keys_to_indices.clear() + + def __repr__(self): + return '{%s}' % (', '.join( + '%r: %r' % (e.key, e.value) for e in self.data),) + + def new_entry(self, key, value): + """Called when a key is written that does not currently appear in the + map. + + Returns the score to associate with the key. + """ + raise NotImplementedError() + + def on_access(self, key, value, score): + """Called every time a key that is already in the map is read or + written. + + Returns the new score for the key. + """ + return score + + def on_evict(self, key, value, score): + """Called after a key has been evicted, with the score it had had at + the point of eviction.""" + pass + + def check_valid(self): + """Debugging method for use in tests. + + Asserts that all of the cache's invariants hold. When everything + is working correctly this should be an expensive no-op. + """ + for i, e in enumerate(self.data): + assert self.keys_to_indices[e.key] == i + for j in [i * 2 + 1, i * 2 + 2]: + if j < len(self.data): + assert e.score <= self.data[j].score, self.data + + def __swap(self, i, j): + assert i < j + assert self.data[j].score < self.data[i].score + self.data[i], self.data[j] = self.data[j], self.data[i] + self.keys_to_indices[self.data[i].key] = i + self.keys_to_indices[self.data[j].key] = j + + def __balance(self, i): + """When we have made a modification to the heap such that means that + the heap property has been violated locally around i but previously + held for all other indexes (and no other values have been modified), + this fixes the heap so that the heap property holds everywhere.""" + while i > 0: + parent = (i - 1) // 2 + if self.__out_of_order(parent, i): + self.__swap(parent, i) + i = parent + else: + break + while True: + children = [ + j for j in (2 * i + 1, 2 * i + 2) + if j < len(self.data) + ] + if len(children) == 2: + children.sort(key=lambda j: self.data[j].score) + for j in children: + if self.__out_of_order(i, j): + self.__swap(i, j) + i = j + break + else: + break + + def __out_of_order(self, i, j): + """Returns True if the indices i, j are in the wrong order. + + i must be the parent of j. + """ + assert i == (j - 1) // 2 + return self.data[j].score < self.data[i].score + + +class LRUReusedCache(GenericCache): + """The only concrete implementation of GenericCache we use outside of tests + currently. + + Adopts a modified least-frequently used eviction policy: It evicts the key + that has been used least recently, but it will always preferentially evict + keys that have only ever been accessed once. Among keys that have been + accessed more than once, it ignores the number of accesses. + + This retains most of the benefits of an LRU cache, but adds an element of + scan-resistance to the process: If we end up scanning through a large + number of keys without reusing them, this does not evict the existing + entries in preference for the new ones. + """ + + __slots__ = ('__tick',) + + def __init__(self, max_size, ): + super(LRUReusedCache, self).__init__(max_size) + self.__tick = 0 + + def tick(self): + self.__tick += 1 + return self.__tick + + def new_entry(self, key, value): + return [1, self.tick()] + + def on_access(self, key, value, score): + score[0] = 2 + score[1] = self.tick() + return score diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/cathetus.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/cathetus.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/cathetus.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/cathetus.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,67 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from sys import float_info +from math import fabs, sqrt, isinf, isnan + + +def cathetus(h, a): + """Given the lengths of the hypotenuse and a side of a right triangle, + return the length of the other side. + + A companion to the C99 hypot() function. Some care is needed to avoid + underflow in the case of small arguments, and overflow in the case of + large arguments as would occur for the naive implementation as + sqrt(h*h - a*a). The behaviour with respect the non-finite arguments + (NaNs and infinities) is designed to be as consistent as possible with + the C99 hypot() specifications. + + This function relies on the system ``sqrt`` function and so, like it, + may be inaccurate up to a relative error of (around) floating-point + epsilon. + + Based on the C99 implementation https://github.com/jjgreen/cathetus + """ + if isnan(h): + return float(u'nan') + + if isinf(h): + if isinf(a): + return float(u'nan') + else: + # Deliberately includes the case when isnan(a), because the + # C99 standard mandates that hypot(inf, nan) == inf + return float(u'inf') + + h = fabs(h) + a = fabs(a) + + if h < a: + return float(u'nan') + + if h > sqrt(float_info.max): + if h > float_info.max / 2: + return sqrt(h - a) * sqrt(h / 2 + a / 2) * sqrt(2) + else: + return sqrt(h - a) * sqrt(h + a) + + if h < sqrt(float_info.min): + return sqrt(h - a) * sqrt(h + a) + + return sqrt((h - a) * (h + a)) diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/charmap.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/charmap.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/charmap.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/charmap.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,378 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import os +import sys +import gzip +import json +import tempfile +import unicodedata + +from hypothesis._settings import note_deprecation +from hypothesis.configuration import tmpdir, storage_directory +from hypothesis.internal.compat import hunichr + +if False: + from typing import Dict, Tuple + intervals = Tuple[Tuple[int, int], ...] + cache_type = Dict[Tuple[Tuple[str, ...], int, int, intervals], intervals] + + +def charmap_file(): + return os.path.join( + storage_directory('unicodedata', unicodedata.unidata_version), + 'charmap.json.gz' + ) + + +_charmap = None + + +def charmap(): + """Return a dict that maps a Unicode category, to a tuple of 2-tuples + covering the codepoint intervals for characters in that category. + + >>> charmap()['Co'] + ((57344, 63743), (983040, 1048573), (1048576, 1114109)) + """ + global _charmap + # Best-effort caching in the face of missing files and/or unwritable + # filesystems is fairly simple: check if loaded, else try loading, + # else calculate and try writing the cache. + if _charmap is None: + f = charmap_file() + try: + with gzip.GzipFile(f, 'rb') as i: + tmp_charmap = dict(json.loads(i)) + + except Exception: + tmp_charmap = {} + for i in range(0, sys.maxunicode + 1): + cat = unicodedata.category(hunichr(i)) + rs = tmp_charmap.setdefault(cat, []) + if rs and rs[-1][-1] == i - 1: + rs[-1][-1] += 1 + else: + rs.append([i, i]) + + try: + # Write the Unicode table atomically + fd, tmpfile = tempfile.mkstemp(dir=tmpdir()) + os.close(fd) + # Explicitly set the mtime to get reproducible output + with gzip.GzipFile(tmpfile, 'wb', mtime=1) as o: + result = json.dumps(sorted(tmp_charmap.items())) + o.write(result.encode()) + + os.rename(tmpfile, f) + except Exception: + pass + + # convert between lists and tuples + _charmap = {k: tuple(tuple(pair) for pair in pairs) + for k, pairs in tmp_charmap.items()} + # each value is a tuple of 2-tuples (that is, tuples of length 2) + # and that both elements of that tuple are integers. + for vs in _charmap.values(): + ints = list(sum(vs, ())) + assert all([isinstance(x, int) for x in ints]) + assert ints == sorted(ints) + assert all([len(tup) == 2 for tup in vs]) + + assert _charmap is not None + return _charmap + + +_categories = None + + +def categories(): + """Return a tuple of Unicode categories in a normalised order. + + >>> categories() # doctest: +ELLIPSIS + ('Zl', 'Zp', 'Co', 'Me', 'Pc', ..., 'Cc', 'Cs') + """ + global _categories + if _categories is None: + cm = charmap() + _categories = sorted( + cm.keys(), key=lambda c: len(cm[c]) + ) + _categories.remove('Cc') # Other, Control + _categories.remove('Cs') # Other, Surrogate + _categories.append('Cc') + _categories.append('Cs') + return tuple(_categories) + + +def as_general_categories(cats, name='cats'): + """Return a tuple of Unicode categories in a normalised order. + + This function expands one-letter designations of a major class to include + all subclasses: + + >>> as_general_categories(['N']) + ('Nd', 'Nl', 'No') + + See section 4.5 of the Unicode standard for more on classes: + https://www.unicode.org/versions/Unicode10.0.0/ch04.pdf + + If the collection ``cats`` includes any elements that do not represent a + major class or a class with subclass, a deprecation warning is raised. + """ + if cats is None: + return None + major_classes = ('L', 'M', 'N', 'P', 'S', 'Z', 'C') + cs = categories() + out = set(cats) + for c in cats: + if c in major_classes: + out.discard(c) + out.update(x for x in cs if x.startswith(c)) + elif c not in cs: + note_deprecation( + 'In %s=%r, %r is not a valid Unicode category. This will ' + 'be an error in a future version.' % (name, cats, c)) + return tuple(c for c in cs if c in out) + + +def _union_intervals(x, y): + """Merge two sequences of intervals into a single tuple of intervals. + + Any integer bounded by `x` or `y` is also bounded by the result. + + >>> _union_intervals([(3, 10)], [(1, 2), (5, 17)]) + ((1, 17),) + """ + if not x: + return tuple((u, v) for u, v in y) + if not y: + return tuple((u, v) for u, v in x) + intervals = sorted(x + y, reverse=True) + result = [intervals.pop()] + while intervals: + # 1. intervals is in descending order + # 2. pop() takes from the RHS. + # 3. (a, b) was popped 1st, then (u, v) was popped 2nd + # 4. Therefore: a <= u + # 5. We assume that u <= v and a <= b + # 6. So we need to handle 2 cases of overlap, and one disjoint case + # | u--v | u----v | u--v | + # | a----b | a--b | a--b | + u, v = intervals.pop() + a, b = result[-1] + if u <= b + 1: + # Overlap cases + result[-1] = (a, max(v, b)) + else: + # Disjoint case + result.append((u, v)) + return tuple(result) + + +def _subtract_intervals(x, y): + """Set difference for lists of intervals. That is, returns a list of + intervals that bounds all values bounded by x that are not also bounded by + y. x and y are expected to be in sorted order. + + For example _subtract_intervals([(1, 10)], [(2, 3), (9, 15)]) would + return [(1, 1), (4, 8)], removing the values 2, 3, 9 and 10 from the + interval. + """ + if not y: + return tuple(x) + x = list(map(list, x)) + i = 0 + j = 0 + result = [] + while i < len(x) and j < len(y): + # Iterate in parallel over x and y. j stays pointing at the smallest + # interval in the left hand side that could still overlap with some + # element of x at index >= i. + # Similarly, i is not incremented until we know that it does not + # overlap with any element of y at index >= j. + + xl, xr = x[i] + assert xl <= xr + yl, yr = y[j] + assert yl <= yr + + if yr < xl: + # The interval at y[j] is strictly to the left of the interval at + # x[i], so will not overlap with it or any later interval of x. + j += 1 + elif yl > xr: + # The interval at y[j] is strictly to the right of the interval at + # x[i], so all of x[i] goes into the result as no further intervals + # in y will intersect it. + result.append(x[i]) + i += 1 + elif yl <= xl: + if yr >= xr: + # x[i] is contained entirely in y[j], so we just skip over it + # without adding it to the result. + i += 1 + else: + # The beginning of x[i] is contained in y[j], so we update the + # left endpoint of x[i] to remove this, and increment j as we + # now have moved past it. Note that this is not added to the + # result as is, as more intervals from y may intersect it so it + # may need updating further. + x[i][0] = yr + 1 + j += 1 + else: + # yl > xl, so the left hand part of x[i] is not contained in y[j], + # so there are some values we should add to the result. + result.append((xl, yl - 1)) + + if yr + 1 <= xr: + # If y[j] finishes before x[i] does, there may be some values + # in x[i] left that should go in the result (or they may be + # removed by a later interval in y), so we update x[i] to + # reflect that and increment j because it no longer overlaps + # with any remaining element of x. + x[i][0] = yr + 1 + j += 1 + else: + # Every element of x[i] other than the initial part we have + # already added is contained in y[j], so we move to the next + # interval. + i += 1 + # Any remaining intervals in x do not overlap with any of y, as if they did + # we would not have incremented j to the end, so can be added to the result + # as they are. + result.extend(x[i:]) + return tuple(map(tuple, result)) + + +def _intervals(s): + """Return a tuple of intervals, covering the codepoints of characters in + `s`. + + >>> _intervals('abcdef0123456789') + ((48, 57), (97, 102)) + """ + intervals = tuple((ord(c), ord(c)) for c in sorted(s)) + return _union_intervals(intervals, intervals) + + +category_index_cache = { + (): (), +} + + +def _category_key(exclude, include): + """Return a normalised tuple of all Unicode categories that are in + `include`, but not in `exclude`. + + If include is None then default to including all categories. + Any item in include that is not a unicode character will be excluded. + + >>> _category_key(exclude=['So'], include=['Lu', 'Me', 'Cs', 'So']) + ('Me', 'Lu', 'Cs') + """ + cs = categories() + if include is None: + include = set(cs) + else: + include = set(include) + exclude = set(exclude or ()) + assert include.issubset(cs) + assert exclude.issubset(cs) + include -= exclude + result = tuple(c for c in cs if c in include) + return result + + +def _query_for_key(key): + """Return a tuple of codepoint intervals covering characters that match one + or more categories in the tuple of categories `key`. + + >>> _query_for_key(categories()) + ((0, 1114111),) + >>> _query_for_key(('Zl', 'Zp', 'Co')) + ((8232, 8233), (57344, 63743), (983040, 1048573), (1048576, 1114109)) + """ + try: + return category_index_cache[key] + except KeyError: + pass + assert key + if set(key) == set(categories()): + result = ((0, sys.maxunicode),) + else: + result = _union_intervals( + _query_for_key(key[:-1]), charmap()[key[-1]] + ) + category_index_cache[key] = result + return result + + +limited_category_index_cache = {} # type: cache_type + + +def query( + exclude_categories=(), include_categories=None, + min_codepoint=None, + max_codepoint=None, + include_characters='', + exclude_characters='', +): + """Return a tuple of intervals covering the codepoints for all characters + that meet the critera (min_codepoint <= codepoint(c) <= max_codepoint and + any(cat in include_categories for cat in categories(c)) and all(cat not in + exclude_categories for cat in categories(c)) or (c in include_characters) + + >>> query() + ((0, 1114111),) + >>> query(min_codepoint=0, max_codepoint=128) + ((0, 128),) + >>> query(min_codepoint=0, max_codepoint=128, include_categories=['Lu']) + ((65, 90),) + >>> query(min_codepoint=0, max_codepoint=128, include_categories=['Lu'], + ... include_characters=u'☃') + ((65, 90), (9731, 9731)) + """ + if min_codepoint is None: + min_codepoint = 0 + if max_codepoint is None: + max_codepoint = sys.maxunicode + catkey = _category_key(exclude_categories, include_categories) + character_intervals = _intervals(include_characters or '') + exclude_intervals = _intervals(exclude_characters or '') + qkey = ( + catkey, min_codepoint, max_codepoint, + character_intervals, exclude_intervals + ) + try: + return limited_category_index_cache[qkey] + except KeyError: + pass + base = _query_for_key(catkey) + result = [] + for u, v in base: + if v >= min_codepoint and u <= max_codepoint: + result.append(( + max(u, min_codepoint), min(v, max_codepoint) + )) + result = tuple(result) + result = _union_intervals(result, character_intervals) + result = _subtract_intervals(result, exclude_intervals) + limited_category_index_cache[qkey] = result + return result diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/compat.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/compat.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/compat.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/compat.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,563 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +# pylint: skip-file + +from __future__ import division, print_function, absolute_import + +import re +import sys +import math +import time +import array +import codecs +import inspect +import platform +import importlib +from base64 import b64encode +from collections import namedtuple + +try: + from collections import OrderedDict, Counter +except ImportError: + from ordereddict import OrderedDict # type: ignore + from counter import Counter # type: ignore + +try: + from collections import abc +except ImportError: + import collections as abc # type: ignore + +if False: + from typing import Type, Tuple # noqa + + +PY2 = sys.version_info[0] == 2 +PY3 = sys.version_info[0] == 3 +PYPY = platform.python_implementation() == 'PyPy' +CAN_UNPACK_BYTE_ARRAY = sys.version_info[:3] >= (2, 7, 4) +CAN_PACK_HALF_FLOAT = sys.version_info[:2] >= (3, 6) + +WINDOWS = platform.system() == 'Windows' + +if sys.version_info[:2] <= (2, 6): + raise ImportError( + 'Hypothesis is not supported on Python versions before 2.7' + ) + + +def bit_length(n): + return n.bit_length() + + +def quiet_raise(exc): + # Overridden by Py3 version, iff `raise XXX from None` is valid + raise exc + + +if PY3: + def str_to_bytes(s): + return s.encode(a_good_encoding()) + + def int_to_text(i): + return str(i) + + text_type = str + binary_type = bytes + hrange = range + ARG_NAME_ATTRIBUTE = 'arg' + integer_types = (int,) + hunichr = chr + + def unicode_safe_repr(x): + return repr(x) + + def isidentifier(s): + return s.isidentifier() + + def escape_unicode_characters(s): + return codecs.encode(s, 'unicode_escape').decode('ascii') + + def print_unicode(x): + print(x) + + exec(""" +def quiet_raise(exc): + raise exc from None +""") + + def int_from_bytes(data): + return int.from_bytes(data, 'big') + + def int_to_bytes(i, size): + return i.to_bytes(size, 'big') + + def to_bytes_sequence(ls): + return bytes(ls) + + def int_to_byte(i): + return bytes([i]) + + import struct + + struct_pack = struct.pack + struct_unpack = struct.unpack + + def benchmark_time(): + return time.monotonic() +else: + import struct + + def struct_pack(*args): + return hbytes(struct.pack(*args)) + + if CAN_UNPACK_BYTE_ARRAY: + def struct_unpack(fmt, string): + return struct.unpack(fmt, string) + else: + def struct_unpack(fmt, string): + return struct.unpack(fmt, str(string)) + + def int_from_bytes(data): + if CAN_UNPACK_BYTE_ARRAY: + unpackable_data = data + elif isinstance(data, bytearray): + unpackable_data = bytes(data) + else: + unpackable_data = data + assert isinstance(data, (bytes, bytearray)) + result = 0 + i = 0 + while i + 4 <= len(data): + result <<= 32 + result |= struct.unpack('>I', unpackable_data[i:i + 4])[0] + i += 4 + while i < len(data): + result <<= 8 + result |= data[i] + i += 1 + return int(result) + + def int_to_bytes(i, size): + assert i >= 0 + result = bytearray(size) + j = size - 1 + arg = i + while i and j >= 0: + result[j] = i & 255 + i >>= 8 + j -= 1 + if i: + raise OverflowError('i=%r cannot be represented in %r bytes' + % (arg, size)) + return hbytes(result) + + int_to_byte = chr + + def to_bytes_sequence(ls): + return bytearray(ls) + + def str_to_bytes(s): + return s + + def int_to_text(i): + return str(i).decode('ascii') + + VALID_PYTHON_IDENTIFIER = re.compile( + r"^[a-zA-Z_][a-zA-Z0-9_]*$" + ) + + def isidentifier(s): + return VALID_PYTHON_IDENTIFIER.match(s) + + def unicode_safe_repr(x): + r = repr(x) + assert isinstance(r, str) + return r.decode(a_good_encoding()) + + text_type = unicode + binary_type = str + + def hrange(start_or_finish, finish=None, step=None): + try: + if step is None: + if finish is None: + return xrange(start_or_finish) + else: + return xrange(start_or_finish, finish) + else: + return xrange(start_or_finish, finish, step) + except OverflowError: + if step == 0: + raise ValueError(u'step argument may not be zero') + if step is None: + step = 1 + if finish is not None: + start = start_or_finish + else: + start = 0 + finish = start_or_finish + assert step != 0 + if step > 0: + def shimrange(): + i = start + while i < finish: + yield i + i += step + else: + def shimrange(): + i = start + while i > finish: + yield i + i += step + return shimrange() + + ARG_NAME_ATTRIBUTE = 'id' + integer_types = (int, long) + hunichr = unichr + + def escape_unicode_characters(s): + return codecs.encode(s, 'string_escape') + + def print_unicode(x): + if isinstance(x, unicode): + x = x.encode(a_good_encoding()) + print(x) + + def benchmark_time(): + return time.time() + + +# coverage mixes unicode and str filepaths on Python 2, which causes us +# problems if we're running under unicodenazi (it might also cause problems +# when not running under unicodenazi, but hard to say for sure). This method +# exists to work around that: If we're given a unicode filepath, we turn it +# into a string file path using the appropriate encoding. See +# https://bitbucket.org/ned/coveragepy/issues/602/ for more information. +if PY2: + def encoded_filepath(filepath): + if isinstance(filepath, text_type): + return filepath.encode(sys.getfilesystemencoding()) + else: + return filepath +else: + def encoded_filepath(filepath): + return filepath + + +def a_good_encoding(): + return 'utf-8' + + +def to_unicode(x): + if isinstance(x, text_type): + return x + else: + return x.decode(a_good_encoding()) + + +def qualname(f): + try: + return f.__qualname__ + except AttributeError: + pass + try: + return f.im_class.__name__ + '.' + f.__name__ + except AttributeError: + return f.__name__ + + +try: + import typing +except ImportError: + typing_root_type = () # type: Tuple[type, ...] + ForwardRef = None +else: + if hasattr(typing, '_Final'): # new in Python 3.7 + typing_root_type = ( + typing._Final, typing._GenericAlias) # type: ignore + ForwardRef = typing.ForwardRef # type: ignore + else: + typing_root_type = (typing.TypingMeta, typing.TypeVar) # type: ignore + ForwardRef = typing._ForwardRef # type: ignore + + +if PY2: + FullArgSpec = namedtuple('FullArgSpec', 'args, varargs, varkw, defaults, ' + 'kwonlyargs, kwonlydefaults, annotations') + + def getfullargspec(func): + args, varargs, varkw, defaults = inspect.getargspec(func) + return FullArgSpec(args, varargs, varkw, defaults, [], None, + getattr(func, '__annotations__', {})) +else: + from inspect import getfullargspec, FullArgSpec + + +if sys.version_info[:2] < (3, 6): + def get_type_hints(thing): + try: + spec = getfullargspec(thing) + return { + k: v for k, v in spec.annotations.items() + if k in (spec.args + spec.kwonlyargs) and isinstance(v, type) + } + except TypeError: + return {} +else: + import typing + + def get_type_hints(thing): + try: + return typing.get_type_hints(thing) + except TypeError: + return {} + + +importlib_invalidate_caches = getattr( + importlib, 'invalidate_caches', lambda: ()) + + +if PY2: + CODE_FIELD_ORDER = [ + 'co_argcount', + 'co_nlocals', + 'co_stacksize', + 'co_flags', + 'co_code', + 'co_consts', + 'co_names', + 'co_varnames', + 'co_filename', + 'co_name', + 'co_firstlineno', + 'co_lnotab', + 'co_freevars', + 'co_cellvars', + ] +else: + CODE_FIELD_ORDER = [ + 'co_argcount', + 'co_kwonlyargcount', + 'co_nlocals', + 'co_stacksize', + 'co_flags', + 'co_code', + 'co_consts', + 'co_names', + 'co_varnames', + 'co_filename', + 'co_name', + 'co_firstlineno', + 'co_lnotab', + 'co_freevars', + 'co_cellvars', + ] + + +def update_code_location(code, newfile, newlineno): + """Take a code object and lie shamelessly about where it comes from. + + Why do we want to do this? It's for really shallow reasons involving + hiding the hypothesis_temporary_module code from test runners like + py.test's verbose mode. This is a vastly disproportionate terrible + hack that I've done purely for vanity, and if you're reading this + code you're probably here because it's broken something and now + you're angry at me. Sorry. + """ + unpacked = [ + getattr(code, name) for name in CODE_FIELD_ORDER + ] + unpacked[CODE_FIELD_ORDER.index('co_filename')] = newfile + unpacked[CODE_FIELD_ORDER.index('co_firstlineno')] = newlineno + return type(code)(*unpacked) + + +class compatbytes(bytearray): + __name__ = 'bytes' + + def __init__(self, *args, **kwargs): + bytearray.__init__(self, *args, **kwargs) + self.__hash = None + + def __str__(self): + return bytearray.__str__(self) + + def __repr__(self): + return 'compatbytes(b%r)' % (str(self),) + + def __hash__(self): + if self.__hash is None: + self.__hash = hash(str(self)) + return self.__hash + + def count(self, value): + c = 0 + for w in self: + if w == value: + c += 1 + return c + + def index(self, value): + for i, v in enumerate(self): + if v == value: + return i + raise ValueError('Value %r not in sequence %r' % (value, self)) + + def __add__(self, value): + assert isinstance(value, compatbytes) + return compatbytes(bytearray.__add__(self, value)) + + def __radd__(self, value): + assert isinstance(value, compatbytes) + return compatbytes(bytearray.__add__(value, self)) + + def __mul__(self, value): + return compatbytes(bytearray.__mul__(self, value)) + + def __rmul__(self, value): + return compatbytes(bytearray.__rmul__(self, value)) + + def __getitem__(self, *args, **kwargs): + r = bytearray.__getitem__(self, *args, **kwargs) + if isinstance(r, bytearray): + return compatbytes(r) + else: + return r + + __setitem__ = None # type: ignore + + def join(self, parts): + result = bytearray() + first = True + for p in parts: + if not first: + result.extend(self) + first = False + result.extend(p) + return compatbytes(result) + + def __contains__(self, value): + return any(v == value for v in self) + + +if PY2: + hbytes = compatbytes + reasonable_byte_type = bytearray + string_types = (str, unicode) +else: + hbytes = bytes + reasonable_byte_type = bytes + string_types = (str,) + + +EMPTY_BYTES = hbytes(b'') + +if PY2: + def to_str(s): + if isinstance(s, unicode): + return s.encode(a_good_encoding()) + assert isinstance(s, str) + return s +else: + def to_str(s): + return s + + +def cast_unicode(s, encoding=None): + if isinstance(s, bytes): + return s.decode(encoding or a_good_encoding(), 'replace') + return s + + +def get_stream_enc(stream, default=None): + return getattr(stream, 'encoding', None) or default + + +def implements_iterator(it): + """Turn things with a __next__ attribute into iterators on Python 2.""" + if PY2 and not hasattr(it, 'next') and hasattr(it, '__next__'): + it.next = it.__next__ + return it + + +if PY3: + FileNotFoundError = FileNotFoundError # type: Type[IOError] +else: + FileNotFoundError = IOError + +# We need to know what sort of exception gets thrown when you try to write over +# an existing file where you're not allowed to. This is rather less consistent +# between versions than might be hoped. +if PY3: + FileExistsError = FileExistsError # type: Type[IOError] + +elif WINDOWS: + FileExistsError = WindowsError + +else: + # This doesn't happen in this case: We're not on windows and don't support + # the x flag because it's Python 2, so there are no places where this can + # be thrown. + FileExistsError = None + + +if PY2: + # Under Python 2, math.floor and math.ceil return floats, which cannot + # represent large integers - eg `float(2**53) == float(2**53 + 1)`. + # We therefore implement them entirely in (long) integer operations. + def floor(x): + if int(x) != x and x < 0: + return int(x) - 1 + return int(x) + + def ceil(x): + if int(x) != x and x > 0: + return int(x) + 1 + return int(x) +else: + floor = math.floor + ceil = math.ceil + + +try: + from math import gcd +except ImportError: + from fractions import gcd + + +if PY2: + def b64decode(s): + from base64 import b64decode as base + return hbytes(base(s)) +else: + from base64 import b64decode + + +try: + from django.test import TransactionTestCase + from hypothesis.extra.django import HypothesisTestCase + + def bad_django_TestCase(runner): + if runner is None: + return False + return isinstance(runner, TransactionTestCase) and \ + not isinstance(runner, HypothesisTestCase) +except Exception: + # Can't use ImportError, because of e.g. Django config errors + def bad_django_TestCase(runner): + return False diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/conjecture/data.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/conjecture/data.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/conjecture/data.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/conjecture/data.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,343 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from enum import IntEnum + +import attr + +from hypothesis.errors import Frozen, StopTest, InvalidArgument +from hypothesis.internal.compat import hbytes, hrange, text_type, \ + bit_length, benchmark_time, int_from_bytes, unicode_safe_repr +from hypothesis.internal.escalation import mark_for_escalation +from hypothesis.internal.conjecture.utils import calc_label_from_name + +TOP_LABEL = calc_label_from_name('top') +DRAW_BYTES_LABEL = calc_label_from_name('draw_bytes() in ConjectureData') + + +class Status(IntEnum): + OVERRUN = 0 + INVALID = 1 + VALID = 2 + INTERESTING = 3 + + def __repr__(self): + return 'Status.%s' % (self.name,) + + +@attr.s(slots=True) +class Example(object): + depth = attr.ib() + label = attr.ib() + index = attr.ib() + start = attr.ib() + end = attr.ib(default=None) + + # An example is "trivial" if it only contains forced bytes and zero bytes. + # All examples start out as trivial, and then get marked non-trivial when + # we see a byte that is neither forced nor zero. + trivial = attr.ib(default=True) + discarded = attr.ib(default=None) + children = attr.ib(default=attr.Factory(list)) + + @property + def length(self): + return self.end - self.start + + +@attr.s(slots=True, frozen=True) +class Block(object): + start = attr.ib() + end = attr.ib() + index = attr.ib() + + forced = attr.ib() + all_zero = attr.ib() + + @property + def bounds(self): + return (self.start, self.end) + + @property + def length(self): + return self.end - self.start + + @property + def trivial(self): + return self.forced or self.all_zero + + +global_test_counter = 0 + + +MAX_DEPTH = 100 + + +class ConjectureData(object): + + @classmethod + def for_buffer(self, buffer): + buffer = hbytes(buffer) + return ConjectureData( + max_length=len(buffer), + draw_bytes=lambda data, n: + hbytes(buffer[data.index:data.index + n]) + ) + + def __init__(self, max_length, draw_bytes): + self.max_length = max_length + self.is_find = False + self._draw_bytes = draw_bytes + self.overdraw = 0 + self.block_starts = {} + self.blocks = [] + self.buffer = bytearray() + self.output = u'' + self.status = Status.VALID + self.frozen = False + global global_test_counter + self.testcounter = global_test_counter + global_test_counter += 1 + self.start_time = benchmark_time() + self.events = set() + self.forced_indices = set() + self.masked_indices = {} + self.interesting_origin = None + self.draw_times = [] + self.max_depth = 0 + + self.examples = [] + self.example_stack = [] + self.has_discards = False + + self.start_example(TOP_LABEL) + + def __assert_not_frozen(self, name): + if self.frozen: + raise Frozen( + 'Cannot call %s on frozen ConjectureData' % ( + name,)) + + @property + def depth(self): + # We always have a single example wrapping everything. We want to treat + # that as depth 0 rather than depth 1. + return len(self.example_stack) - 1 + + @property + def index(self): + return len(self.buffer) + + def all_block_bounds(self): + return [block.bounds for block in self.blocks] + + def note(self, value): + self.__assert_not_frozen('note') + if not isinstance(value, text_type): + value = unicode_safe_repr(value) + self.output += value + + def draw(self, strategy, label=None): + if self.is_find and not strategy.supports_find: + raise InvalidArgument(( + 'Cannot use strategy %r within a call to find (presumably ' + 'because it would be invalid after the call had ended).' + ) % (strategy,)) + + if strategy.is_empty: + self.mark_invalid() + + if self.depth >= MAX_DEPTH: + self.mark_invalid() + + return self.__draw(strategy, label=label) + + def __draw(self, strategy, label): + at_top_level = self.depth == 0 + if label is None: + label = strategy.label + self.start_example(label=label) + try: + if not at_top_level: + return strategy.do_draw(self) + else: + start_time = benchmark_time() + try: + return strategy.do_draw(self) + except BaseException as e: + mark_for_escalation(e) + raise + finally: + self.draw_times.append(benchmark_time() - start_time) + finally: + self.stop_example() + + def start_example(self, label): + self.__assert_not_frozen('start_example') + + i = len(self.examples) + new_depth = self.depth + 1 + ex = Example( + index=i, + depth=new_depth, label=label, start=self.index, + ) + self.examples.append(ex) + if self.example_stack: + p = self.example_stack[-1] + self.examples[p].children.append(ex) + self.example_stack.append(i) + self.max_depth = max(self.max_depth, self.depth) + return ex + + def stop_example(self, discard=False): + if self.frozen: + return + + k = self.example_stack.pop() + ex = self.examples[k] + ex.end = self.index + + if self.example_stack and not ex.trivial: + self.examples[self.example_stack[-1]].trivial = False + + # We don't want to count empty examples as discards even if the flag + # says we should. This leads to situations like + # https://github.com/HypothesisWorks/hypothesis/issues/1230 + # where it can look like we should discard data but there's nothing + # useful for us to do. + if self.index == ex.start: + discard = False + + ex.discarded = discard + + if discard: + self.has_discards = True + + def note_event(self, event): + self.events.add(event) + + def freeze(self): + if self.frozen: + assert isinstance(self.buffer, hbytes) + return + self.finish_time = benchmark_time() + + while self.example_stack: + self.stop_example() + + self.frozen = True + + if self.status >= Status.VALID: + discards = [] + for ex in self.examples: + if ex.length == 0: + continue + if discards: + u, v = discards[-1] + if u <= ex.start <= ex.end <= v: + continue + if ex.discarded: + discards.append((ex.start, ex.end)) + continue + + self.buffer = hbytes(self.buffer) + self.events = frozenset(self.events) + del self._draw_bytes + + def draw_bits(self, n): + self.__assert_not_frozen('draw_bits') + if n == 0: + result = 0 + elif n % 8 == 0: + return int_from_bytes(self.draw_bytes(n // 8)) + else: + n_bytes = (n // 8) + 1 + self.__check_capacity(n_bytes) + buf = bytearray(self._draw_bytes(self, n_bytes)) + assert len(buf) == n_bytes + mask = (1 << (n % 8)) - 1 + buf[0] &= mask + self.masked_indices[self.index] = mask + buf = hbytes(buf) + self.__write(buf) + result = int_from_bytes(buf) + + assert bit_length(result) <= n + return result + + def write(self, string): + self.__assert_not_frozen('write') + self.__check_capacity(len(string)) + assert isinstance(string, hbytes) + original = self.index + self.__write(string, forced=True) + self.forced_indices.update(hrange(original, self.index)) + return string + + def __check_capacity(self, n): + if self.index + n > self.max_length: + self.overdraw = self.index + n - self.max_length + self.status = Status.OVERRUN + self.freeze() + raise StopTest(self.testcounter) + + def __write(self, result, forced=False): + ex = self.start_example(DRAW_BYTES_LABEL) + initial = self.index + n = len(result) + + block = Block( + start=initial, + end=initial + n, + index=len(self.blocks), + forced=forced, + all_zero=not any(result), + ) + ex.trivial = block.trivial + + self.block_starts.setdefault(n, []).append(block.start) + self.blocks.append(block) + assert self.blocks[block.index] is block + assert len(result) == n + assert self.index == initial + self.buffer.extend(result) + self.stop_example() + + def draw_bytes(self, n): + self.__assert_not_frozen('draw_bytes') + if n == 0: + return hbytes(b'') + self.__check_capacity(n) + result = self._draw_bytes(self, n) + assert len(result) == n + self.__write(result) + return hbytes(result) + + def mark_interesting(self, interesting_origin=None): + self.__assert_not_frozen('mark_interesting') + self.interesting_origin = interesting_origin + self.status = Status.INTERESTING + self.freeze() + raise StopTest(self.testcounter) + + def mark_invalid(self): + self.__assert_not_frozen('mark_invalid') + self.status = Status.INVALID + self.freeze() + raise StopTest(self.testcounter) diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/conjecture/engine.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/conjecture/engine.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/conjecture/engine.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/conjecture/engine.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,2509 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import heapq +from enum import Enum +from random import Random, getrandbits +from weakref import WeakKeyDictionary +from functools import total_ordering + +import attr + +from hypothesis import Phase, Verbosity, HealthCheck +from hypothesis import settings as Settings +from hypothesis._settings import local_settings, note_deprecation +from hypothesis.reporting import debug_report +from hypothesis.internal.compat import Counter, ceil, hbytes, hrange, \ + int_to_bytes, benchmark_time, int_from_bytes, to_bytes_sequence +from hypothesis.internal.healthcheck import fail_health_check +from hypothesis.internal.conjecture.data import MAX_DEPTH, Status, \ + StopTest, ConjectureData +from hypothesis.internal.conjecture.shrinking import Length, Integer, \ + Lexical, Ordering + +# Tell pytest to omit the body of this module from tracebacks +# http://doc.pytest.org/en/latest/example/simple.html#writing-well-integrated-assertion-helpers +__tracebackhide__ = True + + +HUNG_TEST_TIME_LIMIT = 5 * 60 +MAX_SHRINKS = 500 + +CACHE_RESET_FREQUENCY = 1000 +MUTATION_POOL_SIZE = 100 + + +@attr.s +class HealthCheckState(object): + valid_examples = attr.ib(default=0) + invalid_examples = attr.ib(default=0) + overrun_examples = attr.ib(default=0) + draw_times = attr.ib(default=attr.Factory(list)) + + +class ExitReason(Enum): + max_examples = 0 + max_iterations = 1 + timeout = 2 + max_shrinks = 3 + finished = 4 + flaky = 5 + + +class RunIsComplete(Exception): + pass + + +class ConjectureRunner(object): + + def __init__( + self, test_function, settings=None, random=None, + database_key=None, + ): + self._test_function = test_function + self.settings = settings or Settings() + self.shrinks = 0 + self.call_count = 0 + self.event_call_counts = Counter() + self.valid_examples = 0 + self.start_time = benchmark_time() + self.random = random or Random(getrandbits(128)) + self.database_key = database_key + self.status_runtimes = {} + + self.all_drawtimes = [] + self.all_runtimes = [] + + self.events_to_strings = WeakKeyDictionary() + + self.target_selector = TargetSelector(self.random) + + self.interesting_examples = {} + self.covering_examples = {} + + self.shrunk_examples = set() + + self.health_check_state = None + + self.used_examples_from_database = False + self.reset_tree_to_empty() + + def reset_tree_to_empty(self): + # Previously-tested byte streams are recorded in a prefix tree, so that + # we can: + # - Avoid testing the same stream twice (in some cases). + # - Avoid testing a prefix of a past stream (in some cases), + # since that should only result in overrun. + # - Generate stream prefixes that we haven't tried before. + + # Tree nodes are stored in an array to prevent heavy nesting of data + # structures. Branches are dicts mapping bytes to child nodes (which + # will in general only be partially populated). Leaves are + # ConjectureData objects that have been previously seen as the result + # of following that path. + self.tree = [{}] + + # A node is dead if there is nothing left to explore past that point. + # Recursively, a node is dead if either it is a leaf or every byte + # leads to a dead node when starting from here. + self.dead = set() + + # We rewrite the byte stream at various points during parsing, to one + # that will produce an equivalent result but is in some sense more + # canonical. We keep track of these so that when walking the tree we + # can identify nodes where the exact byte value doesn't matter and + # treat all bytes there as equivalent. This significantly reduces the + # size of the search space and removes a lot of redundant examples. + + # Maps tree indices where to the unique byte that is valid at that + # point. Corresponds to data.write() calls. + self.forced = {} + + # Maps tree indices to a mask that restricts bytes at that point. + # Currently this is only updated by draw_bits, but it potentially + # could get used elsewhere. + self.masks = {} + + # Where a tree node consists of the beginning of a block we track the + # size of said block. This allows us to tell when an example is too + # short even if it goes off the unexplored region of the tree - if it + # is at the beginning of a block of size 4 but only has 3 bytes left, + # it's going to overrun the end of the buffer regardless of the + # buffer contents. + self.block_sizes = {} + + def __tree_is_exhausted(self): + return 0 in self.dead + + def test_function(self, data): + if benchmark_time() - self.start_time >= HUNG_TEST_TIME_LIMIT: + fail_health_check(self.settings, ( + 'Your test has been running for at least five minutes. This ' + 'is probably not what you intended, so by default Hypothesis ' + 'turns it into an error.' + ), HealthCheck.hung_test) + + self.call_count += 1 + try: + self._test_function(data) + data.freeze() + except StopTest as e: + if e.testcounter != data.testcounter: + self.save_buffer(data.buffer) + raise e + except BaseException: + self.save_buffer(data.buffer) + raise + finally: + data.freeze() + self.note_details(data) + + self.target_selector.add(data) + + self.debug_data(data) + + if data.status == Status.VALID: + self.valid_examples += 1 + + # Record the test result in the tree, to avoid unnecessary work in + # the future. + + # The tree has two main uses: + + # 1. It is mildly useful in some cases during generation where there is + # a high probability of duplication but it is possible to generate + # many examples. e.g. if we had input of the form none() | text() + # then we would generate duplicates 50% of the time, and would + # like to avoid that and spend more time exploring the text() half + # of the search space. The tree allows us to predict in advance if + # the test would lead to a duplicate and avoid that. + # 2. When shrinking it is *extremely* useful to be able to anticipate + # duplication, because we try many similar and smaller test cases, + # and these will tend to have a very high duplication rate. This is + # where the tree usage really shines. + # + # Unfortunately, as well as being the less useful type of tree usage, + # the first type is also the most expensive! Once we've entered shrink + # mode our time remaining is essentially bounded - we're just here + # until we've found the minimal example. In exploration mode, we might + # be early on in a very long-running processs, and keeping everything + # we've ever seen lying around ends up bloating our memory usage + # substantially by causing us to use O(max_examples) memory. + # + # As a compromise, what we do is reset the cache every so often. This + # keeps our memory usage bounded. It has a few unfortunate failure + # modes in that it means that we can't always detect when we should + # have stopped - if we are exploring a language which has only slightly + # more than cache reset frequency number of members, we will end up + # exploring indefinitely when we could have stopped. However, this is + # a fairly unusual case - thanks to exponential blow-ups in language + # size, most languages are either very large (possibly infinite) or + # very small. Nevertheless we want CACHE_RESET_FREQUENCY to be quite + # high to avoid this case coming up in practice. + if ( + self.call_count % CACHE_RESET_FREQUENCY == 0 and + not self.interesting_examples + ): + self.reset_tree_to_empty() + + # First, iterate through the result's buffer, to create the node that + # will hold this result. Also note any forced or masked bytes. + tree_node = self.tree[0] + indices = [] + node_index = 0 + for i, b in enumerate(data.buffer): + # We build a list of all the node indices visited on our path + # through the tree, since we'll need to refer to them later. + indices.append(node_index) + + # If this buffer position was forced or masked, then mark its + # corresponding node as forced/masked. + if i in data.forced_indices: + self.forced[node_index] = b + try: + self.masks[node_index] = data.masked_indices[i] + except KeyError: + pass + + try: + # Use the current byte to find the next node on our path. + node_index = tree_node[b] + except KeyError: + # That node doesn't exist yet, so create it. + node_index = len(self.tree) + # Create a new branch node. If this should actually be a leaf + # node, it will be overwritten when we store the result. + self.tree.append({}) + tree_node[b] = node_index + + tree_node = self.tree[node_index] + + if node_index in self.dead: + # This part of the tree has already been marked as dead, so + # there's no need to traverse any deeper. + break + + # At each node that begins a block, record the size of that block. + for u, v in data.all_block_bounds(): + # This can happen if we hit a dead node when walking the buffer. + # In that case we already have this section of the tree mapped. + if u >= len(indices): + break + self.block_sizes[indices[u]] = v - u + + # Forcibly mark all nodes beyond the zero-bound point as dead, + # because we don't intend to try any other values there. + self.dead.update(indices[self.cap:]) + + # Now store this result in the tree (if appropriate), and check if + # any nodes need to be marked as dead. + if data.status != Status.OVERRUN and node_index not in self.dead: + # Mark this node as dead, because it produced a result. + # Trying to explore suffixes of it would not be helpful. + self.dead.add(node_index) + # Store the result in the tree as a leaf. This will overwrite the + # branch node that was created during traversal. + self.tree[node_index] = data + + # Review the traversed nodes, to see if any should be marked + # as dead. We check them in reverse order, because as soon as we + # find a live node, all nodes before it must still be live too. + for j in reversed(indices): + mask = self.masks.get(j, 0xff) + assert _is_simple_mask(mask) + max_size = mask + 1 + + if ( + len(self.tree[j]) < max_size and + j not in self.forced + ): + # There are still byte values to explore at this node, + # so it isn't dead yet. + break + if set(self.tree[j].values()).issubset(self.dead): + # Everything beyond this node is known to be dead, + # and there are no more values to explore here (see above), + # so this node must be dead too. + self.dead.add(j) + else: + # Even though all of this node's possible values have been + # tried, there are still some deeper nodes that remain + # alive, so this node isn't dead yet. + break + + if data.status == Status.INTERESTING: + key = data.interesting_origin + changed = False + try: + existing = self.interesting_examples[key] + except KeyError: + changed = True + else: + if sort_key(data.buffer) < sort_key(existing.buffer): + self.shrinks += 1 + self.downgrade_buffer(existing.buffer) + changed = True + + if changed: + self.save_buffer(data.buffer) + self.interesting_examples[key] = data + self.shrunk_examples.discard(key) + + if self.shrinks >= MAX_SHRINKS: + self.exit_with(ExitReason.max_shrinks) + if ( + self.settings.timeout > 0 and + benchmark_time() >= self.start_time + self.settings.timeout + ): + note_deprecation(( + 'Your tests are hitting the settings timeout (%.2fs). ' + 'This functionality will go away in a future release ' + 'and you should not rely on it. Instead, try setting ' + 'max_examples to be some value lower than %d (the number ' + 'of examples your test successfully ran here). Or, if you ' + 'would prefer your tests to run to completion, regardless ' + 'of how long they take, you can set the timeout value to ' + 'hypothesis.unlimited.' + ) % ( + self.settings.timeout, self.valid_examples), + self.settings) + self.exit_with(ExitReason.timeout) + + if not self.interesting_examples: + if self.valid_examples >= self.settings.max_examples: + self.exit_with(ExitReason.max_examples) + if self.call_count >= max( + self.settings.max_examples * 10, + # We have a high-ish default max iterations, so that tests + # don't become flaky when max_examples is too low. + 1000 + ): + self.exit_with(ExitReason.max_iterations) + + if self.__tree_is_exhausted(): + self.exit_with(ExitReason.finished) + + self.record_for_health_check(data) + + def generate_novel_prefix(self): + """Uses the tree to proactively generate a starting sequence of bytes + that we haven't explored yet for this test. + + When this method is called, we assume that there must be at + least one novel prefix left to find. If there were not, then the + test run should have already stopped due to tree exhaustion. + """ + prefix = bytearray() + node = 0 + while True: + assert len(prefix) < self.cap + assert node not in self.dead + + # Figure out the range of byte values we should be trying. + # Normally this will be 0-255, unless the current position has a + # mask. + mask = self.masks.get(node, 0xff) + assert _is_simple_mask(mask) + upper_bound = mask + 1 + + try: + c = self.forced[node] + # This position has a forced byte value, so trying a different + # value wouldn't be helpful. Just add the forced byte, and + # move on to the next position. + prefix.append(c) + node = self.tree[node][c] + continue + except KeyError: + pass + + # Provisionally choose the next byte value. + # This will change later if we find that it was a bad choice. + c = self.random.randrange(0, upper_bound) + + try: + next_node = self.tree[node][c] + if next_node in self.dead: + # Whoops, the byte value we chose for this position has + # already been fully explored. Let's pick a new value, and + # this time choose a value that's definitely still alive. + choices = [ + b for b in hrange(upper_bound) + if self.tree[node].get(b) not in self.dead + ] + assert choices + c = self.random.choice(choices) + node = self.tree[node][c] + else: + # The byte value we chose is in the tree, but it still has + # some unexplored descendants, so it's a valid choice. + node = next_node + prefix.append(c) + except KeyError: + # The byte value we chose isn't in the tree at this position, + # which means we've successfully found a novel prefix. + prefix.append(c) + break + assert node not in self.dead + return hbytes(prefix) + + @property + def cap(self): + return self.settings.buffer_size // 2 + + def record_for_health_check(self, data): + # Once we've actually found a bug, there's no point in trying to run + # health checks - they'll just mask the actually important information. + if data.status == Status.INTERESTING: + self.health_check_state = None + + state = self.health_check_state + + if state is None: + return + + state.draw_times.extend(data.draw_times) + + if data.status == Status.VALID: + state.valid_examples += 1 + elif data.status == Status.INVALID: + state.invalid_examples += 1 + else: + assert data.status == Status.OVERRUN + state.overrun_examples += 1 + + max_valid_draws = 10 + max_invalid_draws = 50 + max_overrun_draws = 20 + + assert state.valid_examples <= max_valid_draws + + if state.valid_examples == max_valid_draws: + self.health_check_state = None + return + + if state.overrun_examples == max_overrun_draws: + fail_health_check(self.settings, ( + 'Examples routinely exceeded the max allowable size. ' + '(%d examples overran while generating %d valid ones)' + '. Generating examples this large will usually lead to' + ' bad results. You could try setting max_size parameters ' + 'on your collections and turning ' + 'max_leaves down on recursive() calls.') % ( + state.overrun_examples, state.valid_examples + ), HealthCheck.data_too_large) + if state.invalid_examples == max_invalid_draws: + fail_health_check(self.settings, ( + 'It looks like your strategy is filtering out a lot ' + 'of data. Health check found %d filtered examples but ' + 'only %d good ones. This will make your tests much ' + 'slower, and also will probably distort the data ' + 'generation quite a lot. You should adapt your ' + 'strategy to filter less. This can also be caused by ' + 'a low max_leaves parameter in recursive() calls') % ( + state.invalid_examples, state.valid_examples + ), HealthCheck.filter_too_much) + + draw_time = sum(state.draw_times) + + if draw_time > 1.0: + fail_health_check(self.settings, ( + 'Data generation is extremely slow: Only produced ' + '%d valid examples in %.2f seconds (%d invalid ones ' + 'and %d exceeded maximum size). Try decreasing ' + "size of the data you're generating (with e.g." + 'max_size or max_leaves parameters).' + ) % ( + state.valid_examples, draw_time, state.invalid_examples, + state.overrun_examples), HealthCheck.too_slow,) + + def save_buffer(self, buffer): + if self.settings.database is not None: + key = self.database_key + if key is None: + return + self.settings.database.save(key, hbytes(buffer)) + + def downgrade_buffer(self, buffer): + if ( + self.settings.database is not None and + self.database_key is not None + ): + self.settings.database.move( + self.database_key, self.secondary_key, buffer) + + @property + def secondary_key(self): + return b'.'.join((self.database_key, b'secondary')) + + @property + def covering_key(self): + return b'.'.join((self.database_key, b'coverage')) + + def note_details(self, data): + runtime = max(data.finish_time - data.start_time, 0.0) + self.all_runtimes.append(runtime) + self.all_drawtimes.extend(data.draw_times) + self.status_runtimes.setdefault(data.status, []).append(runtime) + for event in set(map(self.event_to_string, data.events)): + self.event_call_counts[event] += 1 + + def debug(self, message): + with local_settings(self.settings): + debug_report(message) + + @property + def report_debug_info(self): + return self.settings.verbosity >= Verbosity.debug + + def debug_data(self, data): + if not self.report_debug_info: + return + + stack = [[]] + + def go(ex): + if ex.length == 0: + return + if len(ex.children) == 0: + stack[-1].append(int_from_bytes( + data.buffer[ex.start:ex.end] + )) + else: + node = [] + stack.append(node) + + for v in ex.children: + go(v) + stack.pop() + if len(node) == 1: + stack[-1].extend(node) + else: + stack[-1].append(node) + go(data.examples[0]) + assert len(stack) == 1 + + status = repr(data.status) + + if data.status == Status.INTERESTING: + status = '%s (%r)' % (status, data.interesting_origin,) + + self.debug('%d bytes %r -> %s, %s' % ( + data.index, stack[0], status, data.output, + )) + + def run(self): + with local_settings(self.settings): + try: + self._run() + except RunIsComplete: + pass + for v in self.interesting_examples.values(): + self.debug_data(v) + self.debug( + u'Run complete after %d examples (%d valid) and %d shrinks' + % (self.call_count, self.valid_examples, self.shrinks)) + + def _new_mutator(self): + target_data = [None] + + def draw_new(data, n): + return uniform(self.random, n) + + def draw_existing(data, n): + return target_data[0].buffer[data.index:data.index + n] + + def draw_smaller(data, n): + existing = target_data[0].buffer[data.index:data.index + n] + r = uniform(self.random, n) + if r <= existing: + return r + return _draw_predecessor(self.random, existing) + + def draw_larger(data, n): + existing = target_data[0].buffer[data.index:data.index + n] + r = uniform(self.random, n) + if r >= existing: + return r + return _draw_successor(self.random, existing) + + def reuse_existing(data, n): + choices = data.block_starts.get(n, []) + if choices: + i = self.random.choice(choices) + return hbytes(data.buffer[i:i + n]) + else: + result = uniform(self.random, n) + assert isinstance(result, hbytes) + return result + + def flip_bit(data, n): + buf = bytearray( + target_data[0].buffer[data.index:data.index + n]) + i = self.random.randint(0, n - 1) + k = self.random.randint(0, 7) + buf[i] ^= (1 << k) + return hbytes(buf) + + def draw_zero(data, n): + return hbytes(b'\0' * n) + + def draw_max(data, n): + return hbytes([255]) * n + + def draw_constant(data, n): + return hbytes([self.random.randint(0, 255)]) * n + + def redraw_last(data, n): + u = target_data[0].blocks[-1].start + if data.index + n <= u: + return target_data[0].buffer[data.index:data.index + n] + else: + return uniform(self.random, n) + + options = [ + draw_new, + redraw_last, redraw_last, + reuse_existing, reuse_existing, + draw_existing, draw_smaller, draw_larger, + flip_bit, + draw_zero, draw_max, draw_zero, draw_max, + draw_constant, + ] + + bits = [ + self.random.choice(options) for _ in hrange(3) + ] + + prefix = [None] + + def mutate_from(origin): + target_data[0] = origin + prefix[0] = self.generate_novel_prefix() + return draw_mutated + + def draw_mutated(data, n): + if data.index + n > len(target_data[0].buffer): + result = uniform(self.random, n) + else: + result = self.random.choice(bits)(data, n) + p = prefix[0] + if data.index < len(p): + start = p[data.index:data.index + n] + result = start + result[len(start):] + return self.__zero_bound(data, result) + + return mutate_from + + def __rewrite(self, data, result): + return self.__zero_bound(data, result) + + def __zero_bound(self, data, result): + """This tries to get the size of the generated data under control by + replacing the result with zero if we are too deep or have already + generated too much data. + + This causes us to enter "shrinking mode" there and thus reduce + the size of the generated data. + """ + initial = len(result) + if data.depth * 2 >= MAX_DEPTH or data.index >= self.cap: + data.forced_indices.update( + hrange(data.index, data.index + initial)) + data.hit_zero_bound = True + result = hbytes(initial) + elif data.index + initial >= self.cap: + data.hit_zero_bound = True + n = self.cap - data.index + data.forced_indices.update( + hrange(self.cap, data.index + initial)) + result = result[:n] + hbytes(initial - n) + assert len(result) == initial + return result + + @property + def database(self): + if self.database_key is None: + return None + return self.settings.database + + def has_existing_examples(self): + return ( + self.database is not None and + Phase.reuse in self.settings.phases + ) + + def reuse_existing_examples(self): + """If appropriate (we have a database and have been told to use it), + try to reload existing examples from the database. + + If there are a lot we don't try all of them. We always try the + smallest example in the database (which is guaranteed to be the + last failure) and the largest (which is usually the seed example + which the last failure came from but we don't enforce that). We + then take a random sampling of the remainder and try those. Any + examples that are no longer interesting are cleared out. + """ + if self.has_existing_examples(): + self.debug('Reusing examples from database') + # We have to do some careful juggling here. We have two database + # corpora: The primary and secondary. The primary corpus is a + # small set of minimized examples each of which has at one point + # demonstrated a distinct bug. We want to retry all of these. + + # We also have a secondary corpus of examples that have at some + # point demonstrated interestingness (currently only ones that + # were previously non-minimal examples of a bug, but this will + # likely expand in future). These are a good source of potentially + # interesting examples, but there are a lot of them, so we down + # sample the secondary corpus to a more manageable size. + + corpus = sorted( + self.settings.database.fetch(self.database_key), + key=sort_key + ) + desired_size = max(2, ceil(0.1 * self.settings.max_examples)) + + for extra_key in [self.secondary_key, self.covering_key]: + if len(corpus) < desired_size: + extra_corpus = list( + self.settings.database.fetch(extra_key), + ) + + shortfall = desired_size - len(corpus) + + if len(extra_corpus) <= shortfall: + extra = extra_corpus + else: + extra = self.random.sample(extra_corpus, shortfall) + extra.sort(key=sort_key) + corpus.extend(extra) + + self.used_examples_from_database = len(corpus) > 0 + + for existing in corpus: + last_data = ConjectureData.for_buffer(existing) + try: + self.test_function(last_data) + finally: + if last_data.status != Status.INTERESTING: + self.settings.database.delete( + self.database_key, existing) + self.settings.database.delete( + self.secondary_key, existing) + + def exit_with(self, reason): + self.exit_reason = reason + raise RunIsComplete() + + def generate_new_examples(self): + if Phase.generate not in self.settings.phases: + return + + zero_data = self.cached_test_function( + hbytes(self.settings.buffer_size)) + if zero_data.status == Status.OVERRUN or ( + zero_data.status == Status.VALID and + len(zero_data.buffer) * 2 > self.settings.buffer_size + ): + fail_health_check( + self.settings, + 'The smallest natural example for your test is extremely ' + 'large. This makes it difficult for Hypothesis to generate ' + 'good examples, especially when trying to reduce failing ones ' + 'at the end. Consider reducing the size of your data if it is ' + 'of a fixed size. You could also fix this by improving how ' + 'your data shrinks (see https://hypothesis.readthedocs.io/en/' + 'latest/data.html#shrinking for details), or by introducing ' + 'default values inside your strategy. e.g. could you replace ' + 'some arguments with their defaults by using ' + 'one_of(none(), some_complex_strategy)?', + HealthCheck.large_base_example + ) + + # If the language starts with writes of length >= cap then there is + # only one string in it: Everything after cap is forced to be zero (or + # to be whatever value is written there). That means that once we've + # tried the zero value, there's nothing left for us to do, so we + # exit early here. + for i in hrange(self.cap): + if i not in zero_data.forced_indices: + break + else: + self.exit_with(ExitReason.finished) + + self.health_check_state = HealthCheckState() + + count = 0 + while not self.interesting_examples and ( + count < 10 or self.health_check_state is not None + ): + prefix = self.generate_novel_prefix() + + def draw_bytes(data, n): + if data.index < len(prefix): + result = prefix[data.index:data.index + n] + if len(result) < n: + result += uniform(self.random, n - len(result)) + else: + result = uniform(self.random, n) + return self.__zero_bound(data, result) + + targets_found = len(self.covering_examples) + + last_data = ConjectureData( + max_length=self.settings.buffer_size, + draw_bytes=draw_bytes + ) + self.test_function(last_data) + last_data.freeze() + + count += 1 + + mutations = 0 + mutator = self._new_mutator() + + zero_bound_queue = [] + + while not self.interesting_examples: + if zero_bound_queue: + # Whenever we generated an example and it hits a bound + # which forces zero blocks into it, this creates a weird + # distortion effect by making certain parts of the data + # stream (especially ones to the right) much more likely + # to be zero. We fix this by redistributing the generated + # data by shuffling it randomly. This results in the + # zero data being spread evenly throughout the buffer. + # Hopefully the shrinking this causes will cause us to + # naturally fail to hit the bound. + # If it doesn't then we will queue the new version up again + # (now with more zeros) and try again. + overdrawn = zero_bound_queue.pop() + buffer = bytearray(overdrawn.buffer) + + # These will have values written to them that are different + # from what's in them anyway, so the value there doesn't + # really "count" for distributional purposes, and if we + # leave them in then they can cause the fraction of non + # zero bytes to increase on redraw instead of decrease. + for i in overdrawn.forced_indices: + buffer[i] = 0 + + self.random.shuffle(buffer) + buffer = hbytes(buffer) + + def draw_bytes(data, n): + result = buffer[data.index:data.index + n] + if len(result) < n: + result += hbytes(n - len(result)) + return self.__rewrite(data, result) + + data = ConjectureData( + draw_bytes=draw_bytes, + max_length=self.settings.buffer_size, + ) + self.test_function(data) + data.freeze() + else: + origin = self.target_selector.select() + mutations += 1 + targets_found = len(self.covering_examples) + data = ConjectureData( + draw_bytes=mutator(origin), + max_length=self.settings.buffer_size + ) + self.test_function(data) + data.freeze() + if ( + data.status > origin.status or + len(self.covering_examples) > targets_found + ): + mutations = 0 + elif ( + data.status < origin.status or + mutations >= 10 + ): + # Cap the variations of a single example and move on to + # an entirely fresh start. Ten is an entirely arbitrary + # constant, but it's been working well for years. + mutations = 0 + mutator = self._new_mutator() + if getattr(data, 'hit_zero_bound', False): + zero_bound_queue.append(data) + mutations += 1 + + def _run(self): + self.start_time = benchmark_time() + + self.reuse_existing_examples() + self.generate_new_examples() + self.shrink_interesting_examples() + + self.exit_with(ExitReason.finished) + + def shrink_interesting_examples(self): + """If we've found interesting examples, try to replace each of them + with a minimal interesting example with the same interesting_origin. + + We may find one or more examples with a new interesting_origin + during the shrink process. If so we shrink these too. + """ + if ( + Phase.shrink not in self.settings.phases or + not self.interesting_examples + ): + return + + for prev_data in sorted( + self.interesting_examples.values(), + key=lambda d: sort_key(d.buffer) + ): + assert prev_data.status == Status.INTERESTING + data = ConjectureData.for_buffer(prev_data.buffer) + self.test_function(data) + if data.status != Status.INTERESTING: + self.exit_with(ExitReason.flaky) + + self.clear_secondary_key() + + while len(self.shrunk_examples) < len(self.interesting_examples): + target, example = min([ + (k, v) for k, v in self.interesting_examples.items() + if k not in self.shrunk_examples], + key=lambda kv: (sort_key(kv[1].buffer), sort_key(repr(kv[0]))), + ) + self.debug('Shrinking %r' % (target,)) + + def predicate(d): + if d.status < Status.INTERESTING: + return False + return d.interesting_origin == target + + self.shrink(example, predicate) + + self.shrunk_examples.add(target) + + def clear_secondary_key(self): + if self.has_existing_examples(): + # If we have any smaller examples in the secondary corpus, now is + # a good time to try them to see if they work as shrinks. They + # probably won't, but it's worth a shot and gives us a good + # opportunity to clear out the database. + + # It's not worth trying the primary corpus because we already + # tried all of those in the initial phase. + corpus = sorted( + self.settings.database.fetch(self.secondary_key), + key=sort_key + ) + for c in corpus: + primary = { + v.buffer for v in self.interesting_examples.values() + } + + cap = max(map(sort_key, primary)) + + if sort_key(c) > cap: + break + else: + self.cached_test_function(c) + # We unconditionally remove c from the secondary key as it + # is either now primary or worse than our primary example + # of this reason for interestingness. + self.settings.database.delete(self.secondary_key, c) + + def shrink(self, example, predicate): + s = self.new_shrinker(example, predicate) + s.shrink() + return s.shrink_target + + def new_shrinker(self, example, predicate): + return Shrinker(self, example, predicate) + + def prescreen_buffer(self, buffer): + """Attempt to rule out buffer as a possible interesting candidate. + + Returns False if we know for sure that running this buffer will not + produce an interesting result. Returns True if it might (because it + explores territory we have not previously tried). + + This is purely an optimisation to try to reduce the number of tests we + run. "return True" would be a valid but inefficient implementation. + """ + + # Traverse the tree, to see if we have already tried this buffer + # (or a prefix of it). + node_index = 0 + n = len(buffer) + for k, b in enumerate(buffer): + if node_index in self.dead: + # This buffer (or a prefix of it) has already been tested, + # or has already had its descendants fully explored. + # Testing it again would not be helpful. + return False + try: + # The block size at that point provides a lower bound on how + # many more bytes are required. If the buffer does not have + # enough bytes to fulfill that block size then we can rule out + # this buffer. + if k + self.block_sizes[node_index] > n: + return False + except KeyError: + pass + + # If there's a forced value or a mask at this position, then + # pretend that the buffer already contains a matching value, + # because the test function is going to do the same. + try: + b = self.forced[node_index] + except KeyError: + pass + try: + b = b & self.masks[node_index] + except KeyError: + pass + + try: + node_index = self.tree[node_index][b] + except KeyError: + # The buffer wasn't in the tree, which means we haven't tried + # it. That makes it a possible candidate. + return True + else: + # We ran out of buffer before reaching a leaf or a missing node. + # That means the test function is going to draw beyond the end + # of this buffer, which makes it a bad candidate. + return False + + def cached_test_function(self, buffer): + """Checks the tree to see if we've tested this buffer, and returns the + previous result if we have. + + Otherwise we call through to ``test_function``, and return a + fresh result. + """ + node_index = 0 + for c in buffer: + # If there's a forced value or a mask at this position, then + # pretend that the buffer already contains a matching value, + # because the test function is going to do the same. + try: + c = self.forced[node_index] + except KeyError: + pass + try: + c = c & self.masks[node_index] + except KeyError: + pass + + try: + node_index = self.tree[node_index][c] + except KeyError: + # The byte at this position isn't in the tree, which means + # we haven't tested this buffer. Break out of the tree + # traversal, and run the test function normally. + break + node = self.tree[node_index] + if isinstance(node, ConjectureData): + # This buffer (or a prefix of it) has already been tested. + # Return the stored result instead of trying it again. + return node + else: + # Falling off the end of this loop means that we're about to test + # a prefix of a previously-tested byte stream. The test is going + # to draw beyond the end of the buffer, and fail due to overrun. + # Currently there is no special handling for this case. + pass + + # We didn't find a match in the tree, so we need to run the test + # function normally. + result = ConjectureData.for_buffer(buffer) + self.test_function(result) + return result + + def event_to_string(self, event): + if isinstance(event, str): + return event + try: + return self.events_to_strings[event] + except KeyError: + pass + result = str(event) + self.events_to_strings[event] = result + return result + + +def _is_simple_mask(mask): + """A simple mask is ``(2 ** n - 1)`` for some ``n``, so it has the effect + of keeping the lowest ``n`` bits and discarding the rest. + + A mask in this form can produce any integer between 0 and the mask itself + (inclusive), and the total number of these values is ``(mask + 1)``. + """ + return (mask & (mask + 1)) == 0 + + +def _draw_predecessor(rnd, xs): + r = bytearray() + any_strict = False + for x in to_bytes_sequence(xs): + if not any_strict: + c = rnd.randint(0, x) + if c < x: + any_strict = True + else: + c = rnd.randint(0, 255) + r.append(c) + return hbytes(r) + + +def _draw_successor(rnd, xs): + r = bytearray() + any_strict = False + for x in to_bytes_sequence(xs): + if not any_strict: + c = rnd.randint(x, 255) + if c > x: + any_strict = True + else: + c = rnd.randint(0, 255) + r.append(c) + return hbytes(r) + + +def sort_key(buffer): + return (len(buffer), buffer) + + +def uniform(random, n): + return int_to_bytes(random.getrandbits(n * 8), n) + + +def pop_random(random, values): + """Remove a random element of values, possibly changing the ordering of its + elements.""" + + # We pick the element at a random index. Rather than removing that element + # from the list (which would be an O(n) operation), we swap it to the end + # and return the last element of the list. This changes the order of + # the elements, but as long as these elements are only accessed through + # random sampling that doesn't matter. + i = random.randrange(0, len(values)) + values[i], values[-1] = values[-1], values[i] + return values.pop() + + +class TargetSelector(object): + """Data structure for selecting targets to use for mutation. + + The main purpose of the TargetSelector is to maintain a pool of "reasonably + useful" examples, while keeping the pool of bounded size. + + In particular it ensures: + + 1. We only retain examples of the best status we've seen so far (not + counting INTERESTING, which is special). + 2. We preferentially return examples we've never returned before when + select() is called. + 3. The number of retained examples is never more than self.pool_size, with + past examples discarded automatically, preferring ones that we have + already explored from. + + These invariants are fairly heavily prone to change - they're not + especially well validated as being optimal, and are mostly just a decent + compromise between diversity and keeping the pool size bounded. + """ + + def __init__(self, random, pool_size=MUTATION_POOL_SIZE): + self.random = random + self.best_status = Status.OVERRUN + self.pool_size = pool_size + self.reset() + + def __len__(self): + return len(self.fresh_examples) + len(self.used_examples) + + def reset(self): + self.fresh_examples = [] + self.used_examples = [] + + def add(self, data): + if data.status == Status.INTERESTING: + return + if data.status < self.best_status: + return + if data.status > self.best_status: + self.best_status = data.status + self.reset() + + # Note that technically data could be a duplicate. This rarely happens + # (only if we've exceeded the CACHE_RESET_FREQUENCY number of test + # function calls), but it's certainly possible. This could result in + # us having the same example multiple times, possibly spread over both + # lists. We could check for this, but it's not a major problem so we + # don't bother. + self.fresh_examples.append(data) + if len(self) > self.pool_size: + pop_random(self.random, self.used_examples or self.fresh_examples) + assert self.pool_size == len(self) + + def select(self): + if self.fresh_examples: + result = pop_random(self.random, self.fresh_examples) + self.used_examples.append(result) + return result + else: + return self.random.choice(self.used_examples) + + +def block_program(description): + """Mini-DSL for block rewriting. A sequence of commands that will be run + over all contiguous sequences of blocks of the description length in order. + Commands are: + + * ".", keep this block unchanged + * "-", subtract one from this block. + * "0", replace this block with zero + * "X", delete this block + + If a command does not apply (currently only because it's - on a zero + block) the block will be silently skipped over. As a side effect of + running a block program its score will be updated. + """ + + def run(self): + n = len(description) + i = 0 + while i + n <= len(self.shrink_target.blocks): + attempt = bytearray(self.shrink_target.buffer) + failed = False + for k, d in reversed(list(enumerate(description))): + j = i + k + u, v = self.blocks[j].bounds + if d == '-': + value = int_from_bytes(attempt[u:v]) + if value == 0: + failed = True + break + else: + attempt[u:v] = int_to_bytes(value - 1, v - u) + elif d == 'X': + del attempt[u:v] + else: # pragma: no cover + assert False, 'Unrecognised command %r' % (d,) + if failed or not self.incorporate_new_buffer(attempt): + i += 1 + run.command = description + run.__name__ = 'block_program(%r)' % (description,) + return run + + +class PassClassification(Enum): + CANDIDATE = 0 + HOPEFUL = 1 + DUBIOUS = 2 + AVOID = 3 + SPECIAL = 4 + + +@total_ordering +@attr.s(slots=True, cmp=False) +class ShrinkPass(object): + pass_function = attr.ib() + index = attr.ib() + + classification = attr.ib(default=PassClassification.CANDIDATE) + + successes = attr.ib(default=0) + runs = attr.ib(default=0) + calls = attr.ib(default=0) + shrinks = attr.ib(default=0) + deletions = attr.ib(default=0) + + @property + def failures(self): + return self.runs - self.successes + + @property + def name(self): + return self.pass_function.__name__ + + def __eq__(self, other): + return self.index == other.index + + def __hash__(self): + return hash(self.index) + + def __lt__(self, other): + return self.key() < other.key() + + def key(self): + # Smaller is better. + return ( + self.runs, + self.failures, + self.calls, + self.index + ) + + +class Shrinker(object): + """A shrinker is a child object of a ConjectureRunner which is designed to + manage the associated state of a particular shrink problem. + + Currently the only shrink problem we care about is "interesting and with a + particular interesting_origin", but this is abstracted into a general + purpose predicate for more flexibility later - e.g. we are likely to want + to shrink with respect to a particular coverage target later. + + Data with a status < VALID may be assumed not to satisfy the predicate. + + The expected usage pattern is that this is only ever called from within the + engine. + """ + + DEFAULT_PASSES = [ + 'pass_to_descendant', + 'zero_examples', + 'adaptive_example_deletion', + 'reorder_examples', + 'minimize_duplicated_blocks', + 'minimize_individual_blocks', + ] + + EMERGENCY_PASSES = [ + block_program('-XX'), + block_program('XX'), + 'example_deletion_with_block_lowering', + 'shrink_offset_pairs', + 'minimize_block_pairs_retaining_sum', + ] + + def __init__(self, engine, initial, predicate): + """Create a shrinker for a particular engine, with a given starting + point and predicate. When shrink() is called it will attempt to find an + example for which predicate is True and which is strictly smaller than + initial. + + Note that initial is a ConjectureData object, and predicate + takes ConjectureData objects. + """ + self.__engine = engine + self.__predicate = predicate + self.discarding_failed = False + self.__shrinking_prefixes = set() + + self.initial_size = len(initial.buffer) + + # We add a second level of caching local to the shrinker. This is a bit + # of a hack. Ideally we'd be able to rely on the engine's functionality + # for this. Doing it this way has two benefits: Firstly, the engine + # does not currently cache overruns (and probably shouldn't, but could + # recreate them on demand if necessary), and secondly Python dicts are + # much faster than our pure Python tree-based lookups. + self.__test_function_cache = {} + + # We keep track of the current best example on the shrink_target + # attribute. + self.shrink_target = None + self.update_shrink_target(initial) + self.shrinks = 0 + + self.initial_calls = self.__engine.call_count + + self.current_pass_depth = 0 + self.passes_by_name = {} + self.clear_passes() + + for p in Shrinker.DEFAULT_PASSES: + self.add_new_pass(p) + + for p in Shrinker.EMERGENCY_PASSES: + self.add_new_pass(p, classification=PassClassification.AVOID) + + self.add_new_pass( + 'lower_common_block_offset', + classification=PassClassification.SPECIAL + ) + + def clear_passes(self): + """Reset all passes on the shrinker, leaving it in a blank state. + + This is mostly useful for testing. + """ + # Note that we deliberately do not clear passes_by_name. This means + # that we can still look up and explicitly run the standard passes, + # they just won't be avaiable by default. + + self.passes = [] + self.passes_awaiting_requeue = [] + self.pass_queues = {c: [] for c in PassClassification} + + self.known_programs = set() + + def add_new_pass(self, run, classification=PassClassification.CANDIDATE): + """Creates a shrink pass corresponding to calling ``run(self)``""" + if isinstance(run, str): + run = getattr(Shrinker, run) + p = ShrinkPass( + pass_function=run, index=len(self.passes), + classification=classification, + ) + if hasattr(run, 'command'): + self.known_programs.add(run.command) + self.passes.append(p) + self.passes_awaiting_requeue.append(p) + self.passes_by_name[p.name] = p + return p + + def shrink_pass(self, name): + if hasattr(Shrinker, name) and name not in self.passes_by_name: + self.add_new_pass(name, classification=PassClassification.SPECIAL) + return self.passes_by_name[name] + + def requeue_passes(self): + """Move all passes from passes_awaiting_requeue to their relevant + queues.""" + while self.passes_awaiting_requeue: + p = self.passes_awaiting_requeue.pop() + heapq.heappush(self.pass_queues[p.classification], p) + + def has_queued_passes(self, classification): + """Checks if any shrink passes are currently enqued under this + classification (note that there may be passes with this classification + currently awaiting requeue).""" + return len(self.pass_queues[classification]) > 0 + + def pop_queued_pass(self, classification): + """Pop and run a single queued pass with this classification.""" + sp = heapq.heappop(self.pass_queues[classification]) + self.passes_awaiting_requeue.append(sp) + self.run_shrink_pass(sp) + + def run_queued_until_change(self, classification): + """Run passes with this classification until there are no more or one + of them succeeds in shrinking the target.""" + initial = self.shrink_target + while ( + self.has_queued_passes(classification) and + self.shrink_target is initial + ): + self.pop_queued_pass(classification) + return self.shrink_target is not initial + + def run_one_queued_pass(self, classification): + """Run a single queud pass with this classification (if there are + any).""" + if self.has_queued_passes(classification): + self.pop_queued_pass(classification) + + def run_queued_passes(self, classification): + """Run all queued passes with this classification.""" + while self.has_queued_passes(classification): + self.pop_queued_pass(classification) + + @property + def calls(self): + return self.__engine.call_count + + def consider_new_buffer(self, buffer): + buffer = hbytes(buffer) + return buffer.startswith(self.buffer) or \ + self.incorporate_new_buffer(buffer) + + def incorporate_new_buffer(self, buffer): + buffer = hbytes(buffer[:self.shrink_target.index]) + try: + existing = self.__test_function_cache[buffer] + except KeyError: + pass + else: + return self.incorporate_test_data(existing) + + # Sometimes an attempt at lexicographic minimization will do the wrong + # thing because the buffer has changed under it (e.g. something has + # turned into a write, the bit size has changed). The result would be + # an invalid string, but it's better for us to just ignore it here as + # it turns out to involve quite a lot of tricky book-keeping to get + # this right and it's better to just handle it in one place. + if sort_key(buffer) >= sort_key(self.shrink_target.buffer): + return False + + if self.shrink_target.buffer.startswith(buffer): + return False + + if not self.__engine.prescreen_buffer(buffer): + return False + + assert sort_key(buffer) <= sort_key(self.shrink_target.buffer) + data = ConjectureData.for_buffer(buffer) + self.__engine.test_function(data) + self.__test_function_cache[buffer] = data + return self.incorporate_test_data(data) + + def incorporate_test_data(self, data): + self.__test_function_cache[data.buffer] = data + if ( + self.__predicate(data) and + sort_key(data.buffer) < sort_key(self.shrink_target.buffer) + ): + self.update_shrink_target(data) + self.__shrinking_block_cache = {} + return True + return False + + def cached_test_function(self, buffer): + buffer = hbytes(buffer) + try: + return self.__test_function_cache[buffer] + except KeyError: + pass + result = self.__engine.cached_test_function(buffer) + self.incorporate_test_data(result) + self.__test_function_cache[buffer] = result + return result + + def debug(self, msg): + self.__engine.debug(msg) + + @property + def random(self): + return self.__engine.random + + def run_shrink_pass(self, sp): + """Runs the function associated with ShrinkPass sp and updates the + relevant metadata. + + Note that sp may or may not be a pass currently associated with + this shrinker. This does not handle any requeing that is + required. + """ + if isinstance(sp, str): + sp = self.shrink_pass(sp) + + self.debug('Shrink Pass %s' % (sp.name,)) + + initial_shrinks = self.shrinks + initial_calls = self.calls + size = len(self.shrink_target.buffer) + try: + sp.pass_function(self) + finally: + calls = self.calls - initial_calls + shrinks = self.shrinks - initial_shrinks + deletions = size - len(self.shrink_target.buffer) + + sp.calls += calls + sp.shrinks += shrinks + sp.deletions += deletions + sp.runs += 1 + self.debug('Shrink Pass %s completed.' % (sp.name,)) + + # Complex state machine alert! A pass run can either succeed (we made + # at least one shrink) or fail (we didn't). This changes the pass's + # current classification according to the following possible + # transitions: + # + # CANDIDATE -------> HOPEFUL + # | ^ + # | | + # v v + # AVOID ---------> DUBIOUS + # + # From best to worst we want to run HOPEFUL, CANDIDATE, DUBIOUS, AVOID. + # We will try any one of them if we have to but we want to prioritise. + # + # When a run succeeds, a pass will follow an arrow to a better class. + # When it fails, it will follow an arrow to a worse one. + # If no such arrow is available, it stays where it is. + # + # We also have the classification SPECIAL for passes that do not get + # run as part of the normal process. + previous = sp.classification + + # If the pass didn't actually do anything we don't reclassify it. This + # is for things like remove_discarded which often are inapplicable. + if calls > 0 and sp.classification != PassClassification.SPECIAL: + if shrinks == 0: + if sp.successes > 0: + sp.classification = PassClassification.DUBIOUS + else: + sp.classification = PassClassification.AVOID + else: + sp.successes += 1 + if sp.classification == PassClassification.AVOID: + sp.classification = PassClassification.DUBIOUS + else: + sp.classification = PassClassification.HOPEFUL + if previous != sp.classification: + self.debug('Reclassified %s from %s to %s' % ( + sp.name, previous.name, sp.classification.name + )) + + def shrink(self): + """Run the full set of shrinks and update shrink_target. + + This method is "mostly idempotent" - calling it twice is unlikely to + have any effect, though it has a non-zero probability of doing so. + """ + # We assume that if an all-zero block of bytes is an interesting + # example then we're not going to do better than that. + # This might not technically be true: e.g. for integers() | booleans() + # the simplest example is actually [1, 0]. Missing this case is fairly + # harmless and this allows us to make various simplifying assumptions + # about the structure of the data (principally that we're never + # operating on a block of all zero bytes so can use non-zeroness as a + # signpost of complexity). + if ( + not any(self.shrink_target.buffer) or + self.incorporate_new_buffer(hbytes(len(self.shrink_target.buffer))) + ): + return + + try: + self.greedy_shrink() + finally: + if self.__engine.report_debug_info: + def s(n): + return 's' if n != 1 else '' + + total_deleted = self.initial_size - len( + self.shrink_target.buffer) + + self.debug('---------------------') + self.debug('Shrink pass profiling') + self.debug('---------------------') + self.debug('') + calls = self.__engine.call_count - self.initial_calls + self.debug(( + 'Shrinking made a total of %d call%s ' + 'of which %d shrank. This deleted %d byte%s out of %d.' + ) % ( + calls, s(calls), + self.shrinks, + total_deleted, s(total_deleted), + self.initial_size, + )) + for useful in [True, False]: + self.debug('') + if useful: + self.debug('Useful passes:') + else: + self.debug('Useless passes:') + self.debug('') + for p in sorted( + self.passes, + key=lambda t: ( + -t.calls, -t.runs, + t.deletions, t.shrinks, + ), + ): + if p.calls == 0: + continue + if (p.shrinks != 0) != useful: + continue + + self.debug(( + ' * %s ran %d time%s, making %d call%s of which ' + '%d shrank, deleting %d byte%s.' + ) % ( + p.name, + p.runs, s(p.runs), + p.calls, s(p.calls), + p.shrinks, + p.deletions, s(p.deletions), + )) + self.debug('') + + def greedy_shrink(self): + """Run a full set of greedy shrinks (that is, ones that will only ever + move to a better target) and update shrink_target appropriately. + + This method iterates to a fixed point and so is idempontent - calling + it twice will have exactly the same effect as calling it once. + """ + self.run_shrink_pass('alphabet_minimize') + while self.single_greedy_shrink_iteration(): + self.run_shrink_pass('lower_common_block_offset') + + def single_greedy_shrink_iteration(self): + """Performs a single run through each greedy shrink pass, but does not + loop to achieve a fixed point.""" + initial = self.shrink_target + + # What follows is a slightly delicate dance. What we want to do is try + # to ensure that: + # + # 1. If it is possible for us to be deleting data, we should be. + # 2. We do not end up repeating a lot of passes uselessly. + # 3. We do not want to run expensive or useless passes if we can + # possibly avoid doing so. + + self.requeue_passes() + + self.run_shrink_pass('remove_discarded') + + # First run the entire set of solid passes (ones that have previously + # made changes). It's important that we run all of them, not just one, + # as typically each pass may unlock others. + self.run_queued_passes(PassClassification.HOPEFUL) + + # While our solid passes are successfully shrinking the buffer, we can + # just keep doing that (note that this is a stronger condition than + # just making shrinks - it's a much better sense of progress. We can + # make only O(n) length reductions but we can make exponentially many + # shrinks). + if len(self.buffer) < len(initial.buffer): + return True + + # If we're stuck on length reductions then we pull in one candiate pass + # (if there are any). + # This should hopefully help us unlock any local minima that were + # starting to reduce the utility of the previous solid passes. + self.run_one_queued_pass(PassClassification.CANDIDATE) + + # We've pulled in a new candidate pass (or have no candidate passes + # left) and are making shrinks with the solid passes, so lets just + # keep on doing that. + if self.shrink_target is not initial: + return True + + # We're a bit stuck, so it's time to try some new passes. + for classification in [ + # First we try rerunning every pass we've previously seen succeed. + PassClassification.DUBIOUS, + # If that didn't work, we pull in some new candidate passes. + PassClassification.CANDIDATE, + # If that still didn't work, we now pull out all the stops and + # bring in the desperation passes. These are either passes that + # started as CANDIDATE but we have never seen work, or ones that + # are so expensive that they begin life as AVOID. + PassClassification.AVOID + ]: + if self.run_queued_until_change(classification): + return True + + assert self.shrink_target is initial + + return False + + @property + def buffer(self): + return self.shrink_target.buffer + + @property + def blocks(self): + return self.shrink_target.blocks + + def all_block_bounds(self): + return self.shrink_target.all_block_bounds() + + def each_pair_of_blocks(self, accept_first, accept_second): + """Yield each pair of blocks ``(a, b)``, such that ``a.index < + b.index``, but only if ``accept_first(a)`` and ``accept_second(b)`` are + both true.""" + i = 0 + while i < len(self.blocks): + j = i + 1 + while j < len(self.blocks): + block_i = self.blocks[i] + if not accept_first(block_i): + break + block_j = self.blocks[j] + if not accept_second(block_j): + j += 1 + continue + + yield (block_i, block_j) + # After this point, the shrink target could have changed, + # so blocks need to be re-checked. + + j += 1 + i += 1 + + def pass_to_descendant(self): + """Attempt to replace each example with a descendant example. + + This is designed to deal with strategies that call themselves + recursively. For example, suppose we had: + + binary_tree = st.deferred( + lambda: st.one_of( + st.integers(), st.tuples(binary_tree, binary_tree))) + + This pass guarantees that we can replace any binary tree with one of + its subtrees - each of those will create an interval that the parent + could validly be replaced with, and this pass will try doing that. + + This is pretty expensive - it takes O(len(intervals)^2) - so we run it + late in the process when we've got the number of intervals as far down + as possible. + """ + for ex in self.each_non_trivial_example(): + st = self.shrink_target + descendants = sorted(set( + st.buffer[d.start:d.end] for d in self.shrink_target.examples + if d.start >= ex.start and d.end <= ex.end and + d.length < ex.length and d.label == ex.label + ), key=sort_key) + + for d in descendants: + if self.incorporate_new_buffer( + self.buffer[:ex.start] + d + self.buffer[ex.end:] + ): + break + + def is_shrinking_block(self, i): + """Checks whether block i has been previously marked as a shrinking + block. + + If the shrink target has changed since i was last checked, will + attempt to calculate if an equivalent block in a previous shrink + target was marked as shrinking. + """ + if not self.__shrinking_prefixes: + return False + try: + return self.__shrinking_block_cache[i] + except KeyError: + pass + t = self.shrink_target + return self.__shrinking_block_cache.setdefault( + i, + t.buffer[:t.blocks[i].start] in self.__shrinking_prefixes + ) + + def is_payload_block(self, i): + """A block is payload if it is entirely non-structural: We can tinker + with its value freely and this will not affect the shape of the input + language. + + This is mostly a useful concept when we're doing lexicographic + minimimization on multiple blocks at once - by restricting ourself to + payload blocks, we expect the shape of the language to not change + under us (but must still guard against it doing so). + """ + return not ( + self.is_shrinking_block(i) or + self.shrink_target.blocks[i].forced + ) + + def lower_common_block_offset(self): + """Sometimes we find ourselves in a situation where changes to one part + of the byte stream unlock changes to other parts. Sometimes this is + good, but sometimes this can cause us to exhibit exponential slow + downs! + + e.g. suppose we had the following: + + m = draw(integers(min_value=0)) + n = draw(integers(min_value=0)) + assert abs(m - n) > 1 + + If this fails then we'll end up with a loop where on each iteration we + reduce each of m and n by 2 - m can't go lower because of n, then n + can't go lower because of m. + + This will take us O(m) iterations to complete, which is exponential in + the data size, as we gradually zig zag our way towards zero. + + This can only happen if we're failing to reduce the size of the byte + stream: The number of iterations that reduce the length of the byte + stream is bounded by that length. + + So what we do is this: We keep track of which blocks are changing, and + then if there's some non-zero common offset to them we try and minimize + them all at once by lowering that offset. + + This may not work, and it definitely won't get us out of all possible + exponential slow downs (an example of where it doesn't is where the + shape of the blocks changes as a result of this bouncing behaviour), + but it fails fast when it doesn't work and gets us out of a really + nastily slow case when it does. + """ + if len(self.__changed_blocks) <= 1: + return + + current = self.shrink_target + + blocked = [current.buffer[u:v] for u, v in current.all_block_bounds()] + + changed = [ + i for i in sorted(self.__changed_blocks) + if not self.shrink_target.blocks[i].trivial + ] + + if not changed: + return + + ints = [int_from_bytes(blocked[i]) for i in changed] + offset = min(ints) + assert offset > 0 + + for i in hrange(len(ints)): + ints[i] -= offset + + def reoffset(o): + new_blocks = list(blocked) + for i, v in zip(changed, ints): + new_blocks[i] = int_to_bytes(v + o, len(blocked[i])) + return self.incorporate_new_buffer(hbytes().join(new_blocks)) + + new_offset = Integer.shrink(offset, reoffset, random=self.random) + if new_offset == offset: + self.clear_change_tracking() + + def shrink_offset_pairs(self): + """Lowers pairs of blocks that need to maintain a constant difference + between their respective values. + + Before this shrink pass, two blocks explicitly offset from each + other would not get minimized properly: + >>> b = st.integers(0, 255) + >>> find(st.tuples(b, b), lambda x: x[0] == x[1] + 1) + (149,148) + + This expensive (O(n^2)) pass goes through every pair of non-zero + blocks in the current shrink target and sees if the shrink + target can be improved by applying a negative offset to both of them. + """ + + def int_from_block(i): + u, v = self.blocks[i].bounds + block_bytes = self.shrink_target.buffer[u:v] + return int_from_bytes(block_bytes) + + def block_len(i): + return self.blocks[i].length + + # Try reoffseting every pair + def reoffset_pair(pair, o): + n = len(self.blocks) + # Number of blocks may have changed, need to validate + valid_pair = [ + p for p in pair if p < n and int_from_block(p) > 0 and + self.is_payload_block(p) + ] + + if len(valid_pair) < 2: + return + + m = min([int_from_block(p) for p in valid_pair]) + + new_blocks = [self.shrink_target.buffer[u:v] + for u, v in self.shrink_target.all_block_bounds()] + for i in valid_pair: + new_blocks[i] = int_to_bytes( + int_from_block(i) + o - m, block_len(i)) + buffer = hbytes().join(new_blocks) + return self.incorporate_new_buffer(buffer) + + def is_non_zero_payload(block): + return not block.all_zero and self.is_payload_block(block.index) + + for block_i, block_j in self.each_pair_of_blocks( + is_non_zero_payload, + is_non_zero_payload, + ): + i = block_i.index + j = block_j.index + + value_i = int_from_block(i) + value_j = int_from_block(j) + + offset = min(value_i, value_j) + Integer.shrink( + offset, lambda o: reoffset_pair((i, j), o), + random=self.random, + ) + + def mark_shrinking(self, blocks): + """Mark each of these blocks as a shrinking block: That is, lowering + its value lexicographically may cause less data to be drawn after.""" + t = self.shrink_target + for i in blocks: + if self.__shrinking_block_cache.get(i) is True: + continue + self.__shrinking_block_cache[i] = True + prefix = t.buffer[:t.blocks[i].start] + self.__shrinking_prefixes.add(prefix) + + def clear_change_tracking(self): + self.__changed_blocks.clear() + + def mark_changed(self, i): + self.__changed_blocks.add(i) + + def update_shrink_target(self, new_target): + assert new_target.frozen + if self.shrink_target is not None: + current = self.shrink_target.buffer + new = new_target.buffer + assert sort_key(new) < sort_key(current) + self.shrinks += 1 + if ( + len(new_target.blocks) != len(self.shrink_target.blocks) or + new_target.all_block_bounds() != + self.shrink_target.all_block_bounds() + ): + self.clear_change_tracking() + else: + for i, (u, v) in enumerate( + self.shrink_target.all_block_bounds() + ): + if ( + i not in self.__changed_blocks and + current[u:v] != new[u:v] + ): + self.mark_changed(i) + else: + self.__changed_blocks = set() + + self.shrink_target = new_target + self.__shrinking_block_cache = {} + + def try_shrinking_blocks(self, blocks, b): + """Attempts to replace each block in the blocks list with b. Returns + True if it succeeded (which may include some additional modifications + to shrink_target). + + May call mark_shrinking with b if this causes a reduction in size. + + In current usage it is expected that each of the blocks currently have + the same value, although this is not essential. Note that b must be + < the block at min(blocks) or this is not a valid shrink. + + This method will attempt to do some small amount of work to delete data + that occurs after the end of the blocks. This is useful for cases where + there is some size dependency on the value of a block. + """ + initial_attempt = bytearray(self.shrink_target.buffer) + for i, block in enumerate(blocks): + if block >= len(self.blocks): + blocks = blocks[:i] + break + u, v = self.blocks[block].bounds + n = min(v - u, len(b)) + initial_attempt[v - n:v] = b[-n:] + + start = self.shrink_target.blocks[blocks[0]].start + end = self.shrink_target.blocks[blocks[-1]].end + + initial_data = self.cached_test_function(initial_attempt) + + if initial_data.status == Status.INTERESTING: + return initial_data is self.shrink_target + + # If this produced something completely invalid we ditch it + # here rather than trying to persevere. + if initial_data.status < Status.VALID: + return False + + # We've shrunk inside our group of blocks, so we have no way to + # continue. (This only happens when shrinking more than one block at + # a time). + if len(initial_data.buffer) < v: + return False + + lost_data = len(self.shrink_target.buffer) - len(initial_data.buffer) + + # If this did not in fact cause the data size to shrink we + # bail here because it's not worth trying to delete stuff from + # the remainder. + if lost_data <= 0: + return False + + self.mark_shrinking(blocks) + + # We now look for contiguous regions to delete that might help fix up + # this failed shrink. We only look for contiguous regions of the right + # lengths because doing anything more than that starts to get very + # expensive. See example_deletion_with_block_lowering for where we + # try to be more aggressive. + regions_to_delete = {(end, end + lost_data)} + + for j in (blocks[-1] + 1, blocks[-1] + 2): + if j >= min(len(initial_data.blocks), len(self.blocks)): + continue + # We look for a block very shortly after the last one that has + # lost some of its size, and try to delete from the beginning so + # that it retains the same integer value. This is a bit of a hyper + # specific trick designed to make our integers() strategy shrink + # well. + r1, s1 = self.shrink_target.blocks[j].bounds + r2, s2 = initial_data.blocks[j].bounds + lost = (s1 - r1) - (s2 - r2) + # Apparently a coverage bug? An assert False in the body of this + # will reliably fail, but it shows up as uncovered. + if lost <= 0 or r1 != r2: # pragma: no cover + continue + regions_to_delete.add((r1, r1 + lost)) + + for ex in self.shrink_target.examples: + if ex.start > start: + continue + if ex.end <= end: + continue + + replacement = initial_data.examples[ex.index] + + in_original = [ + c for c in ex.children if c.start >= end + ] + + in_replaced = [ + c for c in replacement.children if c.start >= end + ] + + if len(in_replaced) >= len(in_original) or not in_replaced: + continue + + # We've found an example where some of the children went missing + # as a result of this change, and just replacing it with the data + # it would have had and removing the spillover didn't work. This + # means that some of its children towards the right must be + # important, so we try to arrange it so that it retains its + # rightmost children instead of its leftmost. + regions_to_delete.add(( + in_original[0].start, in_original[-len(in_replaced)].start + )) + + for u, v in sorted( + regions_to_delete, key=lambda x: x[1] - x[0], reverse=True + ): + try_with_deleted = bytearray(initial_attempt) + del try_with_deleted[u:v] + if self.incorporate_new_buffer(try_with_deleted): + return True + return False + + def remove_discarded(self): + """Try removing all bytes marked as discarded. + + This pass is primarily to deal with data that has been ignored while + doing rejection sampling - e.g. as a result of an integer range, or a + filtered strategy. + + Such data will also be handled by the adaptive_example_deletion pass, + but that pass is necessarily more conservative and will try deleting + each interval individually. The common case is that all data drawn and + rejected can just be thrown away immediately in one block, so this pass + will be much faster than trying each one individually when it works. + """ + while self.shrink_target.has_discards: + discarded = [] + + for ex in self.shrink_target.examples: + if ex.discarded and ( + not discarded or ex.start >= discarded[-1][-1] + ): + discarded.append((ex.start, ex.end)) + + assert discarded + + attempt = bytearray(self.shrink_target.buffer) + for u, v in reversed(discarded): + del attempt[u:v] + + if not self.incorporate_new_buffer(attempt): + break + + def each_non_trivial_example(self): + """Iterates over all non-trivial examples in the current shrink target, + with care taken to ensure that every example yielded is current. + + Makes the assumption that no modifications will be made to the + shrink target prior to the currently yielded example. If this + assumption is violated this will probably raise an error, so + don't do that. + """ + stack = [0] + + while stack: + target = stack.pop() + if isinstance(target, tuple): + parent, i = target + parent = self.shrink_target.examples[parent] + example_index = parent.children[i].index + else: + example_index = target + + ex = self.shrink_target.examples[example_index] + + if ex.trivial: + continue + + yield ex + + ex = self.shrink_target.examples[example_index] + + if ex.trivial: + continue + + for i in range(len(ex.children)): + stack.append((example_index, i)) + + def example_wise_shrink(self, shrinker, **kwargs): + """Runs a sequence shrinker on the children of each example.""" + for ex in self.each_non_trivial_example(): + st = self.shrink_target + pieces = [ + st.buffer[c.start:c.end] + for c in ex.children + ] + if not pieces: + pieces = [st.buffer[ex.start:ex.end]] + prefix = st.buffer[:ex.start] + suffix = st.buffer[ex.end:] + shrinker.shrink( + pieces, lambda ls: self.incorporate_new_buffer( + prefix + hbytes().join(ls) + suffix, + ), random=self.random, **kwargs + ) + + def adaptive_example_deletion(self): + """Recursive deletion pass that tries to make the example located at + example_index as small as possible. This is the main point at which we + try to lower the size of the data. + + First attempts to replace the example with its minimal possible version + using zero_example. If the example is trivial (either because of that + or because it was anyway) then we assume there's nothing we can + usefully do here and return early. Otherwise, we attempt to minimize it + by deleting its children. + + If we do not make any successful changes, we recurse to the example's + children and attempt the same there. + """ + self.example_wise_shrink(Length) + + def zero_examples(self): + """Attempt to replace each example with a minimal version of itself.""" + for ex in self.each_non_trivial_example(): + u = ex.start + v = ex.end + attempt = self.cached_test_function( + self.buffer[:u] + hbytes(v - u) + self.buffer[v:] + ) + + # FIXME: IOU one attempt to debug this - DRMacIver + # This is a mysterious problem that should be impossible to trigger + # but isn't. I don't know what's going on, and it defeated my + # my attempts to reproduce or debug it. I'd *guess* it's related to + # nondeterminism in the test function. That should be impossible in + # the cases where I'm seeing it, but I haven't been able to put + # together a reliable reproduction of it. + if ex.index >= len(attempt.examples): # pragma: no cover + continue + + in_replacement = attempt.examples[ex.index] + used = in_replacement.length + + if ( + not self.__predicate(attempt) and + in_replacement.end < len(attempt.buffer) and + used < ex.length + ): + self.incorporate_new_buffer( + self.buffer[:u] + hbytes(used) + self.buffer[v:] + ) + + def minimize_duplicated_blocks(self): + """Find blocks that have been duplicated in multiple places and attempt + to minimize all of the duplicates simultaneously. + + This lets us handle cases where two values can't be shrunk + independently of each other but can easily be shrunk together. + For example if we had something like: + + ls = data.draw(lists(integers())) + y = data.draw(integers()) + assert y not in ls + + Suppose we drew y = 3 and after shrinking we have ls = [3]. If we were + to replace both 3s with 0, this would be a valid shrink, but if we were + to replace either 3 with 0 on its own the test would start passing. + + It is also useful for when that duplication is accidental and the value + of the blocks doesn't matter very much because it allows us to replace + more values at once. + """ + def canon(b): + i = 0 + while i < len(b) and b[i] == 0: + i += 1 + return b[i:] + + counts = Counter( + canon(self.shrink_target.buffer[u:v]) + for u, v in self.all_block_bounds() + ) + counts.pop(hbytes(), None) + blocks = [buffer for buffer, count in counts.items() if count > 1] + + blocks.sort(reverse=True) + blocks.sort(key=lambda b: counts[b] * len(b), reverse=True) + for block in blocks: + targets = [ + i for i, (u, v) in enumerate(self.all_block_bounds()) + if canon(self.shrink_target.buffer[u:v]) == block + ] + # This can happen if some blocks have been lost in the previous + # shrinking. + if len(targets) <= 1: + continue + + Lexical.shrink( + block, + lambda b: self.try_shrinking_blocks(targets, b), + random=self.random, full=False + ) + + def minimize_individual_blocks(self): + """Attempt to minimize each block in sequence. + + This is the pass that ensures that e.g. each integer we draw is a + minimum value. So it's the part that guarantees that if we e.g. do + + x = data.draw(integers()) + assert x < 10 + + then in our shrunk example, x = 10 rather than say 97. + """ + i = len(self.blocks) - 1 + while i >= 0: + u, v = self.blocks[i].bounds + Lexical.shrink( + self.shrink_target.buffer[u:v], + lambda b: self.try_shrinking_blocks((i,), b), + random=self.random, full=False, + ) + i -= 1 + + def example_deletion_with_block_lowering(self): + """Sometimes we get stuck where there is data that we could easily + delete, but it changes the number of examples generated, so we have to + change that at the same time. + + We handle most of the common cases in try_shrinking_blocks which is + pretty good at clearing out large contiguous blocks of dead space, + but it fails when there is data that has to stay in particular places + in the list. + + This pass exists as an emergency procedure to get us unstuck. For every + example and every block not inside that example it tries deleting the + example and modifying the block's value by one in either direction. + """ + i = 0 + while i < len(self.shrink_target.blocks): + if not self.is_shrinking_block(i): + i += 1 + continue + + u, v = self.blocks[i].bounds + + j = 0 + while j < len(self.shrink_target.examples): + n = int_from_bytes(self.shrink_target.buffer[u:v]) + if n == 0: + break + ex = self.shrink_target.examples[j] + if ex.start < v or ex.length == 0: + j += 1 + continue + + buf = bytearray(self.shrink_target.buffer) + buf[u:v] = int_to_bytes(n - 1, v - u) + del buf[ex.start:ex.end] + if not self.incorporate_new_buffer(buf): + j += 1 + + i += 1 + + def minimize_block_pairs_retaining_sum(self): + """This pass minimizes pairs of blocks subject to the constraint that + their sum when interpreted as integers remains the same. This allow us + to normalize a number of examples that we would otherwise struggle on. + e.g. consider the following: + + m = data.draw_bits(8) + n = data.draw_bits(8) + if m + n >= 256: + data.mark_interesting() + + The ideal example for this is m=1, n=255, but we will almost never + find that without a pass like this - we would only do so if we + happened to draw n=255 by chance. + + This kind of scenario comes up reasonably often in the context of e.g. + triggering overflow behaviour. + """ + for block_i, block_j in self.each_pair_of_blocks( + lambda block: ( + self.is_payload_block(block.index) and + not block.all_zero + ), + lambda block: self.is_payload_block(block.index), + ): + if block_i.length != block_j.length: + continue + + u, v = block_i.bounds + r, s = block_j.bounds + + m = int_from_bytes(self.shrink_target.buffer[u:v]) + n = int_from_bytes(self.shrink_target.buffer[r:s]) + + def trial(x, y): + if s > len(self.shrink_target.buffer): + return False + attempt = bytearray(self.shrink_target.buffer) + try: + attempt[u:v] = int_to_bytes(x, v - u) + attempt[r:s] = int_to_bytes(y, s - r) + except OverflowError: + return False + return self.incorporate_new_buffer(attempt) + + # We first attempt to move 1 from m to n. If that works + # then we treat that as a sign that it's worth trying + # a more expensive minimization. But if m was already 1 + # (we know it's > 0) then there's no point continuing + # because the value there is now zero. + if trial(m - 1, n + 1) and m > 1: + m = int_from_bytes(self.shrink_target.buffer[u:v]) + n = int_from_bytes(self.shrink_target.buffer[r:s]) + + tot = m + n + Integer.shrink( + m, lambda x: trial(x, tot - x), + random=self.random + ) + + def reorder_examples(self): + """This pass allows us to reorder pairs of examples which come from the + same strategy (or strategies that happen to pun to the same label by + accident, but that shouldn't happen often). + + For example, consider the following: + + .. code-block:: python + + import hypothesis.strategies as st + from hypothesis import given + + @given(st.text(), st.text()) + def test_does_not_exceed_100(x, y): + assert x != y + + Without the ability to reorder x and y this could fail either with + ``x="", ``y="0"``, or the other way around. With reordering it will + reliably fail with ``x=""``, ``y="0"``. + """ + self.example_wise_shrink(Ordering, key=sort_key) + + def alphabet_minimize(self): + """Attempts to replace most bytes in the buffer with 0 or 1. The main + benefit of this is that it significantly increases our cache hit rate + by making things that are equivalent more likely to have the same + representation. + + We only run this once rather than as part of the main passes as + once it's done its magic it's unlikely to ever be useful again. + It's important that it runs first though, because it makes + everything that comes after it faster because of the cache hits. + """ + for c in (1, 0): + alphabet = set(self.buffer) - set(hrange(c + 1)) + + if not alphabet: + continue + + def clear_to(reduced): + reduced = set(reduced) + attempt = hbytes([ + b if b <= c or b in reduced else c + for b in self.buffer + ]) + return self.consider_new_buffer(attempt) + + Length.shrink( + sorted(alphabet), clear_to, + random=self.random, + ) diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/conjecture/floats.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/conjecture/floats.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/conjecture/floats.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/conjecture/floats.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,251 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from array import array + +from hypothesis.internal.compat import hbytes, hrange, int_to_bytes +from hypothesis.internal.floats import float_to_int, int_to_float +from hypothesis.internal.conjecture.utils import calc_label_from_name + +""" +This module implements support for arbitrary floating point numbers in +Conjecture. It doesn't make any attempt to get a good distribution, only to +get a format that will shrink well. + +It works by defining an encoding of non-negative floating point numbers +(including NaN values with a zero sign bit) that has good lexical shrinking +properties. + +This encoding is a tagged union of two separate encodings for floating point +numbers, with the tag being the first bit of 64 and the remaining 63-bits being +the payload. + +If the tag bit is 0, the next 7 bits are ignored, and the remaining 7 bytes are +interpreted as a 7 byte integer in big-endian order and then converted to a +float (there is some redundancy here, as 7 * 8 = 56, which is larger than the +largest integer that floating point numbers can represent exactly, so multiple +encodings may map to the same float). + +If the tag bit is 1, we instead use somemthing that is closer to the normal +representation of floats (and can represent every non-negative float exactly) +but has a better ordering: + +1. NaNs are ordered after everything else. +2. Infinity is ordered after every finite number. +3. The sign is ignored unless two floating point numbers are identical in + absolute magnitude. In that case, the positive is ordered before the + negative. +4. Positive floating point numbers are ordered first by int(x) where + encoding(x) < encoding(y) if int(x) < int(y). +5. If int(x) == int(y) then x and y are sorted towards lower denominators of + their fractional parts. + +The format of this encoding of floating point goes as follows: + + [exponent] [mantissa] + +Each of these is the same size their equivalent in IEEE floating point, but are +in a different format. + +We translate exponents as follows: + + 1. The maximum exponent (2 ** 11 - 1) is left unchanged. + 2. We reorder the remaining exponents so that all of the positive exponents + are first, in increasing order, followed by all of the negative + exponents in decreasing order (where positive/negative is done by the + unbiased exponent e - 1023). + +We translate the mantissa as follows: + + 1. If the unbiased exponent is <= 0 we reverse it bitwise. + 2. If the unbiased exponent is >= 52 we leave it alone. + 3. If the unbiased exponent is in the range [1, 51] then we reverse the + low k bits, where k is 52 - unbiased exponen. + +The low bits correspond to the fractional part of the floating point number. +Reversing it bitwise means that we try to minimize the low bits, which kills +off the higher powers of 2 in the fraction first. +""" + + +MAX_EXPONENT = 0x7ff + +SPECIAL_EXPONENTS = (0, MAX_EXPONENT) + +BIAS = 1023 +MAX_POSITIVE_EXPONENT = (MAX_EXPONENT - 1 - BIAS) + +DRAW_FLOAT_LABEL = calc_label_from_name('drawing a float') + + +def exponent_key(e): + if e == MAX_EXPONENT: + return float('inf') + unbiased = e - BIAS + if unbiased < 0: + return 10000 - unbiased + else: + return unbiased + + +ENCODING_TABLE = array('H', sorted(hrange(MAX_EXPONENT + 1), key=exponent_key)) +DECODING_TABLE = array('H', [0]) * len(ENCODING_TABLE) + +for i, b in enumerate(ENCODING_TABLE): + DECODING_TABLE[b] = i + +del i, b + + +def decode_exponent(e): + """Take draw_bits(11) and turn it into a suitable floating point exponent + such that lexicographically simpler leads to simpler floats.""" + assert 0 <= e <= MAX_EXPONENT + return ENCODING_TABLE[e] + + +def encode_exponent(e): + """Take a floating point exponent and turn it back into the equivalent + result from conjecture.""" + assert 0 <= e <= MAX_EXPONENT + return DECODING_TABLE[e] + + +def reverse_byte(b): + result = 0 + for _ in range(8): + result <<= 1 + result |= (b & 1) + b >>= 1 + return result + + +# Table mapping individual bytes to the equivalent byte with the bits of the +# byte reversed. e.g. 1=0b1 is mapped to 0xb10000000=0x80=128. We use this +# precalculated table to simplify calculating the bitwise reversal of a longer +# integer. +REVERSE_BITS_TABLE = bytearray(map(reverse_byte, range(256))) + + +def reverse64(v): + """Reverse a 64-bit integer bitwise. + + We do this by breaking it up into 8 bytes. The 64-bit integer is then the + concatenation of each of these bytes. We reverse it by reversing each byte + on its own using the REVERSE_BITS_TABLE above, and then concatenating the + reversed bytes. + + In this case concatenating consists of shifting them into the right + position for the word and then oring the bits together. + """ + assert v.bit_length() <= 64 + return ( + (REVERSE_BITS_TABLE[(v >> 0) & 0xff] << 56) | + (REVERSE_BITS_TABLE[(v >> 8) & 0xff] << 48) | + (REVERSE_BITS_TABLE[(v >> 16) & 0xff] << 40) | + (REVERSE_BITS_TABLE[(v >> 24) & 0xff] << 32) | + (REVERSE_BITS_TABLE[(v >> 32) & 0xff] << 24) | + (REVERSE_BITS_TABLE[(v >> 40) & 0xff] << 16) | + (REVERSE_BITS_TABLE[(v >> 48) & 0xff] << 8) | + (REVERSE_BITS_TABLE[(v >> 56) & 0xff] << 0) + ) + + +MANTISSA_MASK = ((1 << 52) - 1) + + +def reverse_bits(x, n): + assert x.bit_length() <= n <= 64 + x = reverse64(x) + x >>= (64 - n) + return x + + +def update_mantissa(unbiased_exponent, mantissa): + if unbiased_exponent <= 0: + mantissa = reverse_bits(mantissa, 52) + elif unbiased_exponent <= 51: + n_fractional_bits = (52 - unbiased_exponent) + fractional_part = mantissa & ((1 << n_fractional_bits) - 1) + mantissa ^= fractional_part + mantissa |= reverse_bits(fractional_part, n_fractional_bits) + return mantissa + + +def lex_to_float(i): + assert i.bit_length() <= 64 + has_fractional_part = i >> 63 + if has_fractional_part: + exponent = (i >> 52) & ((1 << 11) - 1) + exponent = decode_exponent(exponent) + mantissa = i & MANTISSA_MASK + mantissa = update_mantissa(exponent - BIAS, mantissa) + + assert mantissa.bit_length() <= 52 + + return int_to_float((exponent << 52) | mantissa) + else: + integral_part = i & ((1 << 56) - 1) + return float(integral_part) + + +def float_to_lex(f): + if is_simple(f): + assert f >= 0 + return int(f) + return base_float_to_lex(f) + + +def base_float_to_lex(f): + i = float_to_int(f) + i &= ((1 << 63) - 1) + exponent = i >> 52 + mantissa = i & MANTISSA_MASK + mantissa = update_mantissa(exponent - BIAS, mantissa) + exponent = encode_exponent(exponent) + + assert mantissa.bit_length() <= 52 + return (1 << 63) | (exponent << 52) | mantissa + + +def is_simple(f): + try: + i = int(f) + except (ValueError, OverflowError): + return False + if i != f: + return False + return i.bit_length() <= 56 + + +def draw_float(data): + try: + data.start_example(DRAW_FLOAT_LABEL) + f = lex_to_float(data.draw_bits(64)) + if data.draw_bits(1): + f = -f + return f + finally: + data.stop_example() + + +def write_float(data, f): + data.write(int_to_bytes(float_to_lex(abs(f)), 8)) + sign = float_to_int(f) >> 63 + data.write(hbytes([sign])) diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/conjecture/__init__.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/conjecture/__init__.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/conjecture/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/conjecture/__init__.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,16 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/conjecture/shrinking/common.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/conjecture/shrinking/common.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/conjecture/shrinking/common.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/conjecture/shrinking/common.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,221 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + + +"""This module implements various useful common functions for shrinking tasks. +""" + + +def find_integer(f): + """Finds a (hopefully large) integer such that f(n) is True and f(n + 1) is + False. + + f(0) is assumed to be True and will not be checked. + """ + # We first do a linear scan over the small numbers and only start to do + # anything intelligent if f(4) is true. This is because it's very hard to + # win big when the result is small. If the result is 0 and we try 2 first + # then we've done twice as much work as we needed to! + for i in range(1, 5): + if not f(i): + return i - 1 + + # We now know that f(4) is true. We want to find some number for which + # f(n) is *not* true. + # lo is the largest number for which we know that f(lo) is true. + lo = 4 + + # Exponential probe upwards until we find some value hi such that f(hi) + # is not true. Subsequently we maintain the invariant that hi is the + # smallest number for which we know that f(hi) is not true. + hi = 5 + while f(hi): + lo = hi + hi *= 2 + + # Now binary search until lo + 1 = hi. At that point we have f(lo) and not + # f(lo + 1), as desired.. + while lo + 1 < hi: + mid = (lo + hi) // 2 + if f(mid): + lo = mid + else: + hi = mid + return lo + + +class Shrinker(object): + """A Shrinker object manages a single value and a predicate it should + satisfy, and attempts to improve it in some direction, making it smaller + and simpler.""" + + def __init__( + self, initial, predicate, random=None, full=False, debug=False, + name=None, **kwargs + ): + self.setup(**kwargs) + self.current = self.make_immutable(initial) + self.initial = self.current + self.random = random + self.full = full + self.changes = 0 + self.name = name + + self.__predicate = predicate + self.__seen = set() + self.debugging_enabled = debug + + @property + def calls(self): + return len(self.__seen) + + def __repr__(self): + return '%s(%sinitial=%r, current=%r)' % ( + type(self).__name__, + '' if self.name is None else '%r, ' % (self.name,), + self.initial, self.current + ) + + def setup(self, **kwargs): + """Runs initial setup code. + + Convenience function for children that doesn't require messing + with the signature of init. + """ + pass + + def delegate(self, other_class, convert_to, convert_from, **kwargs): + """Delegates shrinking to another shrinker class, by converting the + current value to and from it with provided functions.""" + self.call_shrinker( + other_class, convert_to(self.current), + lambda v: self.consider(convert_from(v)), + **kwargs + ) + + def call_shrinker(self, other_class, initial, predicate, **kwargs): + """Calls another shrinker class, passing through the relevant context + variables. + + Note we explicitly do not pass through full. + """ + + return other_class.shrink( + initial, predicate, + random=self.random, **kwargs + ) + + def debug(self, *args): + if self.debugging_enabled: + print('DEBUG', self, *args) + + @classmethod + def shrink(cls, initial, predicate, **kwargs): + """Shrink the value ``initial`` subject to the constraint that it + satisfies ``predicate``. + + Returns the shrunk value. + """ + shrinker = cls(initial, predicate, **kwargs) + shrinker.run() + return shrinker.current + + def run(self): + """Run for an appropriate number of steps to improve the current value. + + If self.full is True, will run until no further improvements can + be found. + """ + if self.short_circuit(): + return + if self.full: + prev = -1 + while self.changes != prev: + prev = self.changes + self.run_step() + else: + self.run_step() + self.debug('COMPLETE') + + def incorporate(self, value): + """Try using ``value`` as a possible candidate improvement. + + Return True if it works. + """ + value = self.make_immutable(value) + self.check_invariants(value) + if not self.left_is_better(value, self.current): + if value != self.current and (value == value): + self.debug('Rejected %r as worse than self.current=%r' % ( + value, self.current + )) + return False + if value in self.__seen: + return False + self.__seen.add(value) + if self.__predicate(value): + self.debug('shrinking to %r' % (value,)) + self.changes += 1 + self.current = value + return True + return False + + def consider(self, value): + """Returns True if make_immutable(value) == self.current after calling + self.incorporate(value).""" + value = self.make_immutable(value) + if value == self.current: + return True + return self.incorporate(value) + + def make_immutable(self, value): + """Convert value into an immutable (and hashable) representation of + itself. + + It is these immutable versions that the shrinker will work on. + + Defaults to just returning the value. + """ + return value + + def check_invariants(self, value): + """Make appropriate assertions about the value to ensure that it is + valid for this shrinker. + + Does nothing by default. + """ + pass + + def short_circuit(self): + """Possibly attempt to do some shrinking. + + If this returns True, the ``run`` method will terminate early + without doing any more work. + """ + raise NotImplementedError() + + def left_is_better(self, left, right): + """Returns True if the left is strictly simpler than the right + according to the standards of this shrinker.""" + raise NotImplementedError() + + def run_step(self): + """Run a single step of the main shrink loop, attempting to improve the + current value.""" + raise NotImplementedError() diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/conjecture/shrinking/floats.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/conjecture/shrinking/floats.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/conjecture/shrinking/floats.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/conjecture/shrinking/floats.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,97 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import sys +import math + +from hypothesis.internal.conjecture.floats import float_to_lex +from hypothesis.internal.conjecture.shrinking.common import Shrinker +from hypothesis.internal.conjecture.shrinking.integer import Integer + +MAX_PRECISE_INTEGER = 2 ** 53 + + +class Float(Shrinker): + + def setup(self): + self.NAN = float('nan') + self.debugging_enabled = True + + def make_immutable(self, f): + f = float(f) + if math.isnan(f): + # Always use the same NAN so it works properly in self.seen + f = self.NAN + return f + + def check_invariants(self, value): + # We only handle positive floats because we encode the sign separately + # anyway. + assert not (value < 0) + + def left_is_better(self, left, right): + lex1 = float_to_lex(left) + lex2 = float_to_lex(right) + return lex1 < lex2 + + def short_circuit(self): + for g in [sys.float_info.max, float('inf'), float('nan'), ]: + self.consider(g) + + # If we're stuck at a nasty float don't try to shrink it further. These + if math.isinf(self.current) or math.isnan(self.current): + return True + + # If its too large to represent as an integer, bail out here. It's + # better to try shrinking it in the main representation. + return self.current >= MAX_PRECISE_INTEGER + + def run_step(self): + # We check for a bunch of standard "large" floats. If we're currently + # worse than them and the shrink downwards doesn't help, abort early + # because there's not much useful we can do here. + + # Finally we get to the important bit: Each of these is a small change + # to the floating point number that corresponds to a large change in + # the lexical representation. Trying these ensures that our floating + # point shrink can always move past these obstacles. In particular it + # ensures we can always move to integer boundaries and shrink past a + # change that would require shifting the exponent while not changing + # the float value much. + + for g in [math.floor(self.current), math.ceil(self.current)]: + self.consider(g) + + if self.consider(int(self.current)): + self.debug('Just an integer now') + self.delegate( + Integer, convert_to=int, convert_from=float + ) + return + + m, n = self.current.as_integer_ratio() + i, r = divmod(m, n) + + # Now try to minimize the top part of the fraction as an integer. This + # basically splits the float as k + x with 0 <= x < 1 and minimizes + # k as an integer, but without the precision issues that would have. + self.call_shrinker( + Integer, + i, lambda k: self.consider((i * n + r) / n), + ) diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/conjecture/shrinking/__init__.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/conjecture/shrinking/__init__.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/conjecture/shrinking/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/conjecture/shrinking/__init__.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,26 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from hypothesis.internal.conjecture.shrinking.length import Length +from hypothesis.internal.conjecture.shrinking.integer import Integer +from hypothesis.internal.conjecture.shrinking.lexical import Lexical +from hypothesis.internal.conjecture.shrinking.ordering import Ordering + + +__all__ = [ + 'Lexical', 'Length', 'Integer', 'Ordering' +] diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/conjecture/shrinking/integer.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/conjecture/shrinking/integer.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/conjecture/shrinking/integer.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/conjecture/shrinking/integer.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,87 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from hypothesis.internal.compat import hrange +from hypothesis.internal.conjecture.shrinking.common import Shrinker, \ + find_integer + + +""" +This module implements a shrinker for non-negative integers. +""" + + +class Integer(Shrinker): + """Attempts to find a smaller integer. Guaranteed things to try ``0``, + + ``1``, ``initial - 1``, ``initial - 2``. Plenty of optimisations beyond + that but those are the guaranteed ones. + """ + + def short_circuit(self): + for i in hrange(2): + if self.consider(i): + return True + self.mask_high_bits() + if self.size > 8: + # see if we can squeeze the integer into a single byte. + self.consider(self.current >> (self.size - 8)) + self.consider(self.current & 0xff) + return self.current == 2 + + def check_invariants(self, value): + assert value >= 0 + + def left_is_better(self, left, right): + return left < right + + def run_step(self): + self.shift_right() + self.shrink_by_multiples(2) + self.shrink_by_multiples(1) + + def shift_right(self): + base = self.current + find_integer(lambda k: k <= self.size and self.consider( + base >> k + )) + + def mask_high_bits(self): + base = self.current + n = base.bit_length() + + @find_integer + def try_mask(k): + if k >= n: + return False + mask = (1 << (n - k)) - 1 + return self.consider(mask & base) + + @property + def size(self): + return self.current.bit_length() + + def shrink_by_multiples(self, k): + base = self.current + + @find_integer + def shrunk(n): + attempt = base - n * k + return attempt >= 0 and self.consider(attempt) + return shrunk > 0 diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/conjecture/shrinking/length.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/conjecture/shrinking/length.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/conjecture/shrinking/length.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/conjecture/shrinking/length.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,65 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from hypothesis.internal.conjecture.shrinking.common import Shrinker, \ + find_integer + + +""" +This module implements a length minimizer for sequences. + +That is, given some sequence of elements satisfying some predicate, it tries to +find a strictly shorter one satisfying the same predicate. + +Doing so perfectly is provably exponential. This only implements a linear time +worst case algorithm which guarantees certain minimality properties of the +fixed point. +""" + + +class Length(Shrinker): + """Attempts to find a smaller sequence satisfying f. Will only perform + linearly many evaluations, and does not loop to a fixed point. + + Guarantees made at a fixed point: + + 1. No individual element may be deleted. + 2. No *adjacent* pair of elements may be deleted. + """ + + def make_immutable(self, value): + return tuple(value) + + def short_circuit(self): + return self.consider(()) or len(self.current) <= 1 + + def left_is_better(self, left, right): + return len(left) < len(right) + + def run_step(self): + j = 0 + while j < len(self.current): + i = len(self.current) - 1 - j + start = self.current + find_integer( + lambda k: k <= i + 1 and self.consider( + start[:i + 1 - k] + start[i + 1:] + ) + ) + j += 1 diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/conjecture/shrinking/lexical.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/conjecture/shrinking/lexical.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/conjecture/shrinking/lexical.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/conjecture/shrinking/lexical.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,123 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from hypothesis.internal.compat import hbytes, int_to_bytes, int_from_bytes +from hypothesis.internal.conjecture.floats import is_simple, \ + float_to_lex, lex_to_float +from hypothesis.internal.conjecture.shrinking.common import Shrinker +from hypothesis.internal.conjecture.shrinking.floats import Float +from hypothesis.internal.conjecture.shrinking.integer import Integer +from hypothesis.internal.conjecture.shrinking.ordering import Ordering + + +""" +This module implements a lexicographic minimizer for blocks of bytes. +""" + + +class Lexical(Shrinker): + def make_immutable(self, value): + return hbytes(value) + + @property + def size(self): + return len(self.current) + + def check_invariants(self, value): + assert len(value) == self.size + + def left_is_better(self, left, right): + return left < right + + def incorporate_int(self, i): + return self.incorporate(int_to_bytes(i, self.size)) + + def incorporate_float(self, f): + assert self.size == 8 + return self.incorporate_int(float_to_lex(f)) + + def float_hack(self): + """Our encoding of floating point numbers does the right thing when you + lexically shrink it, but there are some highly non-obvious lexical + shrinks corresponding to natural floating point operations. + + We can't actually tell when the floating point encoding is being used + (that would break the assumptions that Hypothesis doesn't inspect + the generated values), but we can cheat: We just guess when it might be + being used and perform shrinks that are valid regardless of our guess + is correct. + + So that's what this method does. It's a cheat to give us good shrinking + of floating at low cost in runtime and only moderate cost in elegance. + """ + # If the block is of the wrong size then we're certainly not using the + # float encoding. + if self.size != 8: + return + + # If the high bit is zero then we're in the integer representation of + # floats so we don't need these hacks because it will shrink normally. + if self.current[0] >> 7 == 0: + return + + i = self.current_int + f = lex_to_float(i) + + # This floating point number can be represented in our simple format. + # So we try converting it to that (which will give the same float, but + # a different encoding of it). If that doesn't work then the float + # value of this doesn't unambiguously give the desired predicate, so + # this approach isn't useful. If it *does* work, then we're now in a + # situation where we don't need it, so either way we return here. + if is_simple(f): + self.incorporate_float(f) + return + + self.delegate( + Float, + convert_to=lambda b: lex_to_float(int_from_bytes(b)), + convert_from=lambda f: int_to_bytes(float_to_lex(f), self.size), + ) + + @property + def current_int(self): + return int_from_bytes(self.current) + + def minimize_as_integer(self, full=False): + Integer.shrink( + self.current_int, + lambda c: c == self.current_int or self.incorporate_int(c), + random=self.random, full=full, + ) + + def partial_sort(self): + Ordering.shrink( + self.current, self.consider, + random=self.random, + ) + + def short_circuit(self): + """This is just an assemblage of other shrinkers, so we rely on their + short circuiting.""" + return False + + def run_step(self): + self.float_hack() + self.minimize_as_integer() + self.partial_sort() diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/conjecture/shrinking/ordering.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/conjecture/shrinking/ordering.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/conjecture/shrinking/ordering.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/conjecture/shrinking/ordering.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,91 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from hypothesis.internal.conjecture.shrinking.common import Shrinker + + +def identity(v): + return v + + +class Ordering(Shrinker): + """A shrinker that tries to make a sequence more sorted. + + Will not change the length or the contents, only tries to reorder + the elements of the sequence. + """ + + def setup(self, key=identity): + self.key = key + + def make_immutable(self, value): + return tuple(value) + + def short_circuit(self): + # If we can flat out sort the target then there's nothing more to do. + return self.consider(sorted(self.current, key=self.key)) + + def left_is_better(self, left, right): + return tuple(map(self.key, left)) < tuple(map(self.key, right)) + + def check_invariants(self, value): + assert len(value) == len(self.current) + assert sorted(value) == sorted(self.current) + + def run_step(self): + self.reinsert() + + def reinsert(self): + for i in range(len(self.current)): + # This is essentially insertion sort, but unlike normal insertion + # sort because of our use of find_integer we only perform + # O(n(log(n))) calls. Because of the rotations we're still O(n^2) + # performance in terms of number of list operations, but we don't + # care about those so much. + original = self.current + + insertion_points = [ + j for j in range(i) + if self.key(self.current[j]) > self.key(self.current[i]) + ] + + def push_back_to(t): + if t >= len(insertion_points): + return True + j = insertion_points[t] + reinserted = list(original) + del reinserted[i] + reinserted.insert(j, original[i]) + if self.consider(reinserted): + return + swapped = list(self.current) + swapped[i], swapped[j] = swapped[j], swapped[i] + return self.consider(swapped) + + if push_back_to(0) or push_back_to(1): + continue + + lo = 1 + hi = len(insertion_points) + while lo + 1 < hi: + mid = (lo + hi) // 2 + if push_back_to(mid): + hi = mid + else: + lo = mid diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/conjecture/utils.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/conjecture/utils.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/conjecture/utils.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/conjecture/utils.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,423 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import enum +import math +import heapq +import hashlib +from fractions import Fraction +from collections import OrderedDict + +from hypothesis._settings import note_deprecation +from hypothesis.internal.compat import abc, floor, hbytes, hrange, \ + qualname, bit_length, str_to_bytes, int_from_bytes +from hypothesis.internal.floats import int_to_float + +LABEL_MASK = 2 ** 64 - 1 + + +def calc_label_from_name(name): + hashed = hashlib.md5(str_to_bytes(name)).digest() + return int_from_bytes(hashed[:8]) + + +def calc_label_from_cls(cls): + return calc_label_from_name(qualname(cls)) + + +def combine_labels(*labels): + label = 0 + for l in labels: + label = (label << 1) & LABEL_MASK + label ^= l + return label + + +INTEGER_RANGE_DRAW_LABEL = calc_label_from_name( + 'another draw in integer_range()') +GEOMETRIC_LABEL = calc_label_from_name('geometric()') +BIASED_COIN_LABEL = calc_label_from_name('biased_coin()') +SAMPLE_IN_SAMPLER_LABLE = calc_label_from_name('a sample() in Sampler') +ONE_FROM_MANY_LABEL = calc_label_from_name('one more from many()') + + +def integer_range(data, lower, upper, center=None): + assert lower <= upper + if lower == upper: + # Write a value even when this is trival so that when a bound depends + # on other values we don't suddenly disappear when the gap shrinks to + # zero - if that happens then often the data stream becomes misaligned + # and we fail to shrink in cases where we really should be able to. + data.write(hbytes([0])) + return int(lower) + + if center is None: + center = lower + center = min(max(center, lower), upper) + + if center == upper: + above = False + elif center == lower: + above = True + else: + above = boolean(data) + + if above: + gap = upper - center + else: + gap = center - lower + + assert gap > 0 + + bits = bit_length(gap) + probe = gap + 1 + + while probe > gap: + data.start_example(INTEGER_RANGE_DRAW_LABEL) + probe = data.draw_bits(bits) + data.stop_example(discard=probe > gap) + + if above: + result = center + probe + else: + result = center - probe + + assert lower <= result <= upper + return int(result) + + +def centered_integer_range(data, lower, upper, center): + return integer_range( + data, lower, upper, center=center + ) + + +try: + from numpy import ndarray +except ImportError: # pragma: no cover + ndarray = () + + +def check_sample(values, strategy_name): + if isinstance(values, ndarray): + if values.ndim != 1: + note_deprecation(( + 'Only one-dimensional arrays are supported for sampling, ' + 'and the given value has {ndim} dimensions (shape ' + '{shape}). This array would give samples of array slices ' + 'instead of elements! Use np.ravel(values) to convert ' + 'to a one-dimensional array, or tuple(values) if you ' + 'want to sample slices. Sampling a multi-dimensional ' + 'array will be an error in a future version of Hypothesis.' + ).format(ndim=values.ndim, shape=values.shape)) + elif not isinstance(values, (OrderedDict, abc.Sequence, enum.EnumMeta)): + note_deprecation( + 'Cannot sample from {values}, not an ordered collection. ' + 'Hypothesis goes to some length to ensure that the {strategy} ' + 'strategy has stable results between runs. To replay a saved ' + 'example, the sampled values must have the same iteration order ' + 'on every run - ruling out sets, dicts, etc due to hash ' + 'randomisation. Most cases can simply use `sorted(values)`, but ' + 'mixed types or special values such as math.nan require careful ' + 'handling - and note that when simplifying an example, ' + 'Hypothesis treats earlier values as simpler.'.format( + values=repr(values), strategy=strategy_name)) + return tuple(values) + + +def choice(data, values): + return values[integer_range(data, 0, len(values) - 1)] + + +def getrandbits(data, n): + n_bytes = n // 8 + if n % 8 != 0: + n_bytes += 1 + return int_from_bytes(data.draw_bytes(n_bytes)) & ((1 << n) - 1) + + +FLOAT_PREFIX = 0b1111111111 << 52 +FULL_FLOAT = int_to_float(FLOAT_PREFIX | ((2 << 53) - 1)) - 1 + + +def fractional_float(data): + return ( + int_to_float(FLOAT_PREFIX | getrandbits(data, 52)) - 1 + ) / FULL_FLOAT + + +def geometric(data, p): + denom = math.log1p(-p) + data.start_example(GEOMETRIC_LABEL) + while True: + probe = fractional_float(data) + if probe < 1.0: + result = int(math.log1p(-probe) / denom) + assert result >= 0, (probe, p, result) + data.stop_example() + return result + + +def boolean(data): + return bool(data.draw_bits(1)) + + +def biased_coin(data, p): + """Return False with probability p (assuming a uniform generator), + shrinking towards False.""" + data.start_example(BIASED_COIN_LABEL) + while True: + # The logic here is a bit complicated and special cased to make it + # play better with the shrinker. + + # We imagine partitioning the real interval [0, 1] into 256 equal parts + # and looking at each part and whether its interior is wholly <= p + # or wholly >= p. At most one part can be neither. + + # We then pick a random part. If it's wholly on one side or the other + # of p then we use that as the answer. If p is contained in the + # interval then we start again with a new probability that is given + # by the fraction of that interval that was <= our previous p. + + # We then take advantage of the fact that we have control of the + # labelling to make this shrink better, using the following tricks: + + # If p is <= 0 or >= 1 the result of this coin is certain. We make sure + # to write a byte to the data stream anyway so that these don't cause + # difficulties when shrinking. + if p <= 0: + data.write(hbytes([0])) + result = False + elif p >= 1: + data.write(hbytes([1])) + result = True + else: + falsey = floor(256 * (1 - p)) + truthy = floor(256 * p) + remainder = 256 * p - truthy + + if falsey + truthy == 256: + if isinstance(p, Fraction): + m = p.numerator + n = p.denominator + else: + m, n = p.as_integer_ratio() + assert n & (n - 1) == 0, n # n is a power of 2 + assert n > m > 0 + truthy = m + falsey = n - m + bits = bit_length(n) - 1 + partial = False + else: + bits = 8 + partial = True + + i = data.draw_bits(bits) + + # We always label the region that causes us to repeat the loop as + # 255 so that shrinking this byte never causes us to need to draw + # more data. + if partial and i == 255: + p = remainder + continue + if falsey == 0: + # Every other partition is truthy, so the result is true + result = True + elif truthy == 0: + # Every other partition is falsey, so the result is false + result = False + elif i <= 1: + # We special case so that zero is always false and 1 is always + # true which makes shrinking easier because we can always + # replace a truthy block with 1. This has the slightly weird + # property that shrinking from 2 to 1 can cause the result to + # grow, but the shrinker always tries 0 and 1 first anyway, so + # this will usually be fine. + result = bool(i) + else: + # Originally everything in the region 0 <= i < falsey was false + # and everything above was true. We swapped one truthy element + # into this region, so the region becomes 0 <= i <= falsey + # except for i = 1. We know i > 1 here, so the test for truth + # becomes i > falsey. + result = i > falsey + break + data.stop_example() + return result + + +class Sampler(object): + """Sampler based on Vose's algorithm for the alias method. See + http://www.keithschwarz.com/darts-dice-coins/ for a good explanation. + + The general idea is that we store a table of triples (base, alternate, p). + base. We then pick a triple uniformly at random, and choose its alternate + value with probability p and else choose its base value. The triples are + chosen so that the resulting mixture has the right distribution. + + We maintain the following invariants to try to produce good shrinks: + + 1. The table is in lexicographic (base, alternate) order, so that choosing + an earlier value in the list always lowers (or at least leaves + unchanged) the value. + 2. base[i] < alternate[i], so that shrinking the draw always results in + shrinking the chosen element. + """ + + def __init__(self, weights): + + n = len(weights) + + self.table = [[i, None, None] for i in hrange(n)] + + total = sum(weights) + + num_type = type(total) + + zero = num_type(0) + one = num_type(1) + + small = [] + large = [] + + probabilities = [w / total for w in weights] + scaled_probabilities = [] + + for i, p in enumerate(probabilities): + scaled = p * n + scaled_probabilities.append(scaled) + if scaled == 1: + self.table[i][2] = zero + elif scaled < 1: + small.append(i) + else: + large.append(i) + heapq.heapify(small) + heapq.heapify(large) + + while small and large: + lo = heapq.heappop(small) + hi = heapq.heappop(large) + + assert lo != hi + assert scaled_probabilities[hi] > one + assert self.table[lo][1] is None + self.table[lo][1] = hi + self.table[lo][2] = one - scaled_probabilities[lo] + scaled_probabilities[hi] = ( + scaled_probabilities[hi] + scaled_probabilities[lo]) - one + + if scaled_probabilities[hi] < 1: + heapq.heappush(small, hi) + elif scaled_probabilities[hi] == 1: + self.table[hi][2] = zero + else: + heapq.heappush(large, hi) + while large: + self.table[large.pop()][2] = zero + while small: + self.table[small.pop()][2] = zero + + for entry in self.table: + assert entry[2] is not None + if entry[1] is None: + entry[1] = entry[0] + elif entry[1] < entry[0]: + entry[0], entry[1] = entry[1], entry[0] + entry[2] = one - entry[2] + self.table.sort() + + def sample(self, data): + data.start_example(SAMPLE_IN_SAMPLER_LABLE) + i = integer_range(data, 0, len(self.table) - 1) + base, alternate, alternate_chance = self.table[i] + use_alternate = biased_coin(data, alternate_chance) + data.stop_example() + if use_alternate: + return alternate + else: + return base + + +class many(object): + """Utility class for collections. Bundles up the logic we use for "should I + keep drawing more values?" and handles starting and stopping examples in + the right place. + + Intended usage is something like: + + elements = many(data, ...) + while elements.more(): + add_stuff_to_result() + """ + + def __init__(self, data, min_size, max_size, average_size): + assert 0 <= min_size <= average_size <= max_size + self.min_size = min_size + self.max_size = max_size + self.data = data + self.stopping_value = 1 - 1.0 / (1 + average_size) + self.count = 0 + self.rejections = 0 + self.drawn = False + self.force_stop = False + self.rejected = False + + def more(self): + """Should I draw another element to add to the collection?""" + if self.drawn: + self.data.stop_example(discard=self.rejected) + + self.drawn = True + self.rejected = False + + self.data.start_example(ONE_FROM_MANY_LABEL) + + if self.min_size == self.max_size: + should_continue = self.count < self.min_size + elif self.force_stop: + should_continue = False + else: + if self.count < self.min_size: + p_continue = 1.0 + elif self.count >= self.max_size: + p_continue = 0.0 + else: + p_continue = self.stopping_value + should_continue = biased_coin(self.data, p_continue) + + if should_continue: + self.count += 1 + return True + else: + self.data.stop_example() + return False + + def reject(self): + """Reject the last example (i.e. don't count it towards our budget of + elements because it's not going to go in the final collection).""" + assert self.count > 0 + self.count -= 1 + self.rejections += 1 + self.rejected = True + if self.rejections > 2 * self.count: + if self.count < self.min_size: + self.data.mark_invalid() + else: + self.force_stop = True diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/coverage.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/coverage.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/coverage.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/coverage.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,118 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import os +import sys +import json +from contextlib import contextmanager + +from hypothesis.internal.reflection import proxies + +if False: + from typing import Set, Dict, Tuple # noqa + +""" +This module implements a custom coverage system that records conditions and +then validates that every condition has been seen to be both True and False +during the execution of our tests. + +The only thing we use it for at present is our argument validation functions, +where we assert that every validation function has been seen to both pass and +fail in the course of testing. + +When not running with a magic environment variable set, this module disables +itself and has essentially no overhead. +""" + +pretty_file_name_cache = {} # type: Dict[str, str] + + +def pretty_file_name(f): + try: + return pretty_file_name_cache[f] + except KeyError: + pass + + parts = f.split(os.path.sep) + parts = parts[parts.index('hypothesis'):] + result = os.path.sep.join(parts) + pretty_file_name_cache[f] = result + return result + + +IN_COVERAGE_TESTS = os.getenv('HYPOTHESIS_INTERNAL_COVERAGE') == 'true' + + +if IN_COVERAGE_TESTS: + with open('branch-check', 'w'): + pass + written = set() # type: Set[Tuple[str, bool]] + + def record_branch(name, value): + key = (name, value) + if key in written: + return + written.add(key) + with open('branch-check', 'a') as log: + log.write(json.dumps({'name': name, 'value': value}) + '\n') + + description_stack = [] + + @contextmanager + def check_block(name, depth): + # We add an extra two callers to the stack: One for the contextmanager + # function, one for our actual caller, so we want to go two extra + # stack frames up. + caller = sys._getframe(depth + 2) + local_description = '%s at %s:%d' % ( + name, + pretty_file_name(caller.f_code.co_filename), + caller.f_lineno, + ) + try: + description_stack.append(local_description) + description = ' in '.join(reversed(description_stack)) + ' passed' + yield + record_branch(description, True) + except BaseException: + record_branch(description, False) + raise + finally: + description_stack.pop() + + @contextmanager + def check(name): + with check_block(name, 2): + yield + + def check_function(f): + @proxies(f) + def accept(*args, **kwargs): + # depth of 2 because of the proxy function calling us. + with check_block(f.__name__, 2): + return f(*args, **kwargs) + return accept +else: + def check_function(f): + return f + + # Mypy bug: https://github.com/python/mypy/issues/4117 + @contextmanager # type: ignore + def check(name): + yield diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/detection.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/detection.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/detection.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/detection.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,26 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from types import MethodType + + +def is_hypothesis_test(test): + if isinstance(test, MethodType): + return is_hypothesis_test(test.__func__) + return getattr(test, 'is_hypothesis_test', False) diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/entropy.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/entropy.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/entropy.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/entropy.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,38 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import random +import contextlib + + +@contextlib.contextmanager +def deterministic_PRNG(): + """Context manager that handles random.seed without polluting global state. + + See issue #1255 and PR #1295 for details and motivation - in short, + leaving the global pseudo-random number generator (PRNG) seeded is a very + bad idea in principle, and breaks all kinds of independence assumptions + in practice. + """ + _random_state = random.getstate() + random.seed(0) + try: + yield + finally: + random.setstate(_random_state) diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/escalation.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/escalation.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/escalation.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/escalation.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,80 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import os +import sys + +import hypothesis +from hypothesis.errors import StopTest, DeadlineExceeded, \ + HypothesisException, UnsatisfiedAssumption +from hypothesis.internal.compat import text_type, binary_type, \ + encoded_filepath + +if False: + from typing import Dict # noqa + + +def belongs_to(package): + root = os.path.dirname(package.__file__) + cache = {text_type: {}, binary_type: {}} + + def accept(filepath): + ftype = type(filepath) + try: + return cache[ftype][filepath] + except KeyError: + pass + new_filepath = encoded_filepath(filepath) + result = os.path.abspath(new_filepath).startswith(root) + cache[ftype][filepath] = result + cache[type(new_filepath)][new_filepath] = result + return result + accept.__name__ = 'is_%s_file' % (package.__name__,) + return accept + + +PREVENT_ESCALATION = os.getenv('HYPOTHESIS_DO_NOT_ESCALATE') == 'true' + +FILE_CACHE = {} # type: Dict[bytes, bool] + + +is_hypothesis_file = belongs_to(hypothesis) + +HYPOTHESIS_CONTROL_EXCEPTIONS = ( + DeadlineExceeded, StopTest, UnsatisfiedAssumption +) + + +def mark_for_escalation(e): + if not isinstance(e, HYPOTHESIS_CONTROL_EXCEPTIONS): + e.hypothesis_internal_always_escalate = True + + +def escalate_hypothesis_internal_error(): + if PREVENT_ESCALATION: + return + error_type, e, tb = sys.exc_info() + if getattr(e, 'hypothesis_internal_always_escalate', False): + raise + import traceback + filepath = traceback.extract_tb(tb)[-1][0] + if is_hypothesis_file(filepath) and not isinstance( + e, (HypothesisException,) + HYPOTHESIS_CONTROL_EXCEPTIONS, + ): + raise diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/floats.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/floats.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/floats.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/floats.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,129 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import math + +from hypothesis.internal.compat import CAN_PACK_HALF_FLOAT, quiet_raise, \ + struct_pack, struct_unpack + +try: + import numpy +except ImportError: + numpy = None + + +# Format codes for (int, float) sized types, used for byte-wise casts. +# See https://docs.python.org/3/library/struct.html#format-characters +STRUCT_FORMATS = { + 16: (b'!H', b'!e'), # Note: 'e' is new in Python 3.6, so we have helpers + 32: (b'!I', b'!f'), + 64: (b'!Q', b'!d'), +} + + +# There are two versions of this: the one that uses Numpy to support Python +# 3.5 and earlier, and the elegant one for new versions. We use the new +# one if Numpy is unavailable too, because it's slightly faster in all cases. +if numpy and not CAN_PACK_HALF_FLOAT: # pragma: no cover + def reinterpret_bits(x, from_, to): + if from_ == b'!e': + arr = numpy.array([x], dtype='>f2') + if numpy.isfinite(x) and not numpy.isfinite(arr[0]): + quiet_raise(OverflowError('%r too large for float16' % (x,))) + buf = arr.tobytes() + else: + buf = struct_pack(from_, x) + if to == b'!e': + return float(numpy.frombuffer(buf, dtype='>f2')[0]) + return struct_unpack(to, buf)[0] + +else: + def reinterpret_bits(x, from_, to): + return struct_unpack(to, struct_pack(from_, x))[0] + + +def float_of(x, width): + assert width in (16, 32, 64) + if width == 64: + return float(x) + elif width == 32: + return reinterpret_bits(float(x), b'!f', b'!f') + else: + return reinterpret_bits(float(x), b'!e', b'!e') + + +def sign(x): + try: + return math.copysign(1.0, x) + except TypeError: + raise TypeError('Expected float but got %r of type %s' % ( + x, type(x).__name__ + )) + + +def is_negative(x): + return sign(x) < 0 + + +def count_between_floats(x, y, width=64): + assert x <= y + if is_negative(x): + if is_negative(y): + return float_to_int(x, width) - float_to_int(y, width) + 1 + else: + return count_between_floats(x, -0.0, width) + \ + count_between_floats(0.0, y, width) + else: + assert not is_negative(y) + return float_to_int(y, width) - float_to_int(x, width) + 1 + + +def float_to_int(value, width=64): + fmt_int, fmt_flt = STRUCT_FORMATS[width] + return reinterpret_bits(value, fmt_flt, fmt_int) + + +def int_to_float(value, width=64): + fmt_int, fmt_flt = STRUCT_FORMATS[width] + return reinterpret_bits(value, fmt_int, fmt_flt) + + +def next_up(value, width=64): + """Return the first float larger than finite `val` - IEEE 754's `nextUp`. + + From https://stackoverflow.com/a/10426033, with thanks to Mark Dickinson. + """ + assert isinstance(value, float) + if math.isnan(value) or (math.isinf(value) and value > 0): + return value + if value == 0.0: + value = 0.0 + fmt_int, fmt_flt = STRUCT_FORMATS[width] + # Note: n is signed; float_to_int returns unsigned + fmt_int = fmt_int.lower() + n = reinterpret_bits(value, fmt_flt, fmt_int) + if n >= 0: + n += 1 + else: + n -= 1 + return reinterpret_bits(n, fmt_int, fmt_flt) + + +def next_down(value, width=64): + return -next_up(-value, width) diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/healthcheck.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/healthcheck.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/healthcheck.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/healthcheck.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,36 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from hypothesis.errors import FailedHealthCheck + + +def fail_health_check(settings, message, label): + # Tell pytest to omit the body of this function from tracebacks + # http://doc.pytest.org/en/latest/example/simple.html#writing-well-integrated-assertion-helpers + __tracebackhide__ = True + + if label in settings.suppress_health_check: + return + message += ( + '\nSee https://hypothesis.readthedocs.io/en/latest/health' + 'checks.html for more information about this. ' + 'If you want to disable just this health check, add %s ' + 'to the suppress_health_check settings for this test.' + ) % (label,) + raise FailedHealthCheck(message, label) diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/__init__.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/__init__.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/__init__.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,16 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/intervalsets.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/intervalsets.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/intervalsets.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/intervalsets.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,84 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + + +class IntervalSet(object): + + def __init__(self, intervals): + self.intervals = tuple(intervals) + self.offsets = [0] + for u, v in self.intervals: + self.offsets.append( + self.offsets[-1] + v - u + 1 + ) + self.size = self.offsets.pop() + + def __len__(self): + return self.size + + def __iter__(self): + for u, v in self.intervals: + for i in range(u, v + 1): + yield i + + def __getitem__(self, i): + if i < 0: + i = self.size + i + if i < 0 or i >= self.size: + raise IndexError('Invalid index %d for [0, %d)' % (i, self.size)) + # Want j = maximal such that offsets[j] <= i + + j = len(self.intervals) - 1 + if self.offsets[j] > i: + hi = j + lo = 0 + # Invariant: offsets[lo] <= i < offsets[hi] + while lo + 1 < hi: + mid = (lo + hi) // 2 + if self.offsets[mid] <= i: + lo = mid + else: + hi = mid + j = lo + t = i - self.offsets[j] + u, v = self.intervals[j] + r = u + t + assert r <= v + return r + + def __repr__(self): + return 'IntervalSet(%r)' % (self.intervals,) + + def index(self, value): + for offset, (u, v) in zip(self.offsets, self.intervals): + if u == value: + return offset + elif u > value: + raise ValueError('%d is not in list' % (value,)) + if value <= v: + return offset + (value - u) + raise ValueError('%d is not in list' % (value,)) + + def index_above(self, value): + for offset, (u, v) in zip(self.offsets, self.intervals): + if u >= value: + return offset + if value <= v: + return offset + (value - u) + return self.size diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/lazyformat.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/lazyformat.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/lazyformat.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/lazyformat.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,42 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + + +class lazyformat(object): + """A format string that isn't evaluated until it's needed.""" + + def __init__(self, format_string, *args): + self.__format_string = format_string + self.__args = args + + def __str__(self): + return self.__format_string % self.__args + + def __eq__(self, other): + return ( + isinstance(other, lazyformat) and + self.__format_string == other.__format_string and + self.__args == other.__args + ) + + def __ne__(self, other): + return not self.__eq__(other) + + def __hash__(self): + return hash(self.__format_string) diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/reflection.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/reflection.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/reflection.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/reflection.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,555 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +"""This file can approximately be considered the collection of hypothesis going +to really unreasonable lengths to produce pretty output.""" + + +from __future__ import division, print_function, absolute_import + +import re +import ast +import uuid +import types +import hashlib +import inspect +from types import ModuleType +from functools import wraps + +from hypothesis.configuration import storage_directory +from hypothesis.vendor.pretty import pretty +from hypothesis.internal.compat import ARG_NAME_ATTRIBUTE, hrange, \ + to_str, qualname, to_unicode, isidentifier, str_to_bytes, \ + getfullargspec, update_code_location + + +def fully_qualified_name(f): + """Returns a unique identifier for f pointing to the module it was defined + on, and an containing functions.""" + if f.__module__ is not None: + return f.__module__ + '.' + qualname(f) + else: + return qualname(f) + + +def is_mock(obj): + """Determine if the given argument is a mock type. + + We want to be able to detect these when dealing with various test + args. As they are sneaky and can look like almost anything else, + we'll check this by looking for random attributes. This is more + robust than looking for types. + """ + for _ in range(10): + if not hasattr(obj, str(uuid.uuid4())): + return False + return True + + +def function_digest(function): + """Returns a string that is stable across multiple invocations across + multiple processes and is prone to changing significantly in response to + minor changes to the function. + + No guarantee of uniqueness though it usually will be. + """ + hasher = hashlib.md5() + try: + hasher.update(to_unicode(inspect.getsource(function)).encode('utf-8')) + # Different errors on different versions of python. What fun. + except (OSError, IOError, TypeError): + pass + try: + hasher.update(str_to_bytes(function.__name__)) + except AttributeError: + pass + try: + hasher.update(function.__module__.__name__.encode('utf-8')) + except AttributeError: + pass + try: + hasher.update(str_to_bytes(repr(getfullargspec(function)))) + except TypeError: + pass + return hasher.digest() + + +def is_typed_named_tuple(cls): + """Return True if cls is probably a subtype of `typing.NamedTuple`. + + Unfortunately types created with `class T(NamedTuple):` actually + subclass `tuple` directly rather than NamedTuple. This is annoying, + and means we just have to hope that nobody defines a different tuple + subclass with similar attributes. + """ + return issubclass(cls, tuple) and hasattr(cls, '_fields') and \ + hasattr(cls, '_field_types') + + +def required_args(target, args=(), kwargs=()): + """Return a set of names of required args to target that were not supplied + in args or kwargs. + + This is used in builds() to determine which arguments to attempt to + fill from type hints. target may be any callable (including classes + and bound methods). args and kwargs should be as they are passed to + builds() - that is, a tuple of values and a dict of names: values. + """ + # We start with a workaround for NamedTuples, which don't have nice inits + if inspect.isclass(target) and is_typed_named_tuple(target): + provided = set(kwargs) | set(target._fields[:len(args)]) + return set(target._fields) - provided + # Then we try to do the right thing with getfullargspec + try: + spec = getfullargspec( + target.__init__ if inspect.isclass(target) else target) + except TypeError: # pragma: no cover + return None + # self appears in the argspec of __init__ and bound methods, but it's an + # error to explicitly supply it - so we might skip the first argument. + skip_self = int(inspect.isclass(target) or inspect.ismethod(target)) + # Start with the args that were not supplied and all kwonly arguments, + # then remove all positional arguments with default values, and finally + # remove kwonly defaults and any supplied keyword arguments + return set(spec.args[skip_self + len(args):] + spec.kwonlyargs) \ + - set(spec.args[len(spec.args) - len(spec.defaults or ()):]) \ + - set(spec.kwonlydefaults or ()) - set(kwargs) + + +def convert_keyword_arguments(function, args, kwargs): + """Returns a pair of a tuple and a dictionary which would be equivalent + passed as positional and keyword args to the function. Unless function has. + + **kwargs the dictionary will always be empty. + """ + argspec = getfullargspec(function) + new_args = [] + kwargs = dict(kwargs) + + defaults = dict(argspec.kwonlydefaults or {}) + + if argspec.defaults: + for name, value in zip( + argspec.args[-len(argspec.defaults):], + argspec.defaults + ): + defaults[name] = value + + n = max(len(args), len(argspec.args)) + + for i in hrange(n): + if i < len(args): + new_args.append(args[i]) + else: + arg_name = argspec.args[i] + if arg_name in kwargs: + new_args.append(kwargs.pop(arg_name)) + elif arg_name in defaults: + new_args.append(defaults[arg_name]) + else: + raise TypeError('No value provided for argument %r' % ( + arg_name + )) + + if kwargs and not argspec.varkw: + if len(kwargs) > 1: + raise TypeError('%s() got unexpected keyword arguments %s' % ( + function.__name__, ', '.join(map(repr, kwargs)) + )) + else: + bad_kwarg = next(iter(kwargs)) + raise TypeError('%s() got an unexpected keyword argument %r' % ( + function.__name__, bad_kwarg + )) + return tuple(new_args), kwargs + + +def convert_positional_arguments(function, args, kwargs): + """Return a tuple (new_args, new_kwargs) where all possible arguments have + been moved to kwargs. + + new_args will only be non-empty if function has a variadic argument. + """ + argspec = getfullargspec(function) + new_kwargs = dict(argspec.kwonlydefaults or {}) + new_kwargs.update(kwargs) + if not argspec.varkw: + for k in new_kwargs.keys(): + if k not in argspec.args and k not in argspec.kwonlyargs: + raise TypeError( + '%s() got an unexpected keyword argument %r' % ( + function.__name__, k + )) + if len(args) < len(argspec.args): + for i in hrange( + len(args), len(argspec.args) - len(argspec.defaults or ()) + ): + if argspec.args[i] not in kwargs: + raise TypeError('No value provided for argument %s' % ( + argspec.args[i], + )) + for kw in argspec.kwonlyargs: + if kw not in new_kwargs: + raise TypeError('No value provided for argument %s' % kw) + + if len(args) > len(argspec.args) and not argspec.varargs: + raise TypeError( + '%s() takes at most %d positional arguments (%d given)' % ( + function.__name__, len(argspec.args), len(args) + ) + ) + + for arg, name in zip(args, argspec.args): + if name in new_kwargs: + raise TypeError( + '%s() got multiple values for keyword argument %r' % ( + function.__name__, name + )) + else: + new_kwargs[name] = arg + return ( + tuple(args[len(argspec.args):]), + new_kwargs, + ) + + +def extract_all_lambdas(tree): + lambdas = [] + + class Visitor(ast.NodeVisitor): + + def visit_Lambda(self, node): + lambdas.append(node) + + Visitor().visit(tree) + + return lambdas + + +def args_for_lambda_ast(l): + return [getattr(n, ARG_NAME_ATTRIBUTE) for n in l.args.args] + + +LINE_CONTINUATION = re.compile(r"\\\n") +WHITESPACE = re.compile(r"\s+") +PROBABLY_A_COMMENT = re.compile("""#[^'"]*$""") +SPACE_FOLLOWS_OPEN_BRACKET = re.compile(r"\( ") +SPACE_PRECEDES_CLOSE_BRACKET = re.compile(r" \)") + + +def extract_lambda_source(f): + """Extracts a single lambda expression from the string source. Returns a + string indicating an unknown body if it gets confused in any way. + + This is not a good function and I am sorry for it. Forgive me my + sins, oh lord + """ + argspec = getfullargspec(f) + arg_strings = [] + # In Python 2 you can have destructuring arguments to functions. This + # results in an argspec with non-string values. I'm not very interested in + # handling these properly, but it's important to not crash on them. + bad_lambda = False + for a in argspec.args: + if isinstance(a, (tuple, list)): # pragma: no cover + arg_strings.append('(%s)' % (', '.join(a),)) + bad_lambda = True + else: + assert isinstance(a, str) + arg_strings.append(a) + if argspec.varargs: + arg_strings.append('*' + argspec.varargs) + elif argspec.kwonlyargs: + arg_strings.append('*') + for a in (argspec.kwonlyargs or []): + default = (argspec.kwonlydefaults or {}).get(a) + if default: + arg_strings.append('{}={}'.format(a, default)) + else: + arg_strings.append(a) + + if_confused = 'lambda %s: ' % (', '.join(arg_strings),) + if bad_lambda: # pragma: no cover + return if_confused + try: + source = inspect.getsource(f) + except IOError: + return if_confused + + source = LINE_CONTINUATION.sub(' ', source) + source = WHITESPACE.sub(' ', source) + source = source.strip() + assert 'lambda' in source + + tree = None + + try: + tree = ast.parse(source) + except SyntaxError: + for i in hrange(len(source) - 1, len('lambda'), -1): + prefix = source[:i] + if 'lambda' not in prefix: + break + try: + tree = ast.parse(prefix) + source = prefix + break + except SyntaxError: + continue + if tree is None: + if source.startswith('@'): + # This will always eventually find a valid expression because + # the decorator must be a valid Python function call, so will + # eventually be syntactically valid and break out of the loop. Thus + # this loop can never terminate normally, so a no branch pragma is + # appropriate. + for i in hrange(len(source) + 1): # pragma: no branch + p = source[1:i] + if 'lambda' in p: + try: + tree = ast.parse(p) + source = p + break + except SyntaxError: + pass + + if tree is None: + return if_confused + + all_lambdas = extract_all_lambdas(tree) + aligned_lambdas = [ + l for l in all_lambdas + if args_for_lambda_ast(l) == argspec.args + ] + if len(aligned_lambdas) != 1: + return if_confused + lambda_ast = aligned_lambdas[0] + assert lambda_ast.lineno == 1 + source = source[lambda_ast.col_offset:].strip() + + source = source[source.index('lambda'):] + for i in hrange(len(source), len('lambda'), -1): # pragma: no branch + try: + parsed = ast.parse(source[:i]) + assert len(parsed.body) == 1 + assert parsed.body + if isinstance(parsed.body[0].value, ast.Lambda): + source = source[:i] + break + except SyntaxError: + pass + lines = source.split('\n') + lines = [PROBABLY_A_COMMENT.sub('', l) for l in lines] + source = '\n'.join(lines) + + source = WHITESPACE.sub(' ', source) + source = SPACE_FOLLOWS_OPEN_BRACKET.sub('(', source) + source = SPACE_PRECEDES_CLOSE_BRACKET.sub(')', source) + source = source.strip() + return source + + +def get_pretty_function_description(f): + if not hasattr(f, '__name__'): + return repr(f) + name = f.__name__ + if name == '': + result = extract_lambda_source(f) + return result + elif isinstance(f, types.MethodType): + self = f.__self__ + if not (self is None or inspect.isclass(self)): + return '%r.%s' % (self, name) + return name + + +def nicerepr(v): + if inspect.isfunction(v): + return get_pretty_function_description(v) + elif isinstance(v, type): + return v.__name__ + else: + return to_str(pretty(v)) + + +def arg_string(f, args, kwargs, reorder=True): + if reorder: + args, kwargs = convert_positional_arguments(f, args, kwargs) + + argspec = getfullargspec(f) + + bits = [] + + for a in argspec.args: + if a in kwargs: + bits.append('%s=%s' % (a, nicerepr(kwargs.pop(a)))) + if kwargs: + for a in sorted(kwargs): + bits.append('%s=%s' % (a, nicerepr(kwargs[a]))) + + return ', '.join([nicerepr(x) for x in args] + bits) + + +def unbind_method(f): + """Take something that might be a method or a function and return the + underlying function.""" + return getattr(f, 'im_func', getattr(f, '__func__', f)) + + +def check_valid_identifier(identifier): + if not isidentifier(identifier): + raise ValueError('%r is not a valid python identifier' % + (identifier,)) + + +def eval_directory(): + return storage_directory('eval_source') + + +eval_cache = {} # type: dict + + +def source_exec_as_module(source): + try: + return eval_cache[source] + except KeyError: + pass + + result = ModuleType('hypothesis_temporary_module_%s' % ( + hashlib.sha1(str_to_bytes(source)).hexdigest(), + )) + assert isinstance(source, str) + exec(source, result.__dict__) + eval_cache[source] = result + return result + + +COPY_ARGSPEC_SCRIPT = """ +from hypothesis.utils.conventions import not_set + +def accept(%(funcname)s): + def %(name)s(%(argspec)s): + return %(funcname)s(%(invocation)s) + return %(name)s +""".strip() + '\n' + + +def define_function_signature(name, docstring, argspec): + """A decorator which sets the name, argspec and docstring of the function + passed into it.""" + check_valid_identifier(name) + for a in argspec.args: + check_valid_identifier(a) + if argspec.varargs is not None: + check_valid_identifier(argspec.varargs) + if argspec.varkw is not None: + check_valid_identifier(argspec.varkw) + n_defaults = len(argspec.defaults or ()) + if n_defaults: + parts = [] + for a in argspec.args[:-n_defaults]: + parts.append(a) + for a in argspec.args[-n_defaults:]: + parts.append('%s=not_set' % (a,)) + else: + parts = list(argspec.args) + used_names = list(argspec.args) + list(argspec.kwonlyargs) + used_names.append(name) + + for a in argspec.kwonlyargs: + check_valid_identifier(a) + + def accept(f): + fargspec = getfullargspec(f) + must_pass_as_kwargs = [] + invocation_parts = [] + for a in argspec.args: + if a not in fargspec.args and not fargspec.varargs: + must_pass_as_kwargs.append(a) + else: + invocation_parts.append(a) + if argspec.varargs: + used_names.append(argspec.varargs) + parts.append('*' + argspec.varargs) + invocation_parts.append('*' + argspec.varargs) + elif argspec.kwonlyargs: + parts.append('*') + for k in must_pass_as_kwargs: + invocation_parts.append('%(k)s=%(k)s' % {'k': k}) + + for k in argspec.kwonlyargs: + invocation_parts.append('%(k)s=%(k)s' % {'k': k}) + if k in (argspec.kwonlydefaults or []): + parts.append('%(k)s=not_set' % {'k': k}) + else: + parts.append(k) + if argspec.varkw: + used_names.append(argspec.varkw) + parts.append('**' + argspec.varkw) + invocation_parts.append('**' + argspec.varkw) + + candidate_names = ['f'] + [ + 'f_%d' % (i,) for i in hrange(1, len(used_names) + 2) + ] + + for funcname in candidate_names: # pragma: no branch + if funcname not in used_names: + break + + base_accept = source_exec_as_module( + COPY_ARGSPEC_SCRIPT % { + 'name': name, + 'funcname': funcname, + 'argspec': ', '.join(parts), + 'invocation': ', '.join(invocation_parts) + }).accept + + result = base_accept(f) + result.__doc__ = docstring + result.__defaults__ = argspec.defaults + if argspec.kwonlydefaults: + result.__kwdefaults__ = argspec.kwonlydefaults + if argspec.annotations: + result.__annotations__ = argspec.annotations + return result + return accept + + +def impersonate(target): + """Decorator to update the attributes of a function so that to external + introspectors it will appear to be the target function. + + Note that this updates the function in place, it doesn't return a + new one. + """ + def accept(f): + f.__code__ = update_code_location( + f.__code__, + target.__code__.co_filename, target.__code__.co_firstlineno + ) + f.__name__ = target.__name__ + f.__module__ = target.__module__ + f.__doc__ = target.__doc__ + return f + return accept + + +def proxies(target): + def accept(proxy): + return impersonate(target)(wraps(target)(define_function_signature( + target.__name__, target.__doc__, getfullargspec(target))(proxy))) + return accept diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/renaming.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/renaming.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/renaming.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/renaming.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,83 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from inspect import cleandoc + +from hypothesis._settings import note_deprecation +from hypothesis.internal.reflection import proxies + +if False: + from typing import Callable # noqa + from hypothesis.searchstrategy.strategies import T # noqa + + +def renamed_arguments(**rename_mapping): + # type: (**str) -> Callable[[T], T] + """Helper function for deprecating arguments that have been renamed to a + new form. + + Note: There are some issues with this function (see + https://github.com/HypothesisWorks/hypothesis-python/issues/1111). + It's not too bad for current uses, but shouldn't be used in new + places without fixing it up. + """ + assert len(set(rename_mapping.values())) == len(rename_mapping) + + def accept(f): + @proxies(f) + def with_name_check(**kwargs): + for k, v in list(kwargs.items()): + if k in rename_mapping and v is not None: + t = rename_mapping[k] + note_deprecation(( + 'The argument %s has been renamed to %s. The old ' + 'name will go away in a future version of ' + 'Hypothesis.') % (k, t)) + kwargs[t] = kwargs.pop(k) + return f(**kwargs) + + # This decorates things in the public API, which all have docstrings. + # (If they're not in the public API, we don't need a deprecation path.) + # But docstrings are stripped when running with PYTHONOPTIMIZE=2. + # + # If somebody's running with that flag, they don't expect any + # docstrings to be present, so this message isn't useful. Absence of + # a docstring is a strong indicator that they're running in this mode, + # so skip adding this message if that's the case. + if with_name_check.__doc__ is not None: + # Appending to the raw docstring gives the new stuff a + # different indentation level and so prevents the later clean step + # from working properly. So we clean here first. + with_name_check.__doc__ = cleandoc(with_name_check.__doc__) + with_name_check.__doc__ += '\n'.join(( + '', '', + 'The following arguments have been renamed:', + '', + ) + tuple( + ' * %s has been renamed to %s' % s + for s in rename_mapping.items() + ) + ( + '', + 'Use of the old names has been deprecated and will be removed', + 'in a future version of Hypothesis.' + ) + ) + + return with_name_check + return accept diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/validation.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/validation.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/internal/validation.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/internal/validation.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,146 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import math +import decimal +from numbers import Real, Rational + +from hypothesis.errors import InvalidArgument +from hypothesis.internal.compat import integer_types +from hypothesis.internal.coverage import check_function + + +@check_function +def check_type(typ, arg, name=''): + if name: + name += '=' + if not isinstance(arg, typ): + if isinstance(typ, type): + typ_string = typ.__name__ + else: + typ_string = 'one of %s' % ( + ', '.join(t.__name__ for t in typ)) + raise InvalidArgument('Expected %s but got %s%r (type=%s)' + % (typ_string, name, arg, type(arg).__name__)) + + +@check_function +def check_valid_integer(value): + """Checks that value is either unspecified, or a valid integer. + + Otherwise raises InvalidArgument. + """ + if value is None: + return + check_type(integer_types, value) + + +@check_function +def check_valid_bound(value, name): + """Checks that value is either unspecified, or a valid interval bound. + + Otherwise raises InvalidArgument. + """ + if value is None or isinstance(value, integer_types + (Rational,)): + return + if not isinstance(value, (Real, decimal.Decimal)): + raise InvalidArgument('%s=%r must be a real number.' % (name, value)) + if math.isnan(value): + raise InvalidArgument(u'Invalid end point %s=%r' % (name, value)) + + +@check_function +def check_valid_magnitude(value, name): + """Checks that value is either unspecified, or a non-negative valid + interval bound. + + Otherwise raises InvalidArgument. + """ + check_valid_bound(value, name) + if value is not None and value < 0: + raise InvalidArgument('%s=%r must not be negative.' % (name, value)) + + +@check_function +def try_convert(typ, value, name): + if value is None: + return None + if isinstance(value, typ): + return value + try: + return typ(value) + except TypeError: + raise InvalidArgument( + 'Cannot convert %s=%r of type %s to type %s' % ( + name, value, type(value).__name__, typ.__name__ + ) + ) + except (OverflowError, ValueError, ArithmeticError): + raise InvalidArgument( + 'Cannot convert %s=%r to type %s' % ( + name, value, typ.__name__ + ) + ) + + +@check_function +def check_valid_size(value, name): + """Checks that value is either unspecified, or a valid non-negative size + expressed as an integer/float. + + Otherwise raises InvalidArgument. + """ + if value is None: + return + check_type(integer_types + (float,), value) + if value < 0: + raise InvalidArgument(u'Invalid size %s=%r < 0' % (name, value)) + if isinstance(value, float) and math.isnan(value): + raise InvalidArgument(u'Invalid size %s=%r' % (name, value)) + + +@check_function +def check_valid_interval(lower_bound, upper_bound, lower_name, upper_name): + """Checks that lower_bound and upper_bound are either unspecified, or they + define a valid interval on the number line. + + Otherwise raises InvalidArgument. + """ + if lower_bound is None or upper_bound is None: + return + if upper_bound < lower_bound: + raise InvalidArgument( + 'Cannot have %s=%r < %s=%r' % ( + upper_name, upper_bound, lower_name, lower_bound + )) + + +@check_function +def check_valid_sizes(min_size, average_size, max_size): + if average_size is not None: + from hypothesis._settings import note_deprecation + note_deprecation( + 'You should remove the average_size argument, because it is ' + 'deprecated and no longer has any effect. Please open an issue ' + 'if the default distribution of examples does not work for you.' + ) + + check_valid_size(min_size, 'min_size') + check_valid_size(max_size, 'max_size') + check_valid_interval(min_size, max_size, 'min_size', 'max_size') diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/provisional.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/provisional.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/provisional.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/provisional.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,66 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +"""This module contains various provisional APIs and strategies. + +It is intended for internal use, to ease code reuse, and is not stable. +Point releases may move or break the contents at any time! + +Internet strategies should conform to https://tools.ietf.org/html/rfc3696 or +the authoritative definitions it links to. If not, report the bug! +""" + +from __future__ import division, print_function, absolute_import + +import string + +import hypothesis.strategies as st + + +@st.defines_strategy_with_reusable_values +def domains(): + """A strategy for :rfc:`1035` fully qualified domain names.""" + atoms = st.text(string.ascii_letters + '0123456789-', + min_size=1, max_size=63 + ).filter(lambda s: '-' not in s[0] + s[-1]) + return st.builds( + lambda x, y: '.'.join(x + [y]), + st.lists(atoms, min_size=1), + # TODO: be more devious about top-level domains + st.sampled_from(['com', 'net', 'org', 'biz', 'info']) + ).filter(lambda url: len(url) <= 255) + + +@st.defines_strategy_with_reusable_values +def ip4_addr_strings(): + """A strategy for IPv4 address strings. + + This consists of four strings representing integers [0..255], + without zero-padding, joined by dots. + """ + return st.builds('{}.{}.{}.{}'.format, *(4 * [st.integers(0, 255)])) + + +@st.defines_strategy_with_reusable_values +def ip6_addr_strings(): + """A strategy for IPv6 address strings. + + This consists of sixteen quads of hex digits (0000 .. FFFF), joined + by colons. Values do not currently have zero-segments collapsed. + """ + part = st.integers(0, 2**16 - 1).map(u'{:04x}'.format) + return st.tuples(*[part] * 8).map(lambda a: u':'.join(a).upper()) diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/reporting.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/reporting.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/reporting.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/reporting.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,74 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import inspect + +from hypothesis._settings import Verbosity, settings +from hypothesis.internal.compat import print_unicode, \ + escape_unicode_characters +from hypothesis.utils.dynamicvariables import DynamicVariable + + +def silent(value): + pass + + +def default(value): + try: + print_unicode(value) + except UnicodeEncodeError: + print_unicode(escape_unicode_characters(value)) + + +reporter = DynamicVariable(default) + + +def current_reporter(): + return reporter.value + + +def with_reporter(new_reporter): + return reporter.with_value(new_reporter) + + +def current_verbosity(): + return settings.default.verbosity + + +def to_text(textish): + if inspect.isfunction(textish): + textish = textish() + if isinstance(textish, bytes): + textish = textish.decode('utf-8') + return textish + + +def verbose_report(text): + if current_verbosity() >= Verbosity.verbose: + current_reporter()(to_text(text)) + + +def debug_report(text): + if current_verbosity() >= Verbosity.debug: + current_reporter()(to_text(text)) + + +def report(text): + if current_verbosity() >= Verbosity.normal: + current_reporter()(to_text(text)) diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/searchstrategy/attrs.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/searchstrategy/attrs.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/searchstrategy/attrs.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/searchstrategy/attrs.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,159 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from functools import reduce +from itertools import chain + +import attr + +import hypothesis.strategies as st +from hypothesis.errors import ResolutionFailed +from hypothesis.internal.compat import string_types, get_type_hints +from hypothesis.utils.conventions import infer +from hypothesis.searchstrategy.types import type_sorting_key + + +def from_attrs(target, args, kwargs, to_infer): + """An internal version of builds(), specialised for Attrs classes.""" + fields = attr.fields(target) + kwargs = {k: v for k, v in kwargs.items() if v is not infer} + for name in to_infer: + kwargs[name] = from_attrs_attribute(getattr(fields, name), target) + # We might make this strategy more efficient if we added a layer here that + # retries drawing if validation fails, for improved composition. + # The treatment of timezones in datetimes() provides a precedent. + return st.tuples(st.tuples(*args), st.fixed_dictionaries(kwargs)).map( + lambda value: target(*value[0], **value[1]) + ) + + +def from_attrs_attribute(attrib, target): + """Infer a strategy from the metadata on an attr.Attribute object.""" + # Try inferring from the default argument. Note that this will only help + # the user passed `infer` to builds() for this attribute, but in that case + # we use it as the minimal example. + default = st.nothing() + if isinstance(attrib.default, attr.Factory): + if not getattr(attrib.default, 'takes_self', False): # new in 17.1 + default = st.builds(attrib.default.factory) + elif attrib.default is not attr.NOTHING: + default = st.just(attrib.default) + + # Try inferring None, exact values, or type from attrs provided validators. + null = st.nothing() # updated to none() on seeing an OptionalValidator + in_collections = [] # list of in_ validator collections to sample from + validator_types = set() # type constraints to pass to types_to_strategy() + if attrib.validator is not None: + validator = attrib.validator + if isinstance(validator, attr.validators._OptionalValidator): + null = st.none() + validator = validator.validator + if isinstance(validator, attr.validators._AndValidator): + vs = validator._validators + else: + vs = [validator] + for v in vs: + if isinstance(v, attr.validators._InValidator): + if isinstance(v.options, string_types): + in_collections.append(list(all_substrings(v.options))) + else: + in_collections.append(v.options) + elif isinstance(v, attr.validators._InstanceOfValidator): + validator_types.add(v.type) + + # This is the important line. We compose the final strategy from various + # parts. The default value, if any, is the minimal shrink, followed by + # None (again, if allowed). We then prefer to sample from values passed + # to an in_ validator if available, but infer from a type otherwise. + # Pick one because (sampled_from((1, 2)) | from_type(int)) would usually + # fail validation by generating e.g. zero! + if in_collections: + sample = st.sampled_from(list(ordered_intersection(in_collections))) + strat = default | null | sample + else: + strat = default | null | types_to_strategy(attrib, validator_types) + + # Better to give a meaningful error here than an opaque "could not draw" + # when we try to get a value but have lost track of where this was created. + if strat.is_empty: + raise ResolutionFailed( + 'Cannot infer a strategy from the default, validator, type, or ' + 'converter for attribute=%r of class=%r' % (attrib, target)) + return strat + + +def types_to_strategy(attrib, types): + """Find all the type metadata for this attribute, reconcile it, and infer a + strategy from the mess.""" + # If we know types from the validator(s), that's sufficient. + if len(types) == 1: + typ, = types + if isinstance(typ, tuple): + return st.one_of(*map(st.from_type, typ)) + return st.from_type(typ) + elif types: + # We have a list of tuples of types, and want to find a type + # (or tuple of types) that is a subclass of all of of them. + type_tuples = [k if isinstance(k, tuple) else (k,) for k in types] + # Flatten the list, filter types that would fail validation, and + # sort so that ordering is stable between runs and shrinks well. + allowed = [t for t in set(sum(type_tuples, ())) + if all(issubclass(t, tup) for tup in type_tuples)] + allowed.sort(key=type_sorting_key) + return st.one_of([st.from_type(t) for t in allowed]) + + # Otherwise, try the `type` attribute as a fallback, and finally try + # the type hints on a converter (desperate!) before giving up. + if isinstance(getattr(attrib, 'type', None), type): + # The convoluted test is because variable annotations may be stored + # in string form; attrs doesn't evaluate them and we don't handle them. + # See PEP 526, PEP 563, and Hypothesis issue #1004 for details. + return st.from_type(attrib.type) + + converter = getattr(attrib, 'converter', None) + if isinstance(converter, type): + return st.from_type(converter) + elif callable(converter): + hints = get_type_hints(converter) + if 'return' in hints: + return st.from_type(hints['return']) + + return st.nothing() + + +def ordered_intersection(in_): + """Set union of n sequences, ordered for reproducibility across runs.""" + intersection = reduce(set.intersection, in_, set(in_[0])) + for x in chain.from_iterable(in_): + if x in intersection: + yield x + intersection.remove(x) + + +def all_substrings(s): + """Generate all substrings of `s`, in order of length then occurrence. + Includes the empty string (first), and any duplicates that are present. + + >>> list(all_substrings('010')) + ['', '0', '1', '0', '01', '10', '010'] + """ + yield s[:0] + for n, _ in enumerate(s): + for i in range(len(s) - n): + yield s[i:i + n + 1] diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/searchstrategy/collections.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/searchstrategy/collections.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/searchstrategy/collections.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/searchstrategy/collections.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,189 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import hypothesis.internal.conjecture.utils as cu +from hypothesis.errors import InvalidArgument +from hypothesis.internal.compat import OrderedDict +from hypothesis.internal.conjecture.utils import combine_labels +from hypothesis.searchstrategy.strategies import SearchStrategy, \ + MappedSearchStrategy + + +class TupleStrategy(SearchStrategy): + """A strategy responsible for fixed length tuples based on heterogenous + strategies for each of their elements.""" + + def __init__(self, strategies): + SearchStrategy.__init__(self) + self.element_strategies = tuple(strategies) + + def do_validate(self): + for s in self.element_strategies: + s.validate() + + def calc_label(self): + return combine_labels( + self.class_label, *[s.label for s in self.element_strategies]) + + def __repr__(self): + if len(self.element_strategies) == 1: + tuple_string = '%s,' % (repr(self.element_strategies[0]),) + else: + tuple_string = ', '.join(map(repr, self.element_strategies)) + return 'TupleStrategy((%s))' % (tuple_string,) + + def calc_has_reusable_values(self, recur): + return all(recur(e) for e in self.element_strategies) + + def do_draw(self, data): + return tuple(data.draw(e) for e in self.element_strategies) + + def calc_is_empty(self, recur): + return any(recur(e) for e in self.element_strategies) + + +class ListStrategy(SearchStrategy): + """A strategy for lists which takes a strategy for its elements and the + allowed lengths, and generates lists with the correct size and contents.""" + + def __init__(self, elements, min_size=0, max_size=float('inf')): + SearchStrategy.__init__(self) + self.min_size = min_size or 0 + self.max_size = max_size if max_size is not None else float('inf') + assert 0 <= self.min_size <= self.max_size + self.average_size = min( + max(self.min_size * 2, self.min_size + 5), + 0.5 * (self.min_size + self.max_size), + ) + self.element_strategy = elements + + def calc_label(self): + return combine_labels(self.class_label, self.element_strategy.label) + + def do_validate(self): + self.element_strategy.validate() + if self.is_empty: + raise InvalidArgument(( + 'Cannot create non-empty lists with elements drawn from ' + 'strategy %r because it has no values.') % ( + self.element_strategy,)) + if self.element_strategy.is_empty and 0 < self.max_size < float('inf'): + from hypothesis._settings import note_deprecation + note_deprecation( + 'Cannot create a collection of max_size=%r, because no ' + 'elements can be drawn from the element strategy %r' + % (self.max_size, self.element_strategy) + ) + + def calc_is_empty(self, recur): + if self.min_size == 0: + return False + else: + return recur(self.element_strategy) + + def do_draw(self, data): + if self.element_strategy.is_empty: + assert self.min_size == 0 + return [] + + elements = cu.many( + data, + min_size=self.min_size, max_size=self.max_size, + average_size=self.average_size + ) + result = [] + while elements.more(): + result.append(data.draw(self.element_strategy)) + return result + + def __repr__(self): + return '%s(%r, min_size=%r, max_size=%r)' % ( + self.__class__.__name__, self.element_strategy, self.min_size, + self.max_size + ) + + +class UniqueListStrategy(ListStrategy): + + def __init__(self, elements, min_size, max_size, key): + super(UniqueListStrategy, self).__init__(elements, min_size, max_size) + self.key = key + + def do_draw(self, data): + if self.element_strategy.is_empty: + assert self.min_size == 0 + return [] + + elements = cu.many( + data, + min_size=self.min_size, max_size=self.max_size, + average_size=self.average_size + ) + seen = set() + result = [] + + while elements.more(): + value = data.draw(self.element_strategy) + k = self.key(value) + if k in seen: + elements.reject() + else: + seen.add(k) + result.append(value) + assert self.max_size >= len(result) >= self.min_size + return result + + +class FixedKeysDictStrategy(MappedSearchStrategy): + """A strategy which produces dicts with a fixed set of keys, given a + strategy for each of their equivalent values. + + e.g. {'foo' : some_int_strategy} would generate dicts with the single + key 'foo' mapping to some integer. + """ + + def __init__(self, strategy_dict): + self.dict_type = type(strategy_dict) + + if isinstance(strategy_dict, OrderedDict): + self.keys = tuple(strategy_dict.keys()) + else: + try: + self.keys = tuple(sorted( + strategy_dict.keys(), + )) + except TypeError: + self.keys = tuple(sorted( + strategy_dict.keys(), key=repr, + )) + super(FixedKeysDictStrategy, self).__init__( + strategy=TupleStrategy( + (strategy_dict[k] for k in self.keys) + ) + ) + + def calc_is_empty(self, recur): + return recur(self.mapped_strategy) + + def __repr__(self): + return 'FixedKeysDictStrategy(%r, %r)' % ( + self.keys, self.mapped_strategy) + + def pack(self, value): + return self.dict_type(zip(self.keys, value)) diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/searchstrategy/datetime.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/searchstrategy/datetime.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/searchstrategy/datetime.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/searchstrategy/datetime.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,120 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import datetime as dt + +from hypothesis.internal.conjecture import utils +from hypothesis.searchstrategy.strategies import SearchStrategy + +__all__ = ['DateStrategy', 'DatetimeStrategy', 'TimedeltaStrategy'] + + +def is_pytz_timezone(tz): + if not isinstance(tz, dt.tzinfo): + return False + module = type(tz).__module__ + return module == 'pytz' or module.startswith('pytz.') + + +class DatetimeStrategy(SearchStrategy): + + def __init__(self, min_value, max_value, timezones_strat): + assert isinstance(min_value, dt.datetime) + assert isinstance(max_value, dt.datetime) + assert min_value.tzinfo is None + assert max_value.tzinfo is None + assert min_value <= max_value + assert isinstance(timezones_strat, SearchStrategy) + self.min_dt = min_value + self.max_dt = max_value + self.tz_strat = timezones_strat + + def _attempt_one_draw(self, data): + result = dict() + cap_low, cap_high = True, True + for name in ('year', 'month', 'day', + 'hour', 'minute', 'second', 'microsecond'): + low = getattr(self.min_dt if cap_low else dt.datetime.min, name) + high = getattr(self.max_dt if cap_high else dt.datetime.max, name) + if name == 'year': + val = utils.centered_integer_range(data, low, high, 2000) + else: + val = utils.integer_range(data, low, high) + result[name] = val + cap_low = cap_low and val == low + cap_high = cap_high and val == high + tz = data.draw(self.tz_strat) + try: + result = dt.datetime(**result) + if is_pytz_timezone(tz): + # Can't just construct; see http://pytz.sourceforge.net + return tz.normalize(tz.localize(result)) + return result.replace(tzinfo=tz) + except (ValueError, OverflowError): + return None + + def do_draw(self, data): + for _ in range(3): + result = self._attempt_one_draw(data) + if result is not None: + return result + data.note_event('3 attempts to create a datetime between %r and %r ' + 'with timezone from %r failed.' % + (self.min_dt, self.max_dt, self.tz_strat)) + data.mark_invalid() + + +class DateStrategy(SearchStrategy): + + def __init__(self, min_value, max_value): + assert isinstance(min_value, dt.date) + assert isinstance(max_value, dt.date) + assert min_value < max_value + self.min_value = min_value + self.days_apart = (max_value - min_value).days + self.center = (dt.date(2000, 1, 1) - min_value).days + + def do_draw(self, data): + return self.min_value + dt.timedelta(days=utils.centered_integer_range( + data, 0, self.days_apart, center=self.center)) + + +class TimedeltaStrategy(SearchStrategy): + + def __init__(self, min_value, max_value): + assert isinstance(min_value, dt.timedelta) + assert isinstance(max_value, dt.timedelta) + assert min_value < max_value + self.min_value = min_value + self.max_value = max_value + + def do_draw(self, data): + result = dict() + low_bound = True + high_bound = True + for name in ('days', 'seconds', 'microseconds'): + low = getattr( + self.min_value if low_bound else dt.timedelta.min, name) + high = getattr( + self.max_value if high_bound else dt.timedelta.max, name) + val = utils.centered_integer_range(data, low, high, 0) + result[name] = val + low_bound = low_bound and val == low + high_bound = high_bound and val == high + return dt.timedelta(**result) diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/searchstrategy/deferred.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/searchstrategy/deferred.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/searchstrategy/deferred.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/searchstrategy/deferred.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,101 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import inspect + +from hypothesis.errors import InvalidArgument +from hypothesis.internal.reflection import get_pretty_function_description +from hypothesis.searchstrategy.strategies import SearchStrategy + + +class DeferredStrategy(SearchStrategy): + """A strategy which may be used before it is fully defined.""" + + def __init__(self, definition): + SearchStrategy.__init__(self) + self.__wrapped_strategy = None + self.__in_repr = False + self.__is_empty = None + self.__definition = definition + + @property + def wrapped_strategy(self): + if self.__wrapped_strategy is None: + if not inspect.isfunction(self.__definition): + raise InvalidArgument(( + 'Excepted a definition to be a function but got %r of type' + ' %s instead.') % ( + self.__definition, type(self.__definition).__name__)) + result = self.__definition() + if result is self: + raise InvalidArgument( + 'Cannot define a deferred strategy to be itself') + if not isinstance(result, SearchStrategy): + raise InvalidArgument(( + 'Expected definition to return a SearchStrategy but ' + 'returned %r of type %s') % ( + result, type(result).__name__ + )) + self.__wrapped_strategy = result + del self.__definition + return self.__wrapped_strategy + + @property + def branches(self): + return self.wrapped_strategy.branches + + @property + def supports_find(self): + return self.wrapped_strategy.supports_find + + def calc_label(self): + """Deferred strategies don't have a calculated label, because we would + end up having to calculate the fixed point of some hash function in + order to calculate it when they recursively refer to themself! + + The label for the wrapped strategy will still appear because it + will be passed to draw. + """ + # This is actually the same as the parent class implementation, but we + # include it explicitly here in order to document that this is a + # deliberate decision. + return self.class_label + + def calc_is_empty(self, recur): + return recur(self.wrapped_strategy) + + def calc_has_reusable_values(self, recur): + return recur(self.wrapped_strategy) + + def __repr__(self): + if self.__wrapped_strategy is not None: + if self.__in_repr: + return '(deferred@%r)' % (id(self),) + try: + self.__in_repr = True + return repr(self.__wrapped_strategy) + finally: + self.__in_repr = False + else: + return 'deferred(%s)' % ( + get_pretty_function_description(self.__definition) + ) + + def do_draw(self, data): + return data.draw(self.wrapped_strategy) diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/searchstrategy/flatmapped.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/searchstrategy/flatmapped.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/searchstrategy/flatmapped.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/searchstrategy/flatmapped.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,52 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from hypothesis.internal.reflection import get_pretty_function_description +from hypothesis.searchstrategy.strategies import SearchStrategy + + +class FlatMapStrategy(SearchStrategy): + + def __init__( + self, strategy, expand + ): + super(FlatMapStrategy, self).__init__() + self.flatmapped_strategy = strategy + self.expand = expand + + def calc_is_empty(self, recur): + return recur(self.flatmapped_strategy) + + def __repr__(self): + if not hasattr(self, u'_cached_repr'): + self._cached_repr = u'%r.flatmap(%s)' % ( + self.flatmapped_strategy, get_pretty_function_description( + self.expand)) + return self._cached_repr + + def do_draw(self, data): + source = data.draw(self.flatmapped_strategy) + return data.draw(self.expand(source)) + + @property + def branches(self): + return [ + FlatMapStrategy(strategy=strategy, expand=self.expand) + for strategy in self.flatmapped_strategy.branches + ] diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/searchstrategy/__init__.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/searchstrategy/__init__.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/searchstrategy/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/searchstrategy/__init__.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,26 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +"""Package defining SearchStrategy, which is the core type that Hypothesis uses +to explore data.""" + + +from .strategies import SearchStrategy, check_strategy + +__all__ = [ + 'SearchStrategy', 'check_strategy' +] diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/searchstrategy/lazy.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/searchstrategy/lazy.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/searchstrategy/lazy.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/searchstrategy/lazy.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,164 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from hypothesis.internal.compat import getfullargspec +from hypothesis.internal.reflection import arg_string, \ + convert_keyword_arguments, convert_positional_arguments +from hypothesis.searchstrategy.strategies import SearchStrategy + +if False: + from typing import Dict # noqa + + +unwrap_cache = {} # type: Dict[SearchStrategy, SearchStrategy] +unwrap_depth = 0 + + +def unwrap_strategies(s): + global unwrap_depth + + if not isinstance(s, SearchStrategy): + return s + try: + return unwrap_cache[s] + except KeyError: + pass + + unwrap_cache[s] = s + + try: + unwrap_depth += 1 + try: + result = unwrap_strategies(s.wrapped_strategy) + unwrap_cache[s] = result + try: + assert result.force_has_reusable_values == \ + s.force_has_reusable_values + except AttributeError: + pass + + try: + result.force_has_reusable_values = s.force_has_reusable_values + except AttributeError: + pass + return result + except AttributeError: + return s + finally: + unwrap_depth -= 1 + if unwrap_depth <= 0: + unwrap_cache.clear() + assert unwrap_depth >= 0 + + +class LazyStrategy(SearchStrategy): + """A strategy which is defined purely by conversion to and from another + strategy. + + Its parameter and distribution come from that other strategy. + """ + + def __init__(self, function, args, kwargs): + SearchStrategy.__init__(self) + self.__wrapped_strategy = None + self.__representation = None + self.__function = function + self.__args = args + self.__kwargs = kwargs + + @property + def supports_find(self): + return self.wrapped_strategy.supports_find + + def calc_is_empty(self, recur): + return recur(self.wrapped_strategy) + + def calc_has_reusable_values(self, recur): + return recur(self.wrapped_strategy) + + def calc_is_cacheable(self, recur): + for source in (self.__args, self.__kwargs.values()): + for v in source: + if isinstance(v, SearchStrategy) and not v.is_cacheable: + return False + return True + + @property + def wrapped_strategy(self): + if self.__wrapped_strategy is None: + unwrapped_args = tuple( + unwrap_strategies(s) for s in self.__args) + unwrapped_kwargs = { + k: unwrap_strategies(v) + for k, v in self.__kwargs.items() + } + + base = self.__function( + *self.__args, **self.__kwargs + ) + if ( + unwrapped_args == self.__args and + unwrapped_kwargs == self.__kwargs + ): + self.__wrapped_strategy = base + else: + self.__wrapped_strategy = self.__function( + *unwrapped_args, + **unwrapped_kwargs) + return self.__wrapped_strategy + + def do_validate(self): + w = self.wrapped_strategy + assert isinstance(w, SearchStrategy), \ + '%r returned non-strategy %r' % (self, w) + w.validate() + + def __repr__(self): + if self.__representation is None: + _args = self.__args + _kwargs = self.__kwargs + argspec = getfullargspec(self.__function) + defaults = dict(argspec.kwonlydefaults or {}) + if argspec.defaults is not None: + for name, value in zip(reversed(argspec.args), + reversed(argspec.defaults)): + defaults[name] = value + if len(argspec.args) > 1 or argspec.defaults: + _args, _kwargs = convert_positional_arguments( + self.__function, _args, _kwargs) + else: + _args, _kwargs = convert_keyword_arguments( + self.__function, _args, _kwargs) + kwargs_for_repr = dict(_kwargs) + for k, v in defaults.items(): + if k in kwargs_for_repr and kwargs_for_repr[k] is defaults[k]: + del kwargs_for_repr[k] + self.__representation = '%s(%s)' % ( + self.__function.__name__, + arg_string( + self.__function, _args, kwargs_for_repr, reorder=False), + ) + return self.__representation + + def do_draw(self, data): + return data.draw(self.wrapped_strategy) + + @property + def label(self): + return self.wrapped_strategy.label diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/searchstrategy/misc.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/searchstrategy/misc.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/searchstrategy/misc.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/searchstrategy/misc.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,100 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import hypothesis.internal.conjecture.utils as d +from hypothesis.types import RandomWithSeed +from hypothesis.searchstrategy.strategies import SearchStrategy, \ + MappedSearchStrategy + + +class BoolStrategy(SearchStrategy): + """A strategy that produces Booleans with a Bernoulli conditional + distribution.""" + + def __repr__(self): + return u'BoolStrategy()' + + def calc_has_reusable_values(self, recur): + return True + + def do_draw(self, data): + return d.boolean(data) + + +def is_simple_data(value): + try: + hash(value) + return True + except TypeError: + return False + + +class JustStrategy(SearchStrategy): + """A strategy which always returns a single fixed value.""" + + def __init__(self, value): + SearchStrategy.__init__(self) + self.value = value + + def __repr__(self): + return 'just(%r)' % (self.value,) + + def calc_has_reusable_values(self, recur): + return True + + def calc_is_cacheable(self, recur): + return is_simple_data(self.value) + + def do_draw(self, data): + return self.value + + +class RandomStrategy(MappedSearchStrategy): + """A strategy which produces Random objects. + + The conditional distribution is simply a RandomWithSeed seeded with + a 128 bits of data chosen uniformly at random. + """ + + def pack(self, i): + return RandomWithSeed(i) + + +class SampledFromStrategy(SearchStrategy): + """A strategy which samples from a set of elements. This is essentially + equivalent to using a OneOfStrategy over Just strategies but may be more + efficient and convenient. + + The conditional distribution chooses uniformly at random from some + non-empty subset of the elements. + """ + + def __init__(self, elements): + SearchStrategy.__init__(self) + self.elements = d.check_sample(elements, 'sampled_from') + assert self.elements + + def calc_has_reusable_values(self, recur): + return True + + def calc_is_cacheable(self, recur): + return is_simple_data(self.elements) + + def do_draw(self, data): + return d.choice(data, self.elements) diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/searchstrategy/numbers.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/searchstrategy/numbers.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/searchstrategy/numbers.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/searchstrategy/numbers.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,185 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import math + +import hypothesis.internal.conjecture.utils as d +import hypothesis.internal.conjecture.floats as flt +from hypothesis.control import assume +from hypothesis.internal.floats import sign +from hypothesis.internal.conjecture.utils import calc_label_from_name +from hypothesis.searchstrategy.strategies import SearchStrategy + + +class IntStrategy(SearchStrategy): + """A generic strategy for integer types that provides the basic methods + other than produce. + + Subclasses should provide the produce method. + """ + + +class IntegersFromStrategy(SearchStrategy): + + def __init__(self, lower_bound, average_size=100000.0): + super(IntegersFromStrategy, self).__init__() + self.lower_bound = lower_bound + self.average_size = average_size + + def __repr__(self): + return 'IntegersFromStrategy(%d)' % (self.lower_bound,) + + def do_draw(self, data): + return int( + self.lower_bound + d.geometric(data, 1.0 / self.average_size)) + + +class WideRangeIntStrategy(IntStrategy): + + distribution = d.Sampler([ + 4.0, 8.0, 1.0, 1.0, 0.5 + ]) + + sizes = [8, 16, 32, 64, 128] + + def __repr__(self): + return 'WideRangeIntStrategy()' + + def do_draw(self, data): + size = self.sizes[self.distribution.sample(data)] + r = data.draw_bits(size) + sign = r & 1 + r >>= 1 + if sign: + r = -r + return int(r) + + +class BoundedIntStrategy(SearchStrategy): + """A strategy for providing integers in some interval with inclusive + endpoints.""" + + def __init__(self, start, end): + SearchStrategy.__init__(self) + self.start = start + self.end = end + + def __repr__(self): + return 'BoundedIntStrategy(%d, %d)' % (self.start, self.end) + + def do_draw(self, data): + return d.integer_range(data, self.start, self.end) + + +NASTY_FLOATS = sorted([ + 0.0, 0.5, 1.1, 1.5, 1.9, 1.0 / 3, 10e6, 10e-6, 1.175494351e-38, + 2.2250738585072014e-308, + 1.7976931348623157e+308, 3.402823466e+38, 9007199254740992, 1 - 10e-6, + 2 + 10e-6, 1.192092896e-07, 2.2204460492503131e-016, + +] + [float('inf'), float('nan')] * 5, key=flt.float_to_lex) +NASTY_FLOATS = list(map(float, NASTY_FLOATS)) +NASTY_FLOATS.extend([-x for x in NASTY_FLOATS]) + +FLOAT_STRATEGY_DO_DRAW_LABEL = calc_label_from_name( + 'getting another float in FloatStrategy') + + +class FloatStrategy(SearchStrategy): + """Generic superclass for strategies which produce floats.""" + + def __init__(self, allow_infinity, allow_nan): + SearchStrategy.__init__(self) + assert isinstance(allow_infinity, bool) + assert isinstance(allow_nan, bool) + self.allow_infinity = allow_infinity + self.allow_nan = allow_nan + + self.nasty_floats = [f for f in NASTY_FLOATS if self.permitted(f)] + weights = [ + 0.2 * len(self.nasty_floats) + ] + [0.8] * len(self.nasty_floats) + self.sampler = d.Sampler(weights) + + def __repr__(self): + return '%s()' % (self.__class__.__name__,) + + def permitted(self, f): + assert isinstance(f, float) + if not self.allow_infinity and math.isinf(f): + return False + if not self.allow_nan and math.isnan(f): + return False + return True + + def do_draw(self, data): + while True: + data.start_example(FLOAT_STRATEGY_DO_DRAW_LABEL) + i = self.sampler.sample(data) + if i == 0: + result = flt.draw_float(data) + else: + result = self.nasty_floats[i - 1] + flt.write_float(data, result) + data.stop_example() + if self.permitted(result): + return result + + +def float_order_key(k): + return (sign(k), k) + + +class FixedBoundedFloatStrategy(SearchStrategy): + """A strategy for floats distributed between two endpoints. + + The conditional distribution tries to produce values clustered + closer to one of the ends. + """ + + def __init__(self, lower_bound, upper_bound): + SearchStrategy.__init__(self) + self.lower_bound = float(lower_bound) + self.upper_bound = float(upper_bound) + assert not math.isinf(self.upper_bound - self.lower_bound) + lb = float_order_key(self.lower_bound) + ub = float_order_key(self.upper_bound) + + self.critical = [ + z for z in (-0.0, 0.0) + if lb <= float_order_key(z) <= ub + ] + self.critical.append(self.lower_bound) + self.critical.append(self.upper_bound) + + def __repr__(self): + return 'FixedBoundedFloatStrategy(%s, %s)' % ( + self.lower_bound, self.upper_bound, + ) + + def do_draw(self, data): + f = self.lower_bound + ( + self.upper_bound - self.lower_bound) * d.fractional_float(data) + assume(self.lower_bound <= f <= self.upper_bound) + assume(sign(self.lower_bound) <= sign(f) <= sign(self.upper_bound)) + # Special handling for bounds of -0.0 + for g in [self.lower_bound, self.upper_bound]: + if f == g: + f = math.copysign(f, g) + return f diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/searchstrategy/recursive.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/searchstrategy/recursive.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/searchstrategy/recursive.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/searchstrategy/recursive.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,109 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from contextlib import contextmanager + +from hypothesis.errors import InvalidArgument +from hypothesis.internal.lazyformat import lazyformat +from hypothesis.internal.reflection import get_pretty_function_description +from hypothesis.searchstrategy.strategies import OneOfStrategy, \ + SearchStrategy + + +class LimitReached(BaseException): + pass + + +class LimitedStrategy(SearchStrategy): + + def __init__(self, strategy): + super(LimitedStrategy, self).__init__() + self.base_strategy = strategy + self.marker = 0 + self.currently_capped = False + + def do_validate(self): + self.base_strategy.validate() + + def do_draw(self, data): + assert self.currently_capped + if self.marker <= 0: + raise LimitReached() + self.marker -= 1 + return data.draw(self.base_strategy) + + @contextmanager + def capped(self, max_templates): + assert not self.currently_capped + try: + self.currently_capped = True + self.marker = max_templates + yield + finally: + self.currently_capped = False + + +class RecursiveStrategy(SearchStrategy): + + def __init__(self, base, extend, max_leaves): + self.max_leaves = max_leaves + self.base = base + self.limited_base = LimitedStrategy(base) + self.extend = extend + + strategies = [self.limited_base, self.extend(self.limited_base)] + while 2 ** len(strategies) <= max_leaves: + strategies.append( + extend(OneOfStrategy(tuple(strategies), bias=0.8))) + self.strategy = OneOfStrategy(strategies) + + def __repr__(self): + if not hasattr(self, '_cached_repr'): + self._cached_repr = 'recursive(%r, %s, max_leaves=%d)' % ( + self.base, get_pretty_function_description(self.extend), + self.max_leaves + ) + return self._cached_repr + + def do_validate(self): + if not isinstance(self.base, SearchStrategy): + raise InvalidArgument( + 'Expected base to be SearchStrategy but got %r' % (self.base,) + ) + extended = self.extend(self.limited_base) + if not isinstance(extended, SearchStrategy): + raise InvalidArgument( + 'Expected extend(%r) to be a SearchStrategy but got %r' % ( + self.limited_base, extended + )) + self.limited_base.validate() + self.extend(self.limited_base).validate() + + def do_draw(self, data): + count = 0 + while True: + try: + with self.limited_base.capped(self.max_leaves): + return data.draw(self.strategy) + except LimitReached: + if count == 0: + data.note_event(lazyformat( + 'Draw for %r exceeded max_leaves ' + 'and had to be retried', self,)) + count += 1 diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/searchstrategy/regex.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/searchstrategy/regex.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/searchstrategy/regex.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/searchstrategy/regex.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,497 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import re +import sys +import operator +import sre_parse +import sre_constants as sre + +import hypothesis.strategies as st +from hypothesis import reject +from hypothesis.internal.compat import PY3, hrange, hunichr, text_type, \ + int_to_byte +from hypothesis.internal.charmap import categories, as_general_categories + +HAS_SUBPATTERN_FLAGS = sys.version_info[:2] >= (3, 6) + + +UNICODE_CATEGORIES = set(categories()) + + +SPACE_CHARS = set(u' \t\n\r\f\v') +UNICODE_SPACE_CHARS = SPACE_CHARS | set(u'\x1c\x1d\x1e\x1f\x85') +UNICODE_DIGIT_CATEGORIES = set(['Nd']) +UNICODE_SPACE_CATEGORIES = set(as_general_categories('Z')) +UNICODE_LETTER_CATEGORIES = set(as_general_categories('L')) +UNICODE_WORD_CATEGORIES = set(as_general_categories(['L', 'N'])) + +# This is verbose, but correct on all versions of Python +BYTES_ALL = set(int_to_byte(i) for i in range(256)) +BYTES_DIGIT = set(b for b in BYTES_ALL if re.match(b'\\d', b)) +BYTES_SPACE = set(b for b in BYTES_ALL if re.match(b'\\s', b)) +BYTES_WORD = set(b for b in BYTES_ALL if re.match(b'\\w', b)) +BYTES_LOOKUP = { + sre.CATEGORY_DIGIT: BYTES_DIGIT, + sre.CATEGORY_SPACE: BYTES_SPACE, + sre.CATEGORY_WORD: BYTES_WORD, + sre.CATEGORY_NOT_DIGIT: BYTES_ALL - BYTES_DIGIT, + sre.CATEGORY_NOT_SPACE: BYTES_ALL - BYTES_SPACE, + sre.CATEGORY_NOT_WORD: BYTES_ALL - BYTES_WORD, +} + +# On Python < 3.4 (including 2.7), the following unicode chars are weird. +# They are matched by the \W, meaning 'not word', but unicodedata.category(c) +# returns one of the word categories above. There's special handling below. +HAS_WEIRD_WORD_CHARS = sys.version_info[:2] < (3, 4) +UNICODE_WEIRD_NONWORD_CHARS = set(u'\U00012432\U00012433\U00012456\U00012457') + + +GROUP_CACHE_STRATEGY = st.shared( + st.builds(dict), key='hypothesis.regex.group_cache' +) + + +@st.composite +def update_group(draw, group_name, strategy): + cache = draw(GROUP_CACHE_STRATEGY) + result = draw(strategy) + cache[group_name] = result + return result + + +@st.composite +def reuse_group(draw, group_name): + cache = draw(GROUP_CACHE_STRATEGY) + try: + return cache[group_name] + except KeyError: + reject() + + +@st.composite +def group_conditional(draw, group_name, if_yes, if_no): + cache = draw(GROUP_CACHE_STRATEGY) + if group_name in cache: + return draw(if_yes) + else: + return draw(if_no) + + +@st.composite +def clear_cache_after_draw(draw, base_strategy): + cache = draw(GROUP_CACHE_STRATEGY) + result = draw(base_strategy) + cache.clear() + return result + + +class Context(object): + __slots__ = ['flags'] + + def __init__(self, groups=None, flags=0): + self.flags = flags + + +class CharactersBuilder(object): + """Helper object that allows to configure `characters` strategy with + various unicode categories and characters. Also allows negation of + configured set. + + :param negate: If True, configure :func:`hypothesis.strategies.characters` + to match anything other than configured character set + :param flags: Regex flags. They affect how and which characters are matched + """ + + def __init__(self, negate=False, flags=0): + self._categories = set() + self._whitelist_chars = set() + self._blacklist_chars = set() + self._negate = negate + self._ignorecase = flags & re.IGNORECASE + self._unicode = not bool(flags & re.ASCII) \ + if PY3 else bool(flags & re.UNICODE) + self.code_to_char = hunichr + + @property + def strategy(self): + """Returns resulting strategy that generates configured char set.""" + max_codepoint = None if self._unicode else 127 + if self._negate: + black_chars = self._blacklist_chars - self._whitelist_chars + return st.characters( + blacklist_categories=self._categories | {'Cc', 'Cs'}, + blacklist_characters=self._whitelist_chars, + whitelist_characters=black_chars, + max_codepoint=max_codepoint, + ) + white_chars = self._whitelist_chars - self._blacklist_chars + return st.characters( + whitelist_categories=self._categories, + blacklist_characters=self._blacklist_chars, + whitelist_characters=white_chars, + max_codepoint=max_codepoint, + ) + + def add_category(self, category): + """Update unicode state to match sre_parse object ``category``.""" + if category == sre.CATEGORY_DIGIT: + self._categories |= UNICODE_DIGIT_CATEGORIES + elif category == sre.CATEGORY_NOT_DIGIT: + self._categories |= UNICODE_CATEGORIES - UNICODE_DIGIT_CATEGORIES + elif category == sre.CATEGORY_SPACE: + self._categories |= UNICODE_SPACE_CATEGORIES + self._whitelist_chars |= UNICODE_SPACE_CHARS \ + if self._unicode else SPACE_CHARS + elif category == sre.CATEGORY_NOT_SPACE: + self._categories |= UNICODE_CATEGORIES - UNICODE_SPACE_CATEGORIES + self._blacklist_chars |= UNICODE_SPACE_CHARS \ + if self._unicode else SPACE_CHARS + elif category == sre.CATEGORY_WORD: + self._categories |= UNICODE_WORD_CATEGORIES + self._whitelist_chars.add(u'_') + if HAS_WEIRD_WORD_CHARS and self._unicode: # pragma: no cover + # This code is workaround of weird behavior in + # specific Python versions and run only on those versions + self._blacklist_chars |= UNICODE_WEIRD_NONWORD_CHARS + elif category == sre.CATEGORY_NOT_WORD: + self._categories |= UNICODE_CATEGORIES - UNICODE_WORD_CATEGORIES + self._blacklist_chars.add(u'_') + if HAS_WEIRD_WORD_CHARS and self._unicode: # pragma: no cover + # This code is workaround of weird behavior in + # specific Python versions and run only on those versions + self._whitelist_chars |= UNICODE_WEIRD_NONWORD_CHARS + else: # pragma: no cover + raise AssertionError('Unknown character category: %s' % category) + + def add_char(self, char): + """Add given char to the whitelist.""" + c = self.code_to_char(char) + self._whitelist_chars.add(c) + if self._ignorecase and \ + re.match(c, c.swapcase(), re.IGNORECASE) is not None: + self._whitelist_chars.add(c.swapcase()) + + +class BytesBuilder(CharactersBuilder): + + def __init__(self, negate=False, flags=0): + self._whitelist_chars = set() + self._blacklist_chars = set() + self._negate = negate + self._ignorecase = flags & re.IGNORECASE + self.code_to_char = int_to_byte + + @property + def strategy(self): + """Returns resulting strategy that generates configured char set.""" + allowed = self._whitelist_chars + if self._negate: + allowed = BYTES_ALL - allowed + return st.sampled_from(sorted(allowed)) + + def add_category(self, category): + """Update characters state to match sre_parse object ``category``.""" + self._whitelist_chars |= BYTES_LOOKUP[category] + + +@st.composite +def maybe_pad(draw, regex, strategy, left_pad_strategy, right_pad_strategy): + """Attempt to insert padding around the result of a regex draw while + preserving the match.""" + result = draw(strategy) + left_pad = draw(left_pad_strategy) + if left_pad and regex.search(left_pad + result): + result = left_pad + result + right_pad = draw(right_pad_strategy) + if right_pad and regex.search(result + right_pad): + result += right_pad + return result + + +def base_regex_strategy(regex, parsed=None): + if parsed is None: + parsed = sre_parse.parse(regex.pattern, flags=regex.flags) + return clear_cache_after_draw(_strategy( + parsed, + Context(flags=regex.flags), + isinstance(regex.pattern, text_type) + )) + + +def regex_strategy(regex, fullmatch): + if not hasattr(regex, 'pattern'): + regex = re.compile(regex) + + is_unicode = isinstance(regex.pattern, text_type) + + parsed = sre_parse.parse(regex.pattern, flags=regex.flags) + + if not parsed: + if is_unicode: + return st.text() + else: + return st.binary() + + if is_unicode: + base_padding_strategy = st.text() + empty = st.just(u'') + newline = st.just(u'\n') + else: + base_padding_strategy = st.binary() + empty = st.just(b'') + newline = st.just(b'\n') + + right_pad = base_padding_strategy + left_pad = base_padding_strategy + + if fullmatch: + right_pad = empty + elif parsed[-1][0] == sre.AT: + if parsed[-1][1] == sre.AT_END_STRING: + right_pad = empty + elif parsed[-1][1] == sre.AT_END: + if regex.flags & re.MULTILINE: + right_pad = st.one_of( + empty, + st.builds(operator.add, newline, right_pad) + ) + else: + right_pad = st.one_of(empty, newline) + if fullmatch: + left_pad = empty + elif parsed[0][0] == sre.AT: + if parsed[0][1] == sre.AT_BEGINNING_STRING: + left_pad = empty + elif parsed[0][1] == sre.AT_BEGINNING: + if regex.flags & re.MULTILINE: + left_pad = st.one_of( + empty, + st.builds(operator.add, left_pad, newline), + ) + else: + left_pad = empty + + base = base_regex_strategy(regex, parsed).filter(regex.search) + + return maybe_pad(regex, base, left_pad, right_pad) + + +def _strategy(codes, context, is_unicode): + """Convert SRE regex parse tree to strategy that generates strings matching + that regex represented by that parse tree. + + `codes` is either a list of SRE regex elements representations or a + particular element representation. Each element is a tuple of element code + (as string) and parameters. E.g. regex 'ab[0-9]+' compiles to following + elements: + + [ + (LITERAL, 97), + (LITERAL, 98), + (MAX_REPEAT, (1, 4294967295, [ + (IN, [ + (RANGE, (48, 57)) + ]) + ])) + ] + + The function recursively traverses regex element tree and converts each + element to strategy that generates strings that match that element. + + Context stores + 1. List of groups (for backreferences) + 2. Active regex flags (e.g. IGNORECASE, DOTALL, UNICODE, they affect + behavior of various inner strategies) + """ + def recurse(codes): + return _strategy(codes, context, is_unicode) + + if is_unicode: + empty = u'' + to_char = hunichr + else: + empty = b'' + to_char = int_to_byte + binary_char = st.binary(min_size=1, max_size=1) + + if not isinstance(codes, tuple): + # List of codes + strategies = [] + + i = 0 + while i < len(codes): + if codes[i][0] == sre.LITERAL and \ + not context.flags & re.IGNORECASE: + # Merge subsequent "literals" into one `just()` strategy + # that generates corresponding text if no IGNORECASE + j = i + 1 + while j < len(codes) and codes[j][0] == sre.LITERAL: + j += 1 + + if i + 1 < j: + strategies.append(st.just( + empty.join([to_char(charcode) + for (_, charcode) in codes[i:j]]) + )) + + i = j + continue + + strategies.append(recurse(codes[i])) + i += 1 + + # We handle this separately at the top level, but some regex can + # contain empty lists internally, so we need to handle this here too. + if not strategies: + return st.just(empty) + + if len(strategies) == 1: + return strategies[0] + return st.tuples(*strategies).map(empty.join) + else: + # Single code + code, value = codes + if code == sre.LITERAL: + # Regex 'a' (single char) + c = to_char(value) + if context.flags & re.IGNORECASE and \ + re.match(c, c.swapcase(), re.IGNORECASE) is not None: + # We do the explicit check for swapped-case matching because + # eg 'ß'.upper() == 'SS' and ignorecase doesn't match it. + return st.sampled_from([c, c.swapcase()]) + return st.just(c) + + elif code == sre.NOT_LITERAL: + # Regex '[^a]' (negation of a single char) + c = to_char(value) + blacklist = set(c) + if context.flags & re.IGNORECASE and \ + re.match(c, c.swapcase(), re.IGNORECASE) is not None: + blacklist |= set(c.swapcase()) + if is_unicode: + return st.characters(blacklist_characters=blacklist) + else: + return binary_char.filter(lambda c: c not in blacklist) + + elif code == sre.IN: + # Regex '[abc0-9]' (set of characters) + negate = value[0][0] == sre.NEGATE + if is_unicode: + builder = CharactersBuilder(negate, context.flags) + else: + builder = BytesBuilder(negate, context.flags) + + for charset_code, charset_value in value: + if charset_code == sre.NEGATE: + # Regex '[^...]' (negation) + # handled by builder = CharactersBuilder(...) above + pass + elif charset_code == sre.LITERAL: + # Regex '[a]' (single char) + builder.add_char(charset_value) + elif charset_code == sre.RANGE: + # Regex '[a-z]' (char range) + low, high = charset_value + for char_code in hrange(low, high + 1): + builder.add_char(char_code) + elif charset_code == sre.CATEGORY: + # Regex '[\w]' (char category) + builder.add_category(charset_value) + else: # pragma: no cover + # Currently there are no known code points other than + # handled here. This code is just future proofing + raise AssertionError('Unknown charset code: %s' + % charset_code) + return builder.strategy + + elif code == sre.ANY: + # Regex '.' (any char) + if is_unicode: + if context.flags & re.DOTALL: + return st.characters() + return st.characters(blacklist_characters=u'\n') + else: + if context.flags & re.DOTALL: + return binary_char + return binary_char.filter(lambda c: c != b'\n') + + elif code == sre.AT: + # Regexes like '^...', '...$', '\bfoo', '\Bfoo' + # An empty string (or newline) will match the token itself, but + # we don't and can't check the position (eg '%' at the end) + return st.just(empty) + + elif code == sre.SUBPATTERN: + # Various groups: '(...)', '(:...)' or '(?P...)' + old_flags = context.flags + if HAS_SUBPATTERN_FLAGS: # pragma: no cover + # This feature is available only in specific Python versions + context.flags = (context.flags | value[1]) & ~value[2] + + strat = _strategy(value[-1], context, is_unicode) + + context.flags = old_flags + + if value[0]: + strat = update_group(value[0], strat) + + return strat + + elif code == sre.GROUPREF: + # Regex '\\1' or '(?P=name)' (group reference) + return reuse_group(value) + + elif code == sre.ASSERT: + # Regex '(?=...)' or '(?<=...)' (positive lookahead/lookbehind) + return recurse(value[1]) + + elif code == sre.ASSERT_NOT: + # Regex '(?!...)' or '(? 50: # pragma: no cover + key = frozenset(mapping.items()) + assert key not in seen, (key, name) + seen.add(key) + to_update = needs_update + needs_update = set() + for strat in to_update: + new_value = getattr(strat, calculation)(recur2(strat)) + if new_value != mapping[strat]: + needs_update.update(listeners[strat]) + mapping[strat] = new_value + + # We now have a complete and accurate calculation of the + # property values for everything we have seen in the course of + # running this calculation. We simultaneously update all of + # them (not just the strategy we started out with). + for k, v in mapping.items(): + setattr(k, cache_key, v) + return getattr(self, cache_key) + + accept.__name__ = name + return property(accept) + + # Returns True if this strategy can never draw a value and will always + # result in the data being marked invalid. + # The fact that this returns False does not guarantee that a valid value + # can be drawn - this is not intended to be perfect, and is primarily + # intended to be an optimisation for some cases. + is_empty = recursive_property('is_empty', True) + + # Returns True if values from this strategy can safely be reused without + # this causing unexpected behaviour. + has_reusable_values = recursive_property('has_reusable_values', True) + + # Whether this strategy is suitable for holding onto in a cache. + is_cacheable = recursive_property('is_cacheable', True) + + def calc_is_cacheable(self, recur): + return True + + def calc_is_empty(self, recur): + # Note: It is correct and significant that the default return value + # from calc_is_empty is False despite the default value for is_empty + # being true. The reason for this is that strategies should be treated + # as empty absent evidence to the contrary, but most basic strategies + # are trivially non-empty and it would be annoying to have to override + # this method to show that. + return False + + def calc_has_reusable_values(self, recur): + return False + + def example(self, random=None): + # type: (Random) -> Ex + """Provide an example of the sort of value that this strategy + generates. This is biased to be slightly simpler than is typical for + values from this strategy, for clarity purposes. + + This method shouldn't be taken too seriously. It's here for interactive + exploration of the API, not for any sort of real testing. + + This method is part of the public API. + """ + context = _current_build_context.value + if context is not None: + if context.data is not None and context.data.depth > 0: + note_deprecation( + 'Using example() inside a strategy definition is a bad ' + 'idea. It will become an error in a future version of ' + "Hypothesis, but it's unlikely that it's doing what you " + 'intend even now. Instead consider using ' + 'hypothesis.strategies.builds() or ' + '@hypothesis.strategies.composite to define your strategy.' + ' See ' + 'https://hypothesis.readthedocs.io/en/latest/data.html' + '#hypothesis.strategies.builds or ' + 'https://hypothesis.readthedocs.io/en/latest/data.html' + '#composite-strategies for more details.' + ) + else: + note_deprecation( + 'Using example() inside a test function is a bad ' + 'idea. It will become an error in a future version of ' + "Hypothesis, but it's unlikely that it's doing what you " + 'intend even now. Instead consider using ' + 'hypothesis.strategies.data() to draw ' + 'more examples during testing. See ' + 'https://hypothesis.readthedocs.io/en/latest/data.html' + '#drawing-interactively-in-tests for more details.' + ) + + from hypothesis import find, settings, Verbosity + + # Conjecture will always try the zero example first. This would result + # in us producing the same example each time, which is boring, so we + # deliberately skip the first example it feeds us. + first = [] # type: list + + def condition(x): + if first: + return True + else: + first.append(x) + return False + try: + return find( + self, + condition, + random=random, + settings=settings( + database=None, + verbosity=Verbosity.quiet, + phases=tuple(set(Phase) - {Phase.shrink}), + ) + ) + except (NoSuchExample, Unsatisfiable): + # This can happen when a strategy has only one example. e.g. + # st.just(x). In that case we wanted the first example after all. + if first: + return first[0] + raise NoExamples( + u'Could not find any valid examples in 100 tries' + ) + + def map(self, pack): + # type: (Callable[[Ex], T]) -> SearchStrategy[T] + """Returns a new strategy that generates values by generating a value + from this strategy and then calling pack() on the result, giving that. + + This method is part of the public API. + """ + return MappedSearchStrategy( + pack=pack, strategy=self + ) + + def flatmap(self, expand): + # type: (Callable[[Ex], SearchStrategy[T]]) -> SearchStrategy[T] + """Returns a new strategy that generates values by generating a value + from this strategy, say x, then generating a value from + strategy(expand(x)) + + This method is part of the public API. + """ + from hypothesis.searchstrategy.flatmapped import FlatMapStrategy + return FlatMapStrategy( + expand=expand, strategy=self + ) + + def filter(self, condition): + # type: (Callable[[Ex], bool]) -> SearchStrategy[Ex] + """Returns a new strategy that generates values from this strategy + which satisfy the provided condition. Note that if the condition is too + hard to satisfy this might result in your tests failing with + Unsatisfiable. + + This method is part of the public API. + """ + return FilteredStrategy( + condition=condition, + strategy=self, + ) + + @property + def branches(self): + # type: () -> List[SearchStrategy[Ex]] + return [self] + + def __or__(self, other): + """Return a strategy which produces values by randomly drawing from one + of this strategy or the other strategy. + + This method is part of the public API. + """ + if not isinstance(other, SearchStrategy): + raise ValueError('Cannot | a SearchStrategy with %r' % (other,)) + return one_of_strategies((self, other)) + + def validate(self): + # type: () -> None + """Throw an exception if the strategy is not valid. + + This can happen due to lazy construction + """ + if self.validate_called: + return + try: + self.validate_called = True + self.do_validate() + self.is_empty + self.has_reusable_values + except Exception: + self.validate_called = False + raise + + LABELS = {} # type: dict + + @property + def class_label(self): + cls = self.__class__ + try: + return cls.LABELS[cls] + except KeyError: + pass + result = calc_label_from_cls(cls) + cls.LABELS[cls] = result + return result + + @property + def label(self): + if self.__label is calculating: + return 0 + if self.__label is None: + self.__label = calculating + self.__label = self.calc_label() + return self.__label + + def calc_label(self): + return self.class_label + + def do_validate(self): + pass + + def do_draw(self, data): + # type: (ConjectureData) -> Ex + raise NotImplementedError('%s.do_draw' % (type(self).__name__,)) + + def __init__(self): + pass + + +class OneOfStrategy(SearchStrategy): + """Implements a union of strategies. Given a number of strategies this + generates values which could have come from any of them. + + The conditional distribution draws uniformly at random from some + non-empty subset of these strategies and then draws from the + conditional distribution of that strategy. + """ + + def __init__(self, strategies, bias=None): + SearchStrategy.__init__(self) + strategies = tuple(strategies) + self.original_strategies = list(strategies) + self.__element_strategies = None + self.bias = bias + self.__in_branches = False + if bias is not None: + assert 0 < bias < 1 + self.sampler = cu.Sampler( + [bias ** i for i in range(len(strategies))]) + else: + self.sampler = None + + def calc_is_empty(self, recur): + return all(recur(e) for e in self.original_strategies) + + def calc_has_reusable_values(self, recur): + return all(recur(e) for e in self.original_strategies) + + def calc_is_cacheable(self, recur): + return all(recur(e) for e in self.original_strategies) + + @property + def element_strategies(self): + if self.__element_strategies is None: + strategies = [] + for arg in self.original_strategies: + check_strategy(arg) + if not arg.is_empty: + strategies.extend( + [s for s in arg.branches if not s.is_empty]) + pruned = [] + seen = set() + for s in strategies: + if s is self: + continue + if s in seen: + continue + seen.add(s) + pruned.append(s) + branch_labels = [] + shift = bit_length(len(pruned)) + for i, p in enumerate(pruned): + branch_labels.append( + (((self.label ^ p.label) << shift) + i) & LABEL_MASK) + self.__element_strategies = pruned + self.__branch_labels = tuple(branch_labels) + return self.__element_strategies + + @property + def branch_labels(self): + self.element_strategies + return self.__branch_labels + + def calc_label(self): + return combine_labels(self.class_label, *[ + p.label for p in self.original_strategies + ]) + + def do_draw(self, data): + # type: (ConjectureData) -> Ex + n = len(self.element_strategies) + assert n > 0 + if n == 1: + return data.draw(self.element_strategies[0]) + + if self.sampler is None: + i = cu.integer_range(data, 0, n - 1) + else: + i = self.sampler.sample(data) + + return data.draw( + self.element_strategies[i], label=self.branch_labels[i]) + + def __repr__(self): + return 'one_of(%s)' % ', '.join(map(repr, self.original_strategies)) + + def do_validate(self): + for e in self.element_strategies: + e.validate() + + @property + def branches(self): + if self.bias is None and not self.__in_branches: + try: + self.__in_branches = True + return self.element_strategies + finally: + self.__in_branches = False + else: + return [self] + + +class MappedSearchStrategy(SearchStrategy): + """A strategy which is defined purely by conversion to and from another + strategy. + + Its parameter and distribution come from that other strategy. + """ + + def __init__(self, strategy, pack=None): + SearchStrategy.__init__(self) + self.mapped_strategy = strategy + if pack is not None: + self.pack = pack + + def calc_is_empty(self, recur): + return recur(self.mapped_strategy) + + def calc_is_cacheable(self, recur): + return recur(self.mapped_strategy) + + def __repr__(self): + if not hasattr(self, '_cached_repr'): + self._cached_repr = '%r.map(%s)' % ( + self.mapped_strategy, get_pretty_function_description( + self.pack) + ) + return self._cached_repr + + def do_validate(self): + self.mapped_strategy.validate() + + def pack(self, x): # type: ignore + """Take a value produced by the underlying mapped_strategy and turn it + into a value suitable for outputting from this strategy.""" + raise NotImplementedError( + '%s.pack()' % (self.__class__.__name__)) + + def do_draw(self, data): + # type: (ConjectureData) -> Ex + for _ in range(3): + i = data.index + try: + data.start_example(MAPPED_SEARCH_STRATEGY_DO_DRAW_LABEL) + result = self.pack(data.draw(self.mapped_strategy)) + data.stop_example() + return result + except UnsatisfiedAssumption: + data.stop_example(discard=True) + if data.index == i: + raise + raise UnsatisfiedAssumption() + + @property + def branches(self): + # type: () -> List[SearchStrategy[Ex]] + return [ + MappedSearchStrategy(pack=self.pack, strategy=strategy) + for strategy in self.mapped_strategy.branches + ] + + +class FilteredStrategy(SearchStrategy): + + def __init__(self, strategy, condition): + super(FilteredStrategy, self).__init__() + self.condition = condition + self.filtered_strategy = strategy + + def calc_is_empty(self, recur): + return recur(self.filtered_strategy) + + def calc_is_cacheable(self, recur): + return recur(self.filtered_strategy) + + def __repr__(self): + if not hasattr(self, '_cached_repr'): + self._cached_repr = '%r.filter(%s)' % ( + self.filtered_strategy, get_pretty_function_description( + self.condition) + ) + return self._cached_repr + + def do_validate(self): + self.filtered_strategy.validate() + + def do_draw(self, data): + # type: (ConjectureData) -> Ex + for i in hrange(3): + start_index = data.index + value = data.draw(self.filtered_strategy) + if self.condition(value): + return value + else: + if i == 0: + data.note_event(lazyformat( + 'Retried draw from %r to satisfy filter', self,)) + # This is to guard against the case where we consume no data. + # As long as we consume data, we'll eventually pass or raise. + # But if we don't this could be an infinite loop. + assume(data.index > start_index) + data.note_event('Aborted test because unable to satisfy %r' % ( + self, + )) + data.mark_invalid() + raise AssertionError('Unreachable, for Mypy') # pragma: no cover + + @property + def branches(self): + # type: () -> List[SearchStrategy[Ex]] + return [ + FilteredStrategy(strategy=strategy, condition=self.condition) + for strategy in self.filtered_strategy.branches + ] + + +@check_function +def check_strategy(arg, name=''): + check_type(SearchStrategy, arg, name) diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/searchstrategy/streams.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/searchstrategy/streams.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/searchstrategy/streams.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/searchstrategy/streams.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,41 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from hypothesis.types import Stream +from hypothesis.searchstrategy.strategies import SearchStrategy + + +class StreamStrategy(SearchStrategy): + + supports_find = False + + def __init__(self, source_strategy): + super(StreamStrategy, self).__init__() + self.source_strategy = source_strategy + + def __repr__(self): + return u'StreamStrategy(%r)' % (self.source_strategy,) + + def do_draw(self, data): + data.can_reproduce_example_from_repr = False + + def gen(): + while True: + yield data.draw(self.source_strategy) + return Stream(gen()) diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/searchstrategy/strings.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/searchstrategy/strings.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/searchstrategy/strings.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/searchstrategy/strings.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,117 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from hypothesis.errors import InvalidArgument +from hypothesis.internal import charmap +from hypothesis.internal.compat import hunichr, text_type, binary_type +from hypothesis.internal.intervalsets import IntervalSet +from hypothesis.internal.conjecture.utils import integer_range +from hypothesis.searchstrategy.strategies import SearchStrategy, \ + MappedSearchStrategy + + +class OneCharStringStrategy(SearchStrategy): + """A strategy which generates single character strings of text type.""" + + specifier = text_type + zero_point = ord('0') + + def __init__(self, + whitelist_categories=None, + blacklist_categories=None, + blacklist_characters=None, + min_codepoint=None, + max_codepoint=None, + whitelist_characters=None): + assert set(whitelist_categories or ()).issubset(charmap.categories()) + assert set(blacklist_categories or ()).issubset(charmap.categories()) + intervals = charmap.query( + include_categories=whitelist_categories, + exclude_categories=blacklist_categories, + min_codepoint=min_codepoint, + max_codepoint=max_codepoint, + include_characters=whitelist_characters, + exclude_characters=blacklist_characters, + ) + if not intervals: + arguments = [ + ('whitelist_categories', whitelist_categories), + ('blacklist_categories', blacklist_categories), + ('whitelist_characters', whitelist_characters), + ('blacklist_characters', blacklist_characters), + ('min_codepoint', min_codepoint), + ('max_codepoint', max_codepoint), + ] + raise InvalidArgument( + 'No characters are allowed to be generated by this ' + 'combination of arguments: ' + ', '.join( + '%s=%r' % arg for arg in arguments if arg[1] is not None) + ) + self.intervals = IntervalSet(intervals) + if whitelist_characters: + self.whitelist_characters = set(whitelist_characters) + else: + self.whitelist_characters = set() + self.zero_point = self.intervals.index_above(ord('0')) + + def do_draw(self, data): + i = integer_range( + data, 0, len(self.intervals) - 1, + center=self.zero_point, + ) + return hunichr(self.intervals[i]) + + +class StringStrategy(MappedSearchStrategy): + """A strategy for text strings, defined in terms of a strategy for lists of + single character text strings.""" + + def __init__(self, list_of_one_char_strings_strategy): + super(StringStrategy, self).__init__( + strategy=list_of_one_char_strings_strategy + ) + + def __repr__(self): + return "%r.map(u''.join)" % self.mapped_strategy + + def pack(self, ls): + return u''.join(ls) + + +class BinaryStringStrategy(MappedSearchStrategy): + """A strategy for strings of bytes, defined in terms of a strategy for + lists of bytes.""" + + def __repr__(self): + return '%r.map(bytearray).map(%s)' % ( + self.mapped_strategy, binary_type.__name__) + + def pack(self, x): + assert isinstance(x, list), repr(x) + ba = bytearray(x) + return binary_type(ba) + + +class FixedSizeBytes(SearchStrategy): + + def __init__(self, size): + self.size = size + + def do_draw(self, data): + return binary_type(data.draw_bytes(self.size)) diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/searchstrategy/types.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/searchstrategy/types.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/searchstrategy/types.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/searchstrategy/types.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,281 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import io +import uuid +import decimal +import datetime +import fractions +import functools +import collections + +import hypothesis.strategies as st +from hypothesis.errors import InvalidArgument, ResolutionFailed +from hypothesis.internal.compat import PY2, ForwardRef, abc, text_type, \ + typing_root_type + + +def type_sorting_key(t): + """Minimise to None, then non-container types, then container types.""" + if not is_a_type(t): + raise InvalidArgument('thing=%s must be a type' % (t,)) + if t is None or t is type(None): # noqa: E721 + return (-1, repr(t)) + if not isinstance(t, type): # pragma: no cover + # Some generics in the typing module are not actually types in 3.7 + return (2, repr(t)) + return (int(issubclass(t, abc.Container)), repr(t)) + + +def try_issubclass(thing, superclass): + thing = getattr(thing, '__origin__', None) or thing + superclass = getattr(superclass, '__origin__', None) or superclass + try: + return issubclass(thing, superclass) + except (AttributeError, TypeError): # pragma: no cover + # Some types can't be the subject or object of an instance or + # subclass check under Python 3.5 + return False + + +def is_a_type(thing): + """Return True if thing is a type or a generic type like thing.""" + return isinstance(thing, type) or isinstance(thing, typing_root_type) + + +def from_typing_type(thing): + # We start with special-case support for Union and Tuple - the latter + # isn't actually a generic type. Support for Callable may be added to + # this section later. + # We then explicitly error on non-Generic types, which don't carry enough + # information to sensibly resolve to strategies at runtime. + # Finally, we run a variation of the subclass lookup in st.from_type + # among generic types in the lookup. + import typing + # Under 3.6 Union is handled directly in st.from_type, as the argument is + # not an instance of `type`. However, under Python 3.5 Union *is* a type + # and we have to handle it here, including failing if it has no parameters. + if hasattr(thing, '__union_params__'): # pragma: no cover + args = sorted(thing.__union_params__ or (), key=type_sorting_key) + if not args: + raise ResolutionFailed('Cannot resolve Union of no types.') + return st.one_of([st.from_type(t) for t in args]) + if getattr(thing, '__origin__', None) == tuple or \ + isinstance(thing, getattr(typing, 'TupleMeta', ())): + elem_types = getattr(thing, '__tuple_params__', None) or () + elem_types += getattr(thing, '__args__', None) or () + if getattr(thing, '__tuple_use_ellipsis__', False) or \ + len(elem_types) == 2 and elem_types[-1] is Ellipsis: + return st.lists(st.from_type(elem_types[0])).map(tuple) + elif len(elem_types) == 1 and elem_types[0] == (): + return st.tuples() # Empty tuple; see issue #1583 + return st.tuples(*map(st.from_type, elem_types)) + if isinstance(thing, typing.TypeVar): + if getattr(thing, '__bound__', None) is not None: + return st.from_type(thing.__bound__) + if getattr(thing, '__constraints__', None): + return st.shared( + st.sampled_from(thing.__constraints__), + key='typevar-with-constraint' + ).flatmap(st.from_type) + # Constraints may be None or () on various Python versions. + return st.text() # An arbitrary type for the typevar + # Now, confirm that we're dealing with a generic type as we expected + if not isinstance(thing, typing_root_type): # pragma: no cover + raise ResolutionFailed('Cannot resolve %s to a strategy' % (thing,)) + # Parametrised generic types have their __origin__ attribute set to the + # un-parametrised version, which we need to use in the subclass checks. + # e.g.: typing.List[int].__origin__ == typing.List + mapping = {k: v for k, v in _global_type_lookup.items() + if isinstance(k, typing_root_type) and try_issubclass(k, thing)} + if typing.Dict in mapping: + # The subtype relationships between generic and concrete View types + # are sometimes inconsistent under Python 3.5, so we pop them out to + # preserve our invariant that all examples of from_type(T) are + # instances of type T - and simplify the strategy for abstract types + # such as Container + for t in (typing.KeysView, typing.ValuesView, typing.ItemsView): + mapping.pop(t, None) + strategies = [v if isinstance(v, st.SearchStrategy) else v(thing) + for k, v in mapping.items() + if sum(try_issubclass(k, T) for T in mapping) == 1] + empty = ', '.join(repr(s) for s in strategies if s.is_empty) + if empty or not strategies: # pragma: no cover + raise ResolutionFailed( + 'Could not resolve %s to a strategy; consider using ' + 'register_type_strategy' % (empty or thing,)) + return st.one_of(strategies) + + +_global_type_lookup = { + # Types with core Hypothesis strategies + type(None): st.none(), + bool: st.booleans(), + int: st.integers(), + float: st.floats(), + complex: st.complex_numbers(), + fractions.Fraction: st.fractions(), + decimal.Decimal: st.decimals(), + text_type: st.text(), + bytes: st.binary(), + datetime.datetime: st.datetimes(), + datetime.date: st.dates(), + datetime.time: st.times(), + datetime.timedelta: st.timedeltas(), + uuid.UUID: st.uuids(), + tuple: st.builds(tuple), + list: st.builds(list), + set: st.builds(set), + frozenset: st.builds(frozenset), + dict: st.builds(dict), + # Built-in types + type: st.sampled_from([type(None), bool, int, str, list, set, dict]), + type(Ellipsis): st.just(Ellipsis), + type(NotImplemented): st.just(NotImplemented), + bytearray: st.binary().map(bytearray), + memoryview: st.binary().map(memoryview), + # Pull requests with more types welcome! +} + +if PY2: + _global_type_lookup.update({ + int: st.integers().filter(lambda x: isinstance(x, int)), + long: st.integers().map(long) # noqa + }) + +try: + from hypothesis.extra.pytz import timezones + _global_type_lookup[datetime.tzinfo] = timezones() +except ImportError: # pragma: no cover + pass +try: # pragma: no cover + import numpy as np + from hypothesis.extra.numpy import \ + arrays, array_shapes, scalar_dtypes, nested_dtypes + _global_type_lookup.update({ + np.dtype: nested_dtypes(), + np.ndarray: arrays(scalar_dtypes(), array_shapes(max_dims=2)), + }) +except ImportError: # pragma: no cover + pass + +try: + import typing +except ImportError: # pragma: no cover + pass +else: + _global_type_lookup.update({ + typing.ByteString: st.binary(), + typing.io.BinaryIO: st.builds(io.BytesIO, st.binary()), # type: ignore + typing.io.TextIO: st.builds(io.StringIO, st.text()), # type: ignore + typing.Reversible: st.lists(st.integers()), + typing.SupportsAbs: st.complex_numbers(), + typing.SupportsComplex: st.complex_numbers(), + typing.SupportsFloat: st.complex_numbers(), + typing.SupportsInt: st.complex_numbers(), + }) + + try: + # These aren't present in the typing module backport. + _global_type_lookup[typing.SupportsBytes] = st.binary() + _global_type_lookup[typing.SupportsRound] = st.complex_numbers() + except AttributeError: # pragma: no cover + pass + + def register(type_, fallback=None): + if isinstance(type_, str): + # Use the name of generic types which are not available on all + # versions, and the function just won't be added to the registry + type_ = getattr(typing, type_, None) + if type_ is None: # pragma: no cover + return lambda f: f + + def inner(func): + if fallback is None: + _global_type_lookup[type_] = func + return func + + @functools.wraps(func) + def really_inner(thing): + if getattr(thing, '__args__', None) is None: + return fallback + return func(thing) + _global_type_lookup[type_] = really_inner + return really_inner + return inner + + @register('Type') + def resolve_Type(thing): + if thing.__args__ is None: + return st.just(type) + args = (thing.__args__[0],) + if getattr(args[0], '__origin__', None) is typing.Union: + args = args[0].__args__ + elif hasattr(args[0], '__union_params__'): # pragma: no cover + args = args[0].__union_params__ + if isinstance(ForwardRef, type): # pragma: no cover + # Duplicate check from from_type here - only paying when needed. + for a in args: + if type(a) == ForwardRef: + raise ResolutionFailed( + 'thing=%s cannot be resolved. Upgrading to ' + 'python>=3.6 may fix this problem via improvements ' + 'to the typing module.' % (thing,)) + return st.sampled_from(sorted(args, key=type_sorting_key)) + + @register(typing.List, st.builds(list)) + def resolve_List(thing): + return st.lists(st.from_type(thing.__args__[0])) + + @register(typing.Set, st.builds(set)) + def resolve_Set(thing): + return st.sets(st.from_type(thing.__args__[0])) + + @register(typing.FrozenSet, st.builds(frozenset)) + def resolve_FrozenSet(thing): + return st.frozensets(st.from_type(thing.__args__[0])) + + @register(typing.Dict, st.builds(dict)) + def resolve_Dict(thing): + # If thing is a Collection instance, we need to fill in the values + keys_vals = [st.from_type(t) for t in thing.__args__] * 2 + return st.dictionaries(keys_vals[0], keys_vals[1]) + + @register('DefaultDict', st.builds(collections.defaultdict)) + def resolve_DefaultDict(thing): + return resolve_Dict(thing).map( + lambda d: collections.defaultdict(None, d)) + + @register(typing.ItemsView, st.builds(dict).map(dict.items)) + def resolve_ItemsView(thing): + return resolve_Dict(thing).map(dict.items) + + @register(typing.KeysView, st.builds(dict).map(dict.keys)) + def resolve_KeysView(thing): + return st.dictionaries(st.from_type(thing.__args__[0]), st.none() + ).map(dict.keys) + + @register(typing.ValuesView, st.builds(dict).map(dict.values)) + def resolve_ValuesView(thing): + return st.dictionaries(st.integers(), st.from_type(thing.__args__[0]) + ).map(dict.values) + + @register(typing.Iterator, st.iterables(st.nothing())) + def resolve_Iterator(thing): + return st.iterables(st.from_type(thing.__args__[0])) diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/_settings.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/_settings.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/_settings.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/_settings.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,842 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +"""A module controlling settings for Hypothesis to use in falsification. + +Either an explicit settings object can be used or the default object on +this module can be modified. +""" + +from __future__ import division, print_function, absolute_import + +import os +import warnings +import threading +import contextlib +from enum import Enum, IntEnum, unique + +import attr + +from hypothesis.errors import InvalidState, InvalidArgument, \ + HypothesisDeprecationWarning +from hypothesis.internal.compat import text_type +from hypothesis.utils.conventions import UniqueIdentifier, not_set +from hypothesis.internal.reflection import proxies, \ + get_pretty_function_description +from hypothesis.internal.validation import try_convert +from hypothesis.utils.dynamicvariables import DynamicVariable + +if False: + from typing import Any, Dict, List # noqa + +__all__ = [ + 'settings', +] + + +unlimited = UniqueIdentifier('unlimited') + + +all_settings = {} # type: Dict[str, Setting] + + +class settingsProperty(object): + + def __init__(self, name, show_default): + self.name = name + self.show_default = show_default + + def __get__(self, obj, type=None): + if obj is None: + return self + else: + try: + result = obj.__dict__[self.name] + # This is a gross hack, but it preserves the old behaviour that + # you can change the storage directory and it will be reflected + # in the default database. + if self.name == 'database' and result is not_set: + from hypothesis.database import ExampleDatabase + result = ExampleDatabase(not_set) + return result + except KeyError: + raise AttributeError(self.name) + + def __set__(self, obj, value): + obj.__dict__[self.name] = value + + def __delete__(self, obj): + raise AttributeError('Cannot delete attribute %s' % (self.name,)) + + @property + def __doc__(self): + description = all_settings[self.name].description + deprecation_message = all_settings[self.name].deprecation_message + default = repr(getattr(settings.default, self.name)) if \ + self.show_default else '(dynamically calculated)' + return '\n\n'.join([description, 'default value: %s' % (default,), + (deprecation_message or '').strip()]).strip() + + +default_variable = DynamicVariable(None) + + +class settingsMeta(type): + + def __init__(self, *args, **kwargs): + super(settingsMeta, self).__init__(*args, **kwargs) + + @property + def default(self): + v = default_variable.value + if v is not None: + return v + if hasattr(settings, '_current_profile'): + settings.load_profile(settings._current_profile) + assert default_variable.value is not None + return default_variable.value + + @default.setter + def default(self, value): + raise AttributeError('Cannot assign settings.default') + + def _assign_default_internal(self, value): + default_variable.value = value + + +class settings( + settingsMeta('settings', (object,), {}) # type: ignore +): + """A settings object controls a variety of parameters that are used in + falsification. These may control both the falsification strategy and the + details of the data that is generated. + + Default values are picked up from the settings.default object and + changes made there will be picked up in newly created settings. + """ + + _WHITELISTED_REAL_PROPERTIES = [ + '_construction_complete', 'storage' + ] + __definitions_are_locked = False + _profiles = {} # type: dict + + def __getattr__(self, name): + if name in all_settings: + return all_settings[name].default + else: + raise AttributeError('settings has no attribute %s' % (name,)) + + def __init__(self, parent=None, **kwargs): + # type: (settings, **Any) -> None + if ( + kwargs.get('database', not_set) is not_set and + kwargs.get('database_file', not_set) is not not_set + ): + if kwargs['database_file'] is None: + kwargs['database'] = None + else: + from hypothesis.database import ExampleDatabase + kwargs['database'] = ExampleDatabase(kwargs['database_file']) + if not kwargs.get('perform_health_check', True): + kwargs['suppress_health_check'] = HealthCheck.all() + if kwargs.get('max_shrinks') == 0: + kwargs['phases'] = tuple( + p for p in _validate_phases(kwargs.get('phases')) + if p != Phase.shrink + ) + self._construction_complete = False + deprecations = [] + defaults = parent or settings.default + if defaults is not None: + for setting in all_settings.values(): + if kwargs.get(setting.name, not_set) is not_set: + kwargs[setting.name] = getattr(defaults, setting.name) + else: + if kwargs[setting.name] != setting.future_default: + if setting.deprecation_message is not None: + deprecations.append(setting) + if setting.validator: + kwargs[setting.name] = setting.validator( + kwargs[setting.name]) + for name, value in kwargs.items(): + if name not in all_settings: + raise InvalidArgument( + 'Invalid argument: %r is not a valid setting' % (name,)) + setattr(self, name, value) + self.storage = threading.local() + self._construction_complete = True + + for d in deprecations: + note_deprecation(d.deprecation_message, self) + + def defaults_stack(self): + try: + return self.storage.defaults_stack + except AttributeError: + self.storage.defaults_stack = [] + return self.storage.defaults_stack + + def __call__(self, test): + """Make the settings object (self) an attribute of the test. + + The settings are later discovered by looking them up on the test + itself. + + Also, we want to issue a deprecation warning for settings used alone + (without @given) so, note the deprecation in the new test, but also + attach the version without the warning as an attribute, so that @given + can unwrap it (since if @given is used, that means we don't want the + deprecation warning). + + When it's time to turn the warning into an error, we'll raise an + exception instead of calling note_deprecation (and can delete + "test(*args, **kwargs)"). + """ + if not callable(test): + raise InvalidArgument( + 'settings objects can be called as a decorator with @given, ' + 'but test=%r' % (test,) + ) + if hasattr(test, '_hypothesis_internal_settings_applied'): + note_deprecation( + '%s has already been decorated with a settings object, which ' + 'will be overridden. This will be an error in a future ' + 'version of Hypothesis.\n Previous: %r\n This: %r' % ( + get_pretty_function_description(test), + test._hypothesis_internal_use_settings, + self + ) + ) + + test._hypothesis_internal_use_settings = self + + # For double-@settings check: + test._hypothesis_internal_settings_applied = True + + @proxies(test) + def new_test(*args, **kwargs): + note_deprecation( + 'Using `@settings` without `@given` does not make sense and ' + 'will be an error in a future version of Hypothesis.' + ) + test(*args, **kwargs) + + # @given will get the test from this attribution (rather than use the + # version with the deprecation warning) + new_test._hypothesis_internal_test_function_without_warning = test + + # This means @given has been applied, so we don't need to worry about + # warning for @settings alone. + has_given_applied = getattr(test, 'is_hypothesis_test', False) + test_to_use = test if has_given_applied else new_test + test_to_use._hypothesis_internal_use_settings = self + # Can't use _hypothesis_internal_use_settings as an indicator that + # @settings was applied, because @given also assigns that attribute. + test._hypothesis_internal_settings_applied = True + return test_to_use + + @classmethod + def _define_setting( + cls, name, description, default, options=None, + validator=None, show_default=True, future_default=not_set, + deprecation_message=None, hide_repr=not_set, + ): + """Add a new setting. + + - name is the name of the property that will be used to access the + setting. This must be a valid python identifier. + - description will appear in the property's docstring + - default is the default value. This may be a zero argument + function in which case it is evaluated and its result is stored + the first time it is accessed on any given settings object. + """ + if settings.__definitions_are_locked: + raise InvalidState( + 'settings have been locked and may no longer be defined.' + ) + if options is not None: + options = tuple(options) + assert default in options + + if future_default is not_set: + future_default = default + + if hide_repr is not_set: + hide_repr = bool(deprecation_message) + + all_settings[name] = Setting( + name, description.strip(), default, options, validator, + future_default, deprecation_message, hide_repr, + ) + setattr(settings, name, settingsProperty(name, show_default)) + + @classmethod + def lock_further_definitions(cls): + settings.__definitions_are_locked = True + + def __setattr__(self, name, value): + if name in settings._WHITELISTED_REAL_PROPERTIES: + return object.__setattr__(self, name, value) + elif name in all_settings: + if self._construction_complete: + raise AttributeError( + 'settings objects are immutable and may not be assigned to' + ' after construction.' + ) + else: + setting = all_settings[name] + if ( + setting.options is not None and + value not in setting.options + ): + raise InvalidArgument( + 'Invalid %s, %r. Valid options: %r' % ( + name, value, setting.options + ) + ) + return object.__setattr__(self, name, value) + else: + raise AttributeError('No such setting %s' % (name,)) + + def __repr__(self): + bits = [] + for name, setting in all_settings.items(): + value = getattr(self, name) + # The only settings that are not shown are those that are + # deprecated and left at their default values. + if value != setting.default or not setting.hide_repr: + bits.append('%s=%r' % (name, value)) + return 'settings(%s)' % ', '.join(sorted(bits)) + + def show_changed(self): + bits = [] + for name, setting in all_settings.items(): + value = getattr(self, name) + if value != setting.default: + bits.append('%s=%r' % (name, value)) + return ', '.join(sorted(bits, key=len)) + + def __enter__(self): + note_deprecation( + 'Settings should be determined only by global state or with the ' + '@settings decorator.' + ) + default_context_manager = default_variable.with_value(self) + self.defaults_stack().append(default_context_manager) + default_context_manager.__enter__() + return self + + def __exit__(self, *args, **kwargs): + default_context_manager = self.defaults_stack().pop() + return default_context_manager.__exit__(*args, **kwargs) + + @staticmethod + def register_profile(name, parent=None, **kwargs): + # type: (str, settings, **Any) -> None + """Registers a collection of values to be used as a settings profile. + + Settings profiles can be loaded by name - for example, you might + create a 'fast' profile which runs fewer examples, keep the 'default' + profile, and create a 'ci' profile that increases the number of + examples and uses a different database to store failures. + + The arguments to this method are exactly as for + :class:`~hypothesis.settings`: optional ``parent`` settings, and + keyword arguments for each setting that will be set differently to + parent (or settings.default, if parent is None). + """ + if not isinstance(name, (str, text_type)): + note_deprecation('name=%r must be a string' % (name,)) + if 'settings' in kwargs: + if parent is None: + parent = kwargs.pop('settings') + note_deprecation('The `settings` argument is deprecated - ' + 'use `parent` instead.') + else: + raise InvalidArgument( + 'The `settings` argument is deprecated, and has been ' + 'replaced by the `parent` argument. Use `parent` only.' + ) + settings._profiles[name] = settings(parent=parent, **kwargs) + + @staticmethod + def get_profile(name): + # type: (str) -> settings + """Return the profile with the given name.""" + if not isinstance(name, (str, text_type)): + note_deprecation('name=%r must be a string' % (name,)) + try: + return settings._profiles[name] + except KeyError: + raise InvalidArgument('Profile %r is not registered' % (name,)) + + @staticmethod + def load_profile(name): + # type: (str) -> None + """Loads in the settings defined in the profile provided. + + If the profile does not exist, InvalidArgument will be raised. + Any setting not defined in the profile will be the library + defined default for that setting. + """ + if not isinstance(name, (str, text_type)): + note_deprecation('name=%r must be a string' % (name,)) + settings._current_profile = name + settings._assign_default_internal(settings.get_profile(name)) + + +@contextlib.contextmanager +def local_settings(s): + default_context_manager = default_variable.with_value(s) + with default_context_manager: + yield s + + +@attr.s() +class Setting(object): + name = attr.ib() + description = attr.ib() + default = attr.ib() + options = attr.ib() + validator = attr.ib() + future_default = attr.ib() + deprecation_message = attr.ib() + hide_repr = attr.ib() + + +settings._define_setting( + 'min_satisfying_examples', + default=not_set, + description=""" +This doesn't actually do anything, but remains for compatibility reasons. +""", + deprecation_message=""" +The min_satisfying_examples setting has been deprecated and disabled, due to +overlap with the filter_too_much healthcheck and poor interaction with the +max_examples setting. +""" +) + +settings._define_setting( + 'max_examples', + default=100, + description=""" +Once this many satisfying examples have been considered without finding any +counter-example, falsification will terminate. +""" +) + +settings._define_setting( + 'max_iterations', + default=not_set, + description=""" +This doesn't actually do anything, but remains for compatibility reasons. +""", + deprecation_message=""" +The max_iterations setting has been disabled, as internal heuristics are more +useful for this purpose than a user setting. It no longer has any effect. +""" +) + +settings._define_setting( + 'buffer_size', + default=8 * 1024, + description=""" +The size of the underlying data used to generate examples. If you need to +generate really large examples you may want to increase this, but it will make +your tests slower. +""" +) + + +settings._define_setting( + 'max_shrinks', + default=not_set, + description=""" +Passing ``max_shrinks=0`` disables the shrinking phase (see the ``phases`` +setting), but any other value has no effect and uses a general heuristic. +""", + deprecation_message=""" +The max_shrinks setting has been disabled, as internal heuristics are more +useful for this purpose than a user setting. +""" +) + + +def _validate_timeout(n): + if n is unlimited: + return -1 + else: + return n + + +settings._define_setting( + 'timeout', + default=60, + description=""" +Once this many seconds have passed, falsify will terminate even +if it has not found many examples. This is a soft rather than a hard +limit - Hypothesis won't e.g. interrupt execution of the called +function to stop it. If this value is <= 0 then no timeout will be +applied. +""", + hide_repr=False, # Still affects behaviour at runtime + deprecation_message=""" +The timeout setting is deprecated and will be removed in a future version of +Hypothesis. To get the future behaviour set ``timeout=hypothesis.unlimited`` +instead (which will remain valid for a further deprecation period after this +setting has gone away). +""", + future_default=unlimited, + validator=_validate_timeout +) + +settings._define_setting( + 'derandomize', + default=False, + description=""" +If this is True then hypothesis will run in deterministic mode +where each falsification uses a random number generator that is seeded +based on the hypothesis to falsify, which will be consistent across +multiple runs. This has the advantage that it will eliminate any +randomness from your tests, which may be preferable for some situations. +It does have the disadvantage of making your tests less likely to +find novel breakages. +""" +) + +settings._define_setting( + 'strict', + default=os.getenv('HYPOTHESIS_STRICT_MODE') == 'true', + description=""" +Strict mode has been deprecated in favor of Python's standard warnings +controls. Ironically, enabling it is therefore an error - it only exists so +that users get the right *type* of error! +""", + deprecation_message=""" +Strict mode is deprecated and will go away in a future version of Hypothesis. +To get the same behaviour, use +warnings.simplefilter('error', HypothesisDeprecationWarning). +""", + future_default=False, +) + + +def _validate_database(db, _from_db_file=False): + from hypothesis.database import ExampleDatabase + if db is None or isinstance(db, ExampleDatabase): + return db + if _from_db_file or db is not_set: + return ExampleDatabase(db) + raise InvalidArgument( + 'Arguments to the database setting must be None or an instance of ' + 'ExampleDatabase. Try passing database=ExampleDatabase(%r), or ' + 'construct and use one of the specific subclasses in ' + 'hypothesis.database' % (db,) + ) + + +settings._define_setting( + 'database', + default=not_set, + show_default=False, + description=""" +An instance of hypothesis.database.ExampleDatabase that will be +used to save examples to and load previous examples from. May be None +in which case no storage will be used, `:memory:` for an in-memory +database, or any path for a directory-based example database. +""", + validator=_validate_database, +) + +settings._define_setting( + 'database_file', + default=not_set, + show_default=False, + description=""" +The file or directory location to save and load previously tried examples; +`:memory:` for an in-memory cache or None to disable caching entirely. +""", + validator=lambda f: _validate_database(f, _from_db_file=True), + deprecation_message=""" +The `database_file` setting is deprecated in favor of the `database` +setting, and will be removed in a future version. It only exists at +all for complicated historical reasons and you should just use +`database` instead. +""", +) + + +@unique +class Phase(IntEnum): + explicit = 0 + reuse = 1 + generate = 2 + shrink = 3 + + +@unique +class HealthCheck(Enum): + """Arguments for :attr:`~hypothesis.settings.suppress_health_check`. + + Each member of this enum is a type of health check to suppress. + """ + + def __repr__(self): + return '%s.%s' % (self.__class__.__name__, self.name) + + @classmethod + def all(cls): + # type: () -> List[HealthCheck] + bad = (HealthCheck.exception_in_generation, HealthCheck.random_module) + return [h for h in list(cls) if h not in bad] + + exception_in_generation = 0 + """Deprecated and no longer does anything. It used to convert errors in + data generation into FailedHealthCheck error.""" + + data_too_large = 1 + """Check for when the typical size of the examples you are generating + exceeds the maximum allowed size too often.""" + + filter_too_much = 2 + """Check for when the test is filtering out too many examples, either + through use of :func:`~hypothesis.assume()` or :ref:`filter() `, + or occasionally for Hypothesis internal reasons.""" + + too_slow = 3 + """Check for when your data generation is extremely slow and likely to hurt + testing.""" + + random_module = 4 + """Deprecated and no longer does anything. It used to check for whether + your tests used the global random module. Now @given tests automatically + seed random so this is no longer an error.""" + + return_value = 5 + """Checks if your tests return a non-None value (which will be ignored and + is unlikely to do what you want).""" + + hung_test = 6 + """Checks if your tests have been running for a very long time.""" + + large_base_example = 7 + """Checks if the natural example to shrink towards is very large.""" + + not_a_test_method = 8 + """Checks if @given has been applied to a method of unittest.TestCase.""" + + +@unique +class Statistics(IntEnum): + never = 0 + interesting = 1 + always = 2 + + +@unique +class Verbosity(IntEnum): + quiet = 0 + normal = 1 + verbose = 2 + debug = 3 + + @staticmethod + def _get_default(): + # type: () -> Verbosity + var = os.getenv('HYPOTHESIS_VERBOSITY_LEVEL') + if var is not None: # pragma: no cover + try: + result = Verbosity[var] + except KeyError: + raise InvalidArgument('No such verbosity level %r' % (var,)) + + warnings.warn(HypothesisDeprecationWarning( + 'The HYPOTHESIS_VERBOSITY_LEVEL environment variable is ' + 'deprecated, and will be ignored by a future version of ' + 'Hypothesis. Configure your verbosity level via a ' + 'settings profile instead.' + )) + return result + return Verbosity.normal + + def __repr__(self): + return 'Verbosity.%s' % (self.name,) + + +settings._define_setting( + 'verbosity', + options=tuple(Verbosity), + default=Verbosity._get_default(), + description='Control the verbosity level of Hypothesis messages', +) + + +def _validate_phases(phases): + if phases is None: + return tuple(Phase) + phases = tuple(phases) + for a in phases: + if not isinstance(a, Phase): + raise InvalidArgument('%r is not a valid phase' % (a,)) + return phases + + +settings._define_setting( + 'phases', + default=tuple(Phase), + description=( + 'Control which phases should be run. ' + + 'See :ref:`the full documentation for more details `' + ), + validator=_validate_phases, +) + +settings._define_setting( + name='stateful_step_count', + default=50, + description=""" +Number of steps to run a stateful program for before giving up on it breaking. +""" +) + +settings._define_setting( + 'perform_health_check', + default=not_set, + description=u""" +If set to True, Hypothesis will run a preliminary health check before +attempting to actually execute your test. +""", + deprecation_message=""" +This setting is deprecated, as `perform_health_check=False` duplicates the +effect of `suppress_health_check=HealthCheck.all()`. Use that instead! +""", +) + + +def validate_health_check_suppressions(suppressions): + suppressions = try_convert(list, suppressions, 'suppress_health_check') + for s in suppressions: + if not isinstance(s, HealthCheck): + note_deprecation(( + 'Non-HealthCheck value %r of type %s in suppress_health_check ' + 'will be ignored, and will become an error in a future ' + 'version of Hypothesis') % ( + s, type(s).__name__, + )) + elif s in ( + HealthCheck.exception_in_generation, HealthCheck.random_module + ): + note_deprecation(( + '%s is now ignored and suppressing it is a no-op. This will ' + 'become an error in a future version of Hypothesis. Simply ' + 'remove it from your list of suppressions to get the same ' + 'effect.') % (s,)) + return suppressions + + +settings._define_setting( + 'suppress_health_check', + default=(), + description="""A list of health checks to disable.""", + validator=validate_health_check_suppressions +) + +settings._define_setting( + 'deadline', + default=not_set, + description=u""" +If set, a time in milliseconds (which may be a float to express +smaller units of time) that each individual example (i.e. each time your test +function is called, not the whole decorated test) within a test is not +allowed to exceed. Tests which take longer than that may be converted into +errors (but will not necessarily be if close to the deadline, to allow some +variability in test run time). + +Set this to None to disable this behaviour entirely. + +In future this will default to 200. For now, a +HypothesisDeprecationWarning will be emitted if you exceed that default +deadline and have not explicitly set a deadline yourself. +""" +) + +settings._define_setting( + 'use_coverage', + default=not_set, + deprecation_message=""" +use_coverage no longer does anything and can be removed from your settings. +""", + description=""" +A flag to enable a feature that no longer exists. This setting is present +only for backwards compatibility purposes. +""" +) + + +class PrintSettings(Enum): + """Flags to determine whether or not to print a detailed example blob to + use with :func:`~hypothesis.reproduce_failure` for failing test cases.""" + + NEVER = 0 + """Never print a blob.""" + + INFER = 1 + """Make an educated guess as to whether it would be appropriate to print + the blob. + + The current rules are that this will print if: + + 1. The output from Hypothesis appears to be unsuitable for use with + :func:`~hypothesis.example`, and + 2. The output is not too long, and + 3. Verbosity is at least normal.""" + + ALWAYS = 2 + """Always print a blob on failure.""" + + +settings._define_setting( + 'print_blob', + default=PrintSettings.INFER, + description=""" +Determines whether to print blobs after tests that can be used to reproduce +failures. + +See :ref:`the documentation on @reproduce_failure ` for +more details of this behaviour. +""" +) + +settings.lock_further_definitions() + + +def note_deprecation(message, s=None): + # type: (str, settings) -> None + if s is None: + s = settings.default + assert s is not None + verbosity = s.verbosity + warning = HypothesisDeprecationWarning(message) + if verbosity > Verbosity.quiet: + warnings.warn(warning, stacklevel=3) + + +settings.register_profile('default', settings()) +settings.load_profile('default') +assert settings.default is not None diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/stateful.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/stateful.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/stateful.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/stateful.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,802 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +"""This module provides support for a stateful style of testing, where tests +attempt to find a sequence of operations that cause a breakage rather than just +a single value. + +Notably, the set of steps available at any point may depend on the +execution to date. +""" + + +from __future__ import division, print_function, absolute_import + +import inspect +import traceback +from copy import copy +from unittest import TestCase + +import attr + +import hypothesis.internal.conjecture.utils as cu +from hypothesis.core import EXCEPTIONS_TO_FAIL, find +from hypothesis.errors import Flaky, NoSuchExample, InvalidArgument, \ + InvalidDefinition, HypothesisException +from hypothesis.control import BuildContext +from hypothesis._settings import Verbosity +from hypothesis._settings import settings as Settings +from hypothesis._settings import note_deprecation +from hypothesis.reporting import report, verbose_report, current_verbosity +from hypothesis.strategies import just, one_of, runner, tuples, \ + fixed_dictionaries +from hypothesis.vendor.pretty import CUnicodeIO, RepresentationPrinter +from hypothesis.internal.compat import int_to_bytes, string_types +from hypothesis.internal.reflection import proxies, nicerepr +from hypothesis.internal.conjecture.data import StopTest +from hypothesis.internal.conjecture.utils import integer_range, \ + calc_label_from_name +from hypothesis.searchstrategy.strategies import OneOfStrategy, \ + SearchStrategy + +STATE_MACHINE_RUN_LABEL = calc_label_from_name('another state machine step') + +if False: + from typing import Any, Dict, List, Text # noqa + + +class TestCaseProperty(object): # pragma: no cover + + def __get__(self, obj, typ=None): + if obj is not None: + typ = type(obj) + return typ._to_test_case() + + def __set__(self, obj, value): + raise AttributeError(u'Cannot set TestCase') + + def __delete__(self, obj): + raise AttributeError(u'Cannot delete TestCase') + + +def find_breaking_runner(state_machine_factory, settings=None): + def is_breaking_run(runner): + try: + runner.run(state_machine_factory()) + return False + except HypothesisException: + raise + except EXCEPTIONS_TO_FAIL: + verbose_report(traceback.format_exc) + return True + if settings is None: + try: + settings = state_machine_factory.TestCase.settings + except AttributeError: + settings = Settings.default + + search_strategy = StateMachineSearchStrategy(settings) + + return find( + search_strategy, + is_breaking_run, + settings=settings, + database_key=state_machine_factory.__name__.encode('utf-8') + ) + + +def run_state_machine_as_test(state_machine_factory, settings=None): + """Run a state machine definition as a test, either silently doing nothing + or printing a minimal breaking program and raising an exception. + + state_machine_factory is anything which returns an instance of + GenericStateMachine when called with no arguments - it can be a class or a + function. settings will be used to control the execution of the test. + """ + try: + breaker = find_breaking_runner(state_machine_factory, settings) + except NoSuchExample: + return + try: + with BuildContext(None, is_final=True): + breaker.run(state_machine_factory(), print_steps=True) + except StopTest: + pass + raise Flaky( + u'Run failed initially but succeeded on a second try' + ) + + +class GenericStateMachine(object): + """A GenericStateMachine is the basic entry point into Hypothesis's + approach to stateful testing. + + The intent is for it to be subclassed to provide state machine descriptions + + The way this is used is that Hypothesis will repeatedly execute something + that looks something like:: + + x = MyStatemachineSubclass() + x.check_invariants() + try: + for _ in range(n_steps): + x.execute_step(x.steps().example()) + x.check_invariants() + finally: + x.teardown() + + And if this ever produces an error it will shrink it down to a small + sequence of example choices demonstrating that. + """ + + find_breaking_runner = None # type: classmethod + + def steps(self): + """Return a SearchStrategy instance the defines the available next + steps.""" + raise NotImplementedError(u'%r.steps()' % (self,)) + + def execute_step(self, step): + """Execute a step that has been previously drawn from self.steps()""" + raise NotImplementedError(u'%r.execute_step()' % (self,)) + + def print_start(self): + """Called right at the start of printing. + + By default does nothing. + """ + + def print_end(self): + """Called right at the end of printing. + + By default does nothing. + """ + + def print_step(self, step): + """Print a step to the current reporter. + + This is called right before a step is executed. + """ + self.step_count = getattr(self, u'step_count', 0) + 1 + report(u'Step #%d: %s' % (self.step_count, nicerepr(step))) + + def teardown(self): + """Called after a run has finished executing to clean up any necessary + state. + + Does nothing by default. + """ + pass + + def check_invariants(self): + """Called after initializing and after executing each step.""" + pass + + _test_case_cache = {} # type: dict + + TestCase = TestCaseProperty() + + @classmethod + def _to_test_case(state_machine_class): + try: + return state_machine_class._test_case_cache[state_machine_class] + except KeyError: + pass + + class StateMachineTestCase(TestCase): + settings = Settings() + + # We define this outside of the class and assign it because you can't + # assign attributes to instance method values in Python 2 + def runTest(self): + run_state_machine_as_test(state_machine_class) + + runTest.is_hypothesis_test = True + StateMachineTestCase.runTest = runTest + base_name = state_machine_class.__name__ + StateMachineTestCase.__name__ = str( + base_name + u'.TestCase' + ) + StateMachineTestCase.__qualname__ = str( + getattr(state_machine_class, u'__qualname__', base_name) + + u'.TestCase' + ) + state_machine_class._test_case_cache[state_machine_class] = ( + StateMachineTestCase + ) + return StateMachineTestCase + + +GenericStateMachine.find_breaking_runner = classmethod(find_breaking_runner) + + +class StateMachineRunner(object): + """A StateMachineRunner is a description of how to run a state machine. + + It contains values that it will use to shape the examples. + """ + + def __init__(self, data, n_steps): + self.data = data + self.data.is_find = False + self.n_steps = n_steps + + def run(self, state_machine, print_steps=None): + if print_steps is None: + print_steps = current_verbosity() >= Verbosity.debug + self.data.hypothesis_runner = state_machine + + should_continue = cu.many( + self.data, min_size=1, max_size=self.n_steps, + average_size=self.n_steps, + ) + + try: + if print_steps: + state_machine.print_start() + state_machine.check_invariants() + + while should_continue.more(): + value = self.data.draw(state_machine.steps()) + if print_steps: + state_machine.print_step(value) + state_machine.execute_step(value) + state_machine.check_invariants() + finally: + if print_steps: + state_machine.print_end() + state_machine.teardown() + + +class StateMachineSearchStrategy(SearchStrategy): + + def __init__(self, settings=None): + self.program_size = (settings or Settings.default).stateful_step_count + + def do_draw(self, data): + return StateMachineRunner(data, self.program_size) + + +@attr.s() +class Rule(object): + targets = attr.ib() + function = attr.ib() + arguments = attr.ib() + precondition = attr.ib() + bundles = attr.ib(init=False) + + def __attrs_post_init__(self): + arguments = {} + bundles = [] + for k, v in sorted(self.arguments.items()): + assert not isinstance(v, BundleReferenceStrategy) + if isinstance(v, Bundle): + bundles.append(v) + arguments[k] = BundleReferenceStrategy(v.name) + else: + arguments[k] = v + self.bundles = tuple(bundles) + self.arguments_strategy = fixed_dictionaries(arguments) + + +self_strategy = runner() + + +class BundleReferenceStrategy(SearchStrategy): + def __init__(self, name): + self.name = name + + def do_draw(self, data): + machine = data.draw(self_strategy) + bundle = machine.bundle(self.name) + if not bundle: + data.mark_invalid() + # Shrink towards the right rather than the left. This makes it easier + # to delete data generated earlier, as when the error is towards the + # end there can be a lot of hard to remove padding. + return bundle[ + integer_range(data, 0, len(bundle) - 1, center=len(bundle)) + ] + + +class Bundle(SearchStrategy): + + def __init__(self, name): + self.name = name + self.__reference_strategy = BundleReferenceStrategy(name) + + def do_draw(self, data): + machine = data.draw(self_strategy) + reference = data.draw(self.__reference_strategy) + return machine.names_to_values[reference.name] + + +def _convert_targets(targets, target): + """Single validator and convertor for target arguments.""" + if target is not None: + if targets: + note_deprecation( + 'Passing both targets=%r and target=%r is redundant, and ' + 'will become an error in a future version of Hypothesis. ' + 'Pass targets=%r instead.' + % (targets, target, tuple(targets) + (target,)) + ) + targets = tuple(targets) + (target,) + + converted_targets = [] + for t in targets: + if isinstance(t, string_types): + note_deprecation( + 'Got %r as a target, but passing the name of a Bundle is ' + 'deprecated - please pass the Bundle directly.' % (t,) + ) + elif not isinstance(t, Bundle): + msg = 'Got invalid target %r of type %r, but all targets must ' \ + 'be either a Bundle or the name of a Bundle.' + if isinstance(t, OneOfStrategy): + msg += ( + '\nIt looks like you passed `one_of(a, b)` or `a | b` as ' + 'a target. You should instead pass `targets=(a, b)` to ' + 'add the return value of this rule to both the `a` and ' + '`b` bundles, or define a rule for each target if it ' + 'should be added to exactly one.' + ) + raise InvalidArgument(msg % (t, type(t))) + while isinstance(t, Bundle): + t = t.name + converted_targets.append(t) + return tuple(converted_targets) + + +RULE_MARKER = u'hypothesis_stateful_rule' +INITIALIZE_RULE_MARKER = u'hypothesis_stateful_initialize_rule' +PRECONDITION_MARKER = u'hypothesis_stateful_precondition' +INVARIANT_MARKER = u'hypothesis_stateful_invariant' + + +def rule(targets=(), target=None, **kwargs): + """Decorator for RuleBasedStateMachine. Any name present in target or + targets will define where the end result of this function should go. If + both are empty then the end result will be discarded. + + ``target`` must be a Bundle, or if the result should go to multiple + bundles you can pass a tuple of them as the ``targets`` argument. + It is invalid to use both arguments for a single rule. If the result + should go to exactly one of several bundles, define a separate rule for + each case. + + kwargs then define the arguments that will be passed to the function + invocation. If their value is a Bundle then values that have previously + been produced for that bundle will be provided, if they are anything else + it will be turned into a strategy and values from that will be provided. + """ + converted_targets = _convert_targets(targets, target) + + def accept(f): + existing_rule = getattr(f, RULE_MARKER, None) + existing_initialize_rule = getattr(f, INITIALIZE_RULE_MARKER, None) + if existing_rule is not None or existing_initialize_rule is not None: + raise InvalidDefinition( + 'A function cannot be used for two distinct rules. ', + Settings.default, + ) + precondition = getattr(f, PRECONDITION_MARKER, None) + rule = Rule(targets=converted_targets, arguments=kwargs, + function=f, precondition=precondition) + + @proxies(f) + def rule_wrapper(*args, **kwargs): + return f(*args, **kwargs) + + setattr(rule_wrapper, RULE_MARKER, rule) + return rule_wrapper + return accept + + +def initialize(targets=(), target=None, **kwargs): + """Decorator for RuleBasedStateMachine. + + An initialize decorator behaves like a rule, but the decorated + method is called at most once in a run. All initialize decorated + methods will be called before any rule decorated methods, in an + arbitrary order. + """ + converted_targets = _convert_targets(targets, target) + + def accept(f): + existing_rule = getattr(f, RULE_MARKER, None) + existing_initialize_rule = getattr(f, INITIALIZE_RULE_MARKER, None) + if existing_rule is not None or existing_initialize_rule is not None: + raise InvalidDefinition( + 'A function cannot be used for two distinct rules. ', + Settings.default, + ) + precondition = getattr(f, PRECONDITION_MARKER, None) + if precondition: + raise InvalidDefinition( + 'An initialization rule cannot have a precondition. ', + Settings.default, + ) + rule = Rule(targets=converted_targets, arguments=kwargs, + function=f, precondition=precondition) + + @proxies(f) + def rule_wrapper(*args, **kwargs): + return f(*args, **kwargs) + + setattr(rule_wrapper, INITIALIZE_RULE_MARKER, rule) + return rule_wrapper + return accept + + +@attr.s() +class VarReference(object): + name = attr.ib() + + +def precondition(precond): + """Decorator to apply a precondition for rules in a RuleBasedStateMachine. + Specifies a precondition for a rule to be considered as a valid step in the + state machine. The given function will be called with the instance of + RuleBasedStateMachine and should return True or False. Usually it will need + to look at attributes on that instance. + + For example:: + + class MyTestMachine(RuleBasedStateMachine): + state = 1 + + @precondition(lambda self: self.state != 0) + @rule(numerator=integers()) + def divide_with(self, numerator): + self.state = numerator / self.state + + This is better than using assume in your rule since more valid rules + should be able to be run. + """ + def decorator(f): + @proxies(f) + def precondition_wrapper(*args, **kwargs): + return f(*args, **kwargs) + + existing_initialize_rule = getattr(f, INITIALIZE_RULE_MARKER, None) + if existing_initialize_rule is not None: + raise InvalidDefinition( + 'An initialization rule cannot have a precondition. ', + Settings.default, + ) + + rule = getattr(f, RULE_MARKER, None) + if rule is None: + setattr(precondition_wrapper, PRECONDITION_MARKER, precond) + else: + new_rule = Rule(targets=rule.targets, arguments=rule.arguments, + function=rule.function, precondition=precond) + setattr(precondition_wrapper, RULE_MARKER, new_rule) + + invariant = getattr(f, INVARIANT_MARKER, None) + if invariant is not None: + new_invariant = Invariant(function=invariant.function, + precondition=precond) + setattr(precondition_wrapper, INVARIANT_MARKER, new_invariant) + + return precondition_wrapper + return decorator + + +@attr.s() +class Invariant(object): + function = attr.ib() + precondition = attr.ib() + + +def invariant(): + """Decorator to apply an invariant for rules in a RuleBasedStateMachine. + The decorated function will be run after every rule and can raise an + exception to indicate failed invariants. + + For example:: + + class MyTestMachine(RuleBasedStateMachine): + state = 1 + + @invariant() + def is_nonzero(self): + assert self.state != 0 + """ + def accept(f): + existing_invariant = getattr(f, INVARIANT_MARKER, None) + if existing_invariant is not None: + raise InvalidDefinition( + 'A function cannot be used for two distinct invariants.', + Settings.default, + ) + precondition = getattr(f, PRECONDITION_MARKER, None) + rule = Invariant(function=f, precondition=precondition) + + @proxies(f) + def invariant_wrapper(*args, **kwargs): + return f(*args, **kwargs) + + setattr(invariant_wrapper, INVARIANT_MARKER, rule) + return invariant_wrapper + return accept + + +LOOP_LABEL = cu.calc_label_from_name('RuleStrategy loop iteration') + + +class RuleStrategy(SearchStrategy): + def __init__(self, machine): + SearchStrategy.__init__(self) + self.machine = machine + self.rules = list(machine.rules()) + + # The order is a bit arbitrary. Primarily we're trying to group rules + # that write to the same location together, and to put rules with no + # target first as they have less effect on the structure. We order from + # fewer to more arguments on grounds that it will plausibly need less + # data. This probably won't work especially well and we could be + # smarter about it, but it's better than just doing it in definition + # order. + self.rules.sort(key=lambda rule: ( + sorted(rule.targets), len(rule.arguments), + rule.function.__name__, + )) + + def do_draw(self, data): + # This strategy is slightly strange in its implementation. + # We don't want the interpretation of the rule we draw to change based + # on whether other rules satisfy their preconditions or have data in + # their bundles. Therefore the index into the rule list needs to stay + # stable. BUT we don't want to draw invalid rules. So what we do is we + # draw an index. We *could* just loop until it's valid, but if most + # rules are invalid then that could result in a very long loop. + # So what we do is the following: + # + # 1. We first draw a rule unconditionally, and check if it's valid. + # If it is, great. Nothing more to do, that's our rule. + # 2. If it is invalid, we now calculate the list of valid rules and + # draw from that list (if there are none, that's an error in the + # definition of the machine and we complain to the user about it). + # 3. Once we've drawn a valid rule, we write that back to the byte + # stream. As a result, when shrinking runs the shrinker can delete + # the initial failed draw + the draw that lead to us finding an + # index into valid_rules, leaving just the written value of i. + # When this is run, it will look as we got lucky and just happened + # to pick a valid rule. + # + # Easy, right? + n = len(self.rules) + i = cu.integer_range(data, 0, n - 1) + u, v = data.blocks[-1].bounds + block_length = v - u + rule = self.rules[i] + if not self.is_valid(rule): + valid_rules = [ + j for j, r in enumerate(self.rules) if self.is_valid(r) + ] + if not valid_rules: + raise InvalidDefinition( + u'No progress can be made from state %r' % (self.machine,) + ) + i = valid_rules[cu.integer_range(data, 0, len(valid_rules) - 1)] + data.write(int_to_bytes(i, block_length)) + rule = self.rules[i] + return (rule, data.draw(rule.arguments_strategy)) + + def is_valid(self, rule): + if rule.precondition and not rule.precondition(self.machine): + return False + for b in rule.bundles: + bundle = self.machine.bundle(b.name) + if not bundle: + return False + return True + + +class RuleBasedStateMachine(GenericStateMachine): + """A RuleBasedStateMachine gives you a more structured way to define state + machines. + + The idea is that a state machine carries a bunch of types of data + divided into Bundles, and has a set of rules which may read data + from bundles (or just from normal strategies) and push data onto + bundles. At any given point a random applicable rule will be + executed. + """ + + _rules_per_class = {} # type: Dict[type, List[classmethod]] + _invariants_per_class = {} # type: Dict[type, List[classmethod]] + _base_rules_per_class = {} # type: Dict[type, List[classmethod]] + _initializers_per_class = {} # type: Dict[type, List[classmethod]] + _base_initializers_per_class = {} # type: Dict[type, List[classmethod]] + + def __init__(self): + if not self.rules(): + raise InvalidDefinition(u'Type %s defines no rules' % ( + type(self).__name__, + )) + self.bundles = {} # type: Dict[Text, list] + self.name_counter = 1 + self.names_to_values = {} # type: Dict[Text, Any] + self.__stream = CUnicodeIO() + self.__printer = RepresentationPrinter(self.__stream) + self._initialize_rules_to_run = copy(self.initialize_rules()) + self.__rules_strategy = RuleStrategy(self) + + def __pretty(self, value): + if isinstance(value, VarReference): + return value.name + self.__stream.seek(0) + self.__stream.truncate(0) + self.__printer.output_width = 0 + self.__printer.buffer_width = 0 + self.__printer.buffer.clear() + self.__printer.pretty(value) + self.__printer.flush() + return self.__stream.getvalue() + + def __repr__(self): + return u'%s(%s)' % ( + type(self).__name__, + nicerepr(self.bundles), + ) + + def upcoming_name(self): + return u'v%d' % (self.name_counter,) + + def new_name(self): + result = self.upcoming_name() + self.name_counter += 1 + return result + + def bundle(self, name): + return self.bundles.setdefault(name, []) + + @classmethod + def initialize_rules(cls): + try: + return cls._initializers_per_class[cls] + except KeyError: + pass + + for k, v in inspect.getmembers(cls): + r = getattr(v, INITIALIZE_RULE_MARKER, None) + if r is not None: + cls.define_initialize_rule( + r.targets, r.function, r.arguments, r.precondition, + ) + cls._initializers_per_class[cls] = \ + cls._base_initializers_per_class.pop(cls, []) + return cls._initializers_per_class[cls] + + @classmethod + def rules(cls): + try: + return cls._rules_per_class[cls] + except KeyError: + pass + + for k, v in inspect.getmembers(cls): + r = getattr(v, RULE_MARKER, None) + if r is not None: + cls.define_rule( + r.targets, r.function, r.arguments, r.precondition, + ) + cls._rules_per_class[cls] = cls._base_rules_per_class.pop(cls, []) + return cls._rules_per_class[cls] + + @classmethod + def invariants(cls): + try: + return cls._invariants_per_class[cls] + except KeyError: + pass + + target = [] + for k, v in inspect.getmembers(cls): + i = getattr(v, INVARIANT_MARKER, None) + if i is not None: + target.append(i) + cls._invariants_per_class[cls] = target + return cls._invariants_per_class[cls] + + @classmethod + def define_initialize_rule( + cls, targets, function, arguments, precondition=None): + converted_arguments = {} + for k, v in arguments.items(): + converted_arguments[k] = v + if cls in cls._initializers_per_class: + target = cls._initializers_per_class[cls] + else: + target = cls._base_initializers_per_class.setdefault(cls, []) + + return target.append( + Rule( + targets, function, converted_arguments, precondition, + ) + ) + + @classmethod + def define_rule(cls, targets, function, arguments, precondition=None): + converted_arguments = {} + for k, v in arguments.items(): + converted_arguments[k] = v + if cls in cls._rules_per_class: + target = cls._rules_per_class[cls] + else: + target = cls._base_rules_per_class.setdefault(cls, []) + + return target.append( + Rule( + targets, function, converted_arguments, precondition, + ) + ) + + def steps(self): + # Pick initialize rules first + if self._initialize_rules_to_run: + return one_of([ + tuples(just(rule), fixed_dictionaries(rule.arguments)) + for rule in self._initialize_rules_to_run + ]) + + return self.__rules_strategy + + def print_start(self): + report(u'state = %s()' % (self.__class__.__name__,)) + + def print_end(self): + report(u'state.teardown()') + + def print_step(self, step): + rule, data = step + data_repr = {} + for k, v in data.items(): + data_repr[k] = self.__pretty(v) + self.step_count = getattr(self, u'step_count', 0) + 1 + report(u'%sstate.%s(%s)' % ( + u'%s = ' % (self.upcoming_name(),) if rule.targets else u'', + rule.function.__name__, + u', '.join(u'%s=%s' % kv for kv in data_repr.items()) + )) + + def execute_step(self, step): + rule, data = step + data = dict(data) + for k, v in list(data.items()): + if isinstance(v, VarReference): + data[k] = self.names_to_values[v.name] + result = rule.function(self, **data) + if rule.targets: + name = self.new_name() + self.names_to_values[name] = result + self.__printer.singleton_pprinters.setdefault( + id(result), lambda obj, p, cycle: p.text(name) + ) + for target in rule.targets: + self.bundle(target).append(VarReference(name)) + if self._initialize_rules_to_run: + self._initialize_rules_to_run.remove(rule) + + def check_invariants(self): + for invar in self.invariants(): + if invar.precondition and not invar.precondition(self): + continue + invar.function(self) diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/statistics.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/statistics.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/statistics.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/statistics.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,110 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import math + +from hypothesis.utils.dynamicvariables import DynamicVariable +from hypothesis.internal.conjecture.data import Status +from hypothesis.internal.conjecture.engine import MAX_SHRINKS, ExitReason + +collector = DynamicVariable(None) + + +class Statistics(object): + + def __init__(self, engine): + self.passing_examples = len( + engine.status_runtimes.get(Status.VALID, ())) + self.invalid_examples = len( + engine.status_runtimes.get(Status.INVALID, []) + + engine.status_runtimes.get(Status.OVERRUN, []) + ) + self.failing_examples = len(engine.status_runtimes.get( + Status.INTERESTING, ())) + + runtimes = sorted( + engine.status_runtimes.get(Status.VALID, []) + + engine.status_runtimes.get(Status.INVALID, []) + + engine.status_runtimes.get(Status.INTERESTING, []) + ) + + self.has_runs = bool(runtimes) + if not self.has_runs: + return + + n = max(0, len(runtimes) - 1) + lower = int(runtimes[int(math.floor(n * 0.05))] * 1000) + upper = int(runtimes[int(math.ceil(n * 0.95))] * 1000) + if upper == 0: + self.runtimes = '< 1ms' + elif lower == upper: + self.runtimes = '~ %dms' % (lower,) + else: + self.runtimes = '%d-%d ms' % (lower, upper) + + if engine.exit_reason == ExitReason.finished: + self.exit_reason = 'nothing left to do' + elif engine.exit_reason == ExitReason.flaky: + self.exit_reason = 'test was flaky' + elif engine.exit_reason == ExitReason.max_shrinks: + self.exit_reason = 'shrunk example %s times' % (MAX_SHRINKS,) + elif engine.exit_reason == ExitReason.max_iterations: + self.exit_reason = (( + 'settings.max_examples={}, but < 10% of examples satisfied ' + 'assumptions').format(engine.settings.max_examples) + ) + else: + self.exit_reason = ( + 'settings.%s=%r' % ( + engine.exit_reason.name, + getattr(engine.settings, engine.exit_reason.name) + ) + ) + + self.events = [ + '%.2f%%, %s' % ( + c / engine.call_count * 100, e + ) for e, c in sorted( + engine.event_call_counts.items(), key=lambda x: -x[1]) + ] + + total_runtime = math.fsum(engine.all_runtimes) + total_drawtime = math.fsum(engine.all_drawtimes) + + if total_drawtime == 0.0 and total_runtime >= 0.0: + self.draw_time_percentage = '~ 0%' + elif total_drawtime < 0.0 or total_runtime <= 0.0: + # This weird condition is possible in two ways: + # 1. drawtime and/or runtime are negative, due to clock changes + # on Python 2 or old OSs (we use monotonic() where available) + # 2. floating-point issues *very rarely* cause math.fsum to be + # off by the lowest bit, so drawtime==0 and runtime!=0, eek! + self.draw_time_percentage = 'NaN' + else: + draw_time_percentage = 100.0 * min( + 1, total_drawtime / total_runtime) + + self.draw_time_percentage = '~ %d%%' % ( + round(draw_time_percentage),) + + +def note_engine_for_statistics(engine): + callback = collector.value + if callback is not None: + callback(Statistics(engine)) diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/strategies.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/strategies.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/strategies.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/strategies.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,2187 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import sys +import enum +import math +import random +import string +import datetime as dt +import operator +from uuid import UUID +from decimal import Context, Decimal, localcontext +from inspect import isclass, isfunction +from fractions import Fraction +from functools import reduce + +import attr + +from hypothesis.errors import InvalidArgument, ResolutionFailed +from hypothesis.control import note, assume, reject, cleanup, \ + current_build_context +from hypothesis._settings import note_deprecation +from hypothesis.internal.cache import LRUReusedCache +from hypothesis.searchstrategy import SearchStrategy, check_strategy +from hypothesis.internal.compat import abc, gcd, ceil, floor, hrange, \ + string_types, get_type_hints, getfullargspec, typing_root_type, \ + implements_iterator +from hypothesis.internal.floats import next_up, float_of, next_down, \ + is_negative, float_to_int, int_to_float, count_between_floats +from hypothesis.internal.charmap import as_general_categories +from hypothesis.internal.cathetus import cathetus +from hypothesis.internal.renaming import renamed_arguments +from hypothesis.utils.conventions import infer, not_set +from hypothesis.internal.reflection import proxies, required_args, \ + is_typed_named_tuple, define_function_signature +from hypothesis.internal.validation import check_type, try_convert, \ + check_valid_size, check_valid_bound, check_valid_sizes, \ + check_valid_integer, check_valid_interval, check_valid_magnitude +from hypothesis.searchstrategy.lazy import LazyStrategy +from hypothesis.searchstrategy.misc import BoolStrategy, JustStrategy, \ + RandomStrategy, SampledFromStrategy +from hypothesis.searchstrategy.shared import SharedStrategy +from hypothesis.searchstrategy.numbers import FloatStrategy, \ + BoundedIntStrategy, IntegersFromStrategy, WideRangeIntStrategy, \ + FixedBoundedFloatStrategy +from hypothesis.searchstrategy.streams import StreamStrategy +from hypothesis.searchstrategy.strings import FixedSizeBytes, \ + StringStrategy, BinaryStringStrategy, OneCharStringStrategy +from hypothesis.searchstrategy.datetime import DateStrategy, \ + DatetimeStrategy, TimedeltaStrategy +from hypothesis.searchstrategy.deferred import DeferredStrategy +from hypothesis.searchstrategy.recursive import RecursiveStrategy +from hypothesis.internal.conjecture.utils import choice, check_sample, \ + integer_range, calc_label_from_cls +from hypothesis.searchstrategy.strategies import OneOfStrategy +from hypothesis.searchstrategy.collections import ListStrategy, \ + TupleStrategy, UniqueListStrategy, FixedKeysDictStrategy + +typing = None # type: Union[None, ModuleType] + +try: + import typing as typing_module + typing = typing_module +except ImportError: + pass + +try: + import numpy +except ImportError: + numpy = None + +if False: + from types import ModuleType # noqa + from random import Random # noqa + from typing import Any, Dict, Union, Sequence, Callable, Pattern # noqa + from typing import TypeVar, Tuple, List, Set, FrozenSet, overload # noqa + from typing import Type, Text, AnyStr, Optional # noqa + + from hypothesis.utils.conventions import InferType # noqa + from hypothesis.searchstrategy.strategies import T, Ex # noqa + K, V = TypeVar['K'], TypeVar['V'] + # See https://github.com/python/mypy/issues/3186 - numbers.Real is wrong! + Real = Union[int, float, Fraction, Decimal] +else: + def overload(f): + return f + +__all__ = [ + 'nothing', + 'just', 'one_of', + 'none', + 'choices', 'streaming', + 'booleans', 'integers', 'floats', 'complex_numbers', 'fractions', + 'decimals', + 'characters', 'text', 'from_regex', 'binary', 'uuids', + 'tuples', 'lists', 'sets', 'frozensets', 'iterables', + 'dictionaries', 'fixed_dictionaries', + 'sampled_from', 'permutations', + 'datetimes', 'dates', 'times', 'timedeltas', + 'builds', + 'randoms', 'random_module', + 'recursive', 'composite', + 'shared', 'runner', 'data', + 'deferred', + 'from_type', 'register_type_strategy', 'emails', +] + +_strategies = set() + + +class FloatKey(object): + + def __init__(self, f): + self.value = float_to_int(f) + + def __eq__(self, other): + return isinstance(other, FloatKey) and ( + other.value == self.value + ) + + def __ne__(self, other): + return not self.__eq__(other) + + def __hash__(self): + return hash(self.value) + + +def convert_value(v): + if isinstance(v, float): + return FloatKey(v) + return (type(v), v) + + +STRATEGY_CACHE = LRUReusedCache(1024) + + +def cacheable(fn): + # type: (T) -> T + @proxies(fn) + def cached_strategy(*args, **kwargs): + kwargs_cache_key = set() + try: + for k, v in kwargs.items(): + kwargs_cache_key.add((k, convert_value(v))) + except TypeError: + return fn(*args, **kwargs) + cache_key = ( + fn, + tuple(map(convert_value, args)), frozenset(kwargs_cache_key)) + try: + return STRATEGY_CACHE[cache_key] + except TypeError: + return fn(*args, **kwargs) + except KeyError: + result = fn(*args, **kwargs) + if not isinstance(result, SearchStrategy) or result.is_cacheable: + STRATEGY_CACHE[cache_key] = result + return result + cached_strategy.__clear_cache = STRATEGY_CACHE.clear + return cached_strategy + + +def base_defines_strategy(force_reusable): + # type: (bool) -> Callable[[T], T] + """Returns a decorator for strategy functions. + + If force_reusable is True, the generated values are assumed to be + reusable, i.e. immutable and safe to cache, across multiple test + invocations. + """ + def decorator(strategy_definition): + """A decorator that registers the function as a strategy and makes it + lazily evaluated.""" + _strategies.add(strategy_definition.__name__) + + @proxies(strategy_definition) + def accept(*args, **kwargs): + result = LazyStrategy(strategy_definition, args, kwargs) + if force_reusable: + result.force_has_reusable_values = True + assert result.has_reusable_values + return result + return accept + return decorator + + +defines_strategy = base_defines_strategy(False) +defines_strategy_with_reusable_values = base_defines_strategy(True) + + +class Nothing(SearchStrategy): + def calc_is_empty(self, recur): + return True + + def do_draw(self, data): + # This method should never be called because draw() will mark the + # data as invalid immediately because is_empty is True. + assert False # pragma: no cover + + def calc_has_reusable_values(self, recur): + return True + + def __repr__(self): + return 'nothing()' + + def map(self, f): + return self + + def filter(self, f): + return self + + def flatmap(self, f): + return self + + +NOTHING = Nothing() + + +@cacheable +def nothing(): + # type: () -> SearchStrategy + """This strategy never successfully draws a value and will always reject on + an attempt to draw. + + Examples from this strategy do not shrink (because there are none). + """ + return NOTHING + + +def just(value): + # type: (T) -> SearchStrategy[T] + """Return a strategy which only generates ``value``. + + Note: ``value`` is not copied. Be wary of using mutable values. + + If ``value`` is the result of a callable, you can use + :func:`builds(callable) ` instead + of ``just(callable())`` to get a fresh value each time. + + Examples from this strategy do not shrink (because there is only one). + """ + return JustStrategy(value) + + +@defines_strategy_with_reusable_values +def none(): + # type: () -> SearchStrategy[None] + """Return a strategy which only generates None. + + Examples from this strategy do not shrink (because there is only + one). + """ + return just(None) + + +@overload +def one_of(args): + # type: (Sequence[SearchStrategy[Any]]) -> SearchStrategy[Any] + pass # pragma: no cover + + +@overload +def one_of(*args): + # type: (SearchStrategy[Any]) -> SearchStrategy[Any] + pass # pragma: no cover + + +def one_of(*args): + # Mypy workaround alert: Any is too loose above; the return paramater + # should be the union of the input parameters. Unfortunately, Mypy <=0.600 + # raises errors due to incompatible inputs instead. See #1270 for links. + # v0.610 doesn't error; it gets inference wrong for 2+ arguments instead. + """Return a strategy which generates values from any of the argument + strategies. + + This may be called with one iterable argument instead of multiple + strategy arguments. In which case ``one_of(x)`` and ``one_of(*x)`` are + equivalent. + + Examples from this strategy will generally shrink to ones that come from + strategies earlier in the list, then shrink according to behaviour of the + strategy that produced them. In order to get good shrinking behaviour, + try to put simpler strategies first. e.g. ``one_of(none(), text())`` is + better than ``one_of(text(), none())``. + + This is especially important when using recursive strategies. e.g. + ``x = st.deferred(lambda: st.none() | st.tuples(x, x))`` will shrink well, + but ``x = st.deferred(lambda: st.tuples(x, x) | st.none())`` will shrink + very badly indeed. + """ + if len(args) == 1 and not isinstance(args[0], SearchStrategy): + try: + args = tuple(args[0]) + except TypeError: + pass + return OneOfStrategy(args) + + +@cacheable +@defines_strategy_with_reusable_values +def integers(min_value=None, max_value=None): + # type: (Real, Real) -> SearchStrategy[int] + """Returns a strategy which generates integers (in Python 2 these may be + ints or longs). + + If min_value is not None then all values will be >= min_value. If + max_value is not None then all values will be <= max_value + + Examples from this strategy will shrink towards zero, and negative values + will also shrink towards positive (i.e. -n may be replaced by +n). + """ + + check_valid_bound(min_value, 'min_value') + check_valid_bound(max_value, 'max_value') + check_valid_interval(min_value, max_value, 'min_value', 'max_value') + + min_int_value = None if min_value is None else ceil(min_value) + max_int_value = None if max_value is None else floor(max_value) + + if min_int_value is not None and max_int_value is not None and \ + min_int_value > max_int_value: + raise InvalidArgument('No integers between min_value=%r and ' + 'max_value=%r' % (min_value, max_value)) + + if min_int_value is None: + if max_int_value is None: + return ( + WideRangeIntStrategy() + ) + else: + return IntegersFromStrategy(0).map(lambda x: max_int_value - x) + else: + if max_int_value is None: + return IntegersFromStrategy(min_int_value) + else: + assert min_int_value <= max_int_value + if min_int_value == max_int_value: + return just(min_int_value) + elif min_int_value >= 0: + return BoundedIntStrategy(min_int_value, max_int_value) + elif max_int_value <= 0: + return BoundedIntStrategy( + -max_int_value, -min_int_value + ).map(lambda t: -t) + else: + return integers(min_value=0, max_value=max_int_value) | \ + integers(min_value=min_int_value, max_value=0) + + +@cacheable +@defines_strategy +def booleans(): + # type: () -> SearchStrategy[bool] + """Returns a strategy which generates instances of bool. + + Examples from this strategy will shrink towards False (i.e. + shrinking will try to replace True with False where possible). + """ + return BoolStrategy() + + +@cacheable +@defines_strategy_with_reusable_values +def floats( + min_value=None, # type: Real + max_value=None, # type: Real + allow_nan=None, # type: bool + allow_infinity=None, # type: bool + width=64, # type: int +): + # type: (...) -> SearchStrategy[float] + """Returns a strategy which generates floats. + + - If min_value is not None, all values will be >= min_value. + - If max_value is not None, all values will be <= max_value. + - If min_value or max_value is not None, it is an error to enable + allow_nan. + - If both min_value and max_value are not None, it is an error to enable + allow_infinity. + + Where not explicitly ruled out by the bounds, all of infinity, -infinity + and NaN are possible values generated by this strategy. + + The width argument specifies the maximum number of bits of precision + required to represent the generated float. Valid values are 16, 32, or 64. + Passing ``width=32`` will still use the builtin 64-bit ``float`` class, + but always for values which can be exactly represented as a 32-bit float. + Half-precision floats (``width=16``) are only supported on Python 3.6, or + if Numpy is installed. + + Examples from this strategy have a complicated and hard to explain + shrinking behaviour, but it tries to improve "human readability". Finite + numbers will be preferred to infinity and infinity will be preferred to + NaN. + """ + + if allow_nan is None: + allow_nan = bool(min_value is None and max_value is None) + elif allow_nan: + if min_value is not None or max_value is not None: + raise InvalidArgument( + 'Cannot have allow_nan=%r, with min_value or max_value' % ( + allow_nan + )) + + if width not in (16, 32, 64): + raise InvalidArgument( + 'Got width=%r, but the only valid values are the integers 16, ' + '32, and 64.' % (width,) + ) + if width == 16 and sys.version_info[:2] < (3, 6) and numpy is None: + raise InvalidArgument( # pragma: no cover + 'width=16 requires either Numpy, or Python >= 3.6' + ) + + check_valid_bound(min_value, 'min_value') + check_valid_bound(max_value, 'max_value') + + min_arg, max_arg = min_value, max_value + if min_value is not None: + min_value = float_of(min_value, width) + assert isinstance(min_value, float) + if max_value is not None: + max_value = float_of(max_value, width) + assert isinstance(max_value, float) + + check_valid_interval(min_value, max_value, 'min_value', 'max_value') + if min_value == float(u'-inf'): + min_value = None + if max_value == float(u'inf'): + max_value = None + + if min_value is not None and min_arg is not None and min_value < min_arg: + min_value = next_up(min_value, width) + assert min_value > min_arg # type: ignore + if max_value is not None and max_arg is not None and max_value > max_arg: + max_value = next_down(max_value, width) + assert max_value < max_arg # type: ignore + if min_value is not None and max_value is not None and \ + min_value > max_value: + raise InvalidArgument( + 'There are no %s-bit floating-point values between min_value=%r ' + 'and max_value=%r' % (width, min_arg, max_arg)) + + if allow_infinity is None: + allow_infinity = bool(min_value is None or max_value is None) + elif allow_infinity: + if min_value is not None and max_value is not None: + raise InvalidArgument( + 'Cannot have allow_infinity=%r, with both min_value and ' + 'max_value' % ( + allow_infinity + )) + + if min_value is None and max_value is None: + result = FloatStrategy( + allow_infinity=allow_infinity, allow_nan=allow_nan, + ) # type: SearchStrategy[float] + elif min_value is not None and max_value is not None: + if min_value == max_value: + assert isinstance(min_value, float) + result = just(min_value) + elif is_negative(min_value): + if is_negative(max_value): + result = floats(min_value=-max_value, max_value=-min_value)\ + .map(operator.neg) + else: + result = floats(min_value=0.0, max_value=max_value) | floats( + min_value=0.0, max_value=-min_value).map(operator.neg) + elif count_between_floats(min_value, max_value) > 1000: + result = FixedBoundedFloatStrategy( + lower_bound=min_value, upper_bound=max_value + ) + else: + ub_int = float_to_int(max_value, width) + lb_int = float_to_int(min_value, width) + assert lb_int <= ub_int + result = integers(min_value=lb_int, max_value=ub_int).map( + lambda x: int_to_float(x, width) + ) + elif min_value is not None: + assert isinstance(min_value, float) + if min_value < 0: + result = floats( + min_value=0.0, allow_infinity=allow_infinity + ) | floats(min_value=min_value, max_value=-0.0) + else: + result = ( + floats(allow_infinity=allow_infinity, allow_nan=False).map( + lambda x: assume(not math.isnan(x)) and + min_value + abs(x) # type: ignore + ) + ) + if min_value == 0 and not is_negative(min_value): + result = result.filter(lambda x: math.copysign(1.0, x) == 1) + else: + assert isinstance(max_value, float) + if max_value > 0: + result = floats( + min_value=0.0, + max_value=max_value, + ) | floats(max_value=-0.0, allow_infinity=allow_infinity) + else: + result = ( + floats(allow_infinity=allow_infinity, allow_nan=False).map( + lambda x: assume(not math.isnan(x)) and + max_value - abs(x) # type: ignore + ) + ) + if max_value == 0 and is_negative(max_value): + result = result.filter(is_negative) + + if width < 64: + def downcast(x): + try: + return float_of(x, width) + except OverflowError: + reject() + return result.map(downcast) + return result + + +@cacheable +@defines_strategy +def tuples(*args): + # type: (*SearchStrategy) -> SearchStrategy[tuple] + """Return a strategy which generates a tuple of the same length as args by + generating the value at index i from args[i]. + + e.g. tuples(integers(), integers()) would generate a tuple of length + two with both values an integer. + + Examples from this strategy shrink by shrinking their component parts. + """ + for arg in args: + check_strategy(arg) + + return TupleStrategy(args) + + +@overload +def sampled_from(elements): + # type: (Sequence[T]) -> SearchStrategy[T] + pass # pragma: no cover + + +@overload +def sampled_from(elements): + # type: (Type[enum.Enum]) -> SearchStrategy[Any] + # `SearchStrategy[Enum]` is unreliable due to mataclass issues. + pass # pragma: no cover + + +@defines_strategy +def sampled_from(elements): + """Returns a strategy which generates any value present in ``elements``. + + Note that as with :func:`~hypothesis.strategies.just`, values will not be + copied and thus you should be careful of using mutable data. + + ``sampled_from`` supports ordered collections, as well as + :class:`~python:enum.Enum` objects. :class:`~python:enum.Flag` objects + may also generate any combination of their members. + + Examples from this strategy shrink by replacing them with values earlier in + the list. So e.g. sampled_from((10, 1)) will shrink by trying to replace + 1 values with 10, and sampled_from((1, 10)) will shrink by trying to + replace 10 values with 1. + """ + values = check_sample(elements, 'sampled_from') + if not values: + return nothing() + if len(values) == 1: + return just(values[0]) + if hasattr(enum, 'Flag') and isclass(elements) and \ + issubclass(elements, enum.Flag): + # Combinations of enum.Flag members are also members. We generate + # these dynamically, because static allocation takes O(2^n) memory. + return sets(sampled_from(values), min_size=1).map( + lambda s: reduce(operator.or_, s)) + return SampledFromStrategy(values) + + +@cacheable +@defines_strategy +def lists( + elements=None, # type: SearchStrategy[Ex] + min_size=None, # type: int + average_size=None, # type: int + max_size=None, # type: int + unique_by=None, # type: Callable[..., Any] + unique=False, # type: bool +): + # type: (...) -> SearchStrategy[List[Ex]] + """Returns a list containing values drawn from elements with length in the + interval [min_size, max_size] (no bounds in that direction if these are + None). If max_size is 0 then elements may be None and only the empty list + will be drawn. + + The average_size argument is deprecated. Internal upgrades since + Hypothesis 1.x mean we no longer needed this hint to generate useful data. + + If unique is True (or something that evaluates to True), we compare direct + object equality, as if unique_by was `lambda x: x`. This comparison only + works for hashable types. + + if unique_by is not None it must be a function returning a hashable type + when given a value drawn from elements. The resulting list will satisfy the + condition that for i != j, unique_by(result[i]) != unique_by(result[j]). + + Examples from this strategy shrink by trying to remove elements from the + list, and by shrinking each individual element of the list. + """ + check_valid_sizes(min_size, average_size, max_size) + if elements is None: + note_deprecation( + 'Passing a strategy for `elements` of the list will be required ' + 'in a future version of Hypothesis. To create lists that are ' + 'always empty, use `builds(list)` or `lists(nothing())`.' + ) + if min_size or average_size or max_size: + # Checked internally for lists with an elements strategy, but + # we're about to skip that and return builds(list) instead... + raise InvalidArgument( + 'Cannot create a non-empty collection (min_size=%r, ' + 'average_size=%r, max_size=%r) without elements.' + % (min_size, average_size, max_size) + ) + return builds(list) + if max_size == 0: + return builds(list) + check_strategy(elements, 'elements') + if unique: + if unique_by is not None: + raise InvalidArgument(( + 'cannot specify both unique and unique_by (you probably only ' + 'want to set unique_by)' + )) + else: + def unique_by(x): + return x + + if unique_by is not None: + return UniqueListStrategy( + elements=elements, + max_size=max_size, + min_size=min_size, + key=unique_by + ) + return ListStrategy(elements, min_size=min_size, max_size=max_size) + + +@cacheable +@defines_strategy +def sets( + elements=None, # type: SearchStrategy[Ex] + min_size=None, # type: int + average_size=None, # type: int + max_size=None, # type: int +): + # type: (...) -> SearchStrategy[Set[Ex]] + """This has the same behaviour as lists, but returns sets instead. + + Note that Hypothesis cannot tell if values are drawn from elements + are hashable until running the test, so you can define a strategy + for sets of an unhashable type but it will fail at test time. + + Examples from this strategy shrink by trying to remove elements from the + set, and by shrinking each individual element of the set. + """ + if elements is None: + note_deprecation( + 'Passing a strategy for `elements` of the set will be required ' + 'in a future version of Hypothesis. To create sets that are ' + 'always empty, use `builds(set)` or `sets(nothing())`.' + ) + return lists( + elements=elements, min_size=min_size, average_size=average_size, + max_size=max_size, unique=True + ).map(set) + + +@cacheable +@defines_strategy +def frozensets( + elements=None, # type: SearchStrategy[Ex] + min_size=None, # type: int + average_size=None, # type: int + max_size=None, # type: int +): + # type: (...) -> SearchStrategy[FrozenSet[Ex]] + """This is identical to the sets function but instead returns + frozensets.""" + if elements is None: + note_deprecation( + 'Passing a strategy for `elements` of the frozenset will be ' + 'required in a future version of Hypothesis. To create ' + 'frozensets that are always empty, use `builds(frozenset)` ' + 'or `frozensets(nothing())`.' + ) + return lists( + elements=elements, min_size=min_size, average_size=average_size, + max_size=max_size, unique=True + ).map(frozenset) + + +@implements_iterator +class PrettyIter(object): + def __init__(self, values): + self._values = values + self._iter = iter(self._values) + + def __iter__(self): + return self._iter + + def __next__(self): + return next(self._iter) + + def __repr__(self): + return 'iter({!r})'.format(self._values) + + +@defines_strategy +def iterables(elements=None, min_size=None, average_size=None, max_size=None, + unique_by=None, unique=False): + """This has the same behaviour as lists, but returns iterables instead. + + Some iterables cannot be indexed (e.g. sets) and some do not have a + fixed length (e.g. generators). This strategy produces iterators, + which cannot be indexed and do not have a fixed length. This ensures + that you do not accidentally depend on sequence behaviour. + """ + if elements is None: + note_deprecation( + 'Passing a strategy for `elements` of the iterable will be ' + 'required in a future version of Hypothesis. To create ' + 'iterables that are always empty, use `iterables(nothing())`.' + ) + + return lists( + elements=elements, min_size=min_size, average_size=average_size, + max_size=max_size, unique_by=unique_by, unique=unique + ).map(PrettyIter) + + +@defines_strategy +def fixed_dictionaries( + mapping # type: Dict[T, SearchStrategy[Ex]] +): + # type: (...) -> SearchStrategy[Dict[T, Ex]] + """Generates a dictionary of the same type as mapping with a fixed set of + keys mapping to strategies. mapping must be a dict subclass. + + Generated values have all keys present in mapping, with the + corresponding values drawn from mapping[key]. If mapping is an + instance of OrderedDict the keys will also be in the same order, + otherwise the order is arbitrary. + + Examples from this strategy shrink by shrinking each individual value in + the generated dictionary. + """ + check_type(dict, mapping, 'mapping') + for v in mapping.values(): + check_strategy(v) + return FixedKeysDictStrategy(mapping) + + +@cacheable +@defines_strategy +def dictionaries( + keys, # type: SearchStrategy[Ex] + values, # type: SearchStrategy[T] + dict_class=dict, # type: type + min_size=None, # type: int + average_size=None, # type: int + max_size=None, # type: int +): + # type: (...) -> SearchStrategy[Dict[Ex, T]] + # Describing the exact dict_class to Mypy drops the key and value types, + # so we report Dict[K, V] instead of Mapping[Any, Any] for now. Sorry! + """Generates dictionaries of type dict_class with keys drawn from the keys + argument and values drawn from the values argument. + + The size parameters have the same interpretation as for lists. + + Examples from this strategy shrink by trying to remove keys from the + generated dictionary, and by shrinking each generated key and value. + """ + check_valid_sizes(min_size, average_size, max_size) + if max_size == 0: + return fixed_dictionaries(dict_class()) + check_strategy(keys) + check_strategy(values) + + return lists( + tuples(keys, values), + min_size=min_size, max_size=max_size, + unique_by=lambda x: x[0] + ).map(dict_class) + + +@defines_strategy +def streaming(elements): + """Generates an infinite stream of values where each value is drawn from + elements. + + The result is iterable (the iterator will never terminate) and + indexable. + + Examples from this strategy shrink by trying to shrink each value drawn. + + .. deprecated:: 3.15.0 + Use :func:`data() ` instead. + """ + note_deprecation( + 'streaming() has been deprecated. Use the data() strategy instead and ' + 'replace stream iteration with data.draw() calls.' + ) + + check_strategy(elements) + return StreamStrategy(elements) + + +@cacheable +@defines_strategy_with_reusable_values +def characters( + whitelist_categories=None, # type: Sequence[Text] + blacklist_categories=None, # type: Sequence[Text] + blacklist_characters=None, # type: Sequence[Text] + min_codepoint=None, # type: int + max_codepoint=None, # type: int + whitelist_characters=None, # type: Sequence[Text] +): + # type: (...) -> SearchStrategy[Text] + """Generates unicode text type (unicode on python 2, str on python 3) + characters following specified filtering rules. + + - When no filtering rules are specifed, any character can be produced. + - If ``min_codepoint`` or ``max_codepoint`` is specifed, then only + characters having a codepoint in that range will be produced. + - If ``whitelist_categories`` is specified, then only characters from those + Unicode categories will be produced. This is a further restriction, + characters must also satisfy ``min_codepoint`` and ``max_codepoint``. + - If ``blacklist_categories`` is specified, then any character from those + categories will not be produced. Any overlap between + ``whitelist_categories`` and ``blacklist_categories`` will raise an + exception, as each character can only belong to a single class. + - If ``whitelist_characters`` is specified, then any additional characters + in that list will also be produced. + - If ``blacklist_characters`` is specified, then any characters in + that list will be not be produced. Any overlap between \ + ``whitelist_characters`` and ``blacklist_characters`` will raise an + exception. + + The ``_codepoint`` arguments must be integers between zero and + :obj:`python:sys.maxunicode`. The ``_characters`` arguments must be + collections of length-one unicode strings, such as a unicode string. + + The ``_categories`` arguments must be used to specify either the + one-letter Unicode major category or the two-letter Unicode + `general category`_. For example, ``('Nd', 'Lu')`` signifies "Number, + decimal digit" and "Letter, uppercase". A single letter ('major category') + can be given to match all corresponding categories, for example ``'P'`` + for characters in any punctuation category. + + .. _general category: https://wikipedia.org/wiki/Unicode_character_property + + Examples from this strategy shrink towards the codepoint for ``'0'``, + or the first allowable codepoint after it if ``'0'`` is excluded. + """ + check_valid_size(min_codepoint, 'min_codepoint') + check_valid_size(max_codepoint, 'max_codepoint') + check_valid_interval(min_codepoint, max_codepoint, + 'min_codepoint', 'max_codepoint') + if all((whitelist_characters is not None, + min_codepoint is None, + max_codepoint is None, + whitelist_categories is None, + blacklist_categories is None, + )): + raise InvalidArgument( + 'Passing only whitelist_characters=%r would have no effect. ' + 'Perhaps you want sampled_from() ?' % (whitelist_characters,)) + blacklist_characters = blacklist_characters or '' + whitelist_characters = whitelist_characters or '' + overlap = set(blacklist_characters).intersection(whitelist_characters) + if overlap: + raise InvalidArgument( + 'Characters %r are present in both whitelist_characters=%r, and ' + 'blacklist_characters=%r' % ( + sorted(overlap), whitelist_characters, blacklist_characters)) + blacklist_categories = as_general_categories( + blacklist_categories, 'blacklist_categories') + if whitelist_categories is not None and not whitelist_categories and \ + not whitelist_characters: + raise InvalidArgument( + 'When whitelist_categories is an empty collection and there are ' + 'no characters specified in whitelist_characters, nothing can ' + 'be generated by the characters() strategy.') + whitelist_categories = as_general_categories( + whitelist_categories, 'whitelist_categories') + both_cats = set( + blacklist_categories or ()).intersection(whitelist_categories or ()) + if both_cats: + raise InvalidArgument( + 'Categories %r are present in both whitelist_categories=%r, and ' + 'blacklist_categories=%r' % ( + sorted(both_cats), whitelist_categories, blacklist_categories)) + + return OneCharStringStrategy(whitelist_categories=whitelist_categories, + blacklist_categories=blacklist_categories, + blacklist_characters=blacklist_characters, + min_codepoint=min_codepoint, + max_codepoint=max_codepoint, + whitelist_characters=whitelist_characters) + + +@cacheable +@defines_strategy_with_reusable_values +def text( + alphabet=None, # type: Union[Sequence[Text], SearchStrategy[Text]] + min_size=None, # type: int + average_size=None, # type: int + max_size=None # type: int +): + # type: (...) -> SearchStrategy[Text] + """Generates values of a unicode text type (unicode on python 2, str on + python 3) with values drawn from alphabet, which should be an iterable of + length one strings or a strategy generating such. If it is None it will + default to generating the full unicode range (excluding surrogate + characters). If it is an empty collection this will only generate empty + strings. + + min_size and max_size have the usual interpretations. + + The average_size argument is deprecated. Internal upgrades since + Hypothesis 1.x mean we no longer needed this hint to generate useful data. + + Examples from this strategy shrink towards shorter strings, and with the + characters in the text shrinking as per the alphabet strategy. + """ + check_valid_sizes(min_size, average_size, max_size) + if alphabet is None: + char_strategy = characters(blacklist_categories=('Cs',)) + elif not alphabet: + if (min_size or 0) > 0: + raise InvalidArgument( + 'Invalid min_size %r > 0 for empty alphabet' % ( + min_size, + ) + ) + return just(u'') + elif isinstance(alphabet, SearchStrategy): + char_strategy = alphabet + else: + if not isinstance(alphabet, abc.Sequence): + note_deprecation( + 'alphabet must be an ordered sequence, or tests may be ' + 'flaky and shrinking weaker, but a %r is not a type of ' + 'sequence. This will be an error in future.' + % (type(alphabet),) + ) + alphabet = list(alphabet) + non_string = [c for c in alphabet if not isinstance(c, string_types)] + if non_string: + note_deprecation( + 'The following elements in alphabet are not unicode ' + 'strings, which will be an error in future: %r' + % (non_string,) + ) + alphabet = [str(c) for c in alphabet] + not_one_char = [c for c in alphabet + if isinstance(c, string_types) and len(c) != 1] + if not_one_char: + note_deprecation( + 'The following elements in alphabet are not of length ' + 'one, which leads to violation of size constraints and ' + 'will be an error in future: %r' % (not_one_char,) + ) + char_strategy = sampled_from(alphabet) + return StringStrategy(lists( + char_strategy, min_size=min_size, max_size=max_size + )) + + +@cacheable +@defines_strategy +def from_regex(regex, fullmatch=False): + # type: (Union[AnyStr, Pattern[AnyStr]], bool) -> SearchStrategy[AnyStr] + """Generates strings that contain a match for the given regex (i.e. ones + for which :func:`python:re.search` will return a non-None result). + + ``regex`` may be a pattern or :func:`compiled regex `. + Both byte-strings and unicode strings are supported, and will generate + examples of the same type. + + You can use regex flags such as :obj:`python:re.IGNORECASE` or + :obj:`python:re.DOTALL` to control generation. Flags can be passed either + in compiled regex or inside the pattern with a ``(?iLmsux)`` group. + + Some regular expressions are only partly supported - the underlying + strategy checks local matching and relies on filtering to resolve + context-dependent expressions. Using too many of these constructs may + cause health-check errors as too many examples are filtered out. This + mainly includes (positive or negative) lookahead and lookbehind groups. + + If you want the generated string to match the whole regex you should use + boundary markers. So e.g. ``r"\\A.\\Z"`` will return a single character + string, while ``"."`` will return any string, and ``r"\\A.$"`` will return + a single character optionally followed by a ``"\\n"``. + Alternatively, passing ``fullmatch=True`` will ensure that the whole + string is a match, as if you had used the ``\\A`` and ``\\Z`` markers. + + Examples from this strategy shrink towards shorter strings and lower + character values, with exact behaviour that may depend on the pattern. + """ + check_type(bool, fullmatch, 'fullmatch') + # TODO: We would like to move this to the top level, but pending some major + # refactoring it's hard to do without creating circular imports. + from hypothesis.searchstrategy.regex import regex_strategy + return regex_strategy(regex, fullmatch) + + +@cacheable +@defines_strategy_with_reusable_values +def binary( + min_size=None, average_size=None, max_size=None +): + # type: (int, int, int) -> SearchStrategy[bytes] + """Generates the appropriate binary type (str in python 2, bytes in python + 3). + + min_size and max_size have the usual interpretations. + + The average_size argument is deprecated. Internal upgrades since + Hypothesis 1.x mean we no longer needed this hint to generate useful data. + + Examples from this strategy shrink towards smaller strings and lower byte + values. + """ + check_valid_sizes(min_size, average_size, max_size) + if min_size == max_size is not None: + return FixedSizeBytes(min_size) + return BinaryStringStrategy( + lists( + integers(min_value=0, max_value=255), + min_size=min_size, max_size=max_size + ) + ) + + +@cacheable +@defines_strategy +def randoms(): + # type: () -> SearchStrategy[Random] + """Generates instances of Random (actually a Hypothesis specific + RandomWithSeed class which displays what it was initially seeded with) + + Examples from this strategy shrink to seeds closer to zero. + """ + return RandomStrategy(integers()) + + +class RandomSeeder(object): + + def __init__(self, seed): + self.seed = seed + + def __repr__(self): + return 'random.seed(%r)' % (self.seed,) + + +class RandomModule(SearchStrategy): + def do_draw(self, data): + data.can_reproduce_example_from_repr = False + seed = data.draw(integers()) + state = random.getstate() + random.seed(seed) + cleanup(lambda: random.setstate(state)) + return RandomSeeder(seed) + + +@cacheable +@defines_strategy +def random_module(): + """If your code depends on the global random module then you need to use + this. + + It will explicitly seed the random module at the start of your test + so that tests are reproducible. The value it passes you is an opaque + object whose only useful feature is that its repr displays the + random seed. It is not itself a random number generator. If you want + a random number generator you should use the randoms() strategy + which will give you one. + + Examples from these strategy shrink to seeds closer to zero. + """ + return shared(RandomModule(), 'hypothesis.strategies.random_module()') + + +@cacheable +@defines_strategy +def builds( + *callable_and_args, # type: Any + **kwargs # type: Union[SearchStrategy[Any], InferType] +): + # type: (...) -> SearchStrategy[Any] + """Generates values by drawing from ``args`` and ``kwargs`` and passing + them to the callable (provided as the first positional argument) in the + appropriate argument position. + + e.g. ``builds(target, integers(), flag=booleans())`` would draw an + integer ``i`` and a boolean ``b`` and call ``target(i, flag=b)``. + + If the callable has type annotations, they will be used to infer a strategy + for required arguments that were not passed to builds. You can also tell + builds to infer a strategy for an optional argument by passing the special + value :const:`hypothesis.infer` as a keyword argument to + builds, instead of a strategy for that argument to the callable. + + If the callable is a class defined with :pypi:`attrs`, missing required + arguments will be inferred from the attribute on a best-effort basis, + e.g. by checking :ref:`attrs standard validators `. + + Examples from this strategy shrink by shrinking the argument values to + the callable. + """ + if callable_and_args: + target, args = callable_and_args[0], callable_and_args[1:] + if not callable(target): + raise InvalidArgument( + 'The first positional argument to builds() must be a callable ' + 'target to construct.') + elif 'target' in kwargs and callable(kwargs['target']): + args = () + note_deprecation( + 'Specifying the target as a keyword argument to builds() is ' + 'deprecated. Provide it as the first positional argument instead.') + target = kwargs.pop('target') + else: + raise InvalidArgument( + 'builds() must be passed a callable as the first positional ' + 'argument, but no positional arguments were given.') + + if infer in args: + # Avoid an implementation nightmare juggling tuples and worse things + raise InvalidArgument('infer was passed as a positional argument to ' + 'builds(), but is only allowed as a keyword arg') + required = required_args(target, args, kwargs) + to_infer = set(k for k, v in kwargs.items() if v is infer) + if required or to_infer: + if isclass(target) and attr.has(target): + # Use our custom introspection for attrs classes + from hypothesis.searchstrategy.attrs import from_attrs + return from_attrs(target, args, kwargs, required | to_infer) + # Otherwise, try using type hints + if isclass(target): + if is_typed_named_tuple(target): + # Special handling for typing.NamedTuple + hints = target._field_types + else: + hints = get_type_hints(target.__init__) + else: + hints = get_type_hints(target) + if to_infer - set(hints): + raise InvalidArgument( + 'passed infer for %s, but there is no type annotation' + % (', '.join(sorted(to_infer - set(hints))))) + for kw in set(hints) & (required | to_infer): + kwargs[kw] = from_type(hints[kw]) + # Mypy doesn't realise that `infer` is gone from kwargs now + kwarg_strat = fixed_dictionaries(kwargs) # type: ignore + return tuples(tuples(*args), kwarg_strat).map( + lambda value: target(*value[0], **value[1]) + ) + + +def _defer_from_type(func): + # type: (T) -> T + """Decorator to make from_type lazy to support recursive definitions.""" + @proxies(func) + def inner(*args, **kwargs): + return deferred(lambda: func(*args, **kwargs)) + return inner + + +@cacheable +@_defer_from_type +def from_type(thing): + # type: (Type[Ex]) -> SearchStrategy[Ex] + """Looks up the appropriate search strategy for the given type. + + ``from_type`` is used internally to fill in missing arguments to + :func:`~hypothesis.strategies.builds` and can be used interactively + to explore what strategies are available or to debug type resolution. + + You can use :func:`~hypothesis.strategies.register_type_strategy` to + handle your custom types, or to globally redefine certain strategies - + for example excluding NaN from floats, or use timezone-aware instead of + naive time and datetime strategies. + + The resolution logic may be changed in a future version, but currently + tries these four options: + + 1. If ``thing`` is in the default lookup mapping or user-registered lookup, + return the corresponding strategy. The default lookup covers all types + with Hypothesis strategies, including extras where possible. + 2. If ``thing`` is from the :mod:`python:typing` module, return the + corresponding strategy (special logic). + 3. If ``thing`` has one or more subtypes in the merged lookup, return + the union of the strategies for those types that are not subtypes of + other elements in the lookup. + 4. Finally, if ``thing`` has type annotations for all required arguments, + it is resolved via :func:`~hypothesis.strategies.builds`. + """ + # TODO: We would like to move this to the top level, but pending some major + # refactoring it's hard to do without creating circular imports. + from hypothesis.searchstrategy import types + + if typing is not None: # pragma: no branch + if not isinstance(thing, type): + # At runtime, `typing.NewType` returns an identity function rather + # than an actual type, but we can check that for a possible match + # and then read the magic attribute to unwrap it. + if all([ + hasattr(thing, '__supertype__'), hasattr(typing, 'NewType'), + isfunction(thing), getattr(thing, '__module__', 0) == 'typing' + ]): + return from_type(thing.__supertype__) + # Under Python 3.6, Unions are not instances of `type` - but we + # still want to resolve them! + if getattr(thing, '__origin__', None) is typing.Union: + args = sorted(thing.__args__, key=types.type_sorting_key) + return one_of([from_type(t) for t in args]) + # We can't resolve forward references, and under Python 3.5 (only) + # a forward reference is an instance of type. Hence, explicit check: + elif hasattr(typing, '_ForwardRef') and \ + type(thing) == typing._ForwardRef: # pragma: no cover + raise ResolutionFailed( + 'thing=%s cannot be resolved. Upgrading to python>=3.6 may ' + 'fix this problem via improvements to the typing module.' + % (thing,)) + if not types.is_a_type(thing): + raise InvalidArgument('thing=%s must be a type' % (thing,)) + # Now that we know `thing` is a type, the first step is to check for an + # explicitly registered strategy. This is the best (and hopefully most + # common) way to resolve a type to a strategy. Note that the value in the + # lookup may be a strategy or a function from type -> strategy; and we + # convert empty results into an explicit error. + if thing in types._global_type_lookup: + strategy = types._global_type_lookup[thing] + if not isinstance(strategy, SearchStrategy): + strategy = strategy(thing) # type: ignore + if strategy.is_empty: # type: ignore + raise ResolutionFailed( + 'Error: %r resolved to an empty strategy' % (thing,)) + return strategy # type: ignore + # If there's no explicitly registered strategy, maybe a subtype of thing + # is registered - if so, we can resolve it to the subclass strategy. + # We'll start by checking if thing is from from the typing module, + # because there are several special cases that don't play well with + # subclass and instance checks. + if typing is not None: # pragma: no branch + if isinstance(thing, typing_root_type): + return types.from_typing_type(thing) + # If it's not from the typing module, we get all registered types that are + # a subclass of `thing` and are not themselves a subtype of any other such + # type. For example, `Number -> integers() | floats()`, but bools() is + # not included because bool is a subclass of int as well as Number. + strategies = [ + v if isinstance(v, SearchStrategy) else v(thing) # type: ignore + for k, v in types._global_type_lookup.items() + if isinstance(k, type) and issubclass(k, thing) and sum( + types.try_issubclass(k, typ) for typ in types._global_type_lookup + ) == 1 + ] + empty = ', '.join(repr(s) for s in strategies if s.is_empty) + if empty: + raise ResolutionFailed( + 'Could not resolve %s to a strategy; consider using ' + 'register_type_strategy' % empty) + elif strategies: + return one_of(strategies) + # If we don't have a strategy registered for this type or any subtype, we + # may be able to fall back on type annotations. + if issubclass(thing, enum.Enum): + return sampled_from(thing) + # If we know that builds(thing) will fail, give a better error message + required = required_args(thing) + if not any([ + not required, + required.issubset(get_type_hints(thing.__init__)), + attr.has(thing), + # NamedTuples are weird enough that we need a specific check for them. + is_typed_named_tuple(thing), + ]): + raise ResolutionFailed('Could not resolve %r to a strategy; consider ' + 'using register_type_strategy' % (thing,)) + # Finally, try to build an instance by calling the type object + return builds(thing) + + +@cacheable +@defines_strategy_with_reusable_values +def fractions( + min_value=None, # type: Union[Real, AnyStr] + max_value=None, # type: Union[Real, AnyStr] + max_denominator=None, # type: int +): + # type: (...) -> SearchStrategy[Fraction] + """Returns a strategy which generates Fractions. + + If min_value is not None then all generated values are no less than + min_value. If max_value is not None then all generated values are no + greater than max_value. min_value and max_value may be anything accepted + by the :class:`~fractions.Fraction` constructor. + + If max_denominator is not None then the denominator of any generated + values is no greater than max_denominator. Note that max_denominator must + be None or a positive integer. + + Examples from this strategy shrink towards smaller denominators, then + closer to zero. + """ + min_value = try_convert(Fraction, min_value, 'min_value') + max_value = try_convert(Fraction, max_value, 'max_value') + + if (min_value is not None and not isinstance(min_value, Fraction) or + max_value is not None and not isinstance(max_value, Fraction)): + assert False, 'Unreachable for Mypy' # pragma: no cover + + check_valid_interval(min_value, max_value, 'min_value', 'max_value') + check_valid_integer(max_denominator) + + if max_denominator is not None: + if max_denominator < 1: + raise InvalidArgument( + 'max_denominator=%r must be >= 1' % max_denominator) + + def fraction_bounds(value): + # type: (Fraction) -> Tuple[Fraction, Fraction] + """Find the best lower and upper approximation for value.""" + # Adapted from CPython's Fraction.limit_denominator here: + # https://github.com/python/cpython/blob/3.6/Lib/fractions.py#L219 + assert max_denominator is not None + if value is None or value.denominator <= max_denominator: + return value, value + p0, q0, p1, q1 = 0, 1, 1, 0 + n, d = value.numerator, value.denominator + while True: + a = n // d + q2 = q0 + a * q1 + if q2 > max_denominator: + break + p0, q0, p1, q1 = p1, q1, p0 + a * p1, q2 + n, d = d, n - a * d + k = (max_denominator - q0) // q1 + low, high = Fraction(p1, q1), Fraction(p0 + k * p1, q0 + k * q1) + assert low < value < high + return low, high + + # Take the high approximation for min_value and low for max_value + bounds = (max_denominator, min_value, max_value) + if min_value is not None: + _, min_value = fraction_bounds(min_value) + if max_value is not None: + max_value, _ = fraction_bounds(max_value) + + if min_value is not None and max_value is not None and \ + min_value > max_value: + raise InvalidArgument( + 'There are no fractions with a denominator <= %r between ' + 'min_value=%r and max_value=%r' % bounds) + + if min_value is not None and min_value == max_value: + return just(min_value) + + def dm_func(denom): + """Take denom, construct numerator strategy, and build fraction.""" + # Four cases of algebra to get integer bounds and scale factor. + min_num, max_num = None, None + if max_value is None and min_value is None: + pass + elif min_value is None: + max_num = denom * max_value.numerator + denom *= max_value.denominator + elif max_value is None: + min_num = denom * min_value.numerator + denom *= min_value.denominator + else: + low = min_value.numerator * max_value.denominator + high = max_value.numerator * min_value.denominator + scale = min_value.denominator * max_value.denominator + # After calculating our integer bounds and scale factor, we remove + # the gcd to avoid drawing more bytes for the example than needed. + # Note that `div` can be at most equal to `scale`. + div = gcd(scale, gcd(low, high)) + min_num = denom * low // div + max_num = denom * high // div + denom *= scale // div + + return builds( + Fraction, + integers(min_value=min_num, max_value=max_num), + just(denom) + ) + + if max_denominator is None: + return integers(min_value=1).flatmap(dm_func) + + return integers(1, max_denominator).flatmap(dm_func).map( + lambda f: f.limit_denominator(max_denominator)) + + +def _as_finite_decimal( + value, # type: Union[Real, AnyStr, None] + name, # type: str + allow_infinity, # type: Optional[bool] +): + # type: (...) -> Optional[Decimal] + """Convert decimal bounds to decimals, carefully.""" + assert name in ('min_value', 'max_value') + if value is None: + return None + if not isinstance(value, Decimal): + with localcontext(Context()): # ensure that default traps are enabled + value = try_convert(Decimal, value, name) + assert isinstance(value, Decimal) + if value.is_finite(): + return value + if value.is_infinite() and (value < 0 if 'min' in name else value > 0): + if allow_infinity or allow_infinity is None: + return None + raise InvalidArgument('allow_infinity=%r, but %s=%r' + % (allow_infinity, name, value)) + # This could be infinity, quiet NaN, or signalling NaN + raise InvalidArgument(u'Invalid %s=%r' % (name, value)) + + +@cacheable +@defines_strategy_with_reusable_values +def decimals( + min_value=None, # type: Union[Real, AnyStr] + max_value=None, # type: Union[Real, AnyStr] + allow_nan=None, # type: bool + allow_infinity=None, # type: bool + places=None, # type: int +): + # type: (...) -> SearchStrategy[Decimal] + """Generates instances of :class:`python:decimal.Decimal`, which may be: + + - A finite rational number, between ``min_value`` and ``max_value``. + - Not a Number, if ``allow_nan`` is True. None means "allow NaN, unless + ``min_value`` and ``max_value`` are not None". + - Positive or negative infinity, if ``max_value`` and ``min_value`` + respectively are None, and ``allow_infinity`` is not False. None means + "allow infinity, unless excluded by the min and max values". + + Note that where floats have one ``NaN`` value, Decimals have four: signed, + and either *quiet* or *signalling*. See `the decimal module docs + `_ for + more information on special values. + + If ``places`` is not None, all finite values drawn from the strategy will + have that number of digits after the decimal place. + + Examples from this strategy do not have a well defined shrink order but + try to maximize human readability when shrinking. + """ + # Convert min_value and max_value to Decimal values, and validate args + check_valid_integer(places) + if places is not None and places < 0: + raise InvalidArgument('places=%r may not be negative' % places) + min_value = _as_finite_decimal(min_value, 'min_value', allow_infinity) + max_value = _as_finite_decimal(max_value, 'max_value', allow_infinity) + check_valid_interval(min_value, max_value, 'min_value', 'max_value') + if allow_infinity and (None not in (min_value, max_value)): + raise InvalidArgument('Cannot allow infinity between finite bounds') + # Set up a strategy for finite decimals. Note that both floating and + # fixed-point decimals require careful handling to remain isolated from + # any external precision context - in short, we always work out the + # required precision for lossless operation and use context methods. + if places is not None: + # Fixed-point decimals are basically integers with a scale factor + def ctx(val): + """Return a context in which this value is lossless.""" + precision = ceil(math.log10(abs(val) or 1)) + places + 1 + return Context(prec=max([precision, 1])) + + def int_to_decimal(val): + context = ctx(val) + return context.quantize(context.multiply(val, factor), factor) + + factor = Decimal(10) ** -places + min_num, max_num = None, None + if min_value is not None: + min_num = ceil(ctx(min_value).divide(min_value, factor)) + if max_value is not None: + max_num = floor(ctx(max_value).divide(max_value, factor)) + if min_num is not None and max_num is not None and min_num > max_num: + raise InvalidArgument( + 'There are no decimals with %d places between min_value=%r ' + 'and max_value=%r ' % (places, min_value, max_value)) + strat = integers(min_num, max_num).map(int_to_decimal) + else: + # Otherwise, they're like fractions featuring a power of ten + def fraction_to_decimal(val): + precision = ceil(math.log10(abs(val.numerator) or 1) + + math.log10(val.denominator)) + 1 + return Context(prec=precision or 1).divide( + Decimal(val.numerator), val.denominator) + + strat = fractions(min_value, max_value).map(fraction_to_decimal) + # Compose with sampled_from for infinities and NaNs as appropriate + special = [] # type: List[Decimal] + if allow_nan or (allow_nan is None and (None in (min_value, max_value))): + special.extend(map(Decimal, ('NaN', '-NaN', 'sNaN', '-sNaN'))) + if allow_infinity or (allow_infinity is max_value is None): + special.append(Decimal('Infinity')) + if allow_infinity or (allow_infinity is min_value is None): + special.append(Decimal('-Infinity')) + return strat | sampled_from(special) + + +def recursive( + base, # type: SearchStrategy[Ex] + extend, # type: Callable[[SearchStrategy[Any]], SearchStrategy[T]] + max_leaves=100, # type: int +): + # type: (...) -> SearchStrategy[Union[T, Ex]] + """base: A strategy to start from. + + extend: A function which takes a strategy and returns a new strategy. + + max_leaves: The maximum number of elements to be drawn from base on a given + run. + + This returns a strategy ``S`` such that ``S = extend(base | S)``. That is, + values may be drawn from base, or from any strategy reachable by mixing + applications of | and extend. + + An example may clarify: ``recursive(booleans(), lists)`` would return a + strategy that may return arbitrarily nested and mixed lists of booleans. + So e.g. ``False``, ``[True]``, ``[False, []]``, and ``[[[[True]]]]`` are + all valid values to be drawn from that strategy. + + Examples from this strategy shrink by trying to reduce the amount of + recursion and by shrinking according to the shrinking behaviour of base + and the result of extend. + + """ + + return RecursiveStrategy(base, extend, max_leaves) + + +class PermutationStrategy(SearchStrategy): + def __init__(self, values): + self.values = values + + def do_draw(self, data): + # Reversed Fisher-Yates shuffle. Reverse order so that it shrinks + # propertly: This way we prefer things that are lexicographically + # closer to the identity. + result = list(self.values) + for i in hrange(len(result)): + j = integer_range(data, i, len(result) - 1) + result[i], result[j] = result[j], result[i] + return result + + +@defines_strategy +def permutations(values): + # type: (Sequence[T]) -> SearchStrategy[List[T]] + """Return a strategy which returns permutations of the ordered collection + ``values``. + + Examples from this strategy shrink by trying to become closer to the + original order of values. + """ + values = check_sample(values, 'permutations') + if not values: + return builds(list) + + return PermutationStrategy(values) + + +@defines_strategy_with_reusable_values +@renamed_arguments( + min_datetime='min_value', + max_datetime='max_value', +) +def datetimes( + min_value=dt.datetime.min, # type: dt.datetime + max_value=dt.datetime.max, # type: dt.datetime + timezones=none(), # type: SearchStrategy[Optional[dt.tzinfo]] + min_datetime=None, # type: dt.datetime + max_datetime=None, # type: dt.datetime +): + # type: (...) -> SearchStrategy[dt.datetime] + """A strategy for generating datetimes, which may be timezone-aware. + + This strategy works by drawing a naive datetime between ``min_datetime`` + and ``max_datetime``, which must both be naive (have no timezone). + + ``timezones`` must be a strategy that generates + :class:`~python:datetime.tzinfo` objects (or None, + which is valid for naive datetimes). A value drawn from this strategy + will be added to a naive datetime, and the resulting tz-aware datetime + returned. + + .. note:: + tz-aware datetimes from this strategy may be ambiguous or non-existent + due to daylight savings, leap seconds, timezone and calendar + adjustments, etc. This is intentional, as malformed timestamps are a + common source of bugs. + + :py:func:`hypothesis.extra.pytz.timezones` requires the :pypi:`pytz` + package, but provides all timezones in the Olsen database. If you want to + allow naive datetimes, combine strategies like ``none() | timezones()``. + + :py:func:`hypothesis.extra.dateutil.timezones` requires the + :pypi:`python-dateutil` package, and similarly provides all timezones + there. + + Alternatively, you can create a list of the timezones you wish to allow + (e.g. from the standard library, ``datetutil``, or ``pytz``) and use + :py:func:`sampled_from`. Ensure that simple values such as None or UTC + are at the beginning of the list for proper minimisation. + + Examples from this strategy shrink towards midnight on January 1st 2000. + """ + # Why must bounds be naive? In principle, we could also write a strategy + # that took aware bounds, but the API and validation is much harder. + # If you want to generate datetimes between two particular momements in + # time I suggest (a) just filtering out-of-bounds values; (b) if bounds + # are very close, draw a value and subtract it's UTC offset, handling + # overflows and nonexistent times; or (c) do something customised to + # handle datetimes in e.g. a four-microsecond span which is not + # representable in UTC. Handling (d), all of the above, leads to a much + # more complex API for all users and a useful feature for very few. + check_type(dt.datetime, min_value, 'min_value') + check_type(dt.datetime, max_value, 'max_value') + if min_value.tzinfo is not None: + raise InvalidArgument('min_value=%r must not have tzinfo' + % (min_value,)) + if max_value.tzinfo is not None: + raise InvalidArgument('max_value=%r must not have tzinfo' + % (max_value,)) + check_valid_interval(min_value, max_value, + 'min_value', 'max_value') + if not isinstance(timezones, SearchStrategy): + raise InvalidArgument( + 'timezones=%r must be a SearchStrategy that can provide tzinfo ' + 'for datetimes (either None or dt.tzinfo objects)' % (timezones,)) + return DatetimeStrategy(min_value, max_value, timezones) + + +@defines_strategy_with_reusable_values +@renamed_arguments( + min_date='min_value', + max_date='max_value', +) +def dates( + min_value=dt.date.min, max_value=dt.date.max, + min_date=None, max_date=None, +): + # type: (dt.date, dt.date, dt.date, dt.date) -> SearchStrategy[dt.date] + """A strategy for dates between ``min_date`` and ``max_date``. + + Examples from this strategy shrink towards January 1st 2000. + """ + check_type(dt.date, min_value, 'min_value') + check_type(dt.date, max_value, 'max_value') + check_valid_interval(min_value, max_value, 'min_value', 'max_value') + if min_value == max_value: + return just(min_value) + return DateStrategy(min_value, max_value) + + +@defines_strategy_with_reusable_values +@renamed_arguments( + min_time='min_value', + max_time='max_value', +) +def times( + min_value=dt.time.min, # type: dt.time + max_value=dt.time.max, # type: dt.time + timezones=none(), # type: SearchStrategy + min_time=None, # type: dt.time + max_time=None, # type: dt.time +): + # type: (...) -> SearchStrategy[dt.time] + """A strategy for times between ``min_time`` and ``max_time``. + + The ``timezones`` argument is handled as for :py:func:`datetimes`. + + Examples from this strategy shrink towards midnight, with the timezone + component shrinking as for the strategy that provided it. + """ + check_type(dt.time, min_value, 'min_value') + check_type(dt.time, max_value, 'max_value') + if min_value.tzinfo is not None: + raise InvalidArgument('min_value=%r must not have tzinfo' % min_value) + if max_value.tzinfo is not None: + raise InvalidArgument('max_value=%r must not have tzinfo' % max_value) + check_valid_interval(min_value, max_value, 'min_value', 'max_value') + day = dt.date(2000, 1, 1) + return datetimes(min_value=dt.datetime.combine(day, min_value), + max_value=dt.datetime.combine(day, max_value), + timezones=timezones).map(lambda t: t.timetz()) + + +@defines_strategy_with_reusable_values +@renamed_arguments( + min_delta='min_value', + max_delta='max_value', +) +def timedeltas( + min_value=dt.timedelta.min, # type: dt.timedelta + max_value=dt.timedelta.max, # type: dt.timedelta + min_delta=None, # type: dt.timedelta + max_delta=None, # type: dt.timedelta +): + # type: (...) -> SearchStrategy[dt.timedelta] + """A strategy for timedeltas between ``min_value`` and ``max_value``. + + Examples from this strategy shrink towards zero. + """ + check_type(dt.timedelta, min_value, 'min_value') + check_type(dt.timedelta, max_value, 'max_value') + check_valid_interval(min_value, max_value, 'min_value', 'max_value') + if min_value == max_value: + return just(min_value) + return TimedeltaStrategy(min_value=min_value, max_value=max_value) + + +class CompositeStrategy(SearchStrategy): + def __init__(self, definition, label, args, kwargs): + self.definition = definition + self.__label = label + self.args = args + self.kwargs = kwargs + + def do_draw(self, data): + first_draw = [True] + + def draw(strategy): + first_draw[0] = False + return data.draw(strategy) + + return self.definition(draw, *self.args, **self.kwargs) + + def calc_label(self): + return self.__label + + +@cacheable +def composite(f): + # type: (Callable[..., Ex]) -> Callable[..., SearchStrategy[Ex]] + """Defines a strategy that is built out of potentially arbitrarily many + other strategies. + + This is intended to be used as a decorator. See + :ref:`the full documentation for more details ` + about how to use this function. + + Examples from this strategy shrink by shrinking the output of each draw + call. + """ + argspec = getfullargspec(f) + + if ( + argspec.defaults is not None and + len(argspec.defaults) == len(argspec.args) + ): + raise InvalidArgument( + 'A default value for initial argument will never be used') + if len(argspec.args) == 0 and not argspec.varargs: + raise InvalidArgument( + 'Functions wrapped with composite must take at least one ' + 'positional argument.' + ) + + annots = {k: v for k, v in argspec.annotations.items() + if k in (argspec.args + argspec.kwonlyargs + ['return'])} + new_argspec = argspec._replace(args=argspec.args[1:], annotations=annots) + + label = calc_label_from_cls(f) + + @defines_strategy + @define_function_signature(f.__name__, f.__doc__, new_argspec) + def accept(*args, **kwargs): + return CompositeStrategy(f, label, args, kwargs) + accept.__module__ = f.__module__ + return accept + + +@defines_strategy_with_reusable_values +@cacheable +def complex_numbers(min_magnitude=0, max_magnitude=None, + allow_infinity=None, allow_nan=None): + # type: (Optional[Real], Real, bool, bool) -> SearchStrategy[complex] + """Returns a strategy that generates complex numbers. + + This strategy draws complex numbers with constrained magnitudes. + The ``min_magnitude`` and ``max_magnitude`` parameters should be + non-negative :class:`~python:numbers.Real` numbers; values + of ``None`` correspond to zero and infinite values respectively. + + If ``min_magnitude`` is positive or ``max_magnitude`` is finite, it + is an error to enable ``allow_nan``. If ``max_magnitude`` is finite, + it is an error to enable ``allow_infinity``. + + The magnitude contraints are respected up to a relative error + of (around) floating-point epsilon, due to implementation via + the system ``sqrt`` function. + + Examples from this strategy shrink by shrinking their real and + imaginary parts, as :func:`~hypothesis.strategies.floats`. + + If you need to generate complex numbers with particular real and + imaginary parts or relationships between parts, consider using + `builds(complex, ...) ` or + `@composite ` respectively. + """ + check_valid_magnitude(min_magnitude, 'min_magnitude') + check_valid_magnitude(max_magnitude, 'max_magnitude') + check_valid_interval(min_magnitude, max_magnitude, + 'min_magnitude', 'max_magnitude') + if max_magnitude == float('inf'): + max_magnitude = None + if min_magnitude == 0: + min_magnitude = None + + if allow_infinity is None: + allow_infinity = bool(max_magnitude is None) + elif allow_infinity and max_magnitude is not None: + raise InvalidArgument( + 'Cannot have allow_infinity=%r with max_magnitude=%r' % + (allow_infinity, max_magnitude) + ) + if allow_nan is None: + allow_nan = bool(min_magnitude is None and max_magnitude is None) + elif allow_nan and not (min_magnitude is None and max_magnitude is None): + raise InvalidArgument( + 'Cannot have allow_nan=%r, min_magnitude=%r max_magnitude=%r' % + (allow_nan, min_magnitude, max_magnitude) + ) + allow_kw = dict(allow_nan=allow_nan, allow_infinity=allow_infinity) + + if min_magnitude is None and max_magnitude is None: + # In this simple but common case, there are no constraints on the + # magnitude and therefore no relationship between the real and + # imaginary parts. + return builds(complex, floats(**allow_kw), floats(**allow_kw)) + + @composite + def constrained_complex(draw): + # Draw the imaginary part, and determine the maximum real part given + # this and the max_magnitude + if max_magnitude is None: + zi = draw(floats(**allow_kw)) + rmax = float('inf') + else: + zi = draw(floats(-max_magnitude, max_magnitude, **allow_kw)) + rmax = cathetus(max_magnitude, zi) + # Draw the real part from the allowed range given the imaginary part + if min_magnitude is None or math.fabs(zi) >= min_magnitude: + zr = draw(floats(-rmax, rmax, **allow_kw)) + else: + zr = draw(floats(cathetus(min_magnitude, zi), rmax, **allow_kw)) + # Order of conditions carefully tuned so that for a given pair of + # magnitude arguments, we always either draw or do not draw the bool + # (crucial for good shrinking behaviour) but only invert when needed. + if min_magnitude is not None and draw(booleans()) and \ + math.fabs(zi) <= min_magnitude: + zr = -zr + return complex(zr, zi) + + return constrained_complex() + + +def shared(base, key=None): + # type: (SearchStrategy[Ex], Any) -> SearchStrategy[Ex] + """Returns a strategy that draws a single shared value per run, drawn from + base. Any two shared instances with the same key will share the same value, + otherwise the identity of this strategy will be used. That is: + + >>> s = integers() # or any other strategy + >>> x = shared(s) + >>> y = shared(s) + + In the above x and y may draw different (or potentially the same) values. + In the following they will always draw the same: + + >>> x = shared(s, key="hi") + >>> y = shared(s, key="hi") + + Examples from this strategy shrink as per their base strategy. + """ + return SharedStrategy(base, key) + + +class Chooser(object): + def __init__(self, build_context, data): + self.build_context = build_context + self.data = data + self.choice_count = 0 + + def __call__(self, values): + if not values: + raise IndexError('Cannot choose from empty sequence') + result = choice(self.data, check_sample(values, 'choices')) + with self.build_context.local(): + self.choice_count += 1 + note('Choice #%d: %r' % (self.choice_count, result)) + return result + + def __repr__(self): + return 'choice' + + +class ChoiceStrategy(SearchStrategy): + supports_find = False + + def do_draw(self, data): + data.can_reproduce_example_from_repr = False + return Chooser(current_build_context(), data) + + +@defines_strategy +def choices(): + """Strategy that generates a function that behaves like random.choice. + + Will note choices made for reproducibility. + + .. deprecated:: 3.15.0 + + Use :func:`data() ` with + :func:`sampled_from() ` instead. + + Examples from this strategy shrink by making each choice function return + an earlier value in the sequence passed to it. + """ + + note_deprecation( + 'choices() has been deprecated. Use the data() strategy instead and ' + 'replace its usage with data.draw(sampled_from(elements))) calls.' + ) + + return shared( + ChoiceStrategy(), + key='hypothesis.strategies.chooser.choice_function' + ) + + +@cacheable +@defines_strategy_with_reusable_values +def uuids(version=None): + # type: (int) -> SearchStrategy[UUID] + """Returns a strategy that generates :class:`UUIDs `. + + If the optional version argument is given, value is passed through + to :class:`~python:uuid.UUID` and only UUIDs of that version will + be generated. + + All returned values from this will be unique, so e.g. if you do + ``lists(uuids())`` the resulting list will never contain duplicates. + + Examples from this strategy don't have any meaningful shrink order. + """ + if version not in (None, 1, 2, 3, 4, 5): + raise InvalidArgument(( + 'version=%r, but version must be in (None, 1, 2, 3, 4, 5) ' + 'to pass to the uuid.UUID constructor.') % (version, ) + ) + return shared(randoms(), key='hypothesis.strategies.uuids.generator').map( + lambda r: UUID(version=version, int=r.getrandbits(128)) + ) + + +class RunnerStrategy(SearchStrategy): + def __init__(self, default): + self.default = default + + def do_draw(self, data): + runner = getattr(data, 'hypothesis_runner', not_set) + if runner is not_set: + if self.default is not_set: + raise InvalidArgument( + 'Cannot use runner() strategy with no ' + 'associated runner or explicit default.' + ) + else: + return self.default + else: + return runner + + +@defines_strategy_with_reusable_values +def runner(default=not_set): + """A strategy for getting "the current test runner", whatever that may be. + The exact meaning depends on the entry point, but it will usually be the + associated 'self' value for it. + + If there is no current test runner and a default is provided, return + that default. If no default is provided, raises InvalidArgument. + + Examples from this strategy do not shrink (because there is only one). + """ + return RunnerStrategy(default) + + +class DataObject(object): + + def __init__(self, data): + self.count = 0 + self.data = data + + def __repr__(self): + return 'data(...)' + + def draw(self, strategy, label=None): + result = self.data.draw(strategy) + self.count += 1 + if label is not None: + note('Draw %d (%s): %r' % (self.count, label, result)) + else: + note('Draw %d: %r' % (self.count, result)) + return result + + +class DataStrategy(SearchStrategy): + supports_find = False + + def do_draw(self, data): + data.can_reproduce_example_from_repr = False + + if not hasattr(data, 'hypothesis_shared_data_strategy'): + data.hypothesis_shared_data_strategy = DataObject(data) + return data.hypothesis_shared_data_strategy + + def __repr__(self): + return 'data()' + + def map(self, f): + self.__not_a_first_class_strategy('map') + + def filter(self, f): + self.__not_a_first_class_strategy('filter') + + def flatmap(self, f): + self.__not_a_first_class_strategy('flatmap') + + def example(self): + self.__not_a_first_class_strategy('example') + + def __not_a_first_class_strategy(self, name): + raise InvalidArgument(( + 'Cannot call %s on a DataStrategy. You should probably be ' + "using @composite for whatever it is you're trying to do." + ) % (name,)) + + +@cacheable +def data(): + # type: () -> SearchStrategy[Any] + """This isn't really a normal strategy, but instead gives you an object + which can be used to draw data interactively from other strategies. + + It can only be used within :func:`@given `, not + :func:`find() `. This is because the lifetime + of the object cannot outlast the test body. + + See :ref:`the rest of the documentation ` for more + complete information. + + Examples from this strategy do not shrink (because there is only one), + but the result of calls to each draw() call shrink as they normally would. + """ + return DataStrategy() + + +def register_type_strategy( + custom_type, # type: type + strategy, # type: Union[SearchStrategy, Callable[[type], SearchStrategy]] +): + # type: (...) -> None + """Add an entry to the global type-to-strategy lookup. + + This lookup is used in :func:`~hypothesis.strategies.builds` and + :func:`@given `. + + :func:`~hypothesis.strategies.builds` will be used automatically for + classes with type annotations on ``__init__`` , so you only need to + register a strategy if one or more arguments need to be more tightly + defined than their type-based default, or if you want to supply a strategy + for an argument with a default value. + + ``strategy`` may be a search strategy, or a function that takes a type and + returns a strategy (useful for generic types). + """ + # TODO: We would like to move this to the top level, but pending some major + # refactoring it's hard to do without creating circular imports. + from hypothesis.searchstrategy import types + if not types.is_a_type(custom_type): + raise InvalidArgument('custom_type=%r must be a type') + elif not (isinstance(strategy, SearchStrategy) or callable(strategy)): + raise InvalidArgument( + 'strategy=%r must be a SearchStrategy, or a function that takes ' + 'a generic type and returns a specific SearchStrategy') + elif isinstance(strategy, SearchStrategy) and strategy.is_empty: + raise InvalidArgument('strategy=%r must not be empty') + types._global_type_lookup[custom_type] = strategy + from_type.__clear_cache() # type: ignore + + +@cacheable +def deferred(definition): + # type: (Callable[[], SearchStrategy[Ex]]) -> SearchStrategy[Ex] + """A deferred strategy allows you to write a strategy that references other + strategies that have not yet been defined. This allows for the easy + definition of recursive and mutually recursive strategies. + + The definition argument should be a zero-argument function that returns a + strategy. It will be evaluated the first time the strategy is used to + produce an example. + + Example usage: + + >>> import hypothesis.strategies as st + >>> x = st.deferred(lambda: st.booleans() | st.tuples(x, x)) + >>> x.example() + (((False, (True, True)), (False, True)), (True, True)) + >>> x.example() + True + + Mutual recursion also works fine: + + >>> a = st.deferred(lambda: st.booleans() | b) + >>> b = st.deferred(lambda: st.tuples(a, a)) + >>> a.example() + True + >>> b.example() + (False, (False, ((False, True), False))) + + Examples from this strategy shrink as they normally would from the strategy + returned by the definition. + """ + return DeferredStrategy(definition) + + +@defines_strategy_with_reusable_values +def emails(): + """A strategy for generating email addresses as unicode strings. The + address format is specific in :rfc:`5322#section-3.4.1`. Values shrink + towards shorter local-parts and host domains. + + This strategy is useful for generating "user data" for tests, as + mishandling of email addresses is a common source of bugs. Future + updates will generate more complicated addresses allowed by the RFC. + """ + from hypothesis.provisional import domains + local_chars = string.ascii_letters + string.digits + "!#$%&'*+-/=^_`{|}~" + local_part = text(local_chars, min_size=1, max_size=64) + # TODO: include dot-atoms, quoted strings, escaped chars, etc in local part + return builds(u'{}@{}'.format, local_part, domains()).filter( + lambda addr: len(addr) <= 255) + + +assert _strategies.issubset(set(__all__)), _strategies - set(__all__) diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/types.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/types.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/types.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/types.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,124 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import inspect +from random import Random +from itertools import islice + +from hypothesis.errors import InvalidArgument + + +class RandomWithSeed(Random): + """A subclass of Random designed to expose the seed it was initially + provided with. + + We consistently use this instead of Random objects because it makes + examples much easier to recreate. + """ + + def __init__(self, seed): + super(RandomWithSeed, self).__init__(seed) + self.seed = seed + + def __copy__(self): + result = RandomWithSeed(self.seed) + result.setstate(self.getstate()) + return result + + def __deepcopy__(self, table): + return self.__copy__() + + def __repr__(self): + return u'RandomWithSeed(%s)' % (self.seed,) + + +class Stream(object): + """A stream is a possibly infinite list. You can index into it, and you can + iterate over it, but you can't ask its length and iterating over it will + not necessarily terminate. + + Behind the scenes streams are backed by a generator, but they "remember" + the values as they evaluate them so you can replay them later. + + Internally Hypothesis uses the fact that you can tell how much of a stream + has been evaluated, but you shouldn't use that. The only public APIs of + a Stream are that you can index, slice, and iterate it. + """ + + def __init__(self, generator=None): + if generator is None: + generator = iter(()) + elif not inspect.isgenerator(generator): + generator = iter(generator) + self.generator = generator + self.fetched = [] + + def map(self, f): + return Stream(f(v) for v in self) + + def __iter__(self): + i = 0 + while i < len(self.fetched): + yield self.fetched[i] + i += 1 + for v in self.generator: + self.fetched.append(v) + yield v + + def __getitem__(self, key): + if isinstance(key, slice): + return Stream(islice( + iter(self), + key.start, key.stop, key.step + )) + + if not isinstance(key, int): + raise InvalidArgument(u'Cannot index stream with %s' % ( + type(key).__name__,)) + self._thunk_to(key + 1) + return self.fetched[key] + + def _thunk_to(self, i): + it = iter(self) + try: + while len(self.fetched) < i: + next(it) + except StopIteration: + raise IndexError( + u'Index %d out of bounds for finite stream of length %d' % ( + i, len(self.fetched) + ) + ) + + def _thunked(self): + return len(self.fetched) + + def __repr__(self): + if not self.fetched: + return u'Stream(...)' + + return u'Stream(%s, ...)' % ( + u', '.join(map(repr, self.fetched)) + ) + + def __deepcopy__(self, table): + return self + + def __copy__(self): + return self diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/utils/conventions.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/utils/conventions.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/utils/conventions.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/utils/conventions.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,45 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +# Notes: we use instances of these objects as singletons which serve as +# identifiers in various patches of code. The more specific types +# (DefaultValueType and InferType) exist so that typecheckers such as Mypy +# can distinguish them from the others. DefaultValueType is only used in +# the Django extra. + + +class UniqueIdentifier(object): + + def __init__(self, identifier): + self.identifier = identifier + + def __repr__(self): + return self.identifier + + +class DefaultValueType(UniqueIdentifier): + pass + + +class InferType(UniqueIdentifier): + pass + + +infer = InferType(u'infer') +not_set = UniqueIdentifier(u'not_set') diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/utils/dynamicvariables.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/utils/dynamicvariables.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/utils/dynamicvariables.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/utils/dynamicvariables.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,45 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import threading +from contextlib import contextmanager + + +class DynamicVariable(object): + + def __init__(self, default): + self.default = default + self.data = threading.local() + + @property + def value(self): + return getattr(self.data, 'value', self.default) + + @value.setter + def value(self, value): + setattr(self.data, 'value', value) + + @contextmanager + def with_value(self, value): + old_value = self.value + try: + self.data.value = value + yield + finally: + self.data.value = old_value diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/utils/__init__.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/utils/__init__.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/utils/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/utils/__init__.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,19 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +"""hypothesis.utils is a package for things that you can consider part of the +semi-public Hypothesis API but aren't really the core point.""" diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/vendor/__init__.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/vendor/__init__.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/vendor/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/vendor/__init__.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,16 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2016 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/vendor/pretty.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/vendor/pretty.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/vendor/pretty.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/vendor/pretty.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,874 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2016 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +# -*- coding: utf-8 -*- +""" +Python advanced pretty printer. This pretty printer is intended to +replace the old `pprint` python module which does not allow developers +to provide their own pretty print callbacks. +This module is based on ruby's `prettyprint.rb` library by `Tanaka Akira`. +Example Usage +------------- +To directly print the representation of an object use `pprint`:: + from pretty import pprint + pprint(complex_object) +To get a string of the output use `pretty`:: + from pretty import pretty + string = pretty(complex_object) +Extending +--------- +The pretty library allows developers to add pretty printing rules for their +own objects. This process is straightforward. All you have to do is to +add a `_repr_pretty_` method to your object and call the methods on the +pretty printer passed:: + class MyObject(object): + def _repr_pretty_(self, p, cycle): + ... +Here is an example implementation of a `_repr_pretty_` method for a list +subclass:: + class MyList(list): + def _repr_pretty_(self, p, cycle): + if cycle: + p.text('MyList(...)') + else: + with p.group(8, 'MyList([', '])'): + for idx, item in enumerate(self): + if idx: + p.text(',') + p.breakable() + p.pretty(item) +The `cycle` parameter is `True` if pretty detected a cycle. You *have* to +react to that or the result is an infinite loop. `p.text()` just adds +non breaking text to the output, `p.breakable()` either adds a whitespace +or breaks here. If you pass it an argument it's used instead of the +default space. `p.pretty` prettyprints another object using the pretty print +method. +The first parameter to the `group` function specifies the extra indentation +of the next line. In this example the next item will either be on the same +line (if the items are short enough) or aligned with the right edge of the +opening bracket of `MyList`. +If you just want to indent something you can use the group function +without open / close parameters. You can also use this code:: + with p.indent(2): + ... +Inheritance diagram: +.. inheritance-diagram:: IPython.lib.pretty + :parts: 3 +:copyright: 2007 by Armin Ronacher. + Portions (c) 2009 by Robert Kern. +:license: BSD License. +""" +from __future__ import division, print_function, absolute_import + +import re +import sys +import types +import datetime +import platform +from io import StringIO +from contextlib import contextmanager +from collections import deque + +from hypothesis.internal.compat import PY3, cast_unicode, string_types, \ + get_stream_enc + +__all__ = ['pretty', 'pprint', 'PrettyPrinter', 'RepresentationPrinter', + 'for_type_by_name'] + + +MAX_SEQ_LENGTH = 1000 +_re_pattern_type = type(re.compile('')) + +PYPY = platform.python_implementation() == 'PyPy' + + +def _safe_getattr(obj, attr, default=None): + """Safe version of getattr. + + Same as getattr, but will return ``default`` on any Exception, + rather than raising. + + """ + try: + return getattr(obj, attr, default) + except Exception: + return default + + +if PY3: + CUnicodeIO = StringIO +else: # pragma: no cover + class CUnicodeIO(StringIO): + """StringIO that casts str to unicode on Python 2.""" + + def write(self, text): + return super(CUnicodeIO, self).write( + cast_unicode(text, encoding=get_stream_enc(sys.stdout))) + + +def pretty( + obj, verbose=False, max_width=79, newline='\n', + max_seq_length=MAX_SEQ_LENGTH +): + """Pretty print the object's representation.""" + stream = CUnicodeIO() + printer = RepresentationPrinter( + stream, verbose, max_width, newline, max_seq_length=max_seq_length) + printer.pretty(obj) + printer.flush() + return stream.getvalue() + + +def pprint( + obj, verbose=False, max_width=79, newline='\n', + max_seq_length=MAX_SEQ_LENGTH +): + """Like `pretty` but print to stdout.""" + printer = RepresentationPrinter( + sys.stdout, verbose, max_width, newline, max_seq_length=max_seq_length) + printer.pretty(obj) + printer.flush() + sys.stdout.write(newline) + sys.stdout.flush() + + +class _PrettyPrinterBase(object): + + @contextmanager + def indent(self, indent): + """with statement support for indenting/dedenting.""" + self.indentation += indent + try: + yield + finally: + self.indentation -= indent + + @contextmanager + def group(self, indent=0, open='', close=''): + """like begin_group / end_group but for the with statement.""" + self.begin_group(indent, open) + try: + yield + finally: + self.end_group(indent, close) + + +class PrettyPrinter(_PrettyPrinterBase): + """Baseclass for the `RepresentationPrinter` prettyprinter that is used to + generate pretty reprs of objects. + + Contrary to the `RepresentationPrinter` this printer knows nothing + about the default pprinters or the `_repr_pretty_` callback method. + + """ + + def __init__( + self, output, max_width=79, newline='\n', max_seq_length=MAX_SEQ_LENGTH + ): + self.broken = False + self.output = output + self.max_width = max_width + self.newline = newline + self.max_seq_length = max_seq_length + self.output_width = 0 + self.buffer_width = 0 + self.buffer = deque() + + root_group = Group(0) + self.group_stack = [root_group] + self.group_queue = GroupQueue(root_group) + self.indentation = 0 + + def _break_outer_groups(self): + while self.max_width < self.output_width + self.buffer_width: + group = self.group_queue.deq() + if not group: + return + while group.breakables: + x = self.buffer.popleft() + self.output_width = x.output(self.output, self.output_width) + self.buffer_width -= x.width + while self.buffer and isinstance(self.buffer[0], Text): + x = self.buffer.popleft() + self.output_width = x.output(self.output, self.output_width) + self.buffer_width -= x.width + + def text(self, obj): + """Add literal text to the output.""" + width = len(obj) + if self.buffer: + text = self.buffer[-1] + if not isinstance(text, Text): + text = Text() + self.buffer.append(text) + text.add(obj, width) + self.buffer_width += width + self._break_outer_groups() + else: + self.output.write(obj) + self.output_width += width + + def breakable(self, sep=' '): + """Add a breakable separator to the output. + + This does not mean that it will automatically break here. If no + breaking on this position takes place the `sep` is inserted + which default to one space. + + """ + width = len(sep) + group = self.group_stack[-1] + if group.want_break: + self.flush() + self.output.write(self.newline) + self.output.write(' ' * self.indentation) + self.output_width = self.indentation + self.buffer_width = 0 + else: + self.buffer.append(Breakable(sep, width, self)) + self.buffer_width += width + self._break_outer_groups() + + def break_(self): + """Explicitly insert a newline into the output, maintaining correct + indentation.""" + self.flush() + self.output.write(self.newline) + self.output.write(' ' * self.indentation) + self.output_width = self.indentation + self.buffer_width = 0 + + def begin_group(self, indent=0, open=''): + """ + Begin a group. If you want support for python < 2.5 which doesn't has + the with statement this is the preferred way: + p.begin_group(1, '{') + ... + p.end_group(1, '}') + The python 2.5 expression would be this: + with p.group(1, '{', '}'): + ... + The first parameter specifies the indentation for the next line ( + usually the width of the opening text), the second the opening text. + All parameters are optional. + """ + if open: + self.text(open) + group = Group(self.group_stack[-1].depth + 1) + self.group_stack.append(group) + self.group_queue.enq(group) + self.indentation += indent + + def _enumerate(self, seq): + """like enumerate, but with an upper limit on the number of items.""" + for idx, x in enumerate(seq): + if self.max_seq_length and idx >= self.max_seq_length: + self.text(',') + self.breakable() + self.text('...') + return + yield idx, x + + def end_group(self, dedent=0, close=''): + """End a group. + + See `begin_group` for more details. + + """ + self.indentation -= dedent + group = self.group_stack.pop() + if not group.breakables: + self.group_queue.remove(group) + if close: + self.text(close) + + def flush(self): + """Flush data that is left in the buffer.""" + for data in self.buffer: + self.output_width += data.output(self.output, self.output_width) + self.buffer.clear() + self.buffer_width = 0 + + +def _get_mro(obj_class): + """Get a reasonable method resolution order of a class and its superclasses + for both old-style and new-style classes.""" + if not hasattr(obj_class, '__mro__'): # pragma: no cover + # Old-style class. Mix in object to make a fake new-style class. + try: + obj_class = type(obj_class.__name__, (obj_class, object), {}) + except TypeError: + # Old-style extension type that does not descend from object. + # FIXME: try to construct a more thorough MRO. + mro = [obj_class] + else: + mro = obj_class.__mro__[1:-1] + else: + mro = obj_class.__mro__ + return mro + + +class RepresentationPrinter(PrettyPrinter): + """Special pretty printer that has a `pretty` method that calls the pretty + printer for a python object. + + This class stores processing data on `self` so you must *never* use + this class in a threaded environment. Always lock it or + reinstanciate it. Instances also have a verbose flag callbacks can + access to control their output. For example the default instance + repr prints all attributes and methods that are not prefixed by an + underscore if the printer is in verbose mode. + + """ + + def __init__(self, output, verbose=False, max_width=79, newline='\n', + singleton_pprinters=None, type_pprinters=None, + deferred_pprinters=None, + max_seq_length=MAX_SEQ_LENGTH): + + PrettyPrinter.__init__(self, output, max_width, + newline, max_seq_length=max_seq_length) + self.verbose = verbose + self.stack = [] + if singleton_pprinters is None: + singleton_pprinters = _singleton_pprinters.copy() + self.singleton_pprinters = singleton_pprinters + if type_pprinters is None: + type_pprinters = _type_pprinters.copy() + self.type_pprinters = type_pprinters + if deferred_pprinters is None: + deferred_pprinters = _deferred_type_pprinters.copy() + self.deferred_pprinters = deferred_pprinters + + def pretty(self, obj): + """Pretty print the given object.""" + obj_id = id(obj) + cycle = obj_id in self.stack + self.stack.append(obj_id) + self.begin_group() + try: + obj_class = _safe_getattr(obj, '__class__', None) or type(obj) + # First try to find registered singleton printers for the type. + try: + printer = self.singleton_pprinters[obj_id] + except (TypeError, KeyError): + pass + else: + return printer(obj, self, cycle) + # Next walk the mro and check for either: + # 1) a registered printer + # 2) a _repr_pretty_ method + for cls in _get_mro(obj_class): + if cls in self.type_pprinters: + # printer registered in self.type_pprinters + return self.type_pprinters[cls](obj, self, cycle) + else: + # deferred printer + printer = self._in_deferred_types(cls) + if printer is not None: + return printer(obj, self, cycle) + else: + # Finally look for special method names. + # Some objects automatically create any requested + # attribute. Try to ignore most of them by checking for + # callability. + if '_repr_pretty_' in cls.__dict__: + meth = cls._repr_pretty_ + if callable(meth): + return meth(obj, self, cycle) + return _default_pprint(obj, self, cycle) + finally: + self.end_group() + self.stack.pop() + + def _in_deferred_types(self, cls): + """Check if the given class is specified in the deferred type registry. + + Returns the printer from the registry if it exists, and None if + the class is not in the registry. Successful matches will be + moved to the regular type registry for future use. + + """ + mod = _safe_getattr(cls, '__module__', None) + name = _safe_getattr(cls, '__name__', None) + key = (mod, name) + printer = None + if key in self.deferred_pprinters: + # Move the printer over to the regular registry. + printer = self.deferred_pprinters.pop(key) + self.type_pprinters[cls] = printer + return printer + + +class Printable(object): + + def output(self, stream, output_width): # pragma: no cover + raise NotImplementedError() + + +class Text(Printable): + + def __init__(self): + self.objs = [] + self.width = 0 + + def output(self, stream, output_width): + for obj in self.objs: + stream.write(obj) + return output_width + self.width + + def add(self, obj, width): + self.objs.append(obj) + self.width += width + + +class Breakable(Printable): + + def __init__(self, seq, width, pretty): + self.obj = seq + self.width = width + self.pretty = pretty + self.indentation = pretty.indentation + self.group = pretty.group_stack[-1] + self.group.breakables.append(self) + + def output(self, stream, output_width): + self.group.breakables.popleft() + if self.group.want_break: + stream.write(self.pretty.newline) + stream.write(' ' * self.indentation) + return self.indentation + if not self.group.breakables: + self.pretty.group_queue.remove(self.group) + stream.write(self.obj) + return output_width + self.width + + +class Group(Printable): + + def __init__(self, depth): + self.depth = depth + self.breakables = deque() + self.want_break = False + + +class GroupQueue(object): + + def __init__(self, *groups): + self.queue = [] + for group in groups: + self.enq(group) + + def enq(self, group): + depth = group.depth + while depth > len(self.queue) - 1: + self.queue.append([]) + self.queue[depth].append(group) + + def deq(self): + for stack in self.queue: + for idx, group in enumerate(reversed(stack)): + if group.breakables: + del stack[idx] + group.want_break = True + return group + for group in stack: + group.want_break = True + del stack[:] + + def remove(self, group): + try: + self.queue[group.depth].remove(group) + except ValueError: + pass + + +try: + _baseclass_reprs = (object.__repr__, types.InstanceType.__repr__) # type: ignore +except AttributeError: # Python 3 + _baseclass_reprs = (object.__repr__,) # type: ignore + + +def _default_pprint(obj, p, cycle): + """The default print function. + + Used if an object does not provide one and it's none of the builtin + objects. + + """ + klass = _safe_getattr(obj, '__class__', None) or type(obj) + if _safe_getattr(klass, '__repr__', None) not in _baseclass_reprs: + # A user-provided repr. Find newlines and replace them with p.break_() + _repr_pprint(obj, p, cycle) + return + p.begin_group(1, '<') + p.pretty(klass) + p.text(' at 0x%x' % id(obj)) + if cycle: + p.text(' ...') + elif p.verbose: + first = True + for key in dir(obj): + if not key.startswith('_'): + try: + value = getattr(obj, key) + except AttributeError: + continue + if isinstance(value, types.MethodType): + continue + if not first: + p.text(',') + p.breakable() + p.text(key) + p.text('=') + step = len(key) + 1 + p.indentation += step + p.pretty(value) + p.indentation -= step + first = False + p.end_group(1, '>') + + +def _seq_pprinter_factory(start, end, basetype): + """Factory that returns a pprint function useful for sequences. + + Used by the default pprint for tuples, dicts, and lists. + + """ + def inner(obj, p, cycle): + typ = type(obj) + if ( + basetype is not None and typ is not basetype and + typ.__repr__ != basetype.__repr__ + ): + # If the subclass provides its own repr, use it instead. + return p.text(typ.__repr__(obj)) + + if cycle: + return p.text(start + '...' + end) + step = len(start) + p.begin_group(step, start) + for idx, x in p._enumerate(obj): + if idx: + p.text(',') + p.breakable() + p.pretty(x) + if len(obj) == 1 and type(obj) is tuple: + # Special case for 1-item tuples. + p.text(',') + p.end_group(step, end) + return inner + + +def _set_pprinter_factory(start, end, basetype): + """Factory that returns a pprint function useful for sets and + frozensets.""" + def inner(obj, p, cycle): + typ = type(obj) + if ( + basetype is not None and typ is not basetype and + typ.__repr__ != basetype.__repr__ + ): + # If the subclass provides its own repr, use it instead. + return p.text(typ.__repr__(obj)) + + if cycle: + return p.text(start + '...' + end) + if len(obj) == 0: + # Special case. + p.text(basetype.__name__ + '()') + else: + step = len(start) + p.begin_group(step, start) + # Like dictionary keys, we will try to sort the items if there + # aren't too many + items = obj + if not (p.max_seq_length and len(obj) >= p.max_seq_length): + try: + items = sorted(obj) + except Exception: + # Sometimes the items don't sort. + pass + for idx, x in p._enumerate(items): + if idx: + p.text(',') + p.breakable() + p.pretty(x) + p.end_group(step, end) + return inner + + +def _dict_pprinter_factory(start, end, basetype=None): + """Factory that returns a pprint function used by the default pprint of + dicts and dict proxies.""" + def inner(obj, p, cycle): + typ = type(obj) + if ( + basetype is not None and typ is not basetype and + typ.__repr__ != basetype.__repr__ + ): + # If the subclass provides its own repr, use it instead. + return p.text(typ.__repr__(obj)) + + if cycle: + return p.text('{...}') + p.begin_group(1, start) + keys = obj.keys() + # if dict isn't large enough to be truncated, sort keys before + # displaying + if not (p.max_seq_length and len(obj) >= p.max_seq_length): + try: + keys = sorted(keys) + except Exception: + # Sometimes the keys don't sort. + pass + for idx, key in p._enumerate(keys): + if idx: + p.text(',') + p.breakable() + p.pretty(key) + p.text(': ') + p.pretty(obj[key]) + p.end_group(1, end) + inner.__name__ = '_dict_pprinter_factory(%r, %r, %r)' % ( + start, end, basetype + ) + return inner + + +def _super_pprint(obj, p, cycle): + """The pprint for the super type.""" + try: + # This section works around various pypy versions that don't do + # have the same attributes on super objects + obj.__thisclass__ + obj.__self__ + except AttributeError: # pragma: no cover + assert PYPY + _repr_pprint(obj, p, cycle) + return + p.begin_group(8, '') + + +def _re_pattern_pprint(obj, p, cycle): + """The pprint function for regular expression patterns.""" + p.text('re.compile(') + pattern = repr(obj.pattern) + if pattern[:1] in 'uU': # pragma: no cover + pattern = pattern[1:] + prefix = 'ur' + else: + prefix = 'r' + pattern = prefix + pattern.replace('\\\\', '\\') + p.text(pattern) + if obj.flags: + p.text(',') + p.breakable() + done_one = False + for flag in ('TEMPLATE', 'IGNORECASE', 'LOCALE', 'MULTILINE', 'DOTALL', + 'UNICODE', 'VERBOSE', 'DEBUG'): + if obj.flags & getattr(re, flag): + if done_one: + p.text('|') + p.text('re.' + flag) + done_one = True + p.text(')') + + +def _type_pprint(obj, p, cycle): + """The pprint for classes and types.""" + # Heap allocated types might not have the module attribute, + # and others may set it to None. + + # Checks for a __repr__ override in the metaclass + # != rather than is not because pypy compatibility + if type(obj).__repr__ != type.__repr__: + _repr_pprint(obj, p, cycle) + return + + mod = _safe_getattr(obj, '__module__', None) + try: + name = obj.__qualname__ + if not isinstance(name, string_types): # pragma: no cover + # This can happen if the type implements __qualname__ as a property + # or other descriptor in Python 2. + raise Exception('Try __name__') + except Exception: # pragma: no cover + name = obj.__name__ + if not isinstance(name, string_types): + name = '' + + if mod in (None, '__builtin__', 'builtins', 'exceptions'): + p.text(name) + else: + p.text(mod + '.' + name) + + +def _repr_pprint(obj, p, cycle): + """A pprint that just redirects to the normal repr function.""" + # Find newlines and replace them with p.break_() + output = repr(obj) + for idx, output_line in enumerate(output.splitlines()): + if idx: + p.break_() + p.text(output_line) + + +def _function_pprint(obj, p, cycle): + """Base pprint for all functions and builtin functions.""" + name = _safe_getattr(obj, '__qualname__', obj.__name__) + mod = obj.__module__ + if mod and mod not in ('__builtin__', 'builtins', 'exceptions'): + name = mod + '.' + name + p.text('' % name) + + +def _exception_pprint(obj, p, cycle): + """Base pprint for all exceptions.""" + name = getattr(obj.__class__, '__qualname__', obj.__class__.__name__) + if obj.__class__.__module__ not in ('exceptions', 'builtins'): + name = '%s.%s' % (obj.__class__.__module__, name) + step = len(name) + 1 + p.begin_group(step, name + '(') + for idx, arg in enumerate(getattr(obj, 'args', ())): + if idx: + p.text(',') + p.breakable() + p.pretty(arg) + p.end_group(step, ')') + + +#: the exception base +try: + _exception_base = BaseException +except NameError: # pragma: no cover + _exception_base = Exception # type: ignore + + +#: printers for builtin types +_type_pprinters = { + int: _repr_pprint, + float: _repr_pprint, + str: _repr_pprint, + tuple: _seq_pprinter_factory('(', ')', tuple), + list: _seq_pprinter_factory('[', ']', list), + dict: _dict_pprinter_factory('{', '}', dict), + + set: _set_pprinter_factory('{', '}', set), + frozenset: _set_pprinter_factory('frozenset({', '})', frozenset), + super: _super_pprint, + _re_pattern_type: _re_pattern_pprint, + type: _type_pprint, + types.FunctionType: _function_pprint, + types.BuiltinFunctionType: _function_pprint, + types.MethodType: _repr_pprint, + + datetime.datetime: _repr_pprint, + datetime.timedelta: _repr_pprint, + _exception_base: _exception_pprint +} + +try: # pragma: no cover + if types.DictProxyType != dict: # type: ignore + _type_pprinters[types.DictProxyType] = _dict_pprinter_factory( # type: ignore + '') + _type_pprinters[types.ClassType] = _type_pprint # type: ignore + _type_pprinters[types.SliceType] = _repr_pprint # type: ignore +except AttributeError: # Python 3 + _type_pprinters[slice] = _repr_pprint + +try: # pragma: no cover + _type_pprinters[xrange] = _repr_pprint # type: ignore + _type_pprinters[long] = _repr_pprint # type: ignore + _type_pprinters[unicode] = _repr_pprint # type: ignore +except NameError: + _type_pprinters[range] = _repr_pprint + _type_pprinters[bytes] = _repr_pprint + +#: printers for types specified by name +_deferred_type_pprinters = {} # type: ignore + + +def for_type_by_name(type_module, type_name, func): + """Add a pretty printer for a type specified by the module and name of a + type rather than the type object itself.""" + key = (type_module, type_name) + oldfunc = _deferred_type_pprinters.get(key, None) + _deferred_type_pprinters[key] = func + return oldfunc + + +#: printers for the default singletons +_singleton_pprinters = dict.fromkeys(map(id, [None, True, False, Ellipsis, + NotImplemented]), _repr_pprint) + + +def _defaultdict_pprint(obj, p, cycle): + name = obj.__class__.__name__ + with p.group(len(name) + 1, name + '(', ')'): + if cycle: + p.text('...') + else: + p.pretty(obj.default_factory) + p.text(',') + p.breakable() + p.pretty(dict(obj)) + + +def _ordereddict_pprint(obj, p, cycle): + name = obj.__class__.__name__ + with p.group(len(name) + 1, name + '(', ')'): + if cycle: + p.text('...') + elif len(obj): + p.pretty(list(obj.items())) + + +def _deque_pprint(obj, p, cycle): + name = obj.__class__.__name__ + with p.group(len(name) + 1, name + '(', ')'): + if cycle: + p.text('...') + else: + p.pretty(list(obj)) + + +def _counter_pprint(obj, p, cycle): + name = obj.__class__.__name__ + with p.group(len(name) + 1, name + '(', ')'): + if cycle: + p.text('...') + elif len(obj): + p.pretty(dict(obj)) + + +for_type_by_name('collections', 'defaultdict', _defaultdict_pprint) +for_type_by_name('collections', 'OrderedDict', _ordereddict_pprint) +for_type_by_name('ordereddict', 'OrderedDict', _ordereddict_pprint) +for_type_by_name('collections', 'deque', _deque_pprint) +for_type_by_name('collections', 'Counter', _counter_pprint) +for_type_by_name('counter', 'Counter', _counter_pprint) + +for_type_by_name('_collections', 'defaultdict', _defaultdict_pprint) +for_type_by_name('_collections', 'OrderedDict', _ordereddict_pprint) +for_type_by_name('_collections', 'deque', _deque_pprint) +for_type_by_name('_collections', 'Counter', _counter_pprint) diff -Nru python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/version.py python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/version.py --- python-hypothesis-3.44.1/hypothesis-python/src/hypothesis/version.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/src/hypothesis/version.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,21 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +__version_info__ = (3, 71, 11) +__version__ = '.'.join(map(str, __version_info__)) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/common/arguments.py python-hypothesis-3.71.11/hypothesis-python/tests/common/arguments.py --- python-hypothesis-3.44.1/hypothesis-python/tests/common/arguments.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/common/arguments.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,50 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import pytest + +from hypothesis import given +from hypothesis.errors import InvalidArgument + + +def e(a, *args, **kwargs): + return (a, args, kwargs) + + +def e_to_str(elt): + f, args, kwargs = elt + bits = list(map(repr, args)) + bits.extend(sorted('%s=%r' % (k, v) for k, v in kwargs.items())) + return '%s(%s)' % (f.__name__, ', '.join(bits)) + + +def argument_validation_test(bad_args): + @pytest.mark.parametrize( + ('function', 'args', 'kwargs'), bad_args, + ids=list(map(e_to_str, bad_args)) + ) + def test_raise_invalid_argument(function, args, kwargs): + @given(function(*args, **kwargs)) + def test(x): + pass + + with pytest.raises(InvalidArgument): + test() + + return test_raise_invalid_argument diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/common/debug.py python-hypothesis-3.71.11/hypothesis-python/tests/common/debug.py --- python-hypothesis-3.44.1/hypothesis-python/tests/common/debug.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/common/debug.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,113 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from hypothesis import find, given, assume, reject +from hypothesis import settings as Settings +from hypothesis import unlimited +from hypothesis.errors import NoSuchExample, Unsatisfiable +from tests.common.utils import no_shrink + +TIME_INCREMENT = 0.01 + + +class Timeout(BaseException): + pass + + +def minimal( + definition, condition=None, + settings=None, timeout_after=10, random=None +): + settings = Settings( + settings, max_examples=50000, database=None, timeout=unlimited, + ) + + runtime = [] + + if condition is None: + def condition(x): + return True + + def wrapped_condition(x): + if timeout_after is not None: + if runtime: + runtime[0] += TIME_INCREMENT + if runtime[0] >= timeout_after: + raise Timeout() + result = condition(x) + if result and not runtime: + runtime.append(0.0) + return result + + return find( + definition, + wrapped_condition, + settings=settings, + random=random, + ) + + +def find_any( + definition, condition=None, + settings=None, random=None +): + settings = Settings( + settings, + max_examples=10000, phases=no_shrink, database=None, timeout=unlimited + ) + + if condition is None: + def condition(x): + return True + + return find( + definition, + condition, + settings=settings, + random=random, + ) + + +def assert_no_examples(strategy, condition=None): + if condition is None: + def predicate(x): + reject() + else: + def predicate(x): + assume(condition(x)) + + try: + result = find(strategy, predicate, settings=Settings(phases=no_shrink)) + assert False, 'Expected no results but found %r' % (result,) + except (Unsatisfiable, NoSuchExample): + pass + + +def assert_all_examples(strategy, predicate): + """Asserts that all examples of the given strategy match the predicate. + + :param strategy: Hypothesis strategy to check + :param predicate: (callable) Predicate that takes example and returns bool + """ + @given(strategy) + def assert_examples(s): + assert predicate(s), \ + 'Found %r using strategy %s which does not match' % (s, strategy) + + assert_examples() diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/common/__init__.py python-hypothesis-3.71.11/hypothesis-python/tests/common/__init__.py --- python-hypothesis-3.44.1/hypothesis-python/tests/common/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/common/__init__.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,102 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +import sys +from collections import namedtuple + +try: + import pytest +except ImportError: + pytest = None + +from tests.common.debug import TIME_INCREMENT +from hypothesis.strategies import integers, floats, just, one_of, \ + sampled_from, lists, booleans, dictionaries, tuples, \ + frozensets, complex_numbers, sets, text, binary, decimals, fractions, \ + none, randoms, builds, fixed_dictionaries, recursive + + +__all__ = ['standard_types', 'OrderedPair', 'TIME_INCREMENT'] + +OrderedPair = namedtuple('OrderedPair', ('left', 'right')) + + +ordered_pair = integers().flatmap( + lambda right: integers(min_value=0).map( + lambda length: OrderedPair(right - length, right))) + + +def constant_list(strat): + return strat.flatmap( + lambda v: lists(just(v)), + ) + + +ABC = namedtuple('ABC', ('a', 'b', 'c')) + + +def abc(x, y, z): + return builds(ABC, x, y, z) + + +standard_types = [ + lists(none(), max_size=0), tuples(), + sets(none(), max_size=0), frozensets(none(), max_size=0), + fixed_dictionaries({}), + abc(booleans(), booleans(), booleans()), + abc(booleans(), booleans(), integers()), + fixed_dictionaries({'a': integers(), 'b': booleans()}), + dictionaries(booleans(), integers()), + dictionaries(text(), booleans()), + one_of(integers(), tuples(booleans())), + sampled_from(range(10)), + one_of(just('a'), just('b'), just('c')), + sampled_from(('a', 'b', 'c')), + integers(), + integers(min_value=3), + integers(min_value=(-2 ** 32), max_value=(2 ** 64)), + floats(), floats(min_value=-2.0, max_value=3.0), + floats(), floats(min_value=-2.0), + floats(), floats(max_value=-0.0), + floats(), floats(min_value=0.0), + floats(min_value=3.14, max_value=3.14), + text(), binary(), + booleans(), + tuples(booleans(), booleans()), + frozensets(integers()), + sets(frozensets(booleans())), + complex_numbers(), + fractions(), + decimals(), + lists(lists(booleans())), + lists(floats(0.0, 0.0)), + ordered_pair, constant_list(integers()), + integers().filter(lambda x: abs(x) > 100), + floats(min_value=-sys.float_info.max, max_value=sys.float_info.max), + none(), randoms(), + booleans().flatmap(lambda x: booleans() if x else complex_numbers()), + recursive( + base=booleans(), extend=lambda x: lists(x, max_size=3), + max_leaves=10, + ) +] + + +if pytest is not None: + def parametrize(args, values): + return pytest.mark.parametrize( + args, values, ids=list(map(repr, values))) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/common/setup.py python-hypothesis-3.71.11/hypothesis-python/tests/common/setup.py --- python-hypothesis-3.44.1/hypothesis-python/tests/common/setup.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/common/setup.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,84 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import os +from tempfile import mkdtemp +from warnings import filterwarnings + +from hypothesis import Verbosity, settings, unlimited +from hypothesis._settings import not_set +from hypothesis.configuration import set_hypothesis_home_dir +from hypothesis.internal.charmap import charmap, charmap_file +from hypothesis.internal.coverage import IN_COVERAGE_TESTS + + +def run(): + filterwarnings('error') + filterwarnings('ignore', category=ImportWarning) + filterwarnings('ignore', category=FutureWarning, module='pandas._version') + + # See https://github.com/numpy/numpy/pull/432 + filterwarnings('ignore', message='numpy.dtype size changed') + filterwarnings('ignore', message='numpy.ufunc size changed') + + # Imported by Pandas in version 1.9, but fixed in later versions. + filterwarnings( + 'ignore', + message='Importing from numpy.testing.decorators is deprecated' + ) + filterwarnings( + 'ignore', + message='Importing from numpy.testing.nosetester is deprecated' + ) + + new_home = mkdtemp() + set_hypothesis_home_dir(new_home) + assert settings.default.database.path.startswith(new_home) + + charmap() + assert os.path.exists(charmap_file()), charmap_file() + assert isinstance(settings, type) + + # We do a smoke test here before we mess around with settings. + x = settings() + + import hypothesis._settings as settings_module + + for s in settings_module.all_settings.values(): + v = getattr(x, s.name) + # Check if it has a dynamically defined default and if so skip + # comparison. + if getattr(settings, s.name).show_default: + assert v == s.default, '%r == x.%s != s.%s == %r' % ( + v, s.name, s.name, s.default, + ) + + settings.register_profile('default', settings( + max_examples=10 if IN_COVERAGE_TESTS else not_set, + timeout=unlimited, + )) + + settings.register_profile( + 'speedy', settings( + max_examples=5, + )) + + settings.register_profile('debug', settings(verbosity=Verbosity.debug)) + + settings.load_profile(os.getenv('HYPOTHESIS_PROFILE', 'default')) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/common/strategies.py python-hypothesis-3.71.11/hypothesis-python/tests/common/strategies.py --- python-hypothesis-3.44.1/hypothesis-python/tests/common/strategies.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/common/strategies.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,62 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import time + +from hypothesis.searchstrategy import SearchStrategy +from hypothesis.internal.compat import hbytes, hrange + + +class _Slow(SearchStrategy): + def do_draw(self, data): + time.sleep(1.0) + data.draw_bytes(2) + return None + + +SLOW = _Slow() + + +class HardToShrink(SearchStrategy): + def __init__(self): + self.__last = None + self.accepted = set() + + def do_draw(self, data): + x = hbytes([ + data.draw_bits(8) for _ in range(100) + ]) + if x in self.accepted: + return True + ls = self.__last + if ls is None: + if all(x): + self.__last = x + self.accepted.add(x) + return True + else: + return False + diffs = [i for i in hrange(len(x)) if x[i] != ls[i]] + if len(diffs) == 1: + i = diffs[0] + if x[i] + 1 == ls[i]: + self.__last = x + self.accepted.add(x) + return True + return False diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/common/utils.py python-hypothesis-3.71.11/hypothesis-python/tests/common/utils.py --- python-hypothesis-3.44.1/hypothesis-python/tests/common/utils.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/common/utils.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,116 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import sys +import traceback +import contextlib +from io import BytesIO, StringIO + +from hypothesis.errors import HypothesisDeprecationWarning +from hypothesis._settings import Phase +from hypothesis.reporting import default, with_reporter +from hypothesis.internal.compat import PY2 +from hypothesis.internal.reflection import proxies + +no_shrink = tuple(set(Phase) - {Phase.shrink}) + + +@contextlib.contextmanager +def capture_out(): + old_out = sys.stdout + try: + new_out = BytesIO() if PY2 else StringIO() + sys.stdout = new_out + with with_reporter(default): + yield new_out + finally: + sys.stdout = old_out + + +class ExcInfo(object): + pass + + +@contextlib.contextmanager +def raises(exctype): + e = ExcInfo() + try: + yield e + assert False, "Expected to raise an exception but didn't" + except exctype as err: + traceback.print_exc() + e.value = err + return + + +def fails_with(e): + def accepts(f): + @proxies(f) + def inverted_test(*arguments, **kwargs): + with raises(e): + f(*arguments, **kwargs) + return inverted_test + return accepts + + +fails = fails_with(AssertionError) + + +class NotDeprecated(Exception): + pass + + +@contextlib.contextmanager +def validate_deprecation(): + import warnings + + try: + warnings.simplefilter('always', HypothesisDeprecationWarning) + with warnings.catch_warnings(record=True) as w: + yield + finally: + warnings.simplefilter('error', HypothesisDeprecationWarning) + if not any( + e.category == HypothesisDeprecationWarning for e in w + ): + raise NotDeprecated( + 'Expected to get a deprecation warning but got %r' % ( + [e.category for e in w],)) + + +def checks_deprecated_behaviour(func): + """A decorator for testing deprecated behaviour.""" + @proxies(func) + def _inner(*args, **kwargs): + with validate_deprecation(): + return func(*args, **kwargs) + return _inner + + +def all_values(db): + return set(v for vs in db.data.values() for v in vs) + + +def non_covering_examples(database): + return { + v + for k, vs in database.data.items() + if not k.endswith(b'.coverage') + for v in vs + } diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/conftest.py python-hypothesis-3.71.11/hypothesis-python/tests/conftest.py --- python-hypothesis-3.44.1/hypothesis-python/tests/conftest.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/conftest.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,76 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import gc +import sys +import time as time_module + +import pytest + +from tests.common import TIME_INCREMENT +from tests.common.setup import run + +run() + + +def pytest_configure(config): + config.addinivalue_line( + 'markers', + 'slow: pandas expects this marker to exist.') + + +@pytest.fixture(scope=u'function', autouse=True) +def gc_before_each_test(): + gc.collect() + + +@pytest.fixture(scope=u'function', autouse=True) +def consistently_increment_time(monkeypatch): + """Rather than rely on real system time we monkey patch time.time so that + it passes at a consistent rate between calls. + + The reason for this is that when these tests run on travis, performance is + extremely variable and the VM the tests are on might go to sleep for a bit, + introducing arbitrary delays. This can cause a number of tests to fail + flakily. + + Replacing time with a fake version under our control avoids this problem. + """ + frozen = [False] + + current_time = [time_module.time()] + + def time(): + if not frozen[0]: + current_time[0] += TIME_INCREMENT + return current_time[0] + + def sleep(naptime): + current_time[0] += naptime + + def freeze(): + frozen[0] = True + + monkeypatch.setattr(time_module, 'time', time) + try: + monkeypatch.setattr(time_module, 'monotonic', time) + except AttributeError: + assert sys.version_info[0] == 2 + monkeypatch.setattr(time_module, 'sleep', sleep) + monkeypatch.setattr(time_module, 'freeze', freeze, raising=False) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/__init__.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/__init__.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/__init__.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,16 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_arbitrary_data.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_arbitrary_data.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_arbitrary_data.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_arbitrary_data.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,106 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import pytest + +from hypothesis import find, given, reporting +from hypothesis import strategies as st +from hypothesis.errors import InvalidArgument +from tests.common.utils import raises, capture_out + + +@given(st.integers(), st.data()) +def test_conditional_draw(x, data): + y = data.draw(st.integers(min_value=x)) + assert y >= x + + +def test_prints_on_failure(): + @given(st.data()) + def test(data): + x = data.draw(st.lists(st.integers(0, 10), min_size=2)) + y = data.draw(st.sampled_from(x)) + x.remove(y) + if y in x: + raise ValueError() + + with raises(ValueError): + with capture_out() as out: + with reporting.with_reporter(reporting.default): + test() + result = out.getvalue() + assert 'Draw 1: [0, 0]' in result + assert 'Draw 2: 0' in result + + +def test_prints_labels_if_given_on_failure(): + @given(st.data()) + def test(data): + x = data.draw(st.lists(st.integers(0, 10), min_size=2), + label='Some numbers') + y = data.draw(st.sampled_from(x), label='A number') + assert y in x + x.remove(y) + assert y not in x + + with raises(AssertionError): + with capture_out() as out: + with reporting.with_reporter(reporting.default): + test() + result = out.getvalue() + assert 'Draw 1 (Some numbers): [0, 0]' in result + assert 'Draw 2 (A number): 0' in result + + +def test_given_twice_is_same(): + @given(st.data(), st.data()) + def test(data1, data2): + data1.draw(st.integers()) + data2.draw(st.integers()) + raise ValueError() + + with raises(ValueError): + with capture_out() as out: + with reporting.with_reporter(reporting.default): + test() + result = out.getvalue() + assert 'Draw 1: 0' in result + assert 'Draw 2: 0' in result + + +def test_errors_when_used_in_find(): + with raises(InvalidArgument): + find(st.data(), lambda x: x.draw(st.booleans())) + + +@pytest.mark.parametrize('f', [ + 'filter', 'map', 'flatmap', +]) +def test_errors_when_normal_strategy_functions_are_used(f): + with raises(InvalidArgument): + getattr(st.data(), f)(lambda x: 1) + + +def test_errors_when_asked_for_example(): + with raises(InvalidArgument): + st.data().example() + + +def test_nice_repr(): + assert repr(st.data()) == 'data()' diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_attrs_inference.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_attrs_inference.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_attrs_inference.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_attrs_inference.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,91 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import attr +import pytest + +import hypothesis.strategies as st +from hypothesis import given, infer +from hypothesis.errors import ResolutionFailed + + +@attr.s +class Inferrables(object): + type_ = attr.ib(type=int) + type_converter = attr.ib(converter=bool) + validator_type = attr.ib(validator=attr.validators.instance_of(str)) + validator_type_tuple = attr.ib( + validator=attr.validators.instance_of((str, int)) + ) + validator_type_multiple = attr.ib(validator=[ + attr.validators.instance_of(str), + attr.validators.instance_of((str, int, bool)), + ]) + validator_type_has_overlap = attr.ib(validator=[ + attr.validators.instance_of(str), + attr.validators.instance_of((str, list)), + attr.validators.instance_of(object), + ]) + validator_optional = attr.ib( + validator=attr.validators.optional(lambda inst, atrib, val: float(val)) + ) + validator_in = attr.ib(validator=attr.validators.in_([1, 2, 3])) + validator_in_multiple = attr.ib(validator=[ + attr.validators.in_(list(range(100))), + attr.validators.in_([1, -1]), + ]) + validator_in_multiple_strings = attr.ib(validator=[ + attr.validators.in_('abcd'), + attr.validators.in_(['ab', 'cd']), + ]) + has_default = attr.ib(default=0) + has_default_factory = attr.ib(default=attr.Factory(list)) + has_default_factory_takes_self = attr.ib( # uninferrable but has default + default=attr.Factory(lambda _: list(), takes_self=True)) + + +@attr.s +class Required(object): + a = attr.ib() + + +@attr.s +class UnhelpfulConverter(object): + a = attr.ib(converter=lambda x: x) + + +@given(st.builds(Inferrables, has_default=infer, has_default_factory=infer)) +def test_attrs_inference_builds(c): + pass + + +@given(st.from_type(Inferrables)) +def test_attrs_inference_from_type(c): + pass + + +@pytest.mark.parametrize('c', [Required, UnhelpfulConverter]) +def test_cannot_infer(c): + with pytest.raises(ResolutionFailed): + st.builds(c).example() + + +def test_cannot_infer_takes_self(): + with pytest.raises(ResolutionFailed): + st.builds(Inferrables, has_default_factory_takes_self=infer).example() diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_cache_implementation.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_cache_implementation.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_cache_implementation.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_cache_implementation.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,195 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from random import Random + +import pytest + +import hypothesis.strategies as st +from hypothesis import HealthCheck, note, given, assume, example, settings +from hypothesis.internal.cache import GenericCache, LRUReusedCache + + +class LRUCache(GenericCache): + __slots__ = ('__tick',) + + def __init__(self, max_size): + super(LRUCache, self).__init__(max_size) + self.__tick = 0 + + def new_entry(self, key, value): + return self.tick() + + def on_access(self, key, value, score): + return self.tick() + + def tick(self): + self.__tick += 1 + return self.__tick + + +class LFUCache(GenericCache): + def new_entry(self, key, value): + return 1 + + def on_access(self, key, value, score): + return score + 1 + + +@st.composite +def write_pattern(draw, min_size=0): + keys = draw(st.lists(st.integers(0, 1000), unique=True, min_size=1)) + values = draw(st.lists(st.integers(), unique=True, min_size=1)) + return draw( + st.lists(st.tuples(st.sampled_from(keys), st.sampled_from(values)), + min_size=min_size)) + + +class ValueScored(GenericCache): + def new_entry(self, key, value): + return value + + +class RandomCache(GenericCache): + def __init__(self, max_size): + super(RandomCache, self).__init__(max_size) + self.random = Random(0) + + def new_entry(self, key, value): + return self.random.random() + + def on_access(self, key, value, score): + return self.random.random() + + +@pytest.mark.parametrize( + 'implementation', [ + LRUCache, LFUCache, LRUReusedCache, ValueScored, RandomCache + ] +) +@example(writes=[(0, 0), (3, 0), (1, 0), (2, 0), (2, 0), (1, 0)], size=4) +@example(writes=[(0, 0)], size=1) +@example(writes=[(1, 0), (2, 0), (0, -1), (1, 0)], size=3) +@given(write_pattern(), st.integers(1, 10)) +def test_behaves_like_a_dict_with_losses(implementation, writes, size): + model = {} + target = implementation(max_size=size) + + for k, v in writes: + try: + assert model[k] == target[k] + except KeyError: + pass + model[k] = v + target[k] = v + target.check_valid() + assert target[k] == v + for r, s in model.items(): + try: + assert s == target[r] + except KeyError: + pass + assert len(target) <= min(len(model), size) + + +@settings(suppress_health_check=[HealthCheck.too_slow], deadline=None) +@given(write_pattern(min_size=2), st.data()) +def test_always_evicts_the_lowest_scoring_value(writes, data): + scores = {} + + n_keys = len({k for k, _ in writes}) + + assume(n_keys > 1) + + size = data.draw(st.integers(1, n_keys - 1)) + + evicted = set() + + def new_score(key): + scores[key] = data.draw( + st.integers(0, 1000), label='scores[%r]' % (key,)) + return scores[key] + + last_entry = [None] + + class Cache(GenericCache): + def new_entry(self, key, value): + last_entry[0] = key + evicted.discard(key) + assert key not in scores + return new_score(key) + + def on_access(self, key, value, score): + assert key in scores + return new_score(key) + + def on_evict(self, key, value, score): + note('Evicted %r' % (key,)) + assert score == scores[key] + del scores[key] + if len(scores) > 1: + assert score <= min( + v for k, v in scores.items() + if k != last_entry[0] + ) + evicted.add(key) + + target = Cache(max_size=size) + model = {} + + for k, v in writes: + target[k] = v + model[k] = v + + assert evicted + assert len(evicted) + len(target) == len(model) + assert len(scores) == len(target) + + for k, v in model.items(): + try: + assert target[k] == v + assert k not in evicted + except KeyError: + assert k in evicted + + +def test_basic_access(): + cache = ValueScored(max_size=2) + cache[1] = 0 + cache[1] = 0 + cache[0] = 1 + cache[2] = 0 + assert cache[2] == 0 + assert cache[0] == 1 + assert len(cache) == 2 + + +def test_can_clear_a_cache(): + x = ValueScored(1) + x[0] = 1 + assert len(x) == 1 + x.clear() + assert len(x) == 0 + + +def test_max_size_cache_ignores(): + x = ValueScored(0) + x[0] = 1 + with pytest.raises(KeyError): + x[0] diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_caching.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_caching.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_caching.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_caching.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,56 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import pytest + +import hypothesis.strategies as st +from hypothesis.errors import InvalidArgument + + +def test_no_args(): + assert st.text() is st.text() + + +def test_tuple_lengths(): + assert st.tuples(st.integers()) is st.tuples(st.integers()) + assert st.tuples(st.integers()) is not st.tuples( + st.integers(), st.integers()) + + +def test_values(): + assert st.integers() is not st.integers(min_value=1) + + +def test_alphabet_key(): + assert st.text(alphabet='abcs') is st.text(alphabet='abcs') + + +def test_does_not_error_on_unhashable_posarg(): + st.text(['a', 'b', 'c']) + + +def test_does_not_error_on_unhashable_kwarg(): + with pytest.raises(InvalidArgument): + st.builds(lambda alphabet: 1, alphabet=['a', 'b', 'c']).validate() + + +def test_caches_floats_sensitively(): + assert st.floats(min_value=0.0) is st.floats(min_value=0.0) + assert st.floats(min_value=0.0) is not st.floats(min_value=0) + assert st.floats(min_value=0.0) is not st.floats(min_value=-0.0) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_cathetus.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_cathetus.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_cathetus.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_cathetus.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,153 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import sys +import math +from sys import float_info + +import pytest + +from hypothesis.internal.cathetus import cathetus + + +def test_cathetus_subnormal_underflow(): + u = sys.float_info.min * sys.float_info.epsilon + h = 5 * u + a = 4 * u + assert cathetus(h, a) == 3 * u + + +def test_cathetus_simple_underflow(): + a = sys.float_info.min + h = a * math.sqrt(2) + b = cathetus(h, a) + assert b > 0, ( + 'expecting positive cathetus(%g, %g), got %g' % (h, a, b) + ) + + +def test_cathetus_huge_no_overflow(): + h = sys.float_info.max + a = h / math.sqrt(2) + b = cathetus(h, a) + assert not (math.isinf(b) or math.isnan(b)), ( + 'expecting finite cathetus(%g, %g), got %g' % (h, a, b) + ) + + +def test_cathetus_large_no_overflow(): + h = sys.float_info.max / 3 + a = h / math.sqrt(2) + b = cathetus(h, a) + assert not (math.isinf(b) or math.isnan(b)), ( + 'expecting finite cathetus(%g, %g), got %g' % (h, a, b) + ) + + +@pytest.mark.parametrize('h,a', [ + # NaN hypot + (float(u'nan'), 3), + (float(u'nan'), 0), + (float(u'nan'), float(u'inf')), + (float(u'nan'), float(u'nan')), + # Infeasible + (2, 3), + (2, -3), + (2, float(u'inf')), + (2, float(u'nan')), + # Surprisingly consistent with c99 hypot() + (float(u'inf'), float(u'inf')), +]) +def test_cathetus_nan(h, a): + assert math.isnan(cathetus(h, a)) + + +@pytest.mark.parametrize('h,a', [ + (float(u'inf'), 3), + (float(u'inf'), -3), + (float(u'inf'), 0), + (float(u'inf'), float(u'nan')), +]) +def test_cathetus_infinite(h, a): + assert math.isinf(cathetus(h, a)) + + +@pytest.mark.parametrize('h,a,b', [ + (-5, 4, 3), + (5, -4, 3), + (-5, -4, 3), + (0, 0, 0), + (1, 0, 1), +]) +def test_cathetus_signs(h, a, b): + assert abs(cathetus(h, a) - b) <= abs(b) * float_info.epsilon + + +@pytest.mark.parametrize('a,b,h', [ + (3, 4, 5), + (5, 12, 13), + (8, 15, 17), + (7, 24, 25), + (20, 21, 29), + (12, 35, 37), + (9, 40, 41), + (28, 45, 53), + (11, 60, 61), + (16, 63, 65), + (33, 56, 65), + (48, 55, 73), + (13, 84, 85), + (36, 77, 85), + (39, 80, 89), + (65, 72, 97), + (20, 99, 101), + (60, 91, 109), + (15, 112, 113), + (44, 117, 125), + (88, 105, 137), + (17, 144, 145), + (24, 143, 145), + (51, 140, 149), + (85, 132, 157), + (119, 120, 169), + (52, 165, 173), + (19, 180, 181), + (57, 176, 185), + (104, 153, 185), + (95, 168, 193), + (28, 195, 197), + (84, 187, 205), + (133, 156, 205), + (21, 220, 221), + (140, 171, 221), + (60, 221, 229), + (105, 208, 233), + (120, 209, 241), + (32, 255, 257), + (23, 264, 265), + (96, 247, 265), + (69, 260, 269), + (115, 252, 277), + (160, 231, 281), + (161, 240, 289), + (68, 285, 293), +]) +def test_pythagorean_triples(a, b, h): + assert abs(math.hypot(a, b) - h) <= abs(h) * float_info.epsilon + assert abs(cathetus(h, a) - b) <= abs(b) * float_info.epsilon diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_charmap.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_charmap.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_charmap.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_charmap.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,190 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import os +import sys +import tempfile +import unicodedata + +import hypothesis.strategies as st +import hypothesis.internal.charmap as cm +from hypothesis import given, assume +from hypothesis.internal.compat import hunichr + + +def test_charmap_contains_all_unicode(): + n = 0 + for vs in cm.charmap().values(): + for u, v in vs: + n += (v - u + 1) + assert n == sys.maxunicode + 1 + + +def test_charmap_has_right_categories(): + for cat, intervals in cm.charmap().items(): + for u, v in intervals: + for i in range(u, v + 1): + real = unicodedata.category(hunichr(i)) + assert real == cat, \ + '%d is %s but reported in %s' % (i, real, cat) + + +def assert_valid_range_list(ls): + for u, v in ls: + assert u <= v + for i in range(len(ls) - 1): + assert ls[i] <= ls[i + 1] + assert ls[i][-1] < ls[i + 1][0] + + +@given( + st.sets(st.sampled_from(cm.categories())), + st.sets(st.sampled_from(cm.categories())) | st.none(), +) +def test_query_matches_categories(exclude, include): + values = cm.query(exclude, include) + assert_valid_range_list(values) + for u, v in values: + for i in (u, v, (u + v) // 2): + cat = unicodedata.category(hunichr(i)) + if include is not None: + assert cat in include + assert cat not in exclude + + +@given( + st.sets(st.sampled_from(cm.categories())), + st.sets(st.sampled_from(cm.categories())) | st.none(), + st.integers(0, sys.maxunicode), st.integers(0, sys.maxunicode), +) +def test_query_matches_categories_codepoints(exclude, include, m1, m2): + m1, m2 = sorted((m1, m2)) + values = cm.query(exclude, include, min_codepoint=m1, max_codepoint=m2) + assert_valid_range_list(values) + for u, v in values: + assert m1 <= u + assert v <= m2 + + +@given(st.sampled_from(cm.categories()), st.integers(0, sys.maxunicode)) +def test_exclude_only_excludes_from_that_category(cat, i): + c = hunichr(i) + assume(unicodedata.category(c) != cat) + intervals = cm.query(exclude_categories=(cat,)) + assert any(a <= i <= b for a, b in intervals) + + +def test_reload_charmap(): + x = cm.charmap() + assert x is cm.charmap() + cm._charmap = None + y = cm.charmap() + assert x is not y + assert x == y + + +def test_recreate_charmap(): + x = cm.charmap() + assert x is cm.charmap() + cm._charmap = None + os.unlink(cm.charmap_file()) + y = cm.charmap() + assert x is not y + assert x == y + + +def test_union_empty(): + assert cm._union_intervals([], []) == () + assert cm._union_intervals([], [[1, 2]]) == ((1, 2),) + assert cm._union_intervals([[1, 2]], []) == ((1, 2),) + + +def test_union_handles_totally_overlapped_gap(): + # < xx > Imagine the intervals x and y as bit strings. + # | The bit at position n is set if n falls inside that interval. + # = In this model _union_intervals() performs bit-wise or. + assert cm._union_intervals([[2, 3]], [[1, 2], [4, 5]]) == ((1, 5),) + + +def test_union_handles_partially_overlapped_gap(): + # < x > Imagine the intervals x and y as bit strings. + # | The bit at position n is set if n falls inside that interval. + # = In this model _union_intervals() performs bit-wise or. + assert cm._union_intervals([[3, 3]], [[1, 2], [5, 5]]) == ((1, 3), (5, 5)) + + +def test_successive_union(): + x = [] + for v in cm.charmap().values(): + x = cm._union_intervals(x, v) + assert x == ((0, sys.maxunicode),) + + +def test_can_handle_race_between_exist_and_create(monkeypatch): + x = cm.charmap() + cm._charmap = None + monkeypatch.setattr(os.path, 'exists', lambda p: False) + y = cm.charmap() + assert x is not y + assert x == y + + +def test_exception_in_write_does_not_lead_to_broken_charmap(monkeypatch): + def broken(*args, **kwargs): + raise ValueError() + + cm._charmap = None + monkeypatch.setattr(os.path, 'exists', lambda p: False) + monkeypatch.setattr(os, 'rename', broken) + + cm.charmap() + cm.charmap() + + +def test_regenerate_broken_charmap_file(): + cm.charmap() + file_loc = cm.charmap_file() + + with open(file_loc, 'wb'): + pass + + cm._charmap = None + cm.charmap() + + +def test_exclude_characters_are_included_in_key(): + assert cm.query() != cm.query(exclude_characters='0') + + +def test_error_writing_charmap_file_is_suppressed(monkeypatch): + def broken_mkstemp(dir): + raise RuntimeError() + + monkeypatch.setattr(tempfile, 'mkstemp', broken_mkstemp) + + try: + # Cache the charmap to avoid a performance hit the next time + # somebody tries to use it. + saved = cm._charmap + cm._charmap = None + os.unlink(cm.charmap_file()) + + cm.charmap() + finally: + cm._charmap = saved diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_choices.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_choices.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_choices.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_choices.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,60 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import pytest + +import hypothesis.strategies as st +from hypothesis import find, given +from hypothesis.errors import InvalidArgument +from tests.common.utils import checks_deprecated_behaviour + + +@checks_deprecated_behaviour +def test_exhaustion(): + @given(st.lists(st.text(), min_size=10), st.choices()) + def test(ls, choice): + while ls: + s = choice(ls) + assert s in ls + ls.remove(s) + test() + + +@checks_deprecated_behaviour +def test_choice_is_shared(): + @given(st.choices(), st.choices()) + def test(choice1, choice2): + assert choice1 is choice2 + test() + + +@checks_deprecated_behaviour +def test_cannot_use_choices_within_find(): + with pytest.raises(InvalidArgument): + find(st.choices(), lambda c: True) + + +@checks_deprecated_behaviour +def test_fails_to_draw_from_empty_sequence(): + @given(st.choices()) + def test(choice): + choice([]) + + with pytest.raises(IndexError): + test() diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_complex_numbers.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_complex_numbers.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_complex_numbers.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_complex_numbers.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,127 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import sys +import math + +import hypothesis.strategies as st +from hypothesis import given, assume, reject +from tests.common.debug import minimal +from hypothesis.strategies import complex_numbers + + +def test_minimal(): + assert minimal(complex_numbers(), lambda x: True) == 0 + + +def test_minimal_nonzero_real(): + assert minimal(complex_numbers(), lambda x: x.real != 0) == 1 + + +def test_minimal_nonzero_imaginary(): + assert minimal(complex_numbers(), lambda x: x.imag != 0) == 1j + + +def test_minimal_quadrant1(): + assert minimal( + complex_numbers(), + lambda x: x.imag > 0 and x.real > 0 + ) == 1 + 1j + + +def test_minimal_quadrant2(): + assert minimal( + complex_numbers(), + lambda x: x.imag > 0 and x.real < 0 + ) == -1 + 1j + + +def test_minimal_quadrant3(): + assert minimal( + complex_numbers(), + lambda x: x.imag < 0 and x.real < 0 + ) == -1 - 1j + + +def test_minimal_quadrant4(): + assert minimal( + complex_numbers(), + lambda x: x.imag < 0 and x.real > 0 + ) == 1 - 1j + + +@given(st.data(), st.integers(-5, 5).map(lambda x: 10 ** x)) +def test_max_magnitude_respected(data, mag): + c = data.draw(complex_numbers(max_magnitude=mag)) + assert abs(c) <= mag * (1 + sys.float_info.epsilon) + + +@given(complex_numbers(max_magnitude=0)) +def test_max_magnitude_zero(val): + assert val == 0 + + +@given(st.data(), st.integers(-5, 5).map(lambda x: 10 ** x)) +def test_min_magnitude_respected(data, mag): + c = data.draw(complex_numbers(min_magnitude=mag)) + assert ( + abs(c.real) >= mag or + abs(c.imag) >= mag or + abs(c) >= mag * (1 - sys.float_info.epsilon) + ) + + +def test_minimal_min_magnitude_zero(): + assert minimal( + complex_numbers(min_magnitude=0), + lambda x: True + ) == 0 + + +def test_minimal_min_magnitude_none(): + assert minimal( + complex_numbers(min_magnitude=None), + lambda x: True + ) == 0 + + +def test_minimal_min_magnitude_positive(): + assert minimal( + complex_numbers(min_magnitude=0.5), + lambda x: True + ) in (0.5, 1) + + +def test_minimal_minmax_magnitude(): + assert minimal( + complex_numbers(min_magnitude=0.5, max_magnitude=1.5), + lambda x: True + ) in (0.5, 1) + + +@given(st.data(), st.floats(0, allow_infinity=False, allow_nan=False)) +def test_minmax_magnitude_equal(data, mag): + val = data.draw(st.complex_numbers(min_magnitude=mag, max_magnitude=mag)) + try: + assume(abs(val) < float('inf')) + assert math.isclose(abs(val), mag) + except OverflowError: + reject() + except AttributeError: + pass # Python 2.7.3 does not have math.isclose diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_composite.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_composite.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_composite.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_composite.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,137 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import pytest +from flaky import flaky + +import hypothesis.strategies as st +from hypothesis import given, assume +from hypothesis.errors import InvalidArgument +from tests.common.debug import minimal +from hypothesis.internal.compat import hrange + + +@st.composite +def badly_draw_lists(draw, m=0): + length = draw(st.integers(m, m + 10)) + return [ + draw(st.integers()) for _ in hrange(length) + ] + + +def test_simplify_draws(): + assert minimal(badly_draw_lists(), lambda x: len(x) >= 3) == [0] * 3 + + +def test_can_pass_through_arguments(): + assert minimal(badly_draw_lists(5), lambda x: True) == [0] * 5 + assert minimal(badly_draw_lists(m=6), lambda x: True) == [0] * 6 + + +@st.composite +def draw_ordered_with_assume(draw): + x = draw(st.floats()) + y = draw(st.floats()) + assume(x < y) + return (x, y) + + +@given(draw_ordered_with_assume()) +def test_can_assume_in_draw(xy): + assert xy[0] < xy[1] + + +def test_uses_definitions_for_reprs(): + assert repr(badly_draw_lists()) == 'badly_draw_lists()' + assert repr(badly_draw_lists(1)) == 'badly_draw_lists(m=1)' + assert repr(badly_draw_lists(m=1)) == 'badly_draw_lists(m=1)' + + +def test_errors_given_default_for_draw(): + with pytest.raises(InvalidArgument): + @st.composite + def foo(x=None): + pass + + +def test_errors_given_function_of_no_arguments(): + with pytest.raises(InvalidArgument): + @st.composite + def foo(): + pass + + +def test_errors_given_kwargs_only(): + with pytest.raises(InvalidArgument): + @st.composite + def foo(**kwargs): + pass + + +def test_can_use_pure_args(): + @st.composite + def stuff(*args): + return args[0](st.sampled_from(args[1:])) + assert minimal(stuff(1, 2, 3, 4, 5), lambda x: True) == 1 + + +def test_composite_of_lists(): + @st.composite + def f(draw): + return draw(st.integers()) + draw(st.integers()) + + assert minimal(st.lists(f()), lambda x: len(x) >= 10) == [0] * 10 + + +@flaky(min_passes=3, max_runs=5) +def test_can_shrink_matrices_with_length_param(): + @st.composite + def matrix(draw): + rows = draw(st.integers(1, 10)) + columns = draw(st.integers(1, 10)) + return [ + [draw(st.integers(0, 10000)) for _ in range(columns)] + for _ in range(rows) + ] + + def transpose(m): + return [[row[i] for row in m] for i in range(len(m[0]))] + + def is_square(m): + return len(m) == len(m[0]) + + value = minimal(matrix(), lambda m: is_square(m) and transpose(m) != m) + assert len(value) == 2 + assert len(value[0]) == 2 + assert sorted(value[0] + value[1]) == [0, 0, 0, 1] + + +class MyList(list): + pass + + +@given(st.data(), st.lists(st.integers()).map(MyList)) +def test_does_not_change_arguments(data, ls): + # regression test for issue #1017 or other argument mutation + @st.composite + def strat(draw, arg): + return arg + + ex = data.draw(strat(ls)) + assert ex is ls diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_conjecture_engine.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_conjecture_engine.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_conjecture_engine.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_conjecture_engine.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,1834 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import re +import time +import itertools +from random import Random +from random import seed as seed_random + +import attr +import pytest + +import hypothesis.internal.conjecture.engine as engine_module +from hypothesis import Phase, Verbosity, HealthCheck, settings, unlimited +from hypothesis.errors import FailedHealthCheck +from tests.common.utils import no_shrink, checks_deprecated_behaviour +from hypothesis.database import ExampleDatabase, InMemoryExampleDatabase +from tests.common.strategies import SLOW, HardToShrink +from hypothesis.internal.compat import hbytes, hrange, int_from_bytes +from hypothesis.internal.entropy import deterministic_PRNG +from hypothesis.internal.conjecture.data import MAX_DEPTH, Status, \ + ConjectureData +from hypothesis.internal.conjecture.utils import Sampler, \ + calc_label_from_name +from hypothesis.internal.conjecture.engine import Shrinker, ExitReason, \ + RunIsComplete, TargetSelector, ConjectureRunner, PassClassification, \ + sort_key, block_program + +SOME_LABEL = calc_label_from_name('some label') + + +def run_to_buffer(f): + with deterministic_PRNG(): + runner = ConjectureRunner(f, settings=settings( + max_examples=5000, buffer_size=1024, + database=None, suppress_health_check=HealthCheck.all(), + )) + runner.run() + assert runner.interesting_examples + last_data, = runner.interesting_examples.values() + return hbytes(last_data.buffer) + + +def test_can_index_results(): + @run_to_buffer + def f(data): + data.draw_bytes(5) + data.mark_interesting() + assert f.index(0) == 0 + assert f.count(0) == 5 + + +def test_non_cloneable_intervals(): + @run_to_buffer + def x(data): + data.draw_bytes(10) + data.draw_bytes(9) + data.mark_interesting() + assert x == hbytes(19) + + +def test_duplicate_buffers(): + @run_to_buffer + def x(data): + t = data.draw_bytes(10) + if not any(t): + data.mark_invalid() + s = data.draw_bytes(10) + if s == t: + data.mark_interesting() + assert x == hbytes([0] * 9 + [1]) * 2 + + +def test_deletable_draws(): + @run_to_buffer + def x(data): + while True: + x = data.draw_bytes(2) + if x[0] == 255: + data.mark_interesting() + assert x == hbytes([255, 0]) + + +def zero_dist(random, n): + return hbytes(n) + + +def test_can_load_data_from_a_corpus(): + key = b'hi there' + db = ExampleDatabase() + value = b'=\xc3\xe4l\x81\xe1\xc2H\xc9\xfb\x1a\xb6bM\xa8\x7f' + db.save(key, value) + + def f(data): + if data.draw_bytes(len(value)) == value: + data.mark_interesting() + runner = ConjectureRunner( + f, settings=settings(database=db), database_key=key) + runner.run() + last_data, = runner.interesting_examples.values() + assert last_data.buffer == value + assert len(list(db.fetch(key))) == 1 + + +def slow_shrinker(): + strat = HardToShrink() + + def accept(data): + if data.draw(strat): + data.mark_interesting() + return accept + + +@pytest.mark.parametrize('n', [1, 5]) +def test_terminates_shrinks(n, monkeypatch): + from hypothesis.internal.conjecture import engine + db = InMemoryExampleDatabase() + + def generate_new_examples(self): + def draw_bytes(data, n): + return hbytes([255] * n) + + self.test_function(ConjectureData( + draw_bytes=draw_bytes, max_length=self.settings.buffer_size)) + + monkeypatch.setattr( + ConjectureRunner, 'generate_new_examples', generate_new_examples) + monkeypatch.setattr(engine, 'MAX_SHRINKS', n) + + runner = ConjectureRunner(slow_shrinker(), settings=settings( + max_examples=5000, database=db, timeout=unlimited, + ), random=Random(0), database_key=b'key') + runner.run() + last_data, = runner.interesting_examples.values() + assert last_data.status == Status.INTERESTING + assert runner.shrinks == n + in_db = set(db.data[runner.secondary_key]) + assert len(in_db) == n + + +def test_detects_flakiness(): + failed_once = [False] + count = [0] + + def tf(data): + data.draw_bytes(1) + count[0] += 1 + if not failed_once[0]: + failed_once[0] = True + data.mark_interesting() + runner = ConjectureRunner(tf) + runner.run() + assert count == [2] + + +def test_variadic_draw(): + def draw_list(data): + result = [] + while True: + data.start_example(SOME_LABEL) + d = data.draw_bytes(1)[0] & 7 + if d: + result.append(data.draw_bytes(d)) + data.stop_example() + if not d: + break + return result + + @run_to_buffer + def b(data): + if any(all(d) for d in draw_list(data)): + data.mark_interesting() + ls = draw_list(ConjectureData.for_buffer(b)) + assert len(ls) == 1 + assert len(ls[0]) == 1 + + +def test_draw_to_overrun(): + @run_to_buffer + def x(data): + d = (data.draw_bytes(1)[0] - 8) & 0xff + data.draw_bytes(128 * d) + if d >= 2: + data.mark_interesting() + assert x == hbytes([10]) + hbytes(128 * 2) + + +def test_can_navigate_to_a_valid_example(): + def f(data): + i = int_from_bytes(data.draw_bytes(2)) + data.draw_bytes(i) + data.mark_interesting() + runner = ConjectureRunner(f, settings=settings( + max_examples=5000, buffer_size=2, database=None, + )) + runner.run() + assert runner.interesting_examples + + +def test_stops_after_max_examples_when_reading(): + key = b'key' + + db = ExampleDatabase(':memory:') + for i in range(10): + db.save(key, hbytes([i])) + + seen = [] + + def f(data): + seen.append(data.draw_bytes(1)) + + runner = ConjectureRunner(f, settings=settings( + max_examples=1, + database=db, + ), database_key=key) + runner.run() + assert len(seen) == 1 + + +def test_stops_after_max_examples_when_generating(): + seen = [] + + def f(data): + seen.append(data.draw_bytes(1)) + + runner = ConjectureRunner(f, settings=settings( + max_examples=1, + database=None, + )) + runner.run() + assert len(seen) == 1 + + +def test_interleaving_engines(): + children = [] + + @run_to_buffer + def x(data): + rnd = Random(data.draw_bytes(1)) + + def g(d2): + d2.draw_bytes(1) + data.mark_interesting() + runner = ConjectureRunner(g, random=rnd) + children.append(runner) + runner.run() + if runner.interesting_examples: + data.mark_interesting() + assert x == b'\0' + for c in children: + assert not c.interesting_examples + + +@checks_deprecated_behaviour +def test_run_with_timeout_while_shrinking(): + def f(data): + time.sleep(0.1) + x = data.draw_bytes(32) + if any(x): + data.mark_interesting() + + runner = ConjectureRunner( + f, settings=settings(database=None, timeout=0.2)) + start = time.time() + runner.run() + assert time.time() <= start + 1 + assert runner.interesting_examples + + +@checks_deprecated_behaviour +def test_run_with_timeout_while_boring(): + def f(data): + time.sleep(0.1) + + runner = ConjectureRunner( + f, settings=settings(database=None, timeout=0.2)) + start = time.time() + runner.run() + assert time.time() <= start + 1 + assert runner.valid_examples > 0 + + +@checks_deprecated_behaviour +def test_max_shrinks_can_disable_shrinking(): + seen = set() + + def f(data): + seen.add(hbytes(data.draw_bytes(32))) + data.mark_interesting() + + runner = ConjectureRunner( + f, settings=settings(database=None, max_shrinks=0,)) + runner.run() + assert len(seen) == 1 + + +def test_phases_can_disable_shrinking(): + seen = set() + + def f(data): + seen.add(hbytes(data.draw_bytes(32))) + data.mark_interesting() + + runner = ConjectureRunner(f, settings=settings( + database=None, phases=(Phase.reuse, Phase.generate), + )) + runner.run() + assert len(seen) == 1 + + +def test_erratic_draws(): + n = [0] + + @run_to_buffer + def x(data): + data.draw_bytes(n[0]) + data.draw_bytes(255 - n[0]) + if n[0] == 255: + data.mark_interesting() + else: + n[0] += 1 + + +def test_no_read_no_shrink(): + count = [0] + + @run_to_buffer + def x(data): + count[0] += 1 + data.mark_interesting() + assert x == b'' + assert count == [1] + + +def test_one_dead_branch(): + seed_random(0) + seen = set() + + @run_to_buffer + def x(data): + i = data.draw_bytes(1)[0] + if i > 0: + data.mark_invalid() + i = data.draw_bytes(1)[0] + if len(seen) < 255: + seen.add(i) + elif i not in seen: + data.mark_interesting() + + +def test_fully_exhaust_base(monkeypatch): + """In this test we generate all possible values for the first byte but + never get to the point where we exhaust the root of the tree.""" + seed_random(0) + + seen = set() + + def f(data): + key = (data.draw_bits(2), data.draw_bits(2)) + assert key not in seen + seen.add(key) + + runner = ConjectureRunner(f, settings=settings( + max_examples=10000, phases=no_shrink, buffer_size=1024, database=None, + )) + + for c in hrange(4): + runner.cached_test_function([0, c]) + + assert 1 in runner.dead + + runner.run() + + +def test_saves_on_interrupt(): + def interrupts(data): + raise KeyboardInterrupt() + + db = InMemoryExampleDatabase() + + runner = ConjectureRunner( + interrupts, settings=settings(database=db), database_key=b'key') + + with pytest.raises(KeyboardInterrupt): + runner.run() + assert db.data + + +def test_returns_written(): + value = hbytes(b'\0\1\2\3') + + @run_to_buffer + def written(data): + data.write(value) + data.mark_interesting() + + assert value == written + + +def fails_health_check(label, **kwargs): + def accept(f): + runner = ConjectureRunner(f, settings=settings( + max_examples=100, phases=no_shrink, buffer_size=1024, + database=None, **kwargs + )) + + with pytest.raises(FailedHealthCheck) as e: + runner.run() + assert e.value.health_check == label + assert not runner.interesting_examples + return accept + + +def test_fails_health_check_for_all_invalid(): + @fails_health_check(HealthCheck.filter_too_much) + def _(data): + data.draw_bytes(2) + data.mark_invalid() + + +def test_fails_health_check_for_large_base(): + @fails_health_check(HealthCheck.large_base_example) + def _(data): + data.draw_bytes(10 ** 6) + + +def test_fails_health_check_for_large_non_base(): + @fails_health_check(HealthCheck.data_too_large) + def _(data): + if data.draw_bits(8): + data.draw_bytes(10 ** 6) + + +def test_fails_health_check_for_slow_draws(): + @fails_health_check(HealthCheck.too_slow) + def _(data): + data.draw(SLOW) + + +def test_fails_healthcheck_for_hung_test(): + @fails_health_check(HealthCheck.hung_test, timeout=unlimited) + def _(data): + data.draw_bytes(1) + time.sleep(3600) + + +@pytest.mark.parametrize('n_large', [1, 5, 8, 15]) +def test_can_shrink_variable_draws(n_large): + target = 128 * n_large + + @run_to_buffer + def x(data): + n = data.draw_bits(4) + b = [data.draw_bits(8) for _ in hrange(n)] + if sum(b) >= target: + data.mark_interesting() + assert x.count(0) == 0 + assert sum(x[1:]) == target + + +@pytest.mark.parametrize('n', [1, 5, 8, 15]) +def test_can_shrink_variable_draws_with_just_deletion(n, monkeypatch): + @shrinking_from([n] + [0] * (n - 1) + [1]) + def shrinker(data): + n = data.draw_bits(4) + b = [data.draw_bits(8) for _ in hrange(n)] + if any(b): + data.mark_interesting() + + # We normally would have populated this in minimize_individual_blocks + shrinker.is_shrinking_block = lambda x: True + + fixate(Shrinker.example_deletion_with_block_lowering)(shrinker) + + assert list(shrinker.shrink_target.buffer) == [1, 1] + + +def test_deletion_and_lowering_fails_to_shrink(monkeypatch): + monkeypatch.setattr( + Shrinker, 'shrink', Shrinker.example_deletion_with_block_lowering + ) + # Would normally be added by minimize_individual_blocks, but we skip + # that phase in this test. + monkeypatch.setattr( + Shrinker, 'is_shrinking_block', lambda self, i: i == 0 + ) + + def gen(self): + data = ConjectureData.for_buffer(hbytes(10)) + self.test_function(data) + + monkeypatch.setattr(ConjectureRunner, 'generate_new_examples', gen) + + @run_to_buffer + def x(data): + for _ in hrange(10): + data.draw_bytes(1) + data.mark_interesting() + assert x == hbytes(10) + + +def test_run_nothing(): + def f(data): + assert False + + runner = ConjectureRunner(f, settings=settings(phases=())) + runner.run() + assert runner.call_count == 0 + + +class Foo(object): + def __repr__(self): + return 'stuff' + + +@pytest.mark.parametrize('event', ['hi', Foo()]) +def test_note_events(event): + def f(data): + data.note_event(event) + data.draw_bytes(1) + + runner = ConjectureRunner(f) + runner.run() + assert runner.event_call_counts[str(event)] == runner.call_count > 0 + + +def test_debug_data(capsys): + buf = [0, 1, 2] + + def f(data): + for x in hbytes(buf): + if data.draw_bits(8) != x: + data.mark_invalid() + data.start_example(1) + data.stop_example() + data.mark_interesting() + + runner = ConjectureRunner(f, settings=settings( + max_examples=5000, buffer_size=1024, + database=None, suppress_health_check=HealthCheck.all(), + verbosity=Verbosity.debug + )) + runner.test_function(ConjectureData.for_buffer(buf)) + runner.run() + + out, _ = capsys.readouterr() + assert re.match(u'\\d+ bytes \\[.*\\] -> ', out) + assert 'INTERESTING' in out + assert '[]' not in out + + +def test_zeroes_bytes_above_bound(): + def f(data): + if data.draw_bits(1): + x = data.draw_bytes(9) + assert not any(x[4:8]) + + ConjectureRunner(f, settings=settings(buffer_size=10)).run() + + +def test_can_write_bytes_towards_the_end(): + buf = b'\1\2\3' + + def f(data): + if data.draw_bits(1): + data.draw_bytes(5) + data.write(hbytes(buf)) + assert hbytes(data.buffer[-len(buf):]) == buf + + ConjectureRunner(f, settings=settings(buffer_size=10)).run() + + +def test_can_increase_number_of_bytes_drawn_in_tail(): + # This is designed to trigger a case where the zero bound queue will end up + # increasing the size of data drawn because moving zeroes into the initial + # prefix will increase the amount drawn. + def f(data): + x = data.draw_bytes(5) + n = x.count(0) + b = data.draw_bytes(n + 1) + assert not any(b) + + runner = ConjectureRunner( + f, settings=settings( + max_examples=100, + buffer_size=11, suppress_health_check=HealthCheck.all())) + + runner.run() + + +def test_uniqueness_is_preserved_when_writing_at_beginning(): + seen = set() + + def f(data): + data.write(hbytes(1)) + n = data.draw_bits(3) + assert n not in seen + seen.add(n) + + runner = ConjectureRunner( + f, settings=settings(max_examples=50)) + runner.run() + assert runner.valid_examples == len(seen) + + +@pytest.mark.parametrize('skip_target', [False, True]) +@pytest.mark.parametrize('initial_attempt', [127, 128]) +def test_clears_out_its_database_on_shrinking( + initial_attempt, skip_target, monkeypatch +): + def generate_new_examples(self): + self.test_function( + ConjectureData.for_buffer(hbytes([initial_attempt]))) + + monkeypatch.setattr( + ConjectureRunner, 'generate_new_examples', generate_new_examples) + + key = b'key' + db = InMemoryExampleDatabase() + + def f(data): + if data.draw_bits(8) >= 127: + data.mark_interesting() + + runner = ConjectureRunner( + f, settings=settings(database=db, max_examples=256), database_key=key, + random=Random(0), + ) + + for n in hrange(256): + if n != 127 or not skip_target: + db.save(runner.secondary_key, hbytes([n])) + runner.run() + assert len(runner.interesting_examples) == 1 + for b in db.fetch(runner.secondary_key): + assert b[0] >= 127 + assert len(list(db.fetch(runner.database_key))) == 1 + + +def test_can_delete_intervals(monkeypatch): + def generate_new_examples(self): + self.test_function( + ConjectureData.for_buffer(hbytes([255] * 10 + [1, 3]))) + + monkeypatch.setattr( + ConjectureRunner, 'generate_new_examples', generate_new_examples) + monkeypatch.setattr( + Shrinker, 'shrink', fixate(Shrinker.adaptive_example_deletion) + ) + + def f(data): + while True: + n = data.draw_bits(8) + if n == 255: + continue + elif n == 1: + break + else: + data.mark_invalid() + if data.draw_bits(8) == 3: + data.mark_interesting() + runner = ConjectureRunner(f, settings=settings(database=None)) + runner.run() + x, = runner.interesting_examples.values() + assert x.buffer == hbytes([1, 3]) + + +def test_detects_too_small_block_starts(): + def f(data): + data.draw_bytes(8) + data.mark_interesting() + runner = ConjectureRunner(f, settings=settings(database=None)) + r = ConjectureData.for_buffer(hbytes(8)) + runner.test_function(r) + assert r.status == Status.INTERESTING + assert not runner.prescreen_buffer(hbytes([255] * 7)) + + +def test_shrinks_both_interesting_examples(monkeypatch): + def generate_new_examples(self): + self.test_function(ConjectureData.for_buffer(hbytes([1]))) + + monkeypatch.setattr( + ConjectureRunner, 'generate_new_examples', generate_new_examples) + + def f(data): + n = data.draw_bits(8) + data.mark_interesting(n & 1) + runner = ConjectureRunner(f, database_key=b'key') + runner.run() + assert runner.interesting_examples[0].buffer == hbytes([0]) + assert runner.interesting_examples[1].buffer == hbytes([1]) + + +def test_duplicate_blocks_that_go_away(monkeypatch): + monkeypatch.setattr( + Shrinker, 'shrink', Shrinker.minimize_duplicated_blocks) + monkeypatch.setattr( + ConjectureRunner, 'generate_new_examples', + lambda runner: runner.test_function( + ConjectureData.for_buffer(hbytes([1, 1, 1, 2] * 2 + [5] * 2))) + ) + + @run_to_buffer + def x(data): + x = data.draw_bits(32) + y = data.draw_bits(32) + if x != y: + data.mark_invalid() + b = [data.draw_bytes(1) for _ in hrange(x & 255)] + if len(set(b)) <= 1: + data.mark_interesting() + assert x == hbytes([0] * 8) + + +def test_accidental_duplication(monkeypatch): + @shrinking_from([18] * 20) + def shrinker(data): + x = data.draw_bits(8) + y = data.draw_bits(8) + if x != y: + data.mark_invalid() + if x < 5: + data.mark_invalid() + b = [data.draw_bytes(1) for _ in hrange(x)] + if len(set(b)) == 1: + data.mark_interesting() + shrinker.clear_passes() + shrinker.add_new_pass('minimize_duplicated_blocks') + shrinker.shrink() + assert list(shrinker.buffer) == [5] * 7 + + +def test_discarding(monkeypatch): + monkeypatch.setattr( + Shrinker, 'shrink', Shrinker.remove_discarded) + monkeypatch.setattr( + ConjectureRunner, 'generate_new_examples', + lambda runner: runner.test_function( + ConjectureData.for_buffer(hbytes([0, 1] * 10))) + ) + + @run_to_buffer + def x(data): + count = 0 + while count < 10: + data.start_example(SOME_LABEL) + b = data.draw_bits(1) + if b: + count += 1 + data.stop_example(discard=not b) + data.mark_interesting() + assert x == hbytes(hbytes([1]) * 10) + + +def fixate(f): + def accept(self): + prev = None + while self.shrink_target is not prev: + prev = self.shrink_target + f(self) + return accept + + +def test_can_remove_discarded_data(): + @shrinking_from(hbytes([0] * 10) + hbytes([11])) + def shrinker(data): + while True: + data.start_example(SOME_LABEL) + b = data.draw_bits(8) + data.stop_example(discard=(b == 0)) + if b == 11: + break + data.mark_interesting() + shrinker.run_shrink_pass('remove_discarded') + assert list(shrinker.buffer) == [11] + + +def test_discarding_iterates_to_fixed_point(): + @shrinking_from(hbytes([1] * 10) + hbytes([0])) + def shrinker(data): + data.start_example(0) + data.draw_bits(1) + data.stop_example(discard=True) + while data.draw_bits(1): + pass + data.mark_interesting() + shrinker.run_shrink_pass('remove_discarded') + assert list(shrinker.buffer) == [1, 0] + + +def shrink_pass(name): + def run(self): + self.run_shrink_pass(name) + return run + + +def test_discarding_can_fail(monkeypatch): + @shrinking_from(hbytes([1])) + def shrinker(data): + data.start_example(0) + data.draw_bits(1) + data.stop_example(discard=True) + data.mark_interesting() + shrinker.remove_discarded() + assert shrinker.shrink_target.has_discards + + +@pytest.mark.parametrize('bits', [3, 9]) +@pytest.mark.parametrize('prefix', [b'', b'\0']) +@pytest.mark.parametrize('seed', [0]) +def test_exhaustive_enumeration(prefix, bits, seed): + seen = set() + + def f(data): + if prefix: + data.write(hbytes(prefix)) + assert len(data.buffer) == len(prefix) + k = data.draw_bits(bits) + assert k not in seen + seen.add(k) + + size = 2 ** bits + + seen_prefixes = set() + + runner = ConjectureRunner( + f, settings=settings(database=None, max_examples=size), + random=Random(seed), + ) + with pytest.raises(RunIsComplete): + runner.cached_test_function(b'') + for _ in hrange(size): + p = runner.generate_novel_prefix() + assert p not in seen_prefixes + seen_prefixes.add(p) + data = ConjectureData.for_buffer( + hbytes(p + hbytes(2 + len(prefix)))) + runner.test_function(data) + assert data.status == Status.VALID + node = 0 + for b in data.buffer: + node = runner.tree[node][b] + assert node in runner.dead + assert len(seen) == size + + +def test_depth_bounds_in_generation(): + depth = [0] + + def tails(data, n): + depth[0] = max(depth[0], n) + if data.draw_bits(8): + data.start_example(SOME_LABEL) + tails(data, n + 1) + data.stop_example() + + def f(data): + tails(data, 0) + + runner = ConjectureRunner( + f, settings=settings(database=None, max_examples=20)) + runner.run() + assert 0 < depth[0] <= MAX_DEPTH + + +def test_shrinking_from_mostly_zero(monkeypatch): + monkeypatch.setattr( + ConjectureRunner, 'generate_new_examples', + lambda self: self.cached_test_function(hbytes(5) + hbytes([2])) + ) + + @run_to_buffer + def x(data): + s = [data.draw_bits(8) for _ in hrange(6)] + if any(s): + data.mark_interesting() + + assert x == hbytes(5) + hbytes([1]) + + +def test_handles_nesting_of_discard_correctly(monkeypatch): + monkeypatch.setattr( + Shrinker, 'shrink', Shrinker.remove_discarded) + monkeypatch.setattr( + ConjectureRunner, 'generate_new_examples', + lambda runner: runner.test_function( + ConjectureData.for_buffer(hbytes([0, 0, 1, 1])))) + + @run_to_buffer + def x(data): + while True: + data.start_example(SOME_LABEL) + succeeded = data.draw_bits(1) + data.start_example(SOME_LABEL) + data.draw_bits(1) + data.stop_example(discard=not succeeded) + data.stop_example(discard=not succeeded) + if succeeded: + data.mark_interesting() + + assert x == hbytes([1, 1]) + + +def test_can_zero_subintervals(monkeypatch): + @shrinking_from(hbytes([3, 0, 0, 0, 1]) * 10) + def shrinker(data): + for _ in hrange(10): + data.start_example(SOME_LABEL) + n = data.draw_bits(8) + data.draw_bytes(n) + data.stop_example() + if data.draw_bits(8) != 1: + return + data.mark_interesting() + shrinker.run_shrink_pass('zero_examples') + assert list(shrinker.buffer) == [0, 1] * 10 + + +def test_can_pass_to_an_indirect_descendant(monkeypatch): + initial = hbytes([ + 1, 10, + 0, 0, + 1, 0, + 0, 10, + 0, 0, + ]) + + monkeypatch.setattr( + ConjectureRunner, 'generate_new_examples', + lambda runner: runner.cached_test_function(initial)) + + monkeypatch.setattr(Shrinker, 'shrink', Shrinker.pass_to_descendant) + + def tree(data): + data.start_example(1) + n = data.draw_bits(1) + label = data.draw_bits(8) + if n: + tree(data) + tree(data) + data.stop_example(1) + return label + + @run_to_buffer + def x(data): + if tree(data) == 10: + data.mark_interesting() + + assert list(x) == [0, 10] + + +def test_shrinking_block_pairs(monkeypatch): + monkeypatch.setattr( + Shrinker, 'shrink', lambda self: ( + self.shrink_offset_pairs() + ) + ) + + monkeypatch.setattr( + ConjectureRunner, 'generate_new_examples', + lambda runner: runner.test_function( + ConjectureData.for_buffer([12, 10]))) + + @run_to_buffer + def x(data): + m = data.draw_bits(8) + n = data.draw_bits(8) + if m == n + 2: + data.mark_interesting() + assert x == hbytes([2, 0]) + + +def shrink(buffer, *passes): + def accept(f): + shrinker = shrinking_from(buffer)(f) + + prev = None + while shrinker.shrink_target is not prev: + prev = shrinker.shrink_target + for p in passes: + shrinker.run_shrink_pass(p) + return list(shrinker.buffer) + return accept + + +def test_non_minimal_pair_shrink(monkeypatch): + @shrink([12, 10], 'shrink_offset_pairs') + def x(data): + m = data.draw_bits(8) + if m < 5: + data.mark_invalid() + if m == 5: + data.mark_interesting() + n = data.draw_bits(8) + if m == n + 2: + data.mark_interesting() + + assert x == [5] + + +def test_buffer_changes_during_pair_shrink(monkeypatch): + @shrink([12, 10], 'shrink_offset_pairs') + def x(data): + m = data.draw_bits(8) + if m < 5: + data.mark_invalid() + if m == 5: + data.write(hbytes([1])) + data.mark_interesting() + n = data.draw_bits(8) + if m == n + 2: + data.mark_interesting() + assert x == [5, 1] + + +def test_buffer_changes_during_pair_shrink_stays_interesting(monkeypatch): + monkeypatch.setattr( + Shrinker, 'shrink', lambda self: ( + self.shrink_offset_pairs() + ) + ) + + monkeypatch.setattr( + ConjectureRunner, 'generate_new_examples', + lambda runner: runner.test_function( + ConjectureData.for_buffer([12, 10]))) + + @run_to_buffer + def x(data): + m = data.draw_bits(8) + if m == 12: + data.draw_bits(8) + if m >= 9: + data.mark_interesting() + assert len(x) == 1 + + +def test_shrinking_blocks_from_common_offset(monkeypatch): + monkeypatch.setattr( + Shrinker, 'shrink', lambda self: ( + # Run minimize_individual_blocks twice so we have both blocks show + # as changed regardless of which order this happens in. + self.minimize_individual_blocks(), + self.minimize_individual_blocks(), + self.lower_common_block_offset(), + ) + ) + + monkeypatch.setattr( + ConjectureRunner, 'generate_new_examples', + lambda runner: runner.test_function( + ConjectureData.for_buffer([11, 10]))) + + @run_to_buffer + def x(data): + m = data.draw_bits(8) + n = data.draw_bits(8) + if abs(m - n) <= 1 and max(m, n) > 0: + data.mark_interesting() + assert sorted(x) == [0, 1] + + +def test_handle_empty_draws(monkeypatch): + monkeypatch.setattr( + Shrinker, 'shrink', Shrinker.adaptive_example_deletion) + + lambda runner: runner.test_function(ConjectureData.for_buffer( + [1, 1, 0])) + + @run_to_buffer + def x(data): + while True: + data.start_example(SOME_LABEL) + n = data.draw_bits(1) + data.start_example(SOME_LABEL) + data.stop_example() + data.stop_example(discard=n > 0) + if not n: + break + data.mark_interesting() + assert x == hbytes([0]) + + +def test_large_initial_write(): + big = hbytes(b'\xff') * 512 + + def f(data): + data.write(big) + data.draw_bits(63) + + with deterministic_PRNG(): + runner = ConjectureRunner(f, settings=settings( + max_examples=5000, buffer_size=1024, + database=None, suppress_health_check=HealthCheck.all(), + )) + runner.run() + + assert runner.exit_reason == ExitReason.finished + + +@pytest.mark.parametrize('lo', [0, 1, 50]) +def test_can_shrink_additively(monkeypatch, lo): + monkeypatch.setattr( + ConjectureRunner, 'generate_new_examples', + lambda self: self.test_function( + ConjectureData.for_buffer(hbytes([100, 100])))) + + @run_to_buffer + def x(data): + m = data.draw_bits(8) + n = data.draw_bits(8) + if m >= lo and m + n == 200: + data.mark_interesting() + + assert list(x) == [lo, 200 - lo] + + +def test_can_shrink_additively_losing_size(monkeypatch): + monkeypatch.setattr( + ConjectureRunner, 'generate_new_examples', + lambda self: self.test_function( + ConjectureData.for_buffer(hbytes([100, 100])))) + + monkeypatch.setattr( + Shrinker, 'shrink', lambda self: ( + self.minimize_block_pairs_retaining_sum(), + ) + ) + + @run_to_buffer + def x(data): + m = data.draw_bits(8) + if m >= 10: + if m <= 50: + data.mark_interesting() + else: + n = data.draw_bits(8) + if m + n == 200: + data.mark_interesting() + assert len(x) == 1 + + +def test_can_reorder_examples(monkeypatch): + monkeypatch.setattr( + ConjectureRunner, 'generate_new_examples', + lambda runner: runner.test_function( + ConjectureData.for_buffer([1, 0, 1, 1, 0, 1, 0, 0, 0]))) + + monkeypatch.setattr( + Shrinker, 'shrink', Shrinker.reorder_examples, + ) + + @run_to_buffer + def x(data): + total = 0 + for _ in range(5): + data.start_example(0) + if data.draw_bits(8): + total += data.draw_bits(9) + data.stop_example(0) + if total == 2: + data.mark_interesting() + + assert list(x) == [0, 0, 0, 1, 0, 1, 1, 0, 1] + + +def test_permits_but_ignores_raising_order(monkeypatch): + monkeypatch.setattr( + ConjectureRunner, 'generate_new_examples', + lambda runner: runner.test_function( + ConjectureData.for_buffer([1]))) + + monkeypatch.setattr( + Shrinker, 'shrink', + lambda self: self.incorporate_new_buffer(hbytes([2])) + ) + + @run_to_buffer + def x(data): + data.draw_bits(2) + data.mark_interesting() + + assert list(x) == [1] + + +def test_block_deletion_can_delete_short_ranges(monkeypatch): + @shrinking_from([ + v for i in range(5) for _ in range(i + 1) for v in [0, i]] + ) + def shrinker(data): + while True: + n = data.draw_bits(16) + for _ in range(n): + if data.draw_bits(16) != n: + data.mark_invalid() + if n == 4: + data.mark_interesting() + for i in range(1, 5): + block_program('X' * i)(shrinker) + assert list(shrinker.shrink_target.buffer) == [0, 4] * 5 + + +def test_try_shrinking_blocks_ignores_overrun_blocks(monkeypatch): + monkeypatch.setattr( + ConjectureRunner, 'generate_new_examples', + lambda runner: runner.test_function( + ConjectureData.for_buffer([3, 3, 0, 1]))) + + monkeypatch.setattr( + Shrinker, 'shrink', + lambda self: self.try_shrinking_blocks( + (0, 1, 5), hbytes([2]) + ), + ) + + @run_to_buffer + def x(data): + n1 = data.draw_bits(8) + data.draw_bits(8) + if n1 == 3: + data.draw_bits(8) + k = data.draw_bits(8) + if k == 1: + data.mark_interesting() + + assert list(x) == [2, 2, 1] + + +def shrinking_from(start): + def accept(f): + with deterministic_PRNG(): + runner = ConjectureRunner(f, settings=settings( + max_examples=5000, buffer_size=1024, + database=None, suppress_health_check=HealthCheck.all(), + )) + runner.test_function(ConjectureData.for_buffer(start)) + assert runner.interesting_examples + last_data, = runner.interesting_examples.values() + return runner.new_shrinker( + last_data, lambda d: d.status == Status.INTERESTING + ) + return accept + + +def test_dependent_block_pairs_is_up_to_shrinking_integers(): + # Unit test extracted from a failure in tests/nocover/test_integers.py + distribution = Sampler([ + 4.0, 8.0, 1.0, 1.0, 0.5 + ]) + + sizes = [8, 16, 32, 64, 128] + + @shrinking_from(b'\x03\x01\x00\x00\x00\x00\x00\x01\x00\x02\x01') + def shrinker(data): + size = sizes[distribution.sample(data)] + result = data.draw_bits(size) + sign = (-1) ** (result & 1) + result = (result >> 1) * sign + cap = data.draw_bits(8) + + if result >= 32768 and cap == 1: + data.mark_interesting() + + shrinker.minimize_individual_blocks() + assert list(shrinker.shrink_target.buffer) == [ + 1, 1, 0, 1, 0, 0, 1 + ] + + +def test_finding_a_minimal_balanced_binary_tree(): + # Tests iteration while the shape of the thing being iterated over can + # change. In particular the current example can go from trivial to non + # trivial. + + def tree(data): + # Returns height of a binary tree and whether it is height balanced. + data.start_example('tree') + n = data.draw_bits(1) + if n == 0: + result = (1, True) + else: + h1, b1 = tree(data) + h2, b2 = tree(data) + result = (1 + max(h1, h2), b1 and b2 and abs(h1 - h2) <= 1) + data.stop_example('tree') + return result + + # Starting from an unbalanced tree of depth six + @shrinking_from([1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0]) + def shrinker(data): + _, b = tree(data) + if not b: + data.mark_interesting() + + shrinker.adaptive_example_deletion() + shrinker.reorder_examples() + + assert list(shrinker.shrink_target.buffer) == [ + 1, 0, 1, 0, 1, 0, 0 + ] + + +def test_database_clears_secondary_key(): + key = b'key' + database = InMemoryExampleDatabase() + + def f(data): + if data.draw_bits(8) == 10: + data.mark_interesting() + else: + data.mark_invalid() + + runner = ConjectureRunner(f, settings=settings( + max_examples=1, buffer_size=1024, + database=database, suppress_health_check=HealthCheck.all(), + ), database_key=key) + + for i in range(10): + database.save(runner.secondary_key, hbytes([i])) + + runner.test_function(ConjectureData.for_buffer(hbytes([10]))) + assert runner.interesting_examples + + assert len(set(database.fetch(key))) == 1 + assert len(set(database.fetch(runner.secondary_key))) == 10 + + runner.clear_secondary_key() + + assert len(set(database.fetch(key))) == 1 + assert len(set(database.fetch(runner.secondary_key))) == 0 + + +def test_database_uses_values_from_secondary_key(): + key = b'key' + database = InMemoryExampleDatabase() + + def f(data): + if data.draw_bits(8) >= 5: + data.mark_interesting() + else: + data.mark_invalid() + + runner = ConjectureRunner(f, settings=settings( + max_examples=1, buffer_size=1024, + database=database, suppress_health_check=HealthCheck.all(), + ), database_key=key) + + for i in range(10): + database.save(runner.secondary_key, hbytes([i])) + + runner.test_function(ConjectureData.for_buffer(hbytes([10]))) + assert runner.interesting_examples + + assert len(set(database.fetch(key))) == 1 + assert len(set(database.fetch(runner.secondary_key))) == 10 + + runner.clear_secondary_key() + + assert len(set(database.fetch(key))) == 1 + assert set( + map(int_from_bytes, database.fetch(runner.secondary_key)) + ) == set(range(6, 11)) + + v, = runner.interesting_examples.values() + + assert list(v.buffer) == [5] + + +def test_exit_because_max_iterations(): + + def f(data): + data.draw_bits(64) + data.mark_invalid() + + runner = ConjectureRunner(f, settings=settings( + max_examples=1, buffer_size=1024, + database=None, suppress_health_check=HealthCheck.all(), + )) + + runner.run() + + assert runner.call_count <= 1000 + assert runner.exit_reason == ExitReason.max_iterations + + +def test_skips_non_payload_blocks_when_reducing_sum(): + @shrinking_from([10, 10, 10]) + def shrinker(data): + if sum([data.draw_bits(8) for _ in range(3)]) == 30: + data.mark_interesting() + + shrinker.is_payload_block = lambda b: b != 1 + shrinker.minimize_block_pairs_retaining_sum() + assert list(shrinker.shrink_target.buffer) == [0, 10, 20] + + +def test_dependent_block_pairs_can_lower_to_zero(): + @shrinking_from([1, 0, 1]) + def shrinker(data): + if data.draw_bits(1): + n = data.draw_bits(16) + else: + n = data.draw_bits(8) + + if n == 1: + data.mark_interesting() + shrinker.minimize_individual_blocks() + assert list(shrinker.shrink_target.buffer) == [0, 1] + + +def test_handle_size_too_large_during_dependent_lowering(): + @shrinking_from([1, 255, 0]) + def shrinker(data): + if data.draw_bits(1): + data.draw_bits(16) + data.mark_interesting() + else: + data.draw_bits(8) + shrinker.minimize_individual_blocks() + + +def test_zero_examples_will_zero_blocks(): + @shrinking_from([1, 1, 1]) + def shrinker(data): + n = data.draw_bits(1) + data.draw_bits(1) + m = data.draw_bits(1) + if n == m == 1: + data.mark_interesting() + shrinker.run_shrink_pass('zero_examples') + assert list(shrinker.shrink_target.buffer) == [1, 0, 1] + + +def test_non_trivial_examples(): + initial = hbytes([1, 0, 1]) + + @shrinking_from(initial) + def shrinker(data): + data.draw_bits(1) + data.draw_bits(1) + data.draw_bits(1) + data.mark_interesting() + + assert { + (ex.start, ex.end) for ex in shrinker.each_non_trivial_example() + } == {(0, 3), (0, 1), (2, 3)} + + +def test_become_trivial_during_shrinking(): + @shrinking_from([1, 1, 1]) + def shrinker(data): + data.draw_bits(1) + data.draw_bits(1) + data.draw_bits(1) + data.mark_interesting() + + for ex in shrinker.each_non_trivial_example(): + assert ex.length == 3 + shrinker.incorporate_new_buffer(hbytes(3)) + + +def test_continues_iterating_if_an_example_becomes_trivial(): + @shrinking_from([1, 1, 1]) + def shrinker(data): + data.draw_bits(1) + data.draw_bits(1) + data.draw_bits(1) + data.mark_interesting() + + endpoints = set() + for ex in shrinker.each_non_trivial_example(): + endpoints.add((ex.start, ex.end)) + if ex.start == 1: + shrinker.incorporate_new_buffer([1, 0, 1]) + assert endpoints == {(0, 3), (0, 1), (1, 2), (2, 3)} + + +def test_each_non_trivial_example_includes_each_non_trivial_example(): + @shrinking_from([1, 0, 1]) + def shrinker(data): + data.draw_bits(1) + data.draw_bits(1) + data.draw_bits(1) + data.mark_interesting() + + endpoints = { + (ex.start, ex.end) for ex in shrinker.each_non_trivial_example() + } + + assert endpoints == {(0, 3), (0, 1), (2, 3)} + + +def test_non_trivial_examples_boundaries_can_change(): + initial = hbytes([2, 1, 1]) + + @shrinking_from(initial) + def shrinker(data): + n = data.draw_bits(8) + if n == 2: + data.draw_bits(8) + data.draw_bits(8) + else: + data.draw_bits(16) + data.mark_interesting() + + it = shrinker.each_non_trivial_example() + assert next(it).length == 3 + shrinker.incorporate_new_buffer([1, 1, 1]) + assert next(it).length == 2 + assert next(it).length == 1 + + +def test_block_may_grow_during_lexical_shrinking(): + initial = hbytes([2, 1, 1]) + + @shrinking_from(initial) + def shrinker(data): + n = data.draw_bits(8) + if n == 2: + data.draw_bits(8) + data.draw_bits(8) + else: + data.draw_bits(16) + data.mark_interesting() + + shrinker.minimize_individual_blocks() + assert list(shrinker.shrink_target.buffer) == [0, 0, 0] + + +def test_lower_common_block_offset_does_nothing_when_changed_blocks_are_zero(): + @shrinking_from([1, 0, 1, 0]) + def shrinker(data): + data.draw_bits(1) + data.draw_bits(1) + data.draw_bits(1) + data.draw_bits(1) + data.mark_interesting() + shrinker.mark_changed(1) + shrinker.mark_changed(3) + shrinker.lower_common_block_offset() + assert list(shrinker.shrink_target.buffer) == [1, 0, 1, 0] + + +def test_lower_common_block_offset_ignores_zeros(): + @shrinking_from([2, 2, 0]) + def shrinker(data): + n = data.draw_bits(8) + data.draw_bits(8) + data.draw_bits(8) + if n > 0: + data.mark_interesting() + for i in range(3): + shrinker.mark_changed(i) + shrinker.lower_common_block_offset() + assert list(shrinker.shrink_target.buffer) == [1, 1, 0] + + +def test_pandas_hack(): + @shrinking_from([2, 1, 1, 7]) + def shrinker(data): + n = data.draw_bits(8) + m = data.draw_bits(8) + if n == 1: + if m == 7: + data.mark_interesting() + data.draw_bits(8) + if data.draw_bits(8) == 7: + data.mark_interesting() + shrinker.run_shrink_pass("block_program('-XX')") + assert list(shrinker.shrink_target.buffer) == [1, 7] + + +def test_passes_can_come_back_to_life(): + initial = hbytes([1, 2, 3, 4, 5, 6]) + buf1 = hbytes([0, 1, 3, 4, 5, 6]) + buf2 = hbytes([0, 1, 3, 4, 4, 6]) + + good = { + initial, buf1, buf2 + } + + @shrinking_from(initial) + def shrinker(data): + string = hbytes([data.draw_bits(8) for _ in range(6)]) + if string in good: + data.mark_interesting() + + shrinker.clear_passes() + shrinker.add_new_pass(block_program('--')) + shrinker.add_new_pass(block_program('-')) + + shrinker.single_greedy_shrink_iteration() + assert shrinker.shrink_target.buffer == buf1 + + shrinker.single_greedy_shrink_iteration() + assert shrinker.shrink_target.buffer == buf2 + + +def test_will_enable_previously_bad_passes_when_failing_to_shrink(): + # We lead the shrinker down the garden path a bit where it keeps making + # progress but only lexically. When it finally gets down to the minimum + good = { + hbytes([1, 2, 3, 4, 5, 6]), + hbytes([1, 2, 3, 4, 5, 5]), + hbytes([1, 2, 2, 4, 5, 5]), + hbytes([1, 2, 2, 4, 4, 5]), + hbytes([0, 2, 2, 4, 4, 5]), + hbytes([0, 1, 2, 4, 4, 5]), + } + + initial = max(good) + final = min(good) + + @shrinking_from(initial + hbytes([0, 7])) + def shrinker(data): + string = hbytes([data.draw_bits(8) for _ in range(6)]) + if string in good: + n = 0 + while data.draw_bits(8) != 7: + n += 1 + if not (string == final or n > 0): + data.mark_invalid() + data.mark_interesting() + + # In order to get to the minimized result we want to run both of these, + # but the second pass starts out as disabled (and anyway won't work until + # the first has hit fixity). + shrinker.clear_passes() + shrinker.add_new_pass(block_program('-')) + shrinker.add_new_pass(block_program('X')) + + shrinker.shrink() + + assert shrinker.shrink_target.buffer == final + hbytes([7]) + + +def test_shrink_passes_behave_sensibly_with_standard_operators(): + @shrinking_from(hbytes([1])) + def shrinker(data): + if data.draw_bits(1): + data.mark_interesting() + + passes = shrinker.passes + + lookup = {p: p for p in passes} + for p in passes: + assert lookup[p] is p + + for p, q in itertools.combinations(passes, 2): + assert p < q + assert p != q + + +def test_shrink_pass_may_go_from_solid_to_dubious(): + + initial = hbytes([0, 1, 0, 0, 2, 3]) + + @shrinking_from(initial) + def shrinker(data): + n = len(initial) - 1 - data.draw_bits(1) + for _ in range(n): + data.draw_bits(8) + data.mark_interesting() + + sp = shrinker.shrink_pass('adaptive_example_deletion') + assert sp.classification == PassClassification.CANDIDATE + shrinker.run_shrink_pass(sp) + assert sp.classification == PassClassification.HOPEFUL + shrinker.run_shrink_pass(sp) + assert sp.classification == PassClassification.DUBIOUS + + +def test_runs_adaptive_delete_on_first_pass_if_discarding_does_not_work(): + + @shrinking_from([0, 1]) + def shrinker(data): + while not data.draw_bits(1): + pass + data.mark_interesting() + + shrinker.single_greedy_shrink_iteration() + assert list(shrinker.buffer) == [1] + + +def test_alphabet_minimization(): + @shrink(list(hrange(11)), 'alphabet_minimize') + def x(data): + n = 0 + for _ in hrange(10): + n += (-1) ** (data.draw_bits(8) & 1) + if n == 0 and data.draw_bits(8) == 10: + data.mark_interesting() + assert x == [0, 1] * 5 + [10] + + +def test_keeps_using_solid_passes_while_they_shrink_size(): + good = { + hbytes([0, 1, 2, 3, 4, 5]), + hbytes([0, 1, 2, 3, 5]), + hbytes([0, 1, 3, 5]), + hbytes([1, 3, 5]), + hbytes([1, 5]), + } + initial = max(good, key=sort_key) + + @shrinking_from(initial) + def shrinker(data): + while True: + data.draw_bits(8) + if hbytes(data.buffer) in good: + data.mark_interesting() + shrinker.clear_passes() + + d1 = shrinker.add_new_pass(block_program('X')) + d2 = shrinker.add_new_pass(block_program('-')) + + for _ in range(3): + shrinker.single_greedy_shrink_iteration() + assert d1.classification == PassClassification.HOPEFUL + assert d2.classification == PassClassification.CANDIDATE + + +def test_will_reset_the_tree_as_it_goes(monkeypatch): + monkeypatch.setattr(engine_module, 'CACHE_RESET_FREQUENCY', 3) + + def f(data): + data.draw_bits(8) + + with deterministic_PRNG(): + runner = ConjectureRunner(f, settings=settings( + database=None, suppress_health_check=HealthCheck.all(), + )) + + def step(n): + runner.test_function(ConjectureData.for_buffer([n])) + + step(0) + step(1) + assert len(runner.tree[0]) > 1 + step(2) + assert len(runner.tree[0]) == 1 + + +def test_will_not_reset_the_tree_after_interesting_example(monkeypatch): + monkeypatch.setattr(engine_module, 'CACHE_RESET_FREQUENCY', 3) + + def f(data): + if data.draw_bits(8) == 7: + data.mark_interesting() + + with deterministic_PRNG(): + runner = ConjectureRunner(f, settings=settings( + database=None, suppress_health_check=HealthCheck.all(), + )) + + def step(n): + runner.test_function(ConjectureData.for_buffer([n])) + + step(0) + step(1) + assert len(runner.tree) > 1 + step(7) + assert len(runner.tree) > 1 + t = len(runner.tree) + runner.shrink_interesting_examples() + assert len(runner.tree) > t + + +fake_data_counter = 0 + + +@attr.s() +class FakeData(object): + status = attr.ib(default=Status.VALID) + global_identifer = attr.ib(init=False) + + def __attrs_post_init__(self): + global fake_data_counter + fake_data_counter += 1 + self.global_identifier = fake_data_counter + + +def test_target_selector_will_maintain_a_bounded_pool(): + selector = TargetSelector(random=Random(0), pool_size=3) + + for i in range(100): + selector.add(FakeData()) + assert len(selector) == min(i + 1, 3) + + +def test_target_selector_will_use_novel_examples_preferentially(): + selector = TargetSelector(random=Random(0), pool_size=3) + seen = set() + + for i in range(100): + selector.add(FakeData()) + assert len(selector) == min(i + 1, 3) + t = selector.select().global_identifier + assert t not in seen + seen.add(t) + + +def test_target_selector_will_eventually_reuse_examples(): + selector = TargetSelector(random=Random(0), pool_size=2) + seen = set() + + selector.add(FakeData()) + selector.add(FakeData()) + + for _ in range(2): + x = selector.select() + assert x.global_identifier not in seen + seen.add(x.global_identifier) + + for _ in range(2): + x = selector.select() + assert x.global_identifier in seen diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_conjecture_float_encoding.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_conjecture_float_encoding.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_conjecture_float_encoding.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_conjecture_float_encoding.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,239 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import sys +from random import Random + +import pytest + +import hypothesis.internal.conjecture.floats as flt +from hypothesis import given, assume, example +from hypothesis import strategies as st +from hypothesis.internal.compat import ceil, floor, hbytes, int_to_bytes, \ + int_from_bytes +from hypothesis.internal.floats import float_to_int +from hypothesis.internal.conjecture.data import ConjectureData +from hypothesis.internal.conjecture.shrinking import Lexical + +EXPONENTS = list(range(0, flt.MAX_EXPONENT + 1)) +assert len(EXPONENTS) == 2 ** 11 + + +def assert_reordered_exponents(res): + res = list(res) + assert len(res) == len(EXPONENTS) + for x in res: + assert res.count(x) == 1 + assert 0 <= x <= flt.MAX_EXPONENT + + +def test_encode_permutes_elements(): + assert_reordered_exponents(map(flt.encode_exponent, EXPONENTS)) + + +def test_decode_permutes_elements(): + assert_reordered_exponents(map(flt.decode_exponent, EXPONENTS)) + + +def test_decode_encode(): + for e in EXPONENTS: + assert flt.decode_exponent(flt.encode_exponent(e)) == e + + +def test_encode_decode(): + for e in EXPONENTS: + assert flt.decode_exponent(flt.encode_exponent(e)) == e + + +@given(st.data()) +def test_double_reverse_bounded(data): + n = data.draw(st.integers(1, 64)) + i = data.draw(st.integers(0, 2 ** n - 1)) + j = flt.reverse_bits(i, n) + assert flt.reverse_bits(j, n) == i + + +@given(st.integers(0, 2 ** 64 - 1)) +def test_double_reverse(i): + j = flt.reverse64(i) + assert flt.reverse64(j) == i + + +@example(1.25) +@example(1.0) +@given(st.floats()) +def test_draw_write_round_trip(f): + d = ConjectureData.for_buffer(hbytes(10)) + flt.write_float(d, f) + d2 = ConjectureData.for_buffer(d.buffer) + g = flt.draw_float(d2) + + if f == f: + assert f == g + + assert float_to_int(f) == float_to_int(g) + + d3 = ConjectureData.for_buffer(d2.buffer) + flt.draw_float(d3) + assert d3.buffer == d2.buffer + + +@example(0.0) +@example(2.5) +@example(8.000000000000007) +@example(3.0) +@example(2.0) +@example(1.9999999999999998) +@example(1.0) +@given(st.floats(min_value=0.0)) +def test_floats_round_trip(f): + i = flt.float_to_lex(f) + g = flt.lex_to_float(i) + + assert float_to_int(f) == float_to_int(g) + + +@example(1, 0.5) +@given( + st.integers(1, 2 ** 53), st.floats(0, 1).filter(lambda x: x not in (0, 1)) +) +def test_floats_order_worse_than_their_integral_part(n, g): + f = n + g + assume(int(f) != f) + assume(int(f) != 0) + i = flt.float_to_lex(f) + if f < 0: + g = ceil(f) + else: + g = floor(f) + + assert flt.float_to_lex(float(g)) < i + + +integral_floats = st.floats( + allow_infinity=False, allow_nan=False, min_value=0.0 +).map(lambda x: abs(float(int(x)))) + + +@given(integral_floats, integral_floats) +def test_integral_floats_order_as_integers(x, y): + assume(x != y) + x, y = sorted((x, y)) + assert flt.float_to_lex(x) < flt.float_to_lex(y) + + +@given(st.floats(0, 1)) +def test_fractional_floats_are_worse_than_one(f): + assume(0 < f < 1) + assert flt.float_to_lex(f) > flt.float_to_lex(1) + + +def test_reverse_bits_table_reverses_bits(): + def bits(x): + result = [] + for _ in range(8): + result.append(x & 1) + x >>= 1 + result.reverse() + return result + + for i, b in enumerate(flt.REVERSE_BITS_TABLE): + assert bits(i) == list(reversed(bits(b))) + + +def test_reverse_bits_table_has_right_elements(): + assert sorted(flt.REVERSE_BITS_TABLE) == list(range(256)) + + +def minimal_from(start, condition): + buf = int_to_bytes(flt.float_to_lex(start), 8) + + def parse_buf(b): + return flt.lex_to_float(int_from_bytes(b)) + + shrunk = Lexical.shrink( + buf, lambda b: condition(parse_buf(b)), + full=True, random=Random(0) + ) + return parse_buf(shrunk) + + +INTERESTING_FLOATS = [ + 0.0, 1.0, 2.0, sys.float_info.max, float('inf'), float('nan') +] + + +@pytest.mark.parametrize(('start', 'end'), [ + (a, b) + for a in INTERESTING_FLOATS + for b in INTERESTING_FLOATS + if flt.float_to_lex(a) > flt.float_to_lex(b) +]) +def test_can_shrink_downwards(start, end): + assert minimal_from(start, lambda x: not (x < end)) == end + + +@pytest.mark.parametrize( + 'f', [1, 2, 4, 8, 10, 16, 32, 64, 100, 128, 256, 500, 512, 1000, 1024] +) +@pytest.mark.parametrize( + 'mul', [1.1, 1.5, 9.99, 10] +) +def test_shrinks_downwards_to_integers(f, mul): + g = minimal_from(f * mul, lambda x: x >= f) + assert g == f + + +def test_shrink_to_integer_upper_bound(): + assert minimal_from(1.1, lambda x: 1 < x <= 2) == 2 + + +def test_shrink_up_to_one(): + assert minimal_from(0.5, lambda x: 0.5 <= x <= 1.5) == 1 + + +def test_shrink_down_to_half(): + assert minimal_from(0.75, lambda x: 0 < x < 1) == 0.5 + + +def test_does_not_shrink_across_one(): + # This is something of an odd special case. Because of our encoding we + # prefer all numbers >= 1 to all numbers in 0 < x < 1. For the most part + # this is the correct thing to do, but there are some low negative exponent + # cases where we get odd behaviour like this. + + # This test primarily exists to validate that we don't try to subtract one + # from the starting point and trigger an internal exception. + assert minimal_from(1.1, lambda x: x == 1.1 or 0 < x < 1) == 1.1 + + +@pytest.mark.parametrize('f', [2.0, 10000000.0]) +def test_converts_floats_to_integer_form(f): + assert flt.is_simple(f) + + buf = int_to_bytes(flt.base_float_to_lex(f), 8) + + def parse_buf(b): + return flt.lex_to_float(int_from_bytes(b)) + + shrunk = Lexical.shrink( + buf, lambda b: parse_buf(b) == f, + full=True, random=Random(0) + ) + assert shrunk < buf diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_conjecture_minimizer.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_conjecture_minimizer.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_conjecture_minimizer.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_conjecture_minimizer.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,75 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from random import Random +from collections import Counter + +from hypothesis.internal.compat import hbytes +from hypothesis.internal.conjecture.shrinking import Lexical + + +def test_shrink_to_zero(): + assert Lexical.shrink( + hbytes([255] * 8), lambda x: True, random=Random(0)) == hbytes(8) + + +def test_shrink_to_smallest(): + assert Lexical.shrink( + hbytes([255] * 8), lambda x: sum(x) > 10, random=Random(0), + ) == hbytes([0] * 7 + [11]) + + +def test_float_hack_fails(): + assert Lexical.shrink( + hbytes([255] * 8), lambda x: x[0] >> 7, random=Random(0), + ) == hbytes([128] + [0] * 7) + + +def test_can_sort_bytes_by_reordering(): + start = hbytes([5, 4, 3, 2, 1, 0]) + finish = Lexical.shrink( + start, lambda x: set(x) == set(start), random=Random(0)) + assert finish == hbytes([0, 1, 2, 3, 4, 5]) + + +def test_can_sort_bytes_by_reordering_partially(): + start = hbytes([5, 4, 3, 2, 1, 0]) + finish = Lexical.shrink( + start, lambda x: set(x) == set(start) and x[0] > x[-1], + random=Random(0), + ) + assert finish == hbytes([1, 2, 3, 4, 5, 0]) + + +def test_can_sort_bytes_by_reordering_partially2(): + start = hbytes([5, 4, 3, 2, 1, 0]) + finish = Lexical.shrink( + start, lambda x: Counter(x) == Counter(start) and x[0] > x[2], + random=Random(0), full=True, + ) + assert finish <= hbytes([1, 2, 0, 3, 4, 5]) + + +def test_can_sort_bytes_by_reordering_partially_not_cross_stationary_element(): + start = hbytes([5, 3, 0, 2, 1, 4]) + finish = Lexical.shrink( + start, lambda x: set(x) == set(start) and x[3] == 2, + random=Random(0), + ) + assert finish <= hbytes([0, 3, 5, 2, 1, 4]) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_conjecture_order_shrinking.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_conjecture_order_shrinking.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_conjecture_order_shrinking.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_conjecture_order_shrinking.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,56 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from random import Random + +import hypothesis.strategies as st +from hypothesis import given, example +from hypothesis.internal.conjecture.shrinking import Ordering + + +@example([0, 1, 1, 1, 1, 1, 1, 0]) +@example([0, 0]) +@example([0, 1, -1]) +@given(st.lists(st.integers())) +def test_shrinks_down_to_sorted_the_slow_way(ls): + # We normally would short-circuit and find that we can sort this + # automatically, but here we test that a single run_step could put the + # list in sorted order anyway if it had to, and that that is just an + # optimisation. + shrinker = Ordering(ls, lambda ls: True, random=Random(0), full=False) + shrinker.run_step() + assert list(shrinker.current) == sorted(ls) + + +def test_can_partially_sort_a_list(): + finish = Ordering.shrink( + [5, 4, 3, 2, 1, 0], + lambda x: x[0] > x[-1], + random=Random(0), + ) + assert finish == (1, 2, 3, 4, 5, 0) + + +def test_can_partially_sort_a_list_2(): + finish = Ordering.shrink( + [5, 4, 3, 2, 1, 0], + lambda x: x[0] > x[2], + random=Random(0), full=True + ) + assert finish <= (1, 2, 0, 3, 4, 5) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_conjecture_shrinking_interface.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_conjecture_shrinking_interface.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_conjecture_shrinking_interface.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_conjecture_shrinking_interface.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,40 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from tests.common.utils import capture_out +from hypothesis.internal.conjecture.shrinking import Integer + + +def test_debug_output(): + with capture_out() as o: + Integer.shrink(10, lambda x: True, debug=True) + + assert 'initial=10' in o.getvalue() + assert 'shrinking to 0' in o.getvalue() + + +def test_includes_name_in_repr_if_set(): + assert repr( + Integer(10, lambda x: True, name='hi there') + ) == "Integer('hi there', initial=10, current=10)" + + +def test_normally_contains_no_space_for_name(): + assert repr( + Integer(10, lambda x: True)) == 'Integer(initial=10, current=10)' diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_conjecture_test_data.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_conjecture_test_data.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_conjecture_test_data.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_conjecture_test_data.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,167 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import pytest + +from hypothesis import given +from hypothesis import strategies as st +from hypothesis.errors import Frozen +from hypothesis.internal.compat import hbytes +from hypothesis.internal.conjecture.data import Status, StopTest, \ + ConjectureData +from hypothesis.searchstrategy.strategies import SearchStrategy + + +@given(st.binary()) +def test_buffer_draws_as_self(buf): + x = ConjectureData.for_buffer(buf) + assert x.draw_bytes(len(buf)) == buf + + +def test_cannot_draw_after_freeze(): + x = ConjectureData.for_buffer(b'hi') + x.draw_bytes(1) + x.freeze() + with pytest.raises(Frozen): + x.draw_bytes(1) + + +def test_can_double_freeze(): + x = ConjectureData.for_buffer(b'hi') + x.freeze() + assert x.frozen + x.freeze() + assert x.frozen + + +def test_can_draw_zero_bytes(): + x = ConjectureData.for_buffer(b'') + for _ in range(10): + assert x.draw_bytes(0) == b'' + + +def test_draw_past_end_sets_overflow(): + x = ConjectureData.for_buffer(hbytes(5)) + with pytest.raises(StopTest) as e: + x.draw_bytes(6) + assert e.value.testcounter == x.testcounter + assert x.frozen + assert x.status == Status.OVERRUN + + +def test_notes_repr(): + x = ConjectureData.for_buffer(b'') + x.note(b'hi') + assert repr(b'hi') in x.output + + +def test_can_mark_interesting(): + x = ConjectureData.for_buffer(bytes()) + with pytest.raises(StopTest): + x.mark_interesting() + assert x.frozen + assert x.status == Status.INTERESTING + + +def test_drawing_zero_bits_is_free(): + x = ConjectureData.for_buffer(bytes()) + assert x.draw_bits(0) == 0 + + +def test_can_mark_invalid(): + x = ConjectureData.for_buffer(bytes()) + with pytest.raises(StopTest): + x.mark_invalid() + assert x.frozen + assert x.status == Status.INVALID + + +class BoomStrategy(SearchStrategy): + + def do_draw(self, data): + data.draw_bytes(1) + raise ValueError() + + +def test_closes_interval_on_error_in_strategy(): + x = ConjectureData.for_buffer(b'hi') + with pytest.raises(ValueError): + x.draw(BoomStrategy()) + x.freeze() + assert not any(eg.end is None for eg in x.examples) + + +class BigStrategy(SearchStrategy): + + def do_draw(self, data): + data.draw_bytes(10 ** 6) + + +def test_does_not_double_freeze_in_interval_close(): + x = ConjectureData.for_buffer(b'hi') + with pytest.raises(StopTest): + x.draw(BigStrategy()) + assert x.frozen + assert not any(eg.end is None for eg in x.examples) + + +def test_empty_discards_do_not_count(): + x = ConjectureData.for_buffer(b'') + x.start_example(label=1) + x.stop_example(discard=True) + x.freeze() + assert not x.has_discards + + +def test_triviality(): + d = ConjectureData.for_buffer([1, 0, 1]) + + d.start_example(1) + d.draw_bits(1) + d.draw_bits(1) + d.stop_example(1) + + d.write(hbytes([2])) + d.freeze() + + def eg(u, v): + return [ex for ex in d.examples if ex.start == u and ex.end == v][0] + + assert not eg(0, 2).trivial + assert not eg(0, 1).trivial + assert eg(1, 2).trivial + assert eg(2, 3).trivial + + +def test_example_depth_marking(): + d = ConjectureData.for_buffer(hbytes(24)) + + # These draw sizes are chosen so that each example has a unique length. + d.draw_bytes(2) + d.start_example('inner') + d.draw_bytes(3) + d.draw_bytes(6) + d.stop_example() + d.draw_bytes(12) + d.freeze() + + depths = set((ex.length, ex.depth) for ex in d.examples) + assert depths == set([ + (2, 1), (3, 2), (6, 2), (9, 1), (12, 1), (23, 0) + ]) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_conjecture_utils.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_conjecture_utils.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_conjecture_utils.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_conjecture_utils.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,172 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from fractions import Fraction +from collections import Counter + +import hypothesis.strategies as st +import hypothesis.internal.conjecture.utils as cu +from hypothesis import HealthCheck, given, assume, example, settings +from hypothesis.internal.compat import hbytes, hrange +from hypothesis.internal.coverage import IN_COVERAGE_TESTS +from hypothesis.internal.conjecture.data import ConjectureData + + +def test_does_draw_data_for_empty_range(): + data = ConjectureData.for_buffer(b'\1') + assert cu.integer_range(data, 1, 1) == 1 + data.freeze() + assert data.buffer == hbytes(b'\0') + + +def test_uniform_float_shrinks_to_zero(): + d = ConjectureData.for_buffer(hbytes([0] * 7)) + assert cu.fractional_float(d) == 0.0 + assert len(d.buffer) == 7 + + +def test_uniform_float_can_draw_1(): + d = ConjectureData.for_buffer(hbytes([255] * 7)) + assert cu.fractional_float(d) == 1.0 + assert len(d.buffer) == 7 + + +def test_geometric_can_handle_bad_first_draw(): + assert cu.geometric(ConjectureData.for_buffer(hbytes( + [255] * 7 + [0] * 7)), 0.5) == 0 + + +def test_coin_biased_towards_truth(): + p = 1 - 1.0 / 500 + + for i in range(255): + assert cu.biased_coin( + ConjectureData.for_buffer([i]), p + ) + + second_order = [ + cu.biased_coin(ConjectureData.for_buffer([255, i]), p) + for i in range(255) + ] + + assert False in second_order + assert True in second_order + + +def test_coin_biased_towards_falsehood(): + p = 1.0 / 500 + + for i in range(255): + assert not cu.biased_coin( + ConjectureData.for_buffer([i]), p + ) + + second_order = [ + cu.biased_coin(ConjectureData.for_buffer([255, i]), p) + for i in range(255) + ] + + assert False in second_order + assert True in second_order + + +def test_unbiased_coin_has_no_second_order(): + counts = Counter() + + for i in range(256): + buf = hbytes([i]) + data = ConjectureData.for_buffer(buf) + result = cu.biased_coin(data, 0.5) + if data.buffer == buf: + counts[result] += 1 + + assert counts[False] == counts[True] > 0 + + +def test_can_get_odd_number_of_bits(): + counts = Counter() + for i in range(256): + x = cu.getrandbits(ConjectureData.for_buffer([i]), 3) + assert 0 <= x <= 7 + counts[x] += 1 + assert len(set(counts.values())) == 1 + + +def test_8_bits_just_reads_stream(): + for i in range(256): + assert cu.getrandbits(ConjectureData.for_buffer([i]), 8) == i + + +def test_drawing_certain_coin_still_writes(): + data = ConjectureData.for_buffer([0, 1]) + assert not data.buffer + assert cu.biased_coin(data, 1) + assert data.buffer + + +def test_drawing_impossible_coin_still_writes(): + data = ConjectureData.for_buffer([1, 0]) + assert not data.buffer + assert not cu.biased_coin(data, 0) + assert data.buffer + + +def test_drawing_an_exact_fraction_coin(): + count = 0 + for i in hrange(8): + if cu.biased_coin(ConjectureData.for_buffer([i]), Fraction(3, 8)): + count += 1 + assert count == 3 + + +@st.composite +def weights(draw): + parts = draw(st.lists(st.integers())) + parts.reverse() + base = Fraction(1, 1) + for p in parts: + base = Fraction(1) / (1 + base) + return base + + +@example([Fraction(1, 3), Fraction(1, 3), Fraction(1, 3)]) +@example([Fraction(1, 1), Fraction(1, 2)]) +@example([Fraction(1, 2), Fraction(4, 10)]) +@example([Fraction(1, 1), Fraction(3, 5), Fraction(1, 1)]) +@example([Fraction(2, 257), Fraction(2, 5), Fraction(1, 11)]) +@settings( + deadline=None, suppress_health_check=HealthCheck.all(), + max_examples=0 if IN_COVERAGE_TESTS else settings.default.max_examples, +) +@given(st.lists(weights(), min_size=1)) +def test_sampler_distribution(weights): + total = sum(weights) + n = len(weights) + + assume(total > 0) + + probabilities = [w / total for w in weights] + + sampler = cu.Sampler(weights) + + calculated = [Fraction(0)] * n + for base, alternate, p_alternate in sampler.table: + calculated[base] += (1 - p_alternate) / n + calculated[alternate] += p_alternate / n + assert probabilities == calculated diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_control.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_control.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_control.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_control.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,149 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import pytest + +from hypothesis import Verbosity, given, settings, reporting +from hypothesis.errors import CleanupFailed, InvalidArgument +from hypothesis.control import BuildContext, note, event, cleanup, \ + current_build_context, _current_build_context +from tests.common.utils import capture_out +from hypothesis.strategies import integers +from hypothesis.internal.conjecture.data import ConjectureData as TD + + +def bc(): + return BuildContext(TD.for_buffer(b'')) + + +def test_cannot_cleanup_with_no_context(): + with pytest.raises(InvalidArgument): + cleanup(lambda: None) + assert _current_build_context.value is None + + +def test_cannot_event_with_no_context(): + with pytest.raises(InvalidArgument): + event('hi') + assert _current_build_context.value is None + + +def test_cleanup_executes_on_leaving_build_context(): + data = [] + with bc(): + cleanup(lambda: data.append(1)) + assert not data + assert data == [1] + assert _current_build_context.value is None + + +def test_can_nest_build_context(): + data = [] + with bc(): + cleanup(lambda: data.append(1)) + with bc(): + cleanup(lambda: data.append(2)) + assert not data + assert data == [2] + assert data == [2, 1] + assert _current_build_context.value is None + + +def test_does_not_suppress_exceptions(): + with pytest.raises(AssertionError): + with bc(): + assert False + assert _current_build_context.value is None + + +def test_suppresses_exceptions_in_teardown(): + with capture_out() as o: + with pytest.raises(AssertionError): + with bc(): + def foo(): + raise ValueError() + cleanup(foo) + assert False + + assert u'ValueError' in o.getvalue() + assert _current_build_context.value is None + + +def test_runs_multiple_cleanup_with_teardown(): + with capture_out() as o: + with pytest.raises(AssertionError): + with bc(): + def foo(): + raise ValueError() + cleanup(foo) + + def bar(): + raise TypeError() + cleanup(foo) + cleanup(bar) + assert False + + assert u'ValueError' in o.getvalue() + assert u'TypeError' in o.getvalue() + assert _current_build_context.value is None + + +def test_raises_error_if_cleanup_fails_but_block_does_not(): + with pytest.raises(CleanupFailed): + with bc(): + def foo(): + raise ValueError() + cleanup(foo) + assert _current_build_context.value is None + + +def test_raises_if_note_out_of_context(): + with pytest.raises(InvalidArgument): + note('Hi') + + +def test_raises_if_current_build_context_out_of_context(): + with pytest.raises(InvalidArgument): + current_build_context() + + +def test_current_build_context_is_current(): + with bc() as a: + assert current_build_context() is a + + +def test_prints_all_notes_in_verbose_mode(): + # slightly roundabout because @example messes with verbosity - see #1521 + messages = set() + + @settings(verbosity=Verbosity.debug, database=None) + @given(integers(1, 10)) + def test(x): + msg = 'x -> %d' % (x,) + note(msg) + messages.add(msg) + assert x < 5 + + with capture_out() as out: + with reporting.with_reporter(reporting.default): + with pytest.raises(AssertionError): + test() + v = out.getvalue() + for x in sorted(messages): + assert x in v diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_core.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_core.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_core.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_core.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,91 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import time + +import pytest +from flaky import flaky + +import hypothesis.strategies as s +from hypothesis import find, given, reject, settings +from hypothesis.errors import NoSuchExample, Unsatisfiable +from tests.common.utils import checks_deprecated_behaviour + + +def test_stops_after_max_examples_if_satisfying(): + tracker = [] + + def track(x): + tracker.append(x) + return False + + max_examples = 100 + + with pytest.raises(NoSuchExample): + find( + s.integers(0, 10000), + track, settings=settings(max_examples=max_examples)) + + assert len(tracker) == max_examples + + +def test_stops_after_ten_times_max_examples_if_not_satisfying(): + count = [0] + + def track(x): + count[0] += 1 + reject() + + max_examples = 100 + + with pytest.raises(Unsatisfiable): + find( + s.integers(0, 10000), + track, settings=settings(max_examples=max_examples)) + + assert count[0] == 10 * max_examples + + +@checks_deprecated_behaviour +@flaky(min_passes=1, max_runs=2) +def test_can_time_out_in_simplify(): + def slow_always_true(x): + time.sleep(0.1) + return True + start = time.time() + find( + s.lists(s.booleans()), slow_always_true, + settings=settings(timeout=0.1, database=None) + ) + finish = time.time() + run_time = finish - start + assert run_time <= 0.4 + + +some_normal_settings = settings() + + +def test_is_not_normally_default(): + assert settings.default is not some_normal_settings + + +@given(s.booleans()) +@some_normal_settings +def test_settings_are_default_in_given(x): + assert settings.default is some_normal_settings diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_custom_reprs.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_custom_reprs.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_custom_reprs.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_custom_reprs.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,66 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import pytest + +import hypothesis.strategies as st +from hypothesis import given + + +def test_includes_non_default_args_in_repr(): + assert repr(st.integers()) == 'integers()' + assert repr(st.integers(min_value=1)) == 'integers(min_value=1)' + + +def hi(there, stuff): + return there + + +def test_supports_positional_and_keyword_args_in_builds(): + assert repr(st.builds(hi, st.integers(), there=st.booleans())) == \ + 'builds(hi, integers(), there=booleans())' + + +def test_preserves_sequence_type_of_argument(): + assert repr(st.sampled_from([0])) == 'sampled_from([0])' + + +class IHaveABadRepr(object): + + def __repr__(self): + raise ValueError('Oh no!') + + +def test_errors_are_deferred_until_repr_is_calculated(): + s = st.builds( + lambda x, y: 1, + st.just(IHaveABadRepr()), + y=st.one_of( + st.sampled_from((IHaveABadRepr(),)), st.just(IHaveABadRepr())) + ).map(lambda t: t).filter(lambda t: True).flatmap( + lambda t: st.just(IHaveABadRepr())) + + with pytest.raises(ValueError): + repr(s) + + +@given(st.iterables(st.integers())) +def test_iterables_repr_is_useful(it): + # fairly hard-coded but useful; also ensures _values are inexhaustible + assert repr(it) == 'iter({!r})'.format(it._values) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_database_backend.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_database_backend.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_database_backend.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_database_backend.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,199 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import os +import base64 + +import pytest + +from hypothesis import given, settings +from tests.common.utils import validate_deprecation, \ + checks_deprecated_behaviour +from hypothesis.database import ExampleDatabase, SQLiteExampleDatabase, \ + InMemoryExampleDatabase, DirectoryBasedExampleDatabase +from hypothesis.strategies import lists, binary, tuples + +small_settings = settings(max_examples=50) + + +@given(lists(tuples(binary(), binary()))) +@small_settings +def test_backend_returns_what_you_put_in(xs): + backend = InMemoryExampleDatabase() + mapping = {} + for key, value in xs: + mapping.setdefault(key, set()).add(value) + backend.save(key, value) + for key, values in mapping.items(): + backend_contents = list(backend.fetch(key)) + distinct_backend_contents = set(backend_contents) + assert len(backend_contents) == len(distinct_backend_contents) + assert distinct_backend_contents == set(values) + + +@checks_deprecated_behaviour +def test_does_not_commit_in_error_state(): + backend = SQLiteExampleDatabase(':memory:') + backend.create_db_if_needed() + try: + with backend.cursor() as cursor: + cursor.execute(""" + insert into hypothesis_data_mapping(key, value) + values("a", "b") + """) + raise ValueError() + except ValueError: + pass + + assert list(backend.fetch(b'a')) == [] + + +@checks_deprecated_behaviour +def test_can_double_close(): + backend = SQLiteExampleDatabase(':memory:') + backend.create_db_if_needed() + backend.close() + backend.close() + + +def test_can_delete_keys(): + backend = InMemoryExampleDatabase() + backend.save(b'foo', b'bar') + backend.save(b'foo', b'baz') + backend.delete(b'foo', b'bar') + assert list(backend.fetch(b'foo')) == [b'baz'] + + +@checks_deprecated_behaviour +def test_ignores_badly_stored_values(): + backend = SQLiteExampleDatabase(':memory:') + backend.create_db_if_needed() + with backend.cursor() as cursor: + cursor.execute(""" + insert into hypothesis_data_mapping(key, value) + values(?, ?) + """, (base64.b64encode(b'foo'), u'kittens')) + assert list(backend.fetch(b'foo')) == [] + + +def test_default_database_is_in_memory(): + assert isinstance(ExampleDatabase(), InMemoryExampleDatabase) + + +def test_default_on_disk_database_is_dir(tmpdir): + assert isinstance( + ExampleDatabase(tmpdir.join('foo')), DirectoryBasedExampleDatabase) + + +@checks_deprecated_behaviour +def test_selects_sqlite_database_if_name_matches(tmpdir): + assert isinstance( + ExampleDatabase(tmpdir.join('foo.db')), SQLiteExampleDatabase) + assert isinstance( + ExampleDatabase(tmpdir.join('foo.sqlite')), SQLiteExampleDatabase) + assert isinstance( + ExampleDatabase(tmpdir.join('foo.sqlite3')), SQLiteExampleDatabase) + + +def test_selects_directory_based_if_already_directory(tmpdir): + path = str(tmpdir.join('hi.sqlite3')) + DirectoryBasedExampleDatabase(path).save(b'foo', b'bar') + assert isinstance(ExampleDatabase(path), DirectoryBasedExampleDatabase) + + +@checks_deprecated_behaviour +def test_selects_sqlite_if_already_sqlite(tmpdir): + path = str(tmpdir.join('hi')) + SQLiteExampleDatabase(path).save(b'foo', b'bar') + assert isinstance(ExampleDatabase(path), SQLiteExampleDatabase) + + +def test_does_not_error_when_fetching_when_not_exist(tmpdir): + db = DirectoryBasedExampleDatabase(tmpdir.join('examples')) + db.fetch(b'foo') + + +@pytest.fixture(scope='function', params=['memory', 'sql', 'directory']) +def exampledatabase(request, tmpdir): + if request.param == 'memory': + return ExampleDatabase() + if request.param == 'sql': + with validate_deprecation(): + return SQLiteExampleDatabase(str(tmpdir.join('example.db'))) + if request.param == 'directory': + return DirectoryBasedExampleDatabase(str(tmpdir.join('examples'))) + assert False + + +def test_can_delete_a_key_that_is_not_present(exampledatabase): + exampledatabase.delete(b'foo', b'bar') + + +def test_can_fetch_a_key_that_is_not_present(exampledatabase): + assert list(exampledatabase.fetch(b'foo')) == [] + + +def test_saving_a_key_twice_fetches_it_once(exampledatabase): + exampledatabase.save(b'foo', b'bar') + exampledatabase.save(b'foo', b'bar') + assert list(exampledatabase.fetch(b'foo')) == [b'bar'] + + +def test_can_close_a_database_without_touching_it(exampledatabase): + exampledatabase.close() + + +def test_can_close_a_database_after_saving(exampledatabase): + exampledatabase.save(b'foo', b'bar') + + +def test_class_name_is_in_repr(exampledatabase): + assert type(exampledatabase).__name__ in repr(exampledatabase) + exampledatabase.close() + + +def test_an_absent_value_is_present_after_it_moves(exampledatabase): + exampledatabase.move(b'a', b'b', b'c') + assert next(exampledatabase.fetch(b'b')) == b'c' + + +def test_an_absent_value_is_present_after_it_moves_to_self(exampledatabase): + exampledatabase.move(b'a', b'a', b'b') + assert next(exampledatabase.fetch(b'a')) == b'b' + + +def test_two_directory_databases_can_interact(tmpdir): + path = str(tmpdir) + db1 = DirectoryBasedExampleDatabase(path) + db2 = DirectoryBasedExampleDatabase(path) + db1.save(b'foo', b'bar') + assert list(db2.fetch(b'foo')) == [b'bar'] + db2.save(b'foo', b'bar') + db2.save(b'foo', b'baz') + assert sorted(db1.fetch(b'foo')) == [b'bar', b'baz'] + + +def test_can_handle_disappearing_files(tmpdir, monkeypatch): + path = str(tmpdir) + db = DirectoryBasedExampleDatabase(path) + db.save(b'foo', b'bar') + base_listdir = os.listdir + monkeypatch.setattr(os, 'listdir', + lambda d: base_listdir(d) + ['this-does-not-exist']) + assert list(db.fetch(b'foo')) == [b'bar'] diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_database_seed_deprecation.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_database_seed_deprecation.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_database_seed_deprecation.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_database_seed_deprecation.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,42 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import pytest + +from hypothesis import seed, given, settings +from hypothesis import strategies as st +from tests.common.utils import validate_deprecation +from hypothesis.database import InMemoryExampleDatabase + + +@pytest.mark.parametrize('dec', [ + settings(database=InMemoryExampleDatabase(), derandomize=True), seed(1) +]) +def test_deprecated_determinism_with_database(dec): + @dec + @given(st.booleans()) + def test(i): + raise ValueError() + + with pytest.raises(ValueError): + test() + + with validate_deprecation(): + with pytest.raises(ValueError): + test() diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_datetimes.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_datetimes.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_datetimes.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_datetimes.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,164 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import datetime as dt + +import pytest + +from hypothesis import given +from tests.common.debug import minimal, find_any +from tests.common.utils import checks_deprecated_behaviour +from hypothesis.strategies import none, dates, times, binary, datetimes, \ + timedeltas +from hypothesis.internal.compat import hrange +from hypothesis.searchstrategy.datetime import DatetimeStrategy +from hypothesis.internal.conjecture.data import Status, StopTest, \ + ConjectureData + + +def test_can_find_positive_delta(): + assert minimal(timedeltas(), lambda x: x.days > 0) == dt.timedelta(1) + + +def test_can_find_negative_delta(): + assert minimal(timedeltas(max_value=dt.timedelta(10**6)), + lambda x: x.days < 0) == dt.timedelta(-1) + + +def test_can_find_on_the_second(): + find_any(timedeltas(), lambda x: x.seconds == 0) + + +def test_can_find_off_the_second(): + find_any(timedeltas(), lambda x: x.seconds != 0) + + +def test_simplifies_towards_zero_delta(): + d = minimal(timedeltas()) + assert d.days == d.seconds == d.microseconds == 0 + + +def test_min_value_is_respected(): + assert minimal(timedeltas(min_value=dt.timedelta(days=10))).days == 10 + + +def test_max_value_is_respected(): + assert minimal(timedeltas(max_value=dt.timedelta(days=-10))).days == -10 + + +@given(timedeltas()) +def test_single_timedelta(val): + assert find_any(timedeltas(val, val)) is val + + +def test_simplifies_towards_millenium(): + d = minimal(datetimes()) + assert d.year == 2000 + assert d.month == d.day == 1 + assert d.hour == d.minute == d.second == d.microsecond == 0 + + +@given(datetimes()) +def test_default_datetimes_are_naive(dt): + assert dt.tzinfo is None + + +def test_bordering_on_a_leap_year(): + x = minimal(datetimes(dt.datetime.min.replace(year=2003), + dt.datetime.max.replace(year=2005)), + lambda x: x.month == 2 and x.day == 29, + timeout_after=60) + assert x.year == 2004 + + +def test_DatetimeStrategy_draw_may_fail(): + def is_failure_inducing(b): + try: + return strat._attempt_one_draw( + ConjectureData.for_buffer(b)) is None + except StopTest: + return False + + strat = DatetimeStrategy(dt.datetime.min, dt.datetime.max, none()) + failure_inducing = minimal(binary(), is_failure_inducing) + data = ConjectureData.for_buffer(failure_inducing * 100) + with pytest.raises(StopTest): + data.draw(strat) + assert data.status == Status.INVALID + + +def test_can_find_after_the_year_2000(): + assert minimal(dates(), lambda x: x.year > 2000).year == 2001 + + +def test_can_find_before_the_year_2000(): + assert minimal(dates(), lambda x: x.year < 2000).year == 1999 + + +def test_can_find_each_month(): + for month in hrange(1, 13): + find_any(dates(), lambda x: x.month == month) + + +def test_min_year_is_respected(): + assert minimal(dates(min_value=dt.date.min.replace(2003))).year == 2003 + + +def test_max_year_is_respected(): + assert minimal(dates(max_value=dt.date.min.replace(1998))).year == 1998 + + +@given(dates()) +def test_single_date(val): + assert find_any(dates(val, val)) is val + + +def test_can_find_midnight(): + find_any(times(), lambda x: x.hour == x.minute == x.second == 0) + + +def test_can_find_non_midnight(): + assert minimal(times(), lambda x: x.hour != 0).hour == 1 + + +def test_can_find_on_the_minute(): + find_any(times(), lambda x: x.second == 0) + + +def test_can_find_off_the_minute(): + find_any(times(), lambda x: x.second != 0) + + +def test_simplifies_towards_midnight(): + d = minimal(times()) + assert d.hour == d.minute == d.second == d.microsecond == 0 + + +def test_can_generate_naive_time(): + find_any(times(), lambda d: not d.tzinfo) + + +@given(times()) +def test_naive_times_are_naive(dt): + assert dt.tzinfo is None + + +@checks_deprecated_behaviour +def test_deprecated_min_date_is_respected(): + assert minimal(dates(min_date=dt.date.min.replace(2003))).year == 2003 diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_deadline.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_deadline.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_deadline.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_deadline.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,158 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import time +import warnings + +import pytest + +import hypothesis.strategies as st +from hypothesis import HealthCheck, given, settings, unlimited +from hypothesis.errors import Flaky, DeadlineExceeded, \ + HypothesisDeprecationWarning +from tests.common.utils import capture_out, checks_deprecated_behaviour + + +def test_raises_deadline_on_slow_test(): + @settings(deadline=500) + @given(st.integers()) + def slow(i): + time.sleep(1) + + with pytest.raises(DeadlineExceeded): + slow() + + +def test_only_warns_once(): + @given(st.integers()) + def slow(i): + time.sleep(1) + try: + warnings.simplefilter('always', HypothesisDeprecationWarning) + with warnings.catch_warnings(record=True) as w: + slow() + finally: + warnings.simplefilter('error', HypothesisDeprecationWarning) + assert len(w) == 1 + + +@checks_deprecated_behaviour +@given(st.integers()) +def test_slow_tests_are_deprecated_by_default(i): + time.sleep(1) + + +@given(st.integers()) +@settings(deadline=None) +def test_slow_with_none_deadline(i): + time.sleep(1) + + +def test_raises_flaky_if_a_test_becomes_fast_on_rerun(): + once = [True] + + @settings(deadline=500) + @given(st.integers()) + def test_flaky_slow(i): + if once[0]: + once[0] = False + time.sleep(1) + with pytest.raises(Flaky): + test_flaky_slow() + + +def test_deadlines_participate_in_shrinking(): + @settings(deadline=500) + @given(st.integers()) + def slow_if_large(i): + if i >= 10000: + time.sleep(1) + + with capture_out() as o: + with pytest.raises(DeadlineExceeded): + slow_if_large() + assert 'slow_if_large(i=10000)' in o.getvalue() + + +def test_keeps_you_well_above_the_deadline(): + seen = set() + failed_once = [False] + + @settings(deadline=100, timeout=unlimited, suppress_health_check=[ + HealthCheck.hung_test + ]) + @given(st.integers(0, 2000)) + def slow(i): + # Make sure our initial failure isn't something that immediately goes + # flaky. + if not failed_once[0]: + if i * 0.9 <= 100: + return + else: + failed_once[0] = True + + t = i / 1000 + if i in seen: + time.sleep(0.9 * t) + else: + seen.add(i) + time.sleep(t) + + with pytest.raises(DeadlineExceeded): + slow() + + +def test_gives_a_deadline_specific_flaky_error_message(): + once = [True] + + @settings(deadline=100) + @given(st.integers()) + def slow_once(i): + if once[0]: + once[0] = False + time.sleep(0.2) + + with capture_out() as o: + with pytest.raises(Flaky): + slow_once() + assert 'Unreliable test timing' in o.getvalue() + assert 'took 2' in o.getvalue() + + +@pytest.mark.parametrize('slow_strategy', [False, True]) +@pytest.mark.parametrize('slow_test', [False, True]) +def test_should_only_fail_a_deadline_if_the_test_is_slow( + slow_strategy, slow_test +): + s = st.integers() + if slow_strategy: + s = s.map(lambda x: time.sleep(0.08)) + + @settings(deadline=50) + @given(st.data()) + def test(data): + data.draw(s) + if slow_test: + time.sleep(0.1) + + if slow_test: + with pytest.raises(DeadlineExceeded): + test() + else: + test() diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_debug_information.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_debug_information.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_debug_information.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_debug_information.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,52 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import re + +import pytest + +import hypothesis.strategies as st +from hypothesis import Verbosity, given, settings +from tests.common.utils import capture_out + + +def test_reports_passes(): + @given(st.integers()) + @settings(verbosity=Verbosity.debug) + def test(i): + assert i < 10 + + with capture_out() as out: + with pytest.raises(AssertionError): + test() + + value = out.getvalue() + + assert 'adaptive_example_deletion' in value + assert 'calls' in value + assert 'shrinks' in value + + shrinks_info = re.compile(r"call(s?) of which ([0-9]+) shrank") + + for l in value.splitlines(): + m = shrinks_info.search(l) + if m is not None and int(m.group(2)) != 0: + break + else: + assert False, value diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_deferred_strategies.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_deferred_strategies.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_deferred_strategies.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_deferred_strategies.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,155 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import pytest + +from hypothesis import given +from hypothesis import strategies as st +from hypothesis.errors import InvalidArgument +from tests.common.debug import minimal, assert_no_examples +from hypothesis.internal.compat import hrange + + +def test_binary_tree(): + tree = st.deferred(lambda: st.integers() | st.tuples(tree, tree)) + + assert minimal(tree) == 0 + assert minimal(tree, lambda x: isinstance(x, tuple)) == (0, 0) + + +def test_mutual_recursion(): + t = st.deferred(lambda: a | b) + a = st.deferred(lambda: st.none() | st.tuples(st.just('a'), b)) + b = st.deferred(lambda: st.none() | st.tuples(st.just('b'), a)) + + for c in ('a', 'b'): + assert minimal( + t, lambda x: x is not None and x[0] == c) == (c, None) + + +def test_errors_on_non_function_define(): + x = st.deferred(1) + with pytest.raises(InvalidArgument): + x.example() + + +def test_errors_if_define_does_not_return_search_strategy(): + x = st.deferred(lambda: 1) + with pytest.raises(InvalidArgument): + x.example() + + +def test_errors_on_definition_as_self(): + x = st.deferred(lambda: x) + with pytest.raises(InvalidArgument): + x.example() + + +def test_branches_pass_through_deferred(): + x = st.one_of(st.booleans(), st.integers()) + y = st.deferred(lambda: x) + assert x.branches == y.branches + + +def test_can_draw_one_of_self(): + x = st.deferred(lambda: st.one_of(st.booleans(), x)) + assert minimal(x) is False + assert len(x.branches) == 1 + + +def test_hidden_self_references_just_result_in_no_example(): + bad = st.deferred(lambda: st.none().flatmap(lambda _: bad)) + assert_no_examples(bad) + + +def test_self_recursive_flatmap(): + bad = st.deferred(lambda: bad.flatmap(lambda x: st.none())) + assert_no_examples(bad) + + +def test_self_reference_through_one_of_can_detect_emptiness(): + bad = st.deferred(lambda: st.one_of(bad, bad)) + assert bad.is_empty + + +def test_self_tuple_draws_nothing(): + x = st.deferred(lambda: st.tuples(x)) + assert_no_examples(x) + + +def test_mutually_recursive_tuples_draw_nothing(): + x = st.deferred(lambda: st.tuples(y)) + y = st.tuples(x) + + assert_no_examples(x) + assert_no_examples(y) + + +def test_literals_strategy_is_valid(): + literals = st.deferred(lambda: st.one_of( + st.booleans(), + st.tuples(literals, literals), + literals.map(lambda x: [x]), + )) + + @given(literals) + def test(e): + pass + test() + + assert not literals.has_reusable_values + + +def test_impossible_self_recursion(): + x = st.deferred(lambda: st.tuples(st.none(), x)) + assert x.is_empty + assert x.has_reusable_values + + +def test_very_deep_deferral(): + # This test is designed so that the recursive properties take a very long + # time to converge: Although we can rapidly determine them for the original + # value, each round in the fixed point calculation only manages to update + # a single value in the related strategies, so it takes 100 rounds to + # update everything. Most importantly this triggers our infinite loop + # detection heuristic and we start tracking duplicates, but we shouldn't + # see any because this loop isn't infinite, just long. + def strat(i): + if i == 0: + return st.deferred(lambda: st.one_of(strategies + [st.none()])) + else: + return st.deferred( + lambda: st.tuples(strategies[(i + 1) % len(strategies)])) + + strategies = list(map(strat, hrange(100))) + + assert strategies[0].has_reusable_values + assert not strategies[0].is_empty + + +def test_recursion_in_middle(): + # This test is significant because the integers().map(abs) is not checked + # in the initial pass - when we recurse into x initially we decide that + # x is empty, so the tuple is empty, and don't need to check the third + # argument. Then when we do the more refined test we've discovered that x + # is non-empty, so we need to check the non-emptiness of the last component + # to determine the non-emptiness of the tuples. + x = st.deferred( + lambda: st.tuples(st.none(), x, st.integers().map(abs)) | st.none()) + assert not x.is_empty diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_detection.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_detection.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_detection.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_detection.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,67 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from hypothesis import given +from hypothesis.stateful import GenericStateMachine +from hypothesis.strategies import integers +from hypothesis.internal.detection import is_hypothesis_test + + +def test_functions_default_to_not_tests(): + def foo(): + pass + assert not is_hypothesis_test(foo) + + +def test_methods_default_to_not_tests(): + class Foo(object): + + def foo(): + pass + assert not is_hypothesis_test(Foo().foo) + + +def test_detection_of_functions(): + @given(integers()) + def test(i): + pass + + assert is_hypothesis_test(test) + + +def test_detection_of_methods(): + class Foo(object): + + @given(integers()) + def test(self, i): + pass + + assert is_hypothesis_test(Foo().test) + + +def test_detection_of_stateful_tests(): + class Stuff(GenericStateMachine): + + def steps(self): + return integers() + + def execute_step(self, step): + pass + + assert is_hypothesis_test(Stuff.TestCase().runTest) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_direct_strategies.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_direct_strategies.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_direct_strategies.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_direct_strategies.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,454 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import math +import decimal +import fractions +import collections +from datetime import date, time, datetime, timedelta + +import pytest + +import hypothesis.strategies as ds +from hypothesis import given, settings +from hypothesis.errors import InvalidArgument +from tests.common.debug import minimal +from tests.common.utils import checks_deprecated_behaviour +from hypothesis.internal.reflection import nicerepr + + +def fn_test(*fnkwargs): + fnkwargs = list(fnkwargs) + return pytest.mark.parametrize( + ('fn', 'args'), fnkwargs, + ids=[ + '%s(%s)' % (fn.__name__, ', '.join(map(nicerepr, args))) + for fn, args in fnkwargs + ] + ) + + +def fn_ktest(*fnkwargs): + fnkwargs = list(fnkwargs) + return pytest.mark.parametrize( + ('fn', 'kwargs'), fnkwargs, + ids=[ + '%s(%s)' % (fn.__name__, ', '.join(sorted( + '%s=%r' % (k, v) + for k, v in kwargs.items() + )),) + for fn, kwargs in fnkwargs + ] + ) + + +@fn_ktest( + (ds.integers, {'min_value': float('nan')}), + (ds.integers, {'min_value': 2, 'max_value': 1}), + (ds.integers, {'min_value': 0.1, 'max_value': 0.2}), + (ds.integers, {'min_value': float('nan')}), + (ds.integers, {'max_value': float('nan')}), + (ds.dates, {'min_value': 'fish'}), + (ds.dates, {'max_value': 'fish'}), + (ds.dates, { + 'min_value': date(2017, 8, 22), + 'max_value': date(2017, 8, 21)}), + (ds.datetimes, {'min_value': 'fish'}), + (ds.datetimes, {'max_value': 'fish'}), + (ds.datetimes, { + 'min_value': datetime(2017, 8, 22), + 'max_value': datetime(2017, 8, 21)}), + (ds.decimals, {'min_value': float('nan')}), + (ds.decimals, {'max_value': float('nan')}), + (ds.decimals, {'min_value': 2, 'max_value': 1}), + (ds.decimals, {'max_value': '-snan'}), + (ds.decimals, {'max_value': complex(1, 2)}), + (ds.decimals, {'places': -1}), + (ds.decimals, {'places': 0.5}), + (ds.decimals, {'max_value': 0.0, 'min_value': 1.0}), + (ds.decimals, {'min_value': 1.0, 'max_value': 0.0}), + (ds.decimals, { + 'min_value': 0.0, 'max_value': 1.0, 'allow_infinity': True}), + (ds.decimals, {'min_value': 'inf'}), + (ds.decimals, {'max_value': '-inf'}), + (ds.decimals, {'min_value': '-inf', 'allow_infinity': False}), + (ds.decimals, {'max_value': 'inf', 'allow_infinity': False}), + (ds.decimals, {'min_value': complex(1, 2)}), + (ds.decimals, {'min_value': '0.1', 'max_value': '0.9', 'places': 0}), + (ds.dictionaries, { + 'keys': ds.booleans(), 'values': ds.booleans(), + 'min_size': 10, 'max_size': 1}), + (ds.floats, {'min_value': float('nan')}), + (ds.floats, {'max_value': float('nan')}), + (ds.floats, {'min_value': complex(1, 2)}), + (ds.floats, {'max_value': complex(1, 2)}), + (ds.fractions, {'min_value': 2, 'max_value': 1}), + (ds.fractions, {'min_value': '1/3', 'max_value': '1/3', + 'max_denominator': 2}), + (ds.fractions, {'min_value': float('nan')}), + (ds.fractions, {'max_value': float('nan')}), + (ds.fractions, {'max_denominator': 0}), + (ds.fractions, {'max_denominator': 1.5}), + (ds.fractions, {'min_value': complex(1, 2)}), + (ds.lists, {'min_size': 10, 'max_size': 9}), + (ds.lists, {'min_size': -10, 'max_size': -9}), + (ds.lists, {'max_size': -9}), + (ds.lists, {'min_size': -10}), + (ds.lists, {'min_size': float('nan')}), + (ds.lists, {'elements': 'hi'}), + (ds.text, {'min_size': 10, 'max_size': 9}), + (ds.binary, {'min_size': 10, 'max_size': 9}), + (ds.floats, {'min_value': float('nan')}), + (ds.floats, {'min_value': '0'}), + (ds.floats, {'max_value': '0'}), + (ds.floats, {'max_value': 0.0, 'min_value': 1.0}), + (ds.floats, {'min_value': 0.0, 'allow_nan': True}), + (ds.floats, {'max_value': 0.0, 'allow_nan': True}), + (ds.floats, {'min_value': 0.0, 'max_value': 1.0, 'allow_infinity': True}), + (ds.complex_numbers, {'min_magnitude': float('nan')}), + (ds.complex_numbers, {'max_magnitude': float('nan')}), + (ds.complex_numbers, {'max_magnitude': complex(1, 2)}), + (ds.complex_numbers, {'min_magnitude': -1}), + (ds.complex_numbers, {'max_magnitude': -1}), + (ds.complex_numbers, {'min_magnitude': 3, 'max_magnitude': 2}), + (ds.complex_numbers, {'max_magnitude': 2, 'allow_infinity': True}), + (ds.complex_numbers, {'max_magnitude': 2, 'allow_nan': True}), + (ds.fixed_dictionaries, {'mapping': 'fish'}), + (ds.fixed_dictionaries, {'mapping': {1: 'fish'}}), + (ds.dictionaries, {'keys': ds.integers(), 'values': 1}), + (ds.dictionaries, {'keys': 1, 'values': ds.integers()}), + (ds.text, {'alphabet': '', 'min_size': 1}), + (ds.timedeltas, {'min_value': 'fish'}), + (ds.timedeltas, {'max_value': 'fish'}), + (ds.timedeltas, { + 'min_value': timedelta(hours=1), + 'max_value': timedelta(minutes=1)}), + (ds.times, {'min_value': 'fish'}), + (ds.times, {'max_value': 'fish'}), + (ds.times, { + 'min_value': time(2, 0), + 'max_value': time(1, 0)}), + (ds.uuids, {'version': 6}), + (ds.characters, {'min_codepoint': -1}), + (ds.characters, {'min_codepoint': '1'}), + (ds.characters, {'max_codepoint': -1}), + (ds.characters, {'max_codepoint': '1'}), + (ds.characters, {'whitelist_categories': []}), + (ds.characters, {'whitelist_categories': ['Nd'], + 'blacklist_categories': ['Nd']}), +) +def test_validates_keyword_arguments(fn, kwargs): + with pytest.raises(InvalidArgument): + fn(**kwargs).example() + + +@fn_ktest( + (ds.integers, {'min_value': 0}), + (ds.integers, {'min_value': 11}), + (ds.integers, {'min_value': 11, 'max_value': 100}), + (ds.integers, {'max_value': 0}), + (ds.integers, {'min_value': decimal.Decimal('1.5')}), + (ds.integers, {'min_value': -1.5, 'max_value': -0.5}), + (ds.decimals, {'min_value': 1.0, 'max_value': 1.5}), + (ds.decimals, {'min_value': '1.0', 'max_value': '1.5'}), + (ds.decimals, {'min_value': decimal.Decimal('1.5')}), + (ds.decimals, { + 'max_value': 1.0, 'min_value': -1.0, 'allow_infinity': False}), + (ds.decimals, {'min_value': 1.0, 'allow_nan': False}), + (ds.decimals, {'max_value': 1.0, 'allow_nan': False}), + (ds.decimals, {'max_value': 1.0, 'min_value': -1.0, 'allow_nan': False}), + (ds.decimals, {'min_value': '-inf'}), + (ds.decimals, {'max_value': 'inf'}), + (ds.fractions, { + 'min_value': -1, 'max_value': 1, 'max_denominator': 1000}), + (ds.fractions, {'min_value': 1, 'max_value': 1}), + (ds.fractions, {'min_value': 1, 'max_value': 1, 'max_denominator': 2}), + (ds.fractions, {'min_value': 1.0}), + (ds.fractions, {'min_value': decimal.Decimal('1.0')}), + (ds.fractions, {'min_value': fractions.Fraction(1, 2)}), + (ds.fractions, {'min_value': '1/2', 'max_denominator': 1}), + (ds.fractions, {'max_value': '1/2', 'max_denominator': 1}), + (ds.lists, {'elements': ds.nothing(), 'max_size': 0}), + (ds.lists, {'elements': ds.integers()}), + (ds.lists, {'elements': ds.integers(), 'max_size': 5}), + (ds.lists, {'elements': ds.booleans(), 'min_size': 5}), + (ds.lists, {'elements': ds.booleans(), 'min_size': 5, 'max_size': 10}), + (ds.sets, { + 'min_size': 10, 'max_size': 10, 'elements': ds.integers(), + }), + (ds.booleans, {}), + (ds.just, {'value': 'hi'}), + (ds.integers, {'min_value': 12, 'max_value': 12}), + (ds.floats, {}), + (ds.floats, {'min_value': 1.0}), + (ds.floats, {'max_value': 1.0}), + (ds.floats, {'max_value': 1.0, 'min_value': -1.0}), + (ds.floats, { + 'max_value': 1.0, 'min_value': -1.0, 'allow_infinity': False}), + (ds.floats, {'min_value': 1.0, 'allow_nan': False}), + (ds.floats, {'max_value': 1.0, 'allow_nan': False}), + (ds.floats, {'max_value': 1.0, 'min_value': -1.0, 'allow_nan': False}), + (ds.complex_numbers, {}), + (ds.complex_numbers, {'min_magnitude': 3, 'max_magnitude': 3}), + (ds.complex_numbers, {'max_magnitude': 0}), + (ds.complex_numbers, {'allow_nan': True}), + (ds.complex_numbers, {'allow_nan': True, 'allow_infinity': True}), + (ds.complex_numbers, {'allow_nan': True, 'allow_infinity': False}), + (ds.complex_numbers, {'allow_nan': False}), + (ds.complex_numbers, {'allow_nan': False, 'allow_infinity': True}), + (ds.complex_numbers, {'allow_nan': False, 'allow_infinity': False}), + (ds.complex_numbers, { + 'max_magnitude': float('inf'), 'allow_infinity': True}), + (ds.sampled_from, {'elements': [1]}), + (ds.sampled_from, {'elements': [1, 2, 3]}), + (ds.fixed_dictionaries, {'mapping': {1: ds.integers()}}), + (ds.dictionaries, {'keys': ds.booleans(), 'values': ds.integers()}), + (ds.text, {'alphabet': 'abc'}), + (ds.text, {'alphabet': ''}), + (ds.text, {'alphabet': ds.sampled_from('abc')}), + (ds.characters, {'whitelist_categories': ['N']}), + (ds.characters, {'blacklist_categories': []}), +) +def test_produces_valid_examples_from_keyword(fn, kwargs): + fn(**kwargs).example() + + +@fn_test( + (ds.one_of, (1,)), + (ds.tuples, (1,)), +) +def test_validates_args(fn, args): + with pytest.raises(InvalidArgument): + fn(*args).example() + + +@fn_test( + (ds.one_of, (ds.booleans(), ds.tuples(ds.booleans()))), + (ds.one_of, (ds.booleans(),)), + (ds.text, ()), + (ds.binary, ()), + (ds.builds, (lambda x, y: x + y, ds.integers(), ds.integers())), +) +def test_produces_valid_examples_from_args(fn, args): + fn(*args).example() + + +def test_build_class_with_target_kwarg(): + NamedTupleWithTargetField = collections.namedtuple('Something', ['target']) + ds.builds(NamedTupleWithTargetField, target=ds.integers()).example() + + +@checks_deprecated_behaviour +def test_builds_can_specify_target_with_target_kwarg(): + ds.builds(x=ds.integers(), target=lambda x: x).example() + + +def test_builds_raises_with_no_target(): + with pytest.raises(InvalidArgument): + ds.builds().example() + + +@pytest.mark.parametrize('non_callable', [1, 'abc', ds.integers()]) +def test_builds_raises_if_non_callable_as_target_kwarg(non_callable): + with pytest.raises(InvalidArgument): + ds.builds(target=non_callable).example() + + +@pytest.mark.parametrize('non_callable', [1, 'abc', ds.integers()]) +def test_builds_raises_if_non_callable_as_first_arg(non_callable): + # If there are any positional arguments, then the target (which must be + # callable) must be specified as the first one. + with pytest.raises(InvalidArgument): + ds.builds(non_callable, target=lambda x: x).example() + + +def test_tuples_raise_error_on_bad_kwargs(): + with pytest.raises(TypeError): + ds.tuples(stuff='things') + + +@given(ds.lists(ds.booleans(), min_size=10, max_size=10)) +def test_has_specified_length(xs): + assert len(xs) == 10 + + +@given(ds.integers(max_value=100)) +@settings(max_examples=100) +def test_has_upper_bound(x): + assert x <= 100 + + +@given(ds.integers(min_value=100)) +def test_has_lower_bound(x): + assert x >= 100 + + +@given(ds.integers(min_value=1, max_value=2)) +def test_is_in_bounds(x): + assert 1 <= x <= 2 + + +@given(ds.fractions(min_value=-1, max_value=1, max_denominator=1000)) +def test_fraction_is_in_bounds(x): + assert -1 <= x <= 1 and abs(x.denominator) <= 1000 + + +@given(ds.fractions(min_value=fractions.Fraction(1, 2))) +def test_fraction_gt_positive(x): + assert fractions.Fraction(1, 2) <= x + + +@given(ds.fractions(max_value=fractions.Fraction(-1, 2))) +def test_fraction_lt_negative(x): + assert x <= fractions.Fraction(-1, 2) + + +@given(ds.decimals(min_value=-1.5, max_value=1.5, allow_nan=False)) +def test_decimal_is_in_bounds(x): + # decimal.Decimal("-1.5") == -1.5 (not explicitly testable in py2.6) + assert decimal.Decimal('-1.5') <= x <= decimal.Decimal('1.5') + + +def test_float_can_find_max_value_inf(): + assert minimal( + ds.floats(max_value=float('inf')), lambda x: math.isinf(x) + ) == float('inf') + assert minimal( + ds.floats(min_value=0.0), lambda x: math.isinf(x)) == float('inf') + + +def test_float_can_find_min_value_inf(): + minimal(ds.floats(), lambda x: x < 0 and math.isinf(x)) + minimal( + ds.floats(min_value=float('-inf'), max_value=0.0), + lambda x: math.isinf(x)) + + +def test_can_find_none_list(): + assert minimal(ds.lists(ds.none()), lambda x: len(x) >= 3) == [None] * 3 + + +def test_fractions(): + assert minimal(ds.fractions(), lambda f: f >= 1) == 1 + + +def test_decimals(): + assert minimal(ds.decimals(), lambda f: f.is_finite() and f >= 1) == 1 + + +def test_non_float_decimal(): + minimal( + ds.decimals(), + lambda d: d.is_finite() and decimal.Decimal(float(d)) != d) + + +def test_produces_dictionaries_of_at_least_minimum_size(): + t = minimal( + ds.dictionaries(ds.booleans(), ds.integers(), min_size=2), + lambda x: True) + assert t == {False: 0, True: 0} + + +@given(ds.dictionaries(ds.integers(), ds.integers(), max_size=5)) +@settings(max_examples=50) +def test_dictionaries_respect_size(d): + assert len(d) <= 5 + + +@given(ds.dictionaries(ds.integers(), ds.integers(), max_size=0)) +@settings(max_examples=50) +def test_dictionaries_respect_zero_size(d): + assert len(d) <= 5 + + +@given( + ds.lists(ds.none(), max_size=5) +) +def test_none_lists_respect_max_size(ls): + assert len(ls) <= 5 + + +@given( + ds.lists(ds.none(), max_size=5, min_size=1) +) +def test_none_lists_respect_max_and_min_size(ls): + assert 1 <= len(ls) <= 5 + + +@given(ds.iterables(ds.integers(), max_size=5, min_size=1)) +def test_iterables_are_exhaustible(it): + for _ in it: + pass + with pytest.raises(StopIteration): + next(it) + + +def test_minimal_iterable(): + assert list(minimal(ds.iterables(ds.integers()), lambda x: True)) == [] + + +@checks_deprecated_behaviour +def test_iterables_without_elements_is_deprecated(): + assert list(ds.iterables().example()) == [] + + +@checks_deprecated_behaviour +def test_lists_with_max_size_no_elements_is_deprecated_and_error(): + with pytest.raises(InvalidArgument): + ds.lists(max_size=1).example() + + +@checks_deprecated_behaviour +def test_empty_elements_with_max_size_is_deprecated(): + ds.lists(ds.nothing(), max_size=1).example() + + +@checks_deprecated_behaviour +def test_average_size_is_deprecated(): + ds.lists(ds.integers(), average_size=1).example() + + +@pytest.mark.parametrize('parameter_name', ['min_value', 'max_value']) +@pytest.mark.parametrize('value', [-1, 0, 1]) +def test_no_infinity_for_min_max_values(value, parameter_name): + kwargs = { + 'allow_infinity': False, + parameter_name: value, + } + + @given(ds.floats(**kwargs)) + def test_not_infinite(xs): + assert not math.isinf(xs) + + test_not_infinite() + + +@pytest.mark.parametrize('parameter_name', ['min_value', 'max_value']) +@pytest.mark.parametrize('value', [-1, 0, 1]) +def test_no_nan_for_min_max_values(value, parameter_name): + kwargs = { + 'allow_nan': False, + parameter_name: value, + } + + @given(ds.floats(**kwargs)) + def test_not_nan(xs): + assert not math.isnan(xs) + + test_not_nan() diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_draw_example.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_draw_example.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_draw_example.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_draw_example.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,35 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import pytest + +from tests.common import standard_types +from hypothesis.strategies import lists + + +@pytest.mark.parametrize( + u'spec', standard_types, ids=list(map(repr, standard_types))) +def test_single_example(spec): + spec.example() + + +@pytest.mark.parametrize( + u'spec', standard_types, ids=list(map(repr, standard_types))) +def test_list_example(spec): + lists(spec).example() diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_escalation.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_escalation.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_escalation.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_escalation.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,68 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import pytest + +import hypothesis.strategies as st +import hypothesis.internal.escalation as esc +from hypothesis import given + + +def test_does_not_escalate_errors_in_non_hypothesis_file(): + try: + assert False + except AssertionError: + esc.escalate_hypothesis_internal_error() + + +def test_does_escalate_errors_in_hypothesis_file(monkeypatch): + monkeypatch.setattr(esc, 'is_hypothesis_file', lambda x: True) + + with pytest.raises(AssertionError): + try: + assert False + except AssertionError: + esc.escalate_hypothesis_internal_error() + + +def test_does_not_escalate_errors_in_hypothesis_file_if_disabled(monkeypatch): + monkeypatch.setattr(esc, 'is_hypothesis_file', lambda x: True) + monkeypatch.setattr(esc, 'PREVENT_ESCALATION', True) + + try: + assert False + except AssertionError: + esc.escalate_hypothesis_internal_error() + + +def test_immediately_escalates_errors_in_generation(): + count = [0] + + def explode(s): + count[0] += 1 + raise ValueError() + + @given(st.integers().map(explode)) + def test(i): + pass + + with pytest.raises(ValueError): + test() + + assert count == [1] diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_example.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_example.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_example.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_example.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,76 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from random import Random +from decimal import Decimal + +import pytest + +import hypothesis.strategies as st +from hypothesis import find, given, example, settings +from hypothesis.errors import NoExamples +from hypothesis.control import _current_build_context +from tests.common.utils import checks_deprecated_behaviour + + +@settings(deadline=None) +@given(st.integers()) +def test_deterministic_examples_are_deterministic(seed): + with _current_build_context.with_value(None): + assert st.lists(st.integers()).example(Random(seed)) == \ + st.lists(st.integers()).example(Random(seed)) + + +def test_example_of_none_is_none(): + assert st.none().example() is None + + +def test_exception_in_compare_can_still_have_example(): + st.one_of( + st.none().map(lambda n: Decimal('snan')), + st.just(Decimal(0))).example() + + +def test_does_not_always_give_the_same_example(): + s = st.integers() + assert len(set( + s.example() for _ in range(100) + )) >= 10 + + +def test_raises_on_no_examples(): + with pytest.raises(NoExamples): + st.nothing().example() + + +@checks_deprecated_behaviour +@example(False) +@given(st.booleans()) +def test_example_inside_given(b): + st.integers().example() + + +@checks_deprecated_behaviour +def test_example_inside_find(): + find(st.integers(0, 100), lambda x: st.integers().example()) + + +@checks_deprecated_behaviour +def test_example_inside_strategy(): + st.booleans().map(lambda x: st.integers().example()).example() diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_executors.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_executors.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_executors.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_executors.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,98 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import inspect +from unittest import TestCase + +import pytest + +from hypothesis import given, example +from hypothesis.executors import ConjectureRunner +from hypothesis.strategies import booleans, integers + + +def test_must_use_result_of_test(): + class DoubleRun(object): + + def execute_example(self, function): + x = function() + if inspect.isfunction(x): + return x() + + @given(booleans()) + def boom(self, b): + def f(): + raise ValueError() + return f + + with pytest.raises(ValueError): + DoubleRun().boom() + + +class TestTryReallyHard(TestCase): + + @given(integers()) + def test_something(self, i): + pass + + def execute_example(self, f): + f() + return f() + + +class Valueless(object): + + def execute_example(self, f): + try: + return f() + except ValueError: + return None + + @given(integers()) + @example(1) + def test_no_boom_on_example(self, x): + raise ValueError() + + @given(integers()) + def test_no_boom(self, x): + raise ValueError() + + @given(integers()) + def test_boom(self, x): + assert False + + +def test_boom(): + with pytest.raises(AssertionError): + Valueless().test_boom() + + +def test_no_boom(): + Valueless().test_no_boom() + + +def test_no_boom_on_example(): + Valueless().test_no_boom_on_example() + + +class TestNormal(ConjectureRunner, TestCase): + + @given(booleans()) + def test_stuff(self, b): + pass diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_explicit_examples.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_explicit_examples.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_explicit_examples.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_explicit_examples.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,234 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from unittest import TestCase + +import pytest + +from hypothesis import Verbosity, note, given, example, settings, reporting +from hypothesis.errors import InvalidArgument +from tests.common.utils import capture_out +from hypothesis.strategies import text, integers +from hypothesis.internal.compat import integer_types, print_unicode + + +class TestInstanceMethods(TestCase): + + @given(integers()) + @example(1) + def test_hi_1(self, x): + assert isinstance(x, integer_types) + + @given(integers()) + @example(x=1) + def test_hi_2(self, x): + assert isinstance(x, integer_types) + + @given(x=integers()) + @example(x=1) + def test_hi_3(self, x): + assert isinstance(x, integer_types) + + +def test_kwarg_example_on_testcase(): + class Stuff(TestCase): + + @given(integers()) + @example(x=1) + def test_hi(self, x): + assert isinstance(x, integer_types) + + Stuff(u'test_hi').test_hi() + + +def test_errors_when_run_with_not_enough_args(): + @given(integers(), int) + @example(1) + def foo(x, y): + pass + + with pytest.raises(TypeError): + foo() + + +def test_errors_when_run_with_not_enough_kwargs(): + @given(integers(), int) + @example(x=1) + def foo(x, y): + pass + + with pytest.raises(TypeError): + foo() + + +def test_can_use_examples_after_given(): + long_str = u"This is a very long string that you've no chance of hitting" + + @example(long_str) + @given(text()) + def test_not_long_str(x): + assert x != long_str + + with pytest.raises(AssertionError): + test_not_long_str() + + +def test_can_use_examples_before_given(): + long_str = u"This is a very long string that you've no chance of hitting" + + @given(text()) + @example(long_str) + def test_not_long_str(x): + assert x != long_str + + with pytest.raises(AssertionError): + test_not_long_str() + + +def test_can_use_examples_around_given(): + long_str = u"This is a very long string that you've no chance of hitting" + short_str = u'Still no chance' + + seen = [] + + @example(short_str) + @given(text()) + @example(long_str) + def test_not_long_str(x): + seen.append(x) + + test_not_long_str() + assert set(seen[:2]) == set((long_str, short_str)) + + +@pytest.mark.parametrize((u'x', u'y'), [(1, False), (2, True)]) +@example(z=10) +@given(z=integers()) +def test_is_a_thing(x, y, z): + pass + + +def test_no_args_and_kwargs(): + with pytest.raises(InvalidArgument): + example(1, y=2) + + +def test_no_empty_examples(): + with pytest.raises(InvalidArgument): + example() + + +def test_does_not_print_on_explicit_examples_if_no_failure(): + @example(1) + @given(integers()) + def test_positive(x): + assert x > 0 + + with reporting.with_reporter(reporting.default): + with pytest.raises(AssertionError): + with capture_out() as out: + test_positive() + out = out.getvalue() + assert u'Falsifying example: test_positive(1)' not in out + + +def test_prints_output_for_explicit_examples(): + @example(-1) + @given(integers()) + def test_positive(x): + assert x > 0 + + with reporting.with_reporter(reporting.default): + with pytest.raises(AssertionError): + with capture_out() as out: + test_positive() + out = out.getvalue() + assert u'Falsifying example: test_positive(x=-1)' in out + + +def test_prints_verbose_output_for_explicit_examples(): + @settings(verbosity=Verbosity.verbose) + @example('NOT AN INTEGER') + @given(integers()) + def test_always_passes(x): + pass + + with reporting.with_reporter(reporting.default): + with capture_out() as out: + test_always_passes() + out = out.getvalue() + assert u"Trying example: test_always_passes(x='NOT AN INTEGER')" in out + + +def test_captures_original_repr_of_example(): + @example(x=[]) + @given(integers()) + def test_mutation(x): + x.append(1) + assert not x + + with reporting.with_reporter(reporting.default): + with pytest.raises(AssertionError): + with capture_out() as out: + test_mutation() + out = out.getvalue() + assert u'Falsifying example: test_mutation(x=[])' in out + + +def test_examples_are_tried_in_order(): + @example(x=1) + @example(x=2) + @given(integers()) + @settings(max_examples=0) + @example(x=3) + def test(x): + print_unicode(u"x -> %d" % (x,)) + with capture_out() as out: + with reporting.with_reporter(reporting.default): + test() + ls = out.getvalue().splitlines() + assert ls == [u"x -> 1", u"x -> 2", u"x -> 3"] + + +def test_prints_note_in_failing_example(): + @example(x=42) + @example(x=43) + @given(integers()) + def test(x): + note('x -> %d' % (x,)) + assert x == 42 + + with capture_out() as out: + with reporting.with_reporter(reporting.default): + with pytest.raises(AssertionError): + test() + v = out.getvalue() + print_unicode(v) + assert 'x -> 43' in v + assert 'x -> 42' not in v + + +def test_must_agree_with_number_of_arguments(): + @example(1, 2) + @given(integers()) + def test(a): + pass + + with pytest.raises(InvalidArgument): + test() diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_filestorage.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_filestorage.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_filestorage.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_filestorage.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,60 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import os + +import hypothesis.configuration as fs + +previous_home_dir = None + + +def setup_function(function): + global previous_home_dir + previous_home_dir = fs.hypothesis_home_dir() + fs.set_hypothesis_home_dir(None) + + +def teardown_function(function): + global previous_home_dir + fs.set_hypothesis_home_dir(previous_home_dir) + previous_home_dir = None + + +def test_defaults_to_the_default(): + assert fs.hypothesis_home_dir() == fs.__hypothesis_home_directory_default + + +def test_can_set_homedir_and_it_will_exist(tmpdir): + fs.set_hypothesis_home_dir(str(tmpdir.mkdir(u'kittens'))) + d = fs.hypothesis_home_dir() + assert u'kittens' in d + assert os.path.exists(d) + + +def test_will_pick_up_location_from_env(monkeypatch, tmpdir): + tmpdir = str(tmpdir) + monkeypatch.setattr(os, 'environ', { + 'HYPOTHESIS_STORAGE_DIRECTORY': tmpdir + }) + assert fs.hypothesis_home_dir() == tmpdir + + +def test_storage_directories_are_created_automatically(tmpdir): + fs.set_hypothesis_home_dir(str(tmpdir)) + assert os.path.exists(fs.storage_directory(u'badgers')) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_flakiness.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_flakiness.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_flakiness.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_flakiness.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,126 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import pytest + +from hypothesis import Verbosity, HealthCheck, given, assume, reject, \ + example, settings +from hypothesis.errors import Flaky, Unsatisfiable, UnsatisfiedAssumption +from tests.common.utils import no_shrink +from hypothesis.strategies import lists, booleans, integers, composite, \ + random_module + + +class Nope(Exception): + pass + + +def test_fails_only_once_is_flaky(): + first_call = [True] + + @given(integers()) + def rude(x): + if first_call[0]: + first_call[0] = False + raise Nope() + + with pytest.raises(Flaky): + rude() + + +def test_gives_flaky_error_if_assumption_is_flaky(): + seen = set() + + @given(integers()) + @settings(verbosity=Verbosity.quiet) + def oops(s): + assume(s not in seen) + seen.add(s) + assert False + + with pytest.raises(Flaky): + oops() + + +def test_does_not_attempt_to_shrink_flaky_errors(): + values = [] + + @given(integers()) + def test(x): + values.append(x) + assert len(values) != 1 + with pytest.raises(Flaky): + test() + assert len(set(values)) == 1 + + +class SatisfyMe(Exception): + pass + + +@composite +def single_bool_lists(draw): + n = draw(integers(0, 20)) + result = [False] * (n + 1) + result[n] = True + return result + + +@example([True, False, False, False], [3], None,) +@example([False, True, False, False], [3], None,) +@example([False, False, True, False], [3], None,) +@example([False, False, False, True], [3], None,) +@settings(max_examples=0) +@given( + lists(booleans()) | single_bool_lists(), + lists(integers(1, 3)), random_module()) +def test_failure_sequence_inducing(building, testing, rnd): + buildit = iter(building) + testit = iter(testing) + + def build(x): + try: + assume(not next(buildit)) + except StopIteration: + pass + return x + + @given(integers().map(build)) + @settings( + verbosity=Verbosity.quiet, database=None, + suppress_health_check=HealthCheck.all(), phases=no_shrink + ) + def test(x): + try: + i = next(testit) + except StopIteration: + return + if i == 1: + return + elif i == 2: + reject() + else: + raise Nope() + + try: + test() + except (Nope, Unsatisfiable, Flaky): + pass + except UnsatisfiedAssumption: + raise SatisfyMe() diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_float_nastiness.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_float_nastiness.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_float_nastiness.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_float_nastiness.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,247 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import sys +import math +from decimal import Decimal + +import pytest +from flaky import flaky + +import hypothesis.strategies as st +from hypothesis import given, assume, settings +from hypothesis.errors import InvalidArgument +from tests.common.debug import minimal, find_any +from hypothesis.internal.compat import WINDOWS, CAN_PACK_HALF_FLOAT +from hypothesis.internal.floats import next_up, next_down, float_to_int, \ + int_to_float + +try: + import numpy +except ImportError: + numpy = None + + +@pytest.mark.parametrize(('lower', 'upper'), [ + # Exact values don't matter, but they're large enough so that x + y = inf. + (9.9792015476736e+291, 1.7976931348623157e+308), + (-sys.float_info.max, sys.float_info.max) +]) +def test_floats_are_in_range(lower, upper): + @given(st.floats(lower, upper)) + def test_is_in_range(t): + assert lower <= t <= upper + test_is_in_range() + + +@pytest.mark.parametrize('sign', [-1, 1]) +def test_can_generate_both_zeros(sign): + assert minimal( + st.floats(), + lambda x: math.copysign(1, x) == sign, + ) == sign * 0.0 + + +@pytest.mark.parametrize((u'l', u'r'), [ + (-1.0, 1.0), + (-0.0, 1.0), + (-1.0, 0.0), + (-sys.float_info.min, sys.float_info.min), +]) +@pytest.mark.parametrize('sign', [-1, 1]) +def test_can_generate_both_zeros_when_in_interval(l, r, sign): + assert minimal( + st.floats(l, r), + lambda x: math.copysign(1, x) == sign) == sign * 0.0 + + +@given(st.floats(0.0, 1.0)) +def test_does_not_generate_negative_if_right_boundary_is_positive(x): + assert math.copysign(1, x) == 1 + + +@given(st.floats(-1.0, -0.0)) +def test_does_not_generate_positive_if_right_boundary_is_negative(x): + assert math.copysign(1, x) == -1 + + +@pytest.mark.parametrize((u'l', u'r'), [ + (0.0, 1.0), + (-1.0, 0.0), + (-sys.float_info.min, sys.float_info.min), +]) +@flaky(max_runs=4, min_passes=1) +def test_can_generate_interval_endpoints(l, r): + interval = st.floats(l, r) + minimal(interval, lambda x: x == l, settings=settings(max_examples=10000)) + minimal(interval, lambda x: x == r, settings=settings(max_examples=10000)) + + +@flaky(max_runs=4, min_passes=1) +def test_half_bounded_generates_endpoint(): + find_any(st.floats(min_value=-1.0), lambda x: x == -1.0) + find_any(st.floats(max_value=-1.0), lambda x: x == -1.0) + + +def test_half_bounded_generates_zero(): + find_any(st.floats(min_value=-1.0), lambda x: x == 0.0) + find_any(st.floats(max_value=1.0), lambda x: x == 0.0) + + +@pytest.mark.xfail( + WINDOWS, + reason=( + 'Seems to be triggering a floating point bug on 2.7 + windows + x64')) +@given(st.floats(max_value=-0.0)) +def test_half_bounded_respects_sign_of_upper_bound(x): + assert math.copysign(1, x) == -1 + + +@given(st.floats(min_value=0.0)) +def test_half_bounded_respects_sign_of_lower_bound(x): + assert math.copysign(1, x) == 1 + + +@given(st.floats(allow_nan=False)) +def test_filter_nan(x): + assert not math.isnan(x) + + +@given(st.floats(allow_infinity=False)) +def test_filter_infinity(x): + assert not math.isinf(x) + + +def test_can_guard_against_draws_of_nan(): + """In this test we create a NaN value that naturally "tries" to shrink into + the first strategy, where it is not permitted. This tests a case that is + very unlikely to happen in random generation: When the unconstrained first + branch of generating a float just happens to produce a NaN value. + + Here what happens is that we get a NaN from the *second* strategy, + but this then shrinks into its unconstrained branch. The natural + thing to happen is then to try to zero the branch parameter of the + one_of, but that will put an illegal value there, so it's not + allowed to happen. + """ + tagged_floats = st.one_of( + st.tuples(st.just(0), st.floats(allow_nan=False)), + st.tuples(st.just(1), st.floats(allow_nan=True)), + ) + + tag, f = minimal(tagged_floats, lambda x: math.isnan(x[1])) + assert tag == 1 + + +def test_very_narrow_interval(): + upper_bound = -1.0 + lower_bound = int_to_float(float_to_int(upper_bound) + 10) + assert lower_bound < upper_bound + + @given(st.floats(lower_bound, upper_bound)) + def test(f): + assert lower_bound <= f <= upper_bound + test() + + +@given(st.floats()) +def test_up_means_greater(x): + hi = next_up(x) + if not x < hi: + assert (math.isnan(x) and math.isnan(hi)) or (x > 0 and math.isinf(x)) + + +@given(st.floats()) +def test_down_means_lesser(x): + lo = next_down(x) + if not x > lo: + assert (math.isnan(x) and math.isnan(lo)) or (x < 0 and math.isinf(x)) + + +@given(st.floats(allow_nan=False, allow_infinity=False)) +def test_updown_roundtrip(val): + assert val == next_up(next_down(val)) + assert val == next_down(next_up(val)) + + +@given(st.data(), st.floats(allow_nan=False, allow_infinity=False)) +def test_floats_in_tiny_interval_within_bounds(data, center): + assume(not (math.isinf(next_down(center)) or math.isinf(next_up(center)))) + lo = Decimal.from_float(next_down(center)).next_plus() + hi = Decimal.from_float(next_up(center)).next_minus() + assert float(lo) < lo < center < hi < float(hi) + val = data.draw(st.floats(lo, hi)) + assert lo < val < hi + + +def test_float_free_interval_is_invalid(): + lo = (2 ** 54) + 1 + hi = lo + 2 + assert float(lo) < lo < hi < float(hi), 'There are no floats in [lo .. hi]' + with pytest.raises(InvalidArgument): + st.floats(lo, hi).example() + + +@given(st.floats(width=32, allow_infinity=False)) +def test_float32_can_exclude_infinity(x): + assert not math.isinf(x) + + +@pytest.mark.skipif(not (numpy or CAN_PACK_HALF_FLOAT), reason='dependency') +@given(st.floats(width=32, allow_infinity=False)) +def test_float16_can_exclude_infinity(x): + assert not math.isinf(x) + + +@pytest.mark.parametrize('kwargs', [ + dict(min_value=10 ** 5, width=16), + dict(max_value=10 ** 5, width=16), + dict(min_value=10 ** 40, width=32), + dict(max_value=10 ** 40, width=32), + dict(min_value=10 ** 400, width=64), + dict(max_value=10 ** 400, width=64), + dict(min_value=10 ** 400), + dict(max_value=10 ** 400), +]) +def test_out_of_range(kwargs): + if kwargs.get('width') == 16 and not (CAN_PACK_HALF_FLOAT or numpy): + pytest.skip() + with pytest.raises(OverflowError): + st.floats(**kwargs).validate() + + +def test_invalidargument_iff_half_float_unsupported(): + if numpy is None and not CAN_PACK_HALF_FLOAT: + with pytest.raises(InvalidArgument): + st.floats(width=16).validate() + else: + st.floats(width=16).validate() + + +def test_disallowed_width(): + with pytest.raises(InvalidArgument): + st.floats(width=128).validate() + + +def test_no_single_floats_in_range(): + low = 2. ** 25 + 1 + high = low + 2 + st.floats(low, high).validate() # Note: OK for 64bit floats + with pytest.raises(InvalidArgument): + st.floats(low, high, width=32).validate() diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_float_utils.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_float_utils.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_float_utils.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_float_utils.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,24 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from hypothesis.internal.floats import count_between_floats + + +def test_can_handle_straddling_zero(): + assert count_between_floats(-0.0, 0.0) == 2 diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_given_error_conditions.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_given_error_conditions.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_given_error_conditions.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_given_error_conditions.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,76 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import pytest + +from hypothesis import given, infer, assume, reject +from hypothesis.errors import Unsatisfiable, InvalidArgument +from tests.common.utils import fails_with, validate_deprecation +from hypothesis.strategies import booleans, integers + + +def test_raises_unsatisfiable_if_all_false_in_finite_set(): + @given(booleans()) + def test_assume_false(x): + reject() + + with pytest.raises(Unsatisfiable): + test_assume_false() + + +def test_does_not_raise_unsatisfiable_if_some_false_in_finite_set(): + @given(booleans()) + def test_assume_x(x): + assume(x) + + test_assume_x() + + +def test_error_if_has_no_hints(): + @given(a=infer) + def inner(a): + pass + with pytest.raises(InvalidArgument): + inner() + + +def test_error_if_infer_is_posarg(): + @given(infer) + def inner(ex): + pass + with pytest.raises(InvalidArgument): + inner() + + +def test_given_twice_deprecated(): + @given(booleans()) + @given(integers()) + def inner(a, b): + pass + with validate_deprecation(): + inner() + + +@fails_with(InvalidArgument) +def test_given_is_not_a_class_decorator(): + @given(integers()) + class test_given_is_not_a_class_decorator(): + + def __init__(self, i): + pass diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_health_checks.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_health_checks.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_health_checks.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_health_checks.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,213 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import time + +import pytest +from pytest import raises + +import hypothesis.strategies as st +from hypothesis import HealthCheck, given, settings +from hypothesis.errors import InvalidArgument, FailedHealthCheck +from hypothesis.control import assume +from tests.common.utils import no_shrink, checks_deprecated_behaviour +from hypothesis.internal.compat import int_from_bytes +from hypothesis.searchstrategy.strategies import SearchStrategy + + +def test_slow_generation_fails_a_health_check(): + @given(st.integers().map(lambda x: time.sleep(0.2))) + def test(x): + pass + + with raises(FailedHealthCheck): + test() + + +def test_slow_generation_inline_fails_a_health_check(): + @settings(deadline=None) + @given(st.data()) + def test(data): + data.draw(st.integers().map(lambda x: time.sleep(0.2))) + + with raises(FailedHealthCheck): + test() + + +def test_default_health_check_can_weaken_specific(): + import random + + @settings(suppress_health_check=HealthCheck.all()) + @given(st.lists(st.integers(), min_size=1)) + def test(x): + random.choice(x) + + test() + + +def test_suppressing_filtering_health_check(): + forbidden = set() + + def unhealthy_filter(x): + if len(forbidden) < 200: + forbidden.add(x) + return x not in forbidden + + @given(st.integers().filter(unhealthy_filter)) + def test1(x): + raise ValueError() + + with raises(FailedHealthCheck): + test1() + + forbidden = set() + + @settings(suppress_health_check=[ + HealthCheck.filter_too_much, HealthCheck.too_slow]) + @given(st.integers().filter(unhealthy_filter)) + def test2(x): + raise ValueError() + + with raises(ValueError): + test2() + + +def test_filtering_everything_fails_a_health_check(): + @given(st.integers().filter(lambda x: False)) + @settings(database=None) + def test(x): + pass + + with raises(FailedHealthCheck) as e: + test() + assert 'filter' in e.value.args[0] + + +class fails_regularly(SearchStrategy): + + def do_draw(self, data): + b = int_from_bytes(data.draw_bytes(2)) + assume(b == 3) + print('ohai') + + +def test_filtering_most_things_fails_a_health_check(): + @given(fails_regularly()) + @settings(database=None, phases=no_shrink) + def test(x): + pass + + with raises(FailedHealthCheck) as e: + test() + assert 'filter' in e.value.args[0] + + +def test_large_data_will_fail_a_health_check(): + @given(st.none() | st.binary(min_size=1024)) + @settings(database=None, buffer_size=1000) + def test(x): + pass + + with raises(FailedHealthCheck) as e: + test() + assert 'allowable size' in e.value.args[0] + + +def test_returning_non_none_is_forbidden(): + @given(st.integers()) + def a(x): + return 1 + + with raises(FailedHealthCheck): + a() + + +def test_a_very_slow_test_will_fail_a_health_check(): + @given(st.integers()) + @settings(deadline=None) + def a(x): + time.sleep(1000) + with raises(FailedHealthCheck): + a() + + +def test_the_slow_test_health_check_can_be_disabled(): + @given(st.integers()) + @settings(suppress_health_check=[ + HealthCheck.hung_test, + ], deadline=None) + def a(x): + time.sleep(1000) + a() + + +def test_the_slow_test_health_only_runs_if_health_checks_are_on(): + @given(st.integers()) + @settings(suppress_health_check=HealthCheck.all(), deadline=None) + def a(x): + time.sleep(1000) + a() + + +def test_returning_non_none_does_not_fail_if_health_check_disabled(): + @given(st.integers()) + @settings(suppress_health_check=HealthCheck.all()) + def a(x): + return 1 + + a() + + +def test_large_base_example_fails_health_check(): + @given(st.binary(min_size=7000, max_size=7000)) + def test(b): + pass + + with pytest.raises(FailedHealthCheck) as exc: + test() + + assert exc.value.health_check == HealthCheck.large_base_example + + +def test_example_that_shrinks_to_overrun_fails_health_check(): + @given(st.binary(min_size=9000, max_size=9000) | st.none()) + def test(b): + pass + + with pytest.raises(FailedHealthCheck) as exc: + test() + + assert exc.value.health_check == HealthCheck.large_base_example + + +@pytest.mark.parametrize( + 'check', [HealthCheck.random_module, HealthCheck.exception_in_generation]) +@checks_deprecated_behaviour +def test_noop_health_checks(check): + settings(suppress_health_check=[check]) + + +def test_it_is_an_error_to_suppress_non_iterables(): + with raises(InvalidArgument): + settings(suppress_health_check=1) + + +@checks_deprecated_behaviour +def test_is_is_deprecated_to_suppress_non_healthchecks(): + settings(suppress_health_check=[1]) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_internal_helpers.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_internal_helpers.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_internal_helpers.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_internal_helpers.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,29 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import pytest + +from hypothesis.internal.floats import sign + + +def test_sign_gives_good_type_error(): + x = 'foo' + with pytest.raises(TypeError) as e: + sign(x) + assert repr(x) in e.value.args[0] diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_intervalset.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_intervalset.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_intervalset.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_intervalset.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,110 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import pytest + +import hypothesis.strategies as st +from hypothesis import given, assume, example +from hypothesis.internal.charmap import _subtract_intervals +from hypothesis.internal.intervalsets import IntervalSet + + +def build_intervals(ls): + ls.sort() + result = [] + for u, l in ls: + v = u + l + if result: + a, b = result[-1] + if u <= b + 1: + result[-1] = (a, v) + continue + result.append((u, v)) + return result + + +IntervalLists = st.builds( + build_intervals, + st.lists(st.tuples(st.integers(0, 200), st.integers(0, 20))) +) + +Intervals = st.builds(IntervalSet, IntervalLists) + + +@given(Intervals) +def test_intervals_are_equivalent_to_their_lists(intervals): + ls = list(intervals) + assert len(ls) == len(intervals) + for i in range(len(ls)): + assert ls[i] == intervals[i] + for i in range(1, len(ls) - 1): + assert ls[-i] == intervals[-i] + + +@given(Intervals) +def test_intervals_match_indexes(intervals): + ls = list(intervals) + for v in ls: + assert ls.index(v) == intervals.index(v) + + +@given(Intervals, st.integers()) +def test_error_for_index_of_not_present_value(intervals, v): + assume(v not in intervals) + with pytest.raises(ValueError): + intervals.index(v) + + +def test_validates_index(): + with pytest.raises(IndexError): + IntervalSet([])[1] + + with pytest.raises(IndexError): + IntervalSet([[1, 10]])[11] + + with pytest.raises(IndexError): + IntervalSet([[1, 10]])[-11] + + +def test_index_above_is_index_if_present(): + assert IntervalSet([[1, 10]]).index_above(1) == 0 + assert IntervalSet([[1, 10]]).index_above(2) == 1 + + +def test_index_above_is_length_if_higher(): + assert IntervalSet([[1, 10]]).index_above(100) == 10 + + +def intervals_to_set(ints): + return set(IntervalSet(ints)) + + +@example(x=[(0, 1), (3, 3)], y=[(1, 3)]) +@example(x=[(0, 1)], y=[(0, 0), (1, 1)]) +@example(x=[(0, 1)], y=[(1, 1)]) +@given(IntervalLists, IntervalLists) +def test_subtraction_of_intervals(x, y): + xs = intervals_to_set(x) + ys = intervals_to_set(x) + assume(not xs.isdisjoint(ys)) + z = _subtract_intervals(x, y) + assert z == tuple(sorted(z)) + for a, b in z: + assert a <= b + assert intervals_to_set(z) == intervals_to_set(x) - intervals_to_set(y) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_lambda_formatting.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_lambda_formatting.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_lambda_formatting.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_lambda_formatting.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,180 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2016 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from hypothesis.internal.reflection import get_pretty_function_description + + +def test_bracket_whitespace_is_striped(): + assert get_pretty_function_description( + lambda x: (x + 1) + ) == 'lambda x: (x + 1)' + + +def test_can_have_unicode_in_lambda_sources(): + t = lambda x: 'é' not in x + assert get_pretty_function_description(t) == ( + "lambda x: 'é' not in x" + ) + + +ordered_pair = ( + lambda right: [].map( + lambda length: ())) + + +def test_can_get_descriptions_of_nested_lambdas_with_different_names(): + assert get_pretty_function_description(ordered_pair) == \ + 'lambda right: [].map(lambda length: ())' + + +def test_does_not_error_on_unparsable_source(): + t = [ + lambda x: \ + # This will break ast.parse, but the brackets are needed for the real + # parser to accept this lambda + x][0] + assert get_pretty_function_description(t) == 'lambda x: ' + + +def test_source_of_lambda_is_pretty(): + assert get_pretty_function_description( + lambda x: True + ) == 'lambda x: True' + + +def test_variable_names_are_not_pretty(): + t = lambda x: True + assert get_pretty_function_description(t) == 'lambda x: True' + + +def test_does_not_error_on_dynamically_defined_functions(): + x = eval('lambda t: 1') + get_pretty_function_description(x) + + +def test_collapses_whitespace_nicely(): + t = ( + lambda x, y: 1 + ) + assert get_pretty_function_description(t) == 'lambda x, y: 1' + + +def test_is_not_confused_by_tuples(): + p = (lambda x: x > 1, 2)[0] + + assert get_pretty_function_description(p) == 'lambda x: x > 1' + + +def test_strips_comments_from_the_end(): + t = lambda x: 1 # A lambda comment + assert get_pretty_function_description(t) == 'lambda x: 1' + + +def test_does_not_strip_hashes_within_a_string(): + t = lambda x: '#' + assert get_pretty_function_description(t) == "lambda x: '#'" + + +def test_can_distinguish_between_two_lambdas_with_different_args(): + a, b = (lambda x: 1, lambda y: 2) + assert get_pretty_function_description(a) == 'lambda x: 1' + assert get_pretty_function_description(b) == 'lambda y: 2' + + +def test_does_not_error_if_it_cannot_distinguish_between_two_lambdas(): + a, b = (lambda x: 1, lambda x: 2) + assert 'lambda x:' in get_pretty_function_description(a) + assert 'lambda x:' in get_pretty_function_description(b) + + +def test_lambda_source_break_after_def_with_brackets(): + f = (lambda n: + 'aaa') + + source = get_pretty_function_description(f) + assert source == "lambda n: 'aaa'" + + +def test_lambda_source_break_after_def_with_line_continuation(): + f = lambda n:\ + 'aaa' + + source = get_pretty_function_description(f) + assert source == "lambda n: 'aaa'" + + +def arg_decorator(*s): + def accept(f): + return s + return accept + + +@arg_decorator(lambda x: x + 1) +def plus_one(): + pass + + +@arg_decorator(lambda x: x + 1, lambda y: y * 2) +def two_decorators(): + pass + + +def test_can_extract_lambda_repr_in_a_decorator(): + assert get_pretty_function_description(plus_one[0]) == 'lambda x: x + 1' + + +def test_can_extract_two_lambdas_from_a_decorator_if_args_differ(): + a, b = two_decorators + assert get_pretty_function_description(a) == 'lambda x: x + 1' + assert get_pretty_function_description(b) == 'lambda y: y * 2' + + +@arg_decorator( + lambda x: x + 1 +) +def decorator_with_space(): + pass + + +def test_can_extract_lambda_repr_in_a_decorator_with_spaces(): + assert get_pretty_function_description( + decorator_with_space[0]) == 'lambda x: x + 1' + + +@arg_decorator(lambda: ()) +def to_brackets(): + pass + + +def test_can_handle_brackets_in_decorator_argument(): + assert get_pretty_function_description(to_brackets[0]) == "lambda: ()" + + +def identity(x): + return x + + +@arg_decorator(identity(lambda x: x + 1)) +def decorator_with_wrapper(): + pass + + +def test_can_handle_nested_lambda_in_decorator_argument(): + assert get_pretty_function_description( + decorator_with_wrapper[0]) == "lambda x: x + 1" diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_map.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_map.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_map.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_map.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,31 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from hypothesis import given, assume +from hypothesis import strategies as st +from tests.common.debug import assert_no_examples + + +@given(st.integers().map(lambda x: assume(x % 3 != 0) and x)) +def test_can_assume_in_map(x): + assert x % 3 != 0 + + +def test_assume_in_just_raises_immediately(): + assert_no_examples(st.just(1).map(lambda x: assume(x == 2))) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_nothing.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_nothing.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_nothing.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_nothing.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,75 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import pytest + +from hypothesis import given +from hypothesis import strategies as st +from hypothesis.errors import InvalidArgument +from tests.common.debug import minimal, assert_no_examples + + +def test_resampling(): + x = minimal( + st.lists(st.integers()).flatmap( + lambda x: st.lists(st.sampled_from(x))), + lambda x: len(x) >= 10 and len(set(x)) == 1) + assert x == [0] * 10 + + +@given(st.lists(st.nothing())) +def test_list_of_nothing(xs): + assert xs == [] + + +@given(st.sets(st.nothing())) +def test_set_of_nothing(xs): + assert xs == set() + + +def test_validates_min_size(): + with pytest.raises(InvalidArgument): + st.lists(st.nothing(), min_size=1).validate() + + +def test_function_composition(): + assert st.nothing().map(lambda x: 'hi').is_empty + assert st.nothing().filter(lambda x: True).is_empty + assert st.nothing().flatmap(lambda x: st.integers()).is_empty + + +def test_tuples_detect_empty_elements(): + assert st.tuples(st.nothing()).is_empty + + +def test_fixed_dictionaries_detect_empty_values(): + assert st.fixed_dictionaries({'a': st.nothing()}).is_empty + + +def test_no_examples(): + assert_no_examples(st.nothing()) + + +@pytest.mark.parametrize('s', [ + st.nothing(), st.nothing().map(lambda x: x), + st.nothing().filter(lambda x: True), + st.nothing().flatmap(lambda x: st.integers()) +]) +def test_empty(s): + assert s.is_empty diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_numerics.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_numerics.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_numerics.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_numerics.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,134 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import decimal + +import pytest + +from hypothesis import given, assume, reject +from hypothesis.errors import InvalidArgument +from tests.common.debug import find_any +from hypothesis.strategies import data, none, tuples, decimals, integers, \ + fractions + + +@given(data()) +def test_fuzz_fractions_bounds(data): + denom = data.draw(none() | integers(1, 100), label='denominator') + fracs = none() | fractions(max_denominator=denom) + low, high = data.draw(tuples(fracs, fracs), label='low, high') + if low is not None and high is not None and low > high: + low, high = high, low + try: + val = data.draw(fractions(low, high, denom), label='value') + except InvalidArgument: + reject() # fractions too close for given max_denominator + if low is not None: + assert low <= val + if high is not None: + assert val <= high + if denom is not None: + assert 1 <= val.denominator <= denom + + +@given(data()) +def test_fuzz_decimals_bounds(data): + places = data.draw(none() | integers(0, 20), label='places') + finite_decs = decimals(allow_nan=False, allow_infinity=False, + places=places) | none() + low, high = data.draw(tuples(finite_decs, finite_decs), label='low, high') + if low is not None and high is not None and low > high: + low, high = high, low + ctx = decimal.Context(prec=data.draw(integers(1, 100), label='precision')) + try: + with decimal.localcontext(ctx): + strat = decimals(low, high, allow_nan=False, + allow_infinity=False, places=places) + val = data.draw(strat, label='value') + except InvalidArgument: + reject() # decimals too close for given places + if low is not None: + assert low <= val + if high is not None: + assert val <= high + if places is not None: + assert val.as_tuple().exponent == -places + + +def test_all_decimals_can_be_exact_floats(): + find_any( + decimals(), + lambda x: assume(x.is_finite()) and decimal.Decimal(float(x)) == x + ) + + +@given(fractions(), fractions(), fractions()) +def test_fraction_addition_is_well_behaved(x, y, z): + assert x + y + z == y + x + z + + +def test_decimals_include_nan(): + find_any(decimals(), lambda x: x.is_nan()) + + +def test_decimals_include_inf(): + find_any(decimals(), lambda x: x.is_infinite()) + + +@given(decimals(allow_nan=False)) +def test_decimals_can_disallow_nan(x): + assert not x.is_nan() + + +@given(decimals(allow_infinity=False)) +def test_decimals_can_disallow_inf(x): + assert not x.is_infinite() + + +@pytest.mark.parametrize('places', range(10)) +def test_decimals_have_correct_places(places): + @given(decimals(0, 10, allow_nan=False, places=places)) + def inner_tst(n): + assert n.as_tuple().exponent == -places + inner_tst() + + +@given(decimals(min_value='0.1', max_value='0.2', allow_nan=False, places=1)) +def test_works_with_few_values(dec): + assert dec in (decimal.Decimal('0.1'), decimal.Decimal('0.2')) + + +@given(decimals(places=3, allow_nan=False, allow_infinity=False)) +def test_issue_725_regression(x): + pass + + +@given(decimals(min_value='0.1', max_value='0.3')) +def test_issue_739_regression(x): + pass + + +def test_consistent_decimal_error(): + bad = 'invalid argument to Decimal' + with pytest.raises(InvalidArgument) as excinfo: + decimals(bad).example() + with pytest.raises(InvalidArgument) as excinfo2: + with decimal.localcontext(decimal.Context(traps=[])): + decimals(bad).example() + assert str(excinfo.value) == str(excinfo2.value) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_one_of.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_one_of.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_one_of.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_one_of.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,38 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import hypothesis.strategies as st +from hypothesis import given +from tests.common.debug import assert_no_examples + + +def test_one_of_empty(): + e = st.one_of() + assert e.is_empty + assert_no_examples(e) + + +@given(st.one_of(st.integers().filter(bool))) +def test_one_of_filtered(i): + assert bool(i) + + +@given(st.one_of(st.just(100).flatmap(st.integers))) +def test_one_of_flatmapped(i): + assert i >= 100 diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_permutations.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_permutations.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_permutations.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_permutations.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,49 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from hypothesis import given +from tests.common.debug import minimal +from tests.common.utils import checks_deprecated_behaviour +from hypothesis.strategies import data, sets, integers, permutations + + +def test_can_find_non_trivial_permutation(): + x = minimal( + permutations(list(range(5))), lambda x: x[0] != 0 + ) + + assert x == [1, 0, 2, 3, 4] + + +@given(permutations(list(u'abcd'))) +def test_permutation_values_are_permutations(perm): + assert len(perm) == 4 + assert set(perm) == set(u'abcd') + + +@given(permutations([])) +def test_empty_permutations_are_empty(xs): + assert xs == [] + + +@checks_deprecated_behaviour +@given(data=data(), xs=sets(integers())) +def test_non_sequence_types_are_deprecated(data, xs): + p = data.draw(permutations(xs)) + assert xs == set(p) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_phases.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_phases.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_phases.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_phases.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,93 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import pytest + +import hypothesis.strategies as st +from hypothesis import Phase, given, example, settings +from hypothesis.errors import InvalidArgument +from hypothesis.database import ExampleDatabase, InMemoryExampleDatabase + + +@example(11) +@settings(phases=(Phase.explicit,)) +@given(st.integers()) +def test_only_runs_explicit_examples(i): + assert i == 11 + + +@example(u"hello world") +@settings(phases=(Phase.reuse, Phase.generate, Phase.shrink)) +@given(st.booleans()) +def test_does_not_use_explicit_examples(i): + assert isinstance(i, bool) + + +@settings(phases=(Phase.reuse, Phase.shrink)) +@given(st.booleans()) +def test_this_would_fail_if_you_ran_it(b): + assert False + + +def test_phases_default_to_all(): + assert settings(phases=None).phases == tuple(Phase) + + +def test_does_not_reuse_saved_examples_if_reuse_not_in_phases(): + class BadDatabase(ExampleDatabase): + def save(self, key, value): + pass + + def delete(self, key, value): + pass + + def fetch(self, key): + raise ValueError() + + def close(self): + pass + + @settings(database=BadDatabase(), phases=(Phase.generate,)) + @given(st.integers()) + def test_usage(i): + pass + + test_usage() + + +def test_will_save_when_reuse_not_in_phases(): + database = InMemoryExampleDatabase() + + assert not database.data + + @settings(database=database, phases=(Phase.generate,)) + @given(st.integers()) + def test_usage(i): + raise ValueError() + + with pytest.raises(ValueError): + test_usage() + + saved, = [v for k, v in database.data.items() if b'coverage' not in k] + assert len(saved) == 1 + + +def test_rejects_non_phases(): + with pytest.raises(InvalidArgument): + settings(phases=['cabbage']) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_pretty.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_pretty.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_pretty.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_pretty.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,754 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +# coding: utf-8 + +"""This file originates in the IPython project and is made use of under the +following licensing terms: + +The IPython licensing terms +IPython is licensed under the terms of the Modified BSD License (also known as +New or Revised or 3-Clause BSD), as follows: + +Copyright (c) 2008-2014, IPython Development Team +Copyright (c) 2001-2007, Fernando Perez +Copyright (c) 2001, Janko Hauser +Copyright (c) 2001, Nathaniel Gray +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of the IPython Development Team nor the names of its +contributors may be used to endorse or promote products derived from this +software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +""" + +from __future__ import division, print_function, absolute_import + +import re +from collections import deque, defaultdict + +import pytest + +from hypothesis.vendor import pretty +from tests.common.utils import capture_out +from hypothesis.internal.compat import PY3, Counter, OrderedDict, \ + a_good_encoding + +py2_only = pytest.mark.skipif(PY3, reason='This test only runs on python 2') + +if PY3: + from io import StringIO + + def unicode_to_str(x, encoding=None): + return x +else: + from StringIO import StringIO + + def unicode_to_str(x, encoding=None): + return x.encode(encoding or a_good_encoding()) + + +def assert_equal(x, y): + assert x == y + + +def assert_true(x): + assert x + + +def assert_in(x, xs): + assert x in xs + + +def skip_without(mod): + try: + __import__(mod) + return lambda f: f + except ImportError: + return pytest.mark.skipif(True, reason='Missing %s' % (mod,)) + + +assert_raises = pytest.raises + + +class MyList(object): + + def __init__(self, content): + self.content = content + + def _repr_pretty_(self, p, cycle): + if cycle: + p.text('MyList(...)') + else: + with p.group(3, 'MyList(', ')'): + for (i, child) in enumerate(self.content): + if i: + p.text(',') + p.breakable() + else: + p.breakable('') + p.pretty(child) + + +class MyDict(dict): + + def _repr_pretty_(self, p, cycle): + p.text('MyDict(...)') + + +class MyObj(object): + + def somemethod(self): + pass + + +class Dummy1(object): + + def _repr_pretty_(self, p, cycle): + p.text('Dummy1(...)') + + +class Dummy2(Dummy1): + _repr_pretty_ = None + + +class NoModule(object): + pass + + +NoModule.__module__ = None + + +class Breaking(object): + + def _repr_pretty_(self, p, cycle): + with p.group(4, 'TG: ', ':'): + p.text('Breaking(') + p.break_() + p.text(')') + + +class BreakingRepr(object): + + def __repr__(self): + return 'Breaking(\n)' + + +class BreakingReprParent(object): + + def _repr_pretty_(self, p, cycle): + with p.group(4, 'TG: ', ':'): + p.pretty(BreakingRepr()) + + +class BadRepr(object): + + def __repr__(self): + return 1 / 0 + + +def test_list(): + assert pretty.pretty([]) == '[]' + assert pretty.pretty([1]) == '[1]' + + +def test_dict(): + assert pretty.pretty({}) == '{}' + assert pretty.pretty({1: 1}) == '{1: 1}' + + +def test_tuple(): + assert pretty.pretty(()) == '()' + assert pretty.pretty((1,)) == '(1,)' + assert pretty.pretty((1, 2)) == '(1, 2)' + + +class ReprDict(dict): + + def __repr__(self): + return 'hi' + + +def test_dict_with_custom_repr(): + assert pretty.pretty(ReprDict()) == 'hi' + + +class ReprList(list): + + def __repr__(self): + return 'bye' + + +class ReprSet(set): + + def __repr__(self): + return 'cat' + + +def test_set_with_custom_repr(): + assert pretty.pretty(ReprSet()) == 'cat' + + +def test_list_with_custom_repr(): + assert pretty.pretty(ReprList()) == 'bye' + + +def test_indentation(): + """Test correct indentation in groups.""" + count = 40 + gotoutput = pretty.pretty(MyList(range(count))) + expectedoutput = 'MyList(\n' + ',\n'.join(' %d' % + i for i in range(count)) + ')' + + assert_equal(gotoutput, expectedoutput) + + +def test_dispatch(): + """Test correct dispatching: The _repr_pretty_ method for MyDict must be + found before the registered printer for dict.""" + gotoutput = pretty.pretty(MyDict()) + expectedoutput = 'MyDict(...)' + + assert_equal(gotoutput, expectedoutput) + + +def test_callability_checking(): + """Test that the _repr_pretty_ method is tested for callability and skipped + if not.""" + gotoutput = pretty.pretty(Dummy2()) + expectedoutput = 'Dummy1(...)' + + assert_equal(gotoutput, expectedoutput) + + +def test_sets(): + """Test that set and frozenset use Python 3 formatting.""" + objects = [set(), frozenset(), set([1]), frozenset([1]), set([1, 2]), + frozenset([1, 2]), set([-1, -2, -3])] + expected = ['set()', 'frozenset()', '{1}', 'frozenset({1})', '{1, 2}', + 'frozenset({1, 2})', '{-3, -2, -1}'] + for obj, expected_output in zip(objects, expected): + got_output = pretty.pretty(obj) + assert_equal(got_output, expected_output) + + +def test_unsortable_set(): + xs = set([1, 2, 3, 'foo', 'bar', 'baz', object()]) + p = pretty.pretty(xs) + for x in xs: + assert pretty.pretty(x) in p + + +def test_unsortable_dict(): + xs = dict((k, 1) for k in [1, 2, 3, 'foo', 'bar', 'baz', object()]) + p = pretty.pretty(xs) + for x in xs: + assert pretty.pretty(x) in p + + +@skip_without('xxlimited') +def test_pprint_heap_allocated_type(): + """Test that pprint works for heap allocated types.""" + import xxlimited + output = pretty.pretty(xxlimited.Null) + assert_equal(output, 'xxlimited.Null') + + +def test_pprint_nomod(): + """Test that pprint works for classes with no __module__.""" + output = pretty.pretty(NoModule) + assert_equal(output, 'NoModule') + + +def test_pprint_break(): + """Test that p.break_ produces expected output.""" + output = pretty.pretty(Breaking()) + expected = 'TG: Breaking(\n ):' + assert_equal(output, expected) + + +def test_pprint_break_repr(): + """Test that p.break_ is used in repr.""" + output = pretty.pretty(BreakingReprParent()) + expected = 'TG: Breaking(\n ):' + assert_equal(output, expected) + + +def test_bad_repr(): + """Don't catch bad repr errors.""" + with assert_raises(ZeroDivisionError): + pretty.pretty(BadRepr()) + + +class BadException(Exception): + + def __str__(self): + return -1 + + +class ReallyBadRepr(object): + __module__ = 1 + + @property + def __class__(self): + raise ValueError('I am horrible') + + def __repr__(self): + raise BadException() + + +def test_really_bad_repr(): + with assert_raises(BadException): + pretty.pretty(ReallyBadRepr()) + + +class SA(object): + pass + + +class SB(SA): + pass + + +try: + super(SA).__self__ + + def test_super_repr(): + output = pretty.pretty(super(SA)) + assert_in('SA', output) + + sb = SB() + output = pretty.pretty(super(SA, sb)) + assert_in('SA', output) +except AttributeError: + def test_super_repr(): + pretty.pretty(super(SA)) + sb = SB() + pretty.pretty(super(SA, sb)) + + +def test_long_list(): + lis = list(range(10000)) + p = pretty.pretty(lis) + last2 = p.rsplit('\n', 2)[-2:] + assert_equal(last2, [' 999,', ' ...]']) + + +def test_long_set(): + s = set(range(10000)) + p = pretty.pretty(s) + last2 = p.rsplit('\n', 2)[-2:] + assert_equal(last2, [' 999,', ' ...}']) + + +def test_long_tuple(): + tup = tuple(range(10000)) + p = pretty.pretty(tup) + last2 = p.rsplit('\n', 2)[-2:] + assert_equal(last2, [' 999,', ' ...)']) + + +def test_long_dict(): + d = dict((n, n) for n in range(10000)) + p = pretty.pretty(d) + last2 = p.rsplit('\n', 2)[-2:] + assert_equal(last2, [' 999: 999,', ' ...}']) + + +def test_unbound_method(): + output = pretty.pretty(MyObj.somemethod) + assert_in('MyObj.somemethod', output) + + +class MetaClass(type): + + def __new__(cls, name): + return type.__new__(cls, name, (object,), {'name': name}) + + def __repr__(self): + return '[CUSTOM REPR FOR CLASS %s]' % self.name + + +ClassWithMeta = MetaClass('ClassWithMeta') + + +def test_metaclass_repr(): + output = pretty.pretty(ClassWithMeta) + assert_equal(output, '[CUSTOM REPR FOR CLASS ClassWithMeta]') + + +def test_unicode_repr(): + u = u"üniçodé" + ustr = unicode_to_str(u) + + class C(object): + + def __repr__(self): + return ustr + + c = C() + p = pretty.pretty(c) + assert_equal(p, u) + p = pretty.pretty([c]) + assert_equal(p, u'[%s]' % u) + + +def test_basic_class(): + def type_pprint_wrapper(obj, p, cycle): + if obj is MyObj: + type_pprint_wrapper.called = True + return pretty._type_pprint(obj, p, cycle) + type_pprint_wrapper.called = False + + stream = StringIO() + printer = pretty.RepresentationPrinter(stream) + printer.type_pprinters[type] = type_pprint_wrapper + printer.pretty(MyObj) + printer.flush() + output = stream.getvalue() + + assert_equal(output, '%s.MyObj' % __name__) + assert_true(type_pprint_wrapper.called) + + +# This is only run on Python 2 because in Python 3 the language prevents you +# from setting a non-unicode value for __qualname__ on a metaclass, and it +# doesn't respect the descriptor protocol if you subclass unicode and implement +# __get__. +@py2_only +def test_fallback_to__name__on_type(): + # Test that we correctly repr types that have non-string values for + # __qualname__ by falling back to __name__ + + class Type(object): + __qualname__ = 5 + + # Test repring of the type. + stream = StringIO() + printer = pretty.RepresentationPrinter(stream) + + printer.pretty(Type) + printer.flush() + output = stream.getvalue() + + # If __qualname__ is malformed, we should fall back to __name__. + expected = '.'.join([__name__, Type.__name__]) + assert_equal(output, expected) + + # Clear stream buffer. + stream.buf = '' + + # Test repring of an instance of the type. + instance = Type() + printer.pretty(instance) + printer.flush() + output = stream.getvalue() + + # Should look like: + # + prefix = '<' + '.'.join([__name__, Type.__name__]) + ' at 0x' + assert_true(output.startswith(prefix)) + + +@py2_only +def test_fail_gracefully_on_bogus__qualname__and__name__(): + # Test that we correctly repr types that have non-string values for both + # __qualname__ and __name__ + + class Meta(type): + __name__ = 5 + + class Type(object): + __metaclass__ = Meta + __qualname__ = 5 + + stream = StringIO() + printer = pretty.RepresentationPrinter(stream) + + printer.pretty(Type) + printer.flush() + output = stream.getvalue() + + # If we can't find __name__ or __qualname__ just use a sentinel string. + expected = '.'.join([__name__, '']) + assert_equal(output, expected) + + # Clear stream buffer. + stream.buf = '' + + # Test repring of an instance of the type. + instance = Type() + printer.pretty(instance) + printer.flush() + output = stream.getvalue() + + # Should look like: + # at 0x7f7658ae07d0> + prefix = '<' + '.'.join([__name__, '']) + ' at 0x' + assert_true(output.startswith(prefix)) + + +def test_collections_defaultdict(): + # Create defaultdicts with cycles + a = defaultdict() + a.default_factory = a + b = defaultdict(list) + b['key'] = b + + # Dictionary order cannot be relied on, test against single keys. + cases = [ + (defaultdict(list), 'defaultdict(list, {})'), + (defaultdict(list, {'key': '-' * 50}), + 'defaultdict(list,\n' + " {'key': '-----------------------------------------" + "---------'})"), + (a, 'defaultdict(defaultdict(...), {})'), + (b, "defaultdict(list, {'key': defaultdict(...)})"), + ] + for obj, expected in cases: + assert_equal(pretty.pretty(obj), expected) + + +def test_collections_ordereddict(): + # Create OrderedDict with cycle + a = OrderedDict() + a['key'] = a + + cases = [ + (OrderedDict(), 'OrderedDict()'), + (OrderedDict((i, i) for i in range(1000, 1010)), + 'OrderedDict([(1000, 1000),\n' + ' (1001, 1001),\n' + ' (1002, 1002),\n' + ' (1003, 1003),\n' + ' (1004, 1004),\n' + ' (1005, 1005),\n' + ' (1006, 1006),\n' + ' (1007, 1007),\n' + ' (1008, 1008),\n' + ' (1009, 1009)])'), + (a, "OrderedDict([('key', OrderedDict(...))])"), + ] + for obj, expected in cases: + assert_equal(pretty.pretty(obj), expected) + + +def test_collections_deque(): + # Create deque with cycle + a = deque() + a.append(a) + + cases = [ + (deque(), 'deque([])'), + (deque(i for i in range(1000, 1020)), + 'deque([1000,\n' + ' 1001,\n' + ' 1002,\n' + ' 1003,\n' + ' 1004,\n' + ' 1005,\n' + ' 1006,\n' + ' 1007,\n' + ' 1008,\n' + ' 1009,\n' + ' 1010,\n' + ' 1011,\n' + ' 1012,\n' + ' 1013,\n' + ' 1014,\n' + ' 1015,\n' + ' 1016,\n' + ' 1017,\n' + ' 1018,\n' + ' 1019])'), + (a, 'deque([deque(...)])'), + ] + for obj, expected in cases: + assert_equal(pretty.pretty(obj), expected) + + +def test_collections_counter(): + class MyCounter(Counter): + pass + cases = [ + (Counter(), 'Counter()'), + (Counter(a=1), "Counter({'a': 1})"), + (MyCounter(a=1), "MyCounter({'a': 1})"), + ] + for obj, expected in cases: + assert_equal(pretty.pretty(obj), expected) + + +def test_cyclic_list(): + x = [] + x.append(x) + assert pretty.pretty(x) == '[[...]]' + + +def test_cyclic_dequeue(): + x = deque() + x.append(x) + assert pretty.pretty(x) == 'deque([deque(...)])' + + +class HashItAnyway(object): + + def __init__(self, value): + self.value = value + + def __hash__(self): + return 0 + + def __eq__(self, other): + return isinstance(other, HashItAnyway) and self.value == other.value + + def __ne__(self, other): + return not self.__eq__(other) + + def _repr_pretty_(self, pretty, cycle): + pretty.pretty(self.value) + + +def test_cyclic_counter(): + c = Counter() + k = HashItAnyway(c) + c[k] = 1 + assert pretty.pretty(c) == 'Counter({Counter(...): 1})' + + +def test_cyclic_dict(): + x = {} + k = HashItAnyway(x) + x[k] = x + assert pretty.pretty(x) == '{{...}: {...}}' + + +def test_cyclic_set(): + x = set() + x.add(HashItAnyway(x)) + assert pretty.pretty(x) == '{{...}}' + + +def test_pprint(): + t = {'hi': 1} + with capture_out() as o: + pretty.pprint(t) + assert o.getvalue().strip() == pretty.pretty(t) + + +class BigList(list): + + def _repr_pretty_(self, printer, cycle): + if cycle: + return '[...]' + else: + with printer.group(open='[', close=']'): + with printer.indent(5): + for v in self: + printer.pretty(v) + printer.breakable(',') + + +def test_print_with_indent(): + pretty.pretty(BigList([1, 2, 3])) + + +class MyException(Exception): + pass + + +def test_exception(): + assert pretty.pretty(ValueError('hi')) == "ValueError('hi')" + assert pretty.pretty(ValueError('hi', 'there')) == \ + "ValueError('hi', 'there')" + assert 'test_pretty.' in pretty.pretty(MyException()) + + +def test_re_evals(): + for r in [ + re.compile(r'hi'), re.compile(r'b\nc', re.MULTILINE), + re.compile(br'hi', 0), re.compile(u'foo', re.MULTILINE | re.UNICODE), + ]: + r2 = eval(pretty.pretty(r), globals()) + assert r.pattern == r2.pattern and r.flags == r2.flags + + +class CustomStuff(object): + + def __init__(self): + self.hi = 1 + self.bye = 'fish' + self.spoon = self + + @property + def oops(self): + raise AttributeError('Nope') + + def squirrels(self): + pass + + +def test_custom(): + assert 'bye' not in pretty.pretty(CustomStuff()) + assert 'bye=' in pretty.pretty(CustomStuff(), verbose=True) + assert 'squirrels' not in pretty.pretty(CustomStuff(), verbose=True) + + +def test_print_builtin_function(): + assert pretty.pretty(abs) == '' + + +def test_pretty_function(): + assert '.' in pretty.pretty(test_pretty_function) + + +def test_empty_printer(): + printer = pretty.RepresentationPrinter( + pretty.CUnicodeIO(), + singleton_pprinters={}, + type_pprinters={ + int: pretty._repr_pprint, + list: pretty._repr_pprint, + }, + deferred_pprinters={}, + ) + printer.pretty([1, 2, 3]) + assert printer.output.getvalue() == u'[1, 2, 3]' + + +def test_breakable_at_group_boundary(): + assert '\n' in pretty.pretty([[], '000000'], max_width=5) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_provisional_strategies.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_provisional_strategies.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_provisional_strategies.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_provisional_strategies.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,42 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from binascii import unhexlify + +from hypothesis import given +from hypothesis.provisional import ip4_addr_strings, ip6_addr_strings + + +@given(ip4_addr_strings()) +def test_is_IP4_addr(address): + as_num = [int(n) for n in address.split('.')] + assert len(as_num) == 4 + assert all(0 <= n <= 255 for n in as_num) + + +@given(ip6_addr_strings()) +def test_is_IP6_addr(address): + # Works for non-normalised addresses produced by this strategy, but not + # a particularly general test + assert address == address.upper() + as_hex = address.split(':') + assert len(as_hex) == 8 + assert all(len(part) == 4 for part in as_hex) + raw = unhexlify(address.replace(u':', u'').encode('ascii')) + assert len(raw) == 16 diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_random_module.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_random_module.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_random_module.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_random_module.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,47 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import random + +import pytest + +import hypothesis.strategies as st +from hypothesis import given, reporting +from tests.common.utils import capture_out + + +def test_can_seed_random(): + with capture_out() as out: + with reporting.with_reporter(reporting.default): + with pytest.raises(AssertionError): + @given(st.random_module()) + def test(r): + assert False + test() + assert 'random.seed(0)' in out.getvalue() + + +@given(st.random_module(), st.random_module()) +def test_seed_random_twice(r, r2): + assert repr(r) == repr(r2) + + +@given(st.random_module()) +def test_does_not_fail_health_check_if_randomness_is_used(r): + random.getrandbits(128) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_recursive.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_recursive.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_recursive.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_recursive.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,55 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import pytest + +import hypothesis.strategies as st +from hypothesis import given +from hypothesis.errors import InvalidArgument +from tests.common.debug import minimal + + +@given(st.recursive(st.booleans(), st.lists, max_leaves=10)) +def test_respects_leaf_limit(xs): + def flatten(x): + if isinstance(x, list): + return sum(map(flatten, x), []) + else: + return [x] + assert len(flatten(xs)) <= 10 + + +def test_can_find_nested(): + x = minimal( + st.recursive(st.booleans(), lambda x: st.tuples(x, x)), + lambda x: isinstance(x, tuple) and isinstance(x[0], tuple) + ) + + assert x == ((False, False), False) + + +def test_recursive_call_validates_expand_returns_strategies(): + with pytest.raises(InvalidArgument): + st.recursive(st.booleans(), lambda x: 1).example() + + +def test_recursive_call_validates_base_is_strategy(): + x = st.recursive(1, lambda x: st.none()) + with pytest.raises(InvalidArgument): + x.example() diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_reflection.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_reflection.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_reflection.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_reflection.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,601 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import sys +from copy import deepcopy +from functools import partial + +import pytest +from mock import Mock, MagicMock, NonCallableMock, NonCallableMagicMock + +from tests.common.utils import raises +from hypothesis.internal.compat import PY3, FullArgSpec, getfullargspec +from hypothesis.internal.reflection import is_mock, proxies, arg_string, \ + required_args, unbind_method, eval_directory, function_digest, \ + fully_qualified_name, source_exec_as_module, \ + convert_keyword_arguments, define_function_signature, \ + convert_positional_arguments, get_pretty_function_description + + +def do_conversion_test(f, args, kwargs): + result = f(*args, **kwargs) + + cargs, ckwargs = convert_keyword_arguments(f, args, kwargs) + assert result == f(*cargs, **ckwargs) + + cargs2, ckwargs2 = convert_positional_arguments(f, args, kwargs) + assert result == f(*cargs2, **ckwargs2) + + +def test_simple_conversion(): + def foo(a, b, c): + return (a, b, c) + + assert convert_keyword_arguments( + foo, (1, 2, 3), {}) == ((1, 2, 3), {}) + assert convert_keyword_arguments( + foo, (), {'a': 3, 'b': 2, 'c': 1}) == ((3, 2, 1), {}) + + do_conversion_test(foo, (1, 0), {'c': 2}) + do_conversion_test(foo, (1,), {'c': 2, 'b': 'foo'}) + + +def test_populates_defaults(): + def bar(x=[], y=1): + pass + + assert convert_keyword_arguments(bar, (), {}) == (([], 1), {}) + assert convert_keyword_arguments(bar, (), {'y': 42}) == (([], 42), {}) + do_conversion_test(bar, (), {}) + do_conversion_test(bar, (1,), {}) + + +def test_leaves_unknown_kwargs_in_dict(): + def bar(x, **kwargs): + pass + + assert convert_keyword_arguments(bar, (1,), {'foo': 'hi'}) == ( + (1,), {'foo': 'hi'} + ) + assert convert_keyword_arguments(bar, (), {'x': 1, 'foo': 'hi'}) == ( + (1,), {'foo': 'hi'} + ) + do_conversion_test(bar, (1,), {}) + do_conversion_test(bar, (), {'x': 1, 'y': 1}) + + +def test_errors_on_bad_kwargs(): + def bar(): + pass + + with raises(TypeError): + convert_keyword_arguments(bar, (), {'foo': 1}) + + +def test_passes_varargs_correctly(): + def foo(*args): + pass + + assert convert_keyword_arguments(foo, (1, 2, 3), {}) == ((1, 2, 3), {}) + + do_conversion_test(foo, (1, 2, 3), {}) + + +def test_errors_if_keyword_precedes_positional(): + def foo(x, y): + pass + with raises(TypeError): + convert_keyword_arguments(foo, (1,), {'x': 2}) + + +def test_errors_if_not_enough_args(): + def foo(a, b, c, d=1): + pass + + with raises(TypeError): + convert_keyword_arguments(foo, (1, 2), {'d': 4}) + + +def test_errors_on_extra_kwargs(): + def foo(a): + pass + + with raises(TypeError) as e: + convert_keyword_arguments(foo, (1,), {'b': 1}) + assert 'keyword' in e.value.args[0] + + with raises(TypeError) as e2: + convert_keyword_arguments(foo, (1,), {'b': 1, 'c': 2}) + assert 'keyword' in e2.value.args[0] + + +def test_positional_errors_if_too_many_args(): + def foo(a): + pass + + with raises(TypeError) as e: + convert_positional_arguments(foo, (1, 2), {}) + assert '2 given' in e.value.args[0] + + +def test_positional_errors_if_too_few_args(): + def foo(a, b, c): + pass + + with raises(TypeError): + convert_positional_arguments(foo, (1, 2), {}) + + +def test_positional_does_not_error_if_extra_args_are_kwargs(): + def foo(a, b, c): + pass + + convert_positional_arguments(foo, (1, 2), {'c': 3}) + + +def test_positional_errors_if_given_bad_kwargs(): + def foo(a): + pass + + with raises(TypeError) as e: + convert_positional_arguments(foo, (), {'b': 1}) + assert 'unexpected keyword argument' in e.value.args[0] + + +def test_positional_errors_if_given_duplicate_kwargs(): + def foo(a): + pass + + with raises(TypeError) as e: + convert_positional_arguments(foo, (2,), {'a': 1}) + assert 'multiple values' in e.value.args[0] + + +def test_names_of_functions_are_pretty(): + assert get_pretty_function_description( + test_names_of_functions_are_pretty + ) == 'test_names_of_functions_are_pretty' + + +class Foo(object): + + @classmethod + def bar(cls): + pass + + def baz(cls): + pass + + def __repr__(self): + return 'SoNotFoo()' + + +def test_class_names_are_not_included_in_class_method_prettiness(): + assert get_pretty_function_description(Foo.bar) == 'bar' + + +def test_repr_is_included_in_bound_method_prettiness(): + assert get_pretty_function_description(Foo().baz) == 'SoNotFoo().baz' + + +def test_class_is_not_included_in_unbound_method(): + assert ( + get_pretty_function_description(Foo.baz) + == 'baz' + ) + + +def test_does_not_error_on_confused_sources(): + def ed(f, *args): + return f + + x = ed( + lambda x, y: ( + x * y + ).conjugate() == x.conjugate() * y.conjugate(), complex, complex) + + get_pretty_function_description(x) + + +def test_digests_are_reasonably_unique(): + assert ( + function_digest(test_simple_conversion) != + function_digest(test_does_not_error_on_confused_sources) + ) + + +def test_digest_returns_the_same_value_for_two_calls(): + assert ( + function_digest(test_simple_conversion) == + function_digest(test_simple_conversion) + ) + + +def test_can_digest_a_built_in_function(): + import math + assert function_digest(math.isnan) != function_digest(range) + + +def test_can_digest_a_unicode_lambda(): + function_digest(lambda x: '☃' in str(x)) + + +def test_can_digest_a_function_with_no_name(): + def foo(x, y): + pass + function_digest(partial(foo, 1)) + + +def test_arg_string_is_in_order(): + def foo(c, a, b, f, a1): + pass + + assert arg_string(foo, (1, 2, 3, 4, 5), {}) == 'c=1, a=2, b=3, f=4, a1=5' + assert arg_string( + foo, (1, 2), + {'b': 3, 'f': 4, 'a1': 5}) == 'c=1, a=2, b=3, f=4, a1=5' + + +def test_varkwargs_are_sorted_and_after_real_kwargs(): + def foo(d, e, f, **kwargs): + pass + + assert arg_string( + foo, (), {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5, 'f': 6} + ) == 'd=4, e=5, f=6, a=1, b=2, c=3' + + +def test_varargs_come_without_equals(): + def foo(a, *args): + pass + + assert arg_string(foo, (1, 2, 3, 4), {}) == '2, 3, 4, a=1' + + +def test_can_mix_varargs_and_varkwargs(): + def foo(*args, **kwargs): + pass + + assert arg_string( + foo, (1, 2, 3), {'c': 7} + ) == '1, 2, 3, c=7' + + +def test_arg_string_does_not_include_unprovided_defaults(): + def foo(a, b, c=9, d=10): + pass + + assert arg_string(foo, (1,), {'b': 1, 'd': 11}) == 'a=1, b=1, d=11' + + +class A(object): + + def f(self): + pass + + def g(self): + pass + + +class B(A): + pass + + +class C(A): + + def f(self): + pass + + +def test_unbind_gives_parent_class_function(): + assert unbind_method(B().f) == unbind_method(A.f) + + +def test_unbind_distinguishes_different_functions(): + assert unbind_method(A.f) != unbind_method(A.g) + + +def test_unbind_distinguishes_overridden_functions(): + assert unbind_method(C().f) != unbind_method(A.f) + + +def universal_acceptor(*args, **kwargs): + return args, kwargs + + +def has_one_arg(hello): + pass + + +def has_two_args(hello, world): + pass + + +def has_a_default(x, y, z=1): + pass + + +def has_varargs(*args): + pass + + +def has_kwargs(**kwargs): + pass + + +@pytest.mark.parametrize('f', [ + has_one_arg, + has_two_args, + has_varargs, + has_kwargs, +]) +def test_copying_preserves_argspec(f): + af = getfullargspec(f) + t = define_function_signature('foo', 'docstring', af)(universal_acceptor) + at = getfullargspec(t) + assert af.args == at.args + assert af.varargs == at.varargs + assert af.varkw == at.varkw + assert len(af.defaults or ()) == len(at.defaults or ()) + assert af.kwonlyargs == at.kwonlyargs + assert af.kwonlydefaults == at.kwonlydefaults + assert af.annotations == at.annotations + + +def test_name_does_not_clash_with_function_names(): + def f(): + pass + + @define_function_signature('f', 'A docstring for f', getfullargspec(f)) + def g(): + pass + g() + + +def test_copying_sets_name(): + f = define_function_signature( + 'hello_world', 'A docstring for hello_world', + getfullargspec(has_two_args))(universal_acceptor) + assert f.__name__ == 'hello_world' + + +def test_copying_sets_docstring(): + f = define_function_signature( + 'foo', 'A docstring for foo', + getfullargspec(has_two_args))(universal_acceptor) + assert f.__doc__ == 'A docstring for foo' + + +def test_uses_defaults(): + f = define_function_signature( + 'foo', 'A docstring for foo', + getfullargspec(has_a_default))(universal_acceptor) + assert f(3, 2) == ((3, 2, 1), {}) + + +def test_uses_varargs(): + f = define_function_signature( + 'foo', 'A docstring for foo', + getfullargspec(has_varargs))(universal_acceptor) + assert f(1, 2) == ((1, 2), {}) + + +DEFINE_FOO_FUNCTION = """ +def foo(x): + return x +""" + + +def test_exec_as_module_execs(): + m = source_exec_as_module(DEFINE_FOO_FUNCTION) + assert m.foo(1) == 1 + + +def test_exec_as_module_caches(): + assert ( + source_exec_as_module(DEFINE_FOO_FUNCTION) is + source_exec_as_module(DEFINE_FOO_FUNCTION) + ) + + +def test_exec_leaves_sys_path_unchanged(): + old_path = deepcopy(sys.path) + source_exec_as_module('hello_world = 42') + assert sys.path == old_path + + +def test_define_function_signature_works_with_conflicts(): + def accepts_everything(*args, **kwargs): + pass + + define_function_signature('hello', 'A docstring for hello', FullArgSpec( + args=('f',), varargs=None, varkw=None, defaults=None, + kwonlyargs=[], kwonlydefaults=None, annotations={} + ))(accepts_everything)(1) + + define_function_signature('hello', 'A docstring for hello', FullArgSpec( + args=(), varargs='f', varkw=None, defaults=None, + kwonlyargs=[], kwonlydefaults=None, annotations={} + ))(accepts_everything)(1) + + define_function_signature('hello', 'A docstring for hello', FullArgSpec( + args=(), varargs=None, varkw='f', defaults=None, + kwonlyargs=[], kwonlydefaults=None, annotations={} + ))(accepts_everything)() + + define_function_signature('hello', 'A docstring for hello', FullArgSpec( + args=('f', 'f_3'), varargs='f_1', varkw='f_2', defaults=None, + kwonlyargs=[], kwonlydefaults=None, annotations={} + ))(accepts_everything)(1, 2) + + +def test_define_function_signature_validates_arguments(): + with raises(ValueError): + define_function_signature('hello_world', None, FullArgSpec( + args=['a b'], varargs=None, varkw=None, defaults=None, + kwonlyargs=[], kwonlydefaults=None, annotations={})) + + +def test_define_function_signature_validates_function_name(): + with raises(ValueError): + define_function_signature('hello world', None, FullArgSpec( + args=['a', 'b'], varargs=None, varkw=None, defaults=None, + kwonlyargs=[], kwonlydefaults=None, annotations={})) + + +class Container(object): + + def funcy(self): + pass + + +def test_fully_qualified_name(): + assert fully_qualified_name(test_copying_preserves_argspec) == \ + 'tests.cover.test_reflection.test_copying_preserves_argspec' + assert fully_qualified_name(Container.funcy) == \ + 'tests.cover.test_reflection.Container.funcy' + assert fully_qualified_name(fully_qualified_name) == \ + 'hypothesis.internal.reflection.fully_qualified_name' + + +def test_qualname_of_function_with_none_module_is_name(): + def f(): + pass + f.__module__ = None + assert fully_qualified_name(f)[-1] == 'f' + + +def test_can_proxy_functions_with_mixed_args_and_varargs(): + def foo(a, *args): + return (a, args) + + @proxies(foo) + def bar(*args, **kwargs): + return foo(*args, **kwargs) + + assert bar(1, 2) == (1, (2,)) + + +def test_can_delegate_to_a_function_with_no_positional_args(): + def foo(a, b): + return (a, b) + + @proxies(foo) + def bar(**kwargs): + return foo(**kwargs) + + assert bar(2, 1) == (2, 1) + + +class Snowman(object): + + def __repr__(self): + return '☃' + + +class BittySnowman(object): + + def __repr__(self): + return '☃' + + +def test_can_handle_unicode_repr(): + def foo(x): + pass + assert arg_string(foo, [Snowman()], {}) == 'x=☃' + assert arg_string(foo, [], {'x': Snowman()}) == 'x=☃' + + +class NoRepr(object): + pass + + +def test_can_handle_repr_on_type(): + def foo(x): + pass + assert arg_string(foo, [Snowman], {}) == 'x=Snowman' + assert arg_string(foo, [NoRepr], {}) == 'x=NoRepr' + + +def test_can_handle_repr_of_none(): + def foo(x): + pass + + assert arg_string(foo, [None], {}) == 'x=None' + assert arg_string(foo, [], {'x': None}) == 'x=None' + + +if not PY3: + def test_can_handle_non_unicode_repr_containing_non_ascii(): + def foo(x): + pass + + assert arg_string(foo, [BittySnowman()], {}) == 'x=☃' + assert arg_string(foo, [], {'x': BittySnowman()}) == 'x=☃' + + +def test_does_not_put_eval_directory_on_path(): + source_exec_as_module("hello = 'world'") + assert eval_directory() not in sys.path + + +def test_kwargs_appear_in_arg_string(): + def varargs(*args, **kwargs): + pass + assert 'x=1' in arg_string(varargs, (), {'x': 1}) + + +def test_is_mock_with_negative_cases(): + assert not is_mock(None) + assert not is_mock(1234) + assert not is_mock(is_mock) + assert not is_mock(BittySnowman()) + assert not is_mock('foobar') + assert not is_mock(Mock(spec=BittySnowman)) + assert not is_mock(MagicMock(spec=BittySnowman)) + + +def test_is_mock_with_positive_cases(): + assert is_mock(Mock()) + assert is_mock(MagicMock()) + assert is_mock(NonCallableMock()) + assert is_mock(NonCallableMagicMock()) + + +class Target(object): + + def __init__(self, a, b): + pass + + def method(self, a, b): + pass + + +@pytest.mark.parametrize('target', [Target, Target(1, 2).method]) +@pytest.mark.parametrize('args,kwargs,expected', [ + ((), {}, set('ab')), + ((1,), {}, set('b')), + ((1, 2), {}, set()), + ((), dict(a=1), set('b')), + ((), dict(b=2), set('a')), + ((), dict(a=1, b=2), set()), +]) +def test_required_args(target, args, kwargs, expected): + # Mostly checking that `self` (and only self) is correctly excluded + assert required_args(target, args, kwargs) == expected diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_regex.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_regex.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_regex.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_regex.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,426 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import re +import sys +import unicodedata + +import pytest + +import hypothesis.strategies as st +from hypothesis import given, assume +from hypothesis.errors import InvalidArgument +from tests.common.debug import find_any, assert_no_examples, \ + assert_all_examples +from hypothesis.internal.compat import PY3, hrange, hunichr +from hypothesis.searchstrategy.regex import SPACE_CHARS, \ + UNICODE_SPACE_CHARS, HAS_WEIRD_WORD_CHARS, UNICODE_WORD_CATEGORIES, \ + UNICODE_DIGIT_CATEGORIES, UNICODE_SPACE_CATEGORIES, \ + UNICODE_WEIRD_NONWORD_CHARS, base_regex_strategy + + +def is_ascii(s): + return all(ord(c) < 128 for c in s) + + +def is_digit(s): + return all(unicodedata.category(c) in UNICODE_DIGIT_CATEGORIES for c in s) + + +def is_space(s): + return all(c in SPACE_CHARS for c in s) + + +def is_unicode_space(s): + return all( + unicodedata.category(c) in UNICODE_SPACE_CATEGORIES or + c in UNICODE_SPACE_CHARS + for c in s + ) + + +def is_word(s): + return all( + c == '_' or ( + (not HAS_WEIRD_WORD_CHARS or + c not in UNICODE_WEIRD_NONWORD_CHARS) and + unicodedata.category(c) in UNICODE_WORD_CATEGORIES + ) + for c in s + ) + + +def ascii_regex(pattern): + flags = re.ASCII if PY3 else 0 + return re.compile(pattern, flags) + + +def unicode_regex(pattern): + return re.compile(pattern, re.UNICODE) + + +def _test_matching_pattern(pattern, isvalidchar, is_unicode=False): + r = unicode_regex(pattern) if is_unicode else ascii_regex(pattern) + + codepoints = hrange(0, sys.maxunicode + 1) \ + if is_unicode else hrange(1, 128) + for c in [hunichr(x) for x in codepoints]: + if isvalidchar(c): + assert r.search(c), ( + '"%s" supposed to match "%s" (%r, category "%s"), ' + "but it doesn't" % (pattern, c, c, unicodedata.category(c)) + ) + else: + assert not r.search(c), ( + '"%s" supposed not to match "%s" (%r, category "%s"), ' + 'but it does' % (pattern, c, c, unicodedata.category(c)) + ) + + +@pytest.mark.parametrize('category,predicate', [ + (r'\w', is_word), (r'\d', is_digit), (r'\s', None)]) +@pytest.mark.parametrize('invert', [False, True]) +@pytest.mark.parametrize('is_unicode', [False, True]) +def test_matching(category, predicate, invert, is_unicode): + if predicate is None: + # Special behaviour due to \x1c, INFORMATION SEPARATOR FOUR + predicate = is_unicode_space if is_unicode else is_space + pred = predicate + if invert: + category = category.swapcase() + + def pred(s): + return not predicate(s) + + _test_matching_pattern(category, pred, is_unicode) + + +@pytest.mark.parametrize('pattern', [ + u'.', # anything + u'a', u'abc', u'[a][b][c]', u'[^a][^b][^c]', # literals + u'[a-z0-9_]', u'[^a-z0-9_]', # range and negative range + u'ab?', u'ab*', u'ab+', # quantifiers + u'ab{5}', u'ab{5,10}', u'ab{,10}', u'ab{5,}', # repeaters + u'ab|cd|ef', # branch + u'(foo)+', u'([\'"])[a-z]+\\1', + u'(?:[a-z])([\'"])[a-z]+\\1', u'(?P[\'"])[a-z]+(?P=foo)', # groups + u'^abc', # beginning + u'\\d', u'[\\d]', u'[^\\D]', u'\\w', u'[\\w]', u'[^\\W]', + u'\\s', u'[\\s]', u'[^\\S]', # categories +]) +@pytest.mark.parametrize('encode', [False, True]) +def test_can_generate(pattern, encode): + if encode: + pattern = pattern.encode('ascii') + assert_all_examples(st.from_regex(pattern), re.compile(pattern).search) + + +@pytest.mark.parametrize('pattern', [ + re.compile(u'\\Aa\\Z', re.IGNORECASE), + u'(?i)\\Aa\\Z', + re.compile(u'\\A[ab]\\Z', re.IGNORECASE), + u'(?i)\\A[ab]\\Z', +]) +def test_literals_with_ignorecase(pattern): + strategy = st.from_regex(pattern) + + find_any(strategy, lambda s: s == u'a') + find_any(strategy, lambda s: s == u'A') + + +@pytest.mark.parametrize('pattern', [ + re.compile(u'\\A[^a][^b]\\Z', re.IGNORECASE), + u'(?i)\\A[^a][^b]\\Z' +]) +def test_not_literal_with_ignorecase(pattern): + assert_all_examples( + st.from_regex(pattern), + lambda s: s[0] not in (u'a', u'A') and s[1] not in (u'b', u'B') + ) + + +def test_any_doesnt_generate_newline(): + assert_all_examples(st.from_regex(u'\\A.\\Z'), lambda s: s != u'\n') + + +@pytest.mark.parametrize('pattern', [ + re.compile(u'\\A.\\Z', re.DOTALL), u'(?s)\\A.\\Z' +]) +def test_any_with_dotall_generate_newline(pattern): + find_any(st.from_regex(pattern), lambda s: s == u'\n') + + +@pytest.mark.parametrize('pattern', [ + re.compile(b'\\A.\\Z', re.DOTALL), b'(?s)\\A.\\Z' +]) +def test_any_with_dotall_generate_newline_binary(pattern): + find_any(st.from_regex(pattern), lambda s: s == b'\n') + + +@pytest.mark.parametrize('pattern', [ + u'\\d', u'[\\d]', u'[^\\D]', + u'\\w', u'[\\w]', u'[^\\W]', + u'\\s', u'[\\s]', u'[^\\S]', +]) +@pytest.mark.parametrize('is_unicode', [False, True]) +@pytest.mark.parametrize('invert', [False, True]) +def test_groups(pattern, is_unicode, invert): + if u'd' in pattern.lower(): + group_pred = is_digit + elif u'w' in pattern.lower(): + group_pred = is_word + else: + # Special behaviour due to \x1c, INFORMATION SEPARATOR FOUR + group_pred = is_unicode_space if is_unicode else is_space + + if invert: + pattern = pattern.swapcase() + _p = group_pred + + def group_pred(s): + return not _p(s) + + pattern = u'^%s\\Z' % (pattern,) + + compiler = unicode_regex if is_unicode else ascii_regex + strategy = st.from_regex(compiler(pattern)) + + find_any(strategy.filter(group_pred), is_ascii) + if is_unicode: + find_any(strategy, lambda s: group_pred(s) and not is_ascii(s)) + + assert_all_examples(strategy, group_pred) + + +def test_caret_in_the_middle_does_not_generate_anything(): + r = re.compile(u'a^b') + + assert_no_examples(st.from_regex(r)) + + +def test_end_with_terminator_does_not_pad(): + assert_all_examples(st.from_regex(u'abc\\Z'), lambda x: x[-3:] == u"abc") + + +def test_end(): + strategy = st.from_regex(u'\\Aabc$') + + find_any(strategy, lambda s: s == u'abc') + find_any(strategy, lambda s: s == u'abc\n') + + +def test_groupref_exists(): + assert_all_examples( + st.from_regex(u'^(<)?a(?(1)>)$'), + lambda s: s in (u'a', u'a\n', u'', u'\n') + ) + assert_all_examples( + st.from_regex(u'^(a)?(?(1)b|c)$'), + lambda s: s in (u'ab', u'ab\n', u'c', u'c\n') + ) + + +def test_impossible_negative_lookahead(): + assert_no_examples(st.from_regex(u'(?!foo)foo')) + + +@given(st.from_regex(u"(\\Afoo\\Z)")) +def test_can_handle_boundaries_nested(s): + assert s == u"foo" + + +def test_groupref_not_shared_between_regex(): + # If group references are (incorrectly!) shared between regex, this would + # fail as the would only be one reference. + st.tuples(st.from_regex('(a)\\1'), st.from_regex('(b)\\1')).example() + + +@given(st.data()) +def test_group_ref_is_not_shared_between_identical_regex(data): + pattern = re.compile(u"^(.+)\\1\\Z", re.UNICODE) + x = data.draw(base_regex_strategy(pattern)) + y = data.draw(base_regex_strategy(pattern)) + assume(x != y) + assert pattern.match(x).end() == len(x) + assert pattern.match(y).end() == len(y) + + +@given(st.data()) +def test_does_not_leak_groups(data): + a = data.draw(base_regex_strategy(re.compile(u"^(a)\\Z"))) + assert a == 'a' + b = data.draw(base_regex_strategy(re.compile(u"^(?(1)a|b)(.)\\Z"))) + assert b[0] == 'b' + + +def test_positive_lookbehind(): + find_any(st.from_regex(u'.*(?<=ab)c'), lambda s: s.endswith(u'abc')) + + +def test_positive_lookahead(): + st.from_regex(u'a(?=bc).*').filter( + lambda s: s.startswith(u'abc')).example() + + +def test_negative_lookbehind(): + # no efficient support + strategy = st.from_regex(u'[abc]*(? 1000: + raise ValueError() + + with capture_out() as o: + with pytest.raises(ValueError): + test() + assert '@reproduce_failure' not in o.getvalue() + + +class Foo(object): + def __repr__(self): + return 'not a valid python expression' + + +def test_does_print_reproduction_given_an_invalid_repr(): + @given(st.integers().map(lambda x: Foo())) + def test(i): + raise ValueError() + + with capture_out() as o: + with pytest.raises(ValueError): + test() + + assert '@reproduce_failure' in o.getvalue() + + +def test_does_not_print_reproduction_if_told_not_to(): + @settings(print_blob=PrintSettings.NEVER) + @given(st.integers().map(lambda x: Foo())) + def test(i): + raise ValueError() + + with capture_out() as o: + with pytest.raises(ValueError): + test() + + assert '@reproduce_failure' not in o.getvalue() + + +def test_raises_invalid_if_wrong_version(): + b = b'hello world' + n = len(b) + + @reproduce_failure('1.0.0', encode_failure(b)) + @given(st.binary(min_size=n, max_size=n)) + def test(x): + pass + + with pytest.raises(InvalidArgument): + test() + + +def test_does_not_print_reproduction_if_verbosity_set_to_quiet(): + @given(st.data()) + @settings(verbosity=Verbosity.quiet) + def test_always_fails(data): + assert data.draw(st.just(False)) + + with capture_out() as out: + with pytest.raises(AssertionError): + test_always_fails() + + assert '@reproduce_failure' not in out.getvalue() diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_reusable_values.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_reusable_values.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_reusable_values.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_reusable_values.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,94 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import pytest + +import hypothesis.strategies as st +from hypothesis import given, reject, example +from hypothesis.errors import InvalidArgument + +base_reusable_strategies = ( + st.text(), st.binary(), st.dates(), + st.times(), st.timedeltas(), st.booleans(), st.complex_numbers(), + st.floats(), st.floats(-1.0, 1.0), + st.integers(), st.integers(1, 10), st.integers(1), +) + + +@st.deferred +def reusable(): + return st.one_of( + st.sampled_from(base_reusable_strategies), + + st.builds( + st.floats, min_value=st.none() | st.floats(), + max_value=st.none() | st.floats(), allow_infinity=st.booleans(), + allow_nan=st.booleans() + ), + + st.builds(st.just, st.builds(list)), + st.builds(st.sampled_from, st.lists(st.builds(list))), + + st.lists(reusable).map(st.one_of), + st.lists(reusable).map(lambda ls: st.tuples(*ls)), + ) + + +assert not reusable.is_empty + + +@example(st.integers(min_value=1)) +@given(reusable) +def test_reusable_strategies_are_all_reusable(s): + try: + s.validate() + except InvalidArgument: + reject() + + assert s.has_reusable_values + + +for s in base_reusable_strategies: + test_reusable_strategies_are_all_reusable = example(s)( + test_reusable_strategies_are_all_reusable + ) + test_reusable_strategies_are_all_reusable = example(st.tuples(s))( + test_reusable_strategies_are_all_reusable + ) + + +def test_composing_breaks_reusability(): + s = st.integers() + assert s.has_reusable_values + assert not s.filter(lambda x: True).has_reusable_values + assert not s.map(lambda x: x).has_reusable_values + assert not s.flatmap(lambda x: st.just(x)).has_reusable_values + + +@pytest.mark.parametrize('strat', [ + st.lists(st.booleans()), st.sets(st.booleans()), + st.dictionaries(st.booleans(), st.booleans()), +]) +def test_mutable_collections_do_not_have_reusable_values(strat): + assert not strat.has_reusable_values + + +def test_recursion_does_not_break_reusability(): + x = st.deferred(lambda: st.none() | st.tuples(x)) + assert x.has_reusable_values diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_runner_strategy.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_runner_strategy.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_runner_strategy.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_runner_strategy.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,73 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from unittest import TestCase + +import pytest + +from hypothesis import find, given +from hypothesis import strategies as st +from hypothesis.errors import InvalidArgument +from hypothesis.stateful import GenericStateMachine + + +def test_cannot_use_without_a_runner(): + @given(st.runner()) + def f(x): + pass + with pytest.raises(InvalidArgument): + f() + + +def test_cannot_use_in_find_without_default(): + with pytest.raises(InvalidArgument): + find(st.runner(), lambda x: True) + + +def test_is_default_in_find(): + t = object() + assert find(st.runner(t), lambda x: True) == t + + +@given(st.runner(1)) +def test_is_default_without_self(runner): + assert runner == 1 + + +class TestStuff(TestCase): + + @given(st.runner()) + def test_runner_is_self(self, runner): + assert runner is self + + @given(st.runner(default=3)) + def test_runner_is_self_even_with_default(self, runner): + assert runner is self + + +class RunnerStateMachine(GenericStateMachine): + + def steps(self): + return st.runner() + + def execute_step(self, step): + assert self is step + + +TestState = RunnerStateMachine.TestCase diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_sampled_from.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_sampled_from.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_sampled_from.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_sampled_from.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,47 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import enum +import collections + +from hypothesis import given +from tests.common.utils import checks_deprecated_behaviour +from hypothesis.strategies import sampled_from + +an_enum = enum.Enum('A', 'a b c') + +an_ordereddict = collections.OrderedDict([('a', 1), ('b', 2), ('c', 3)]) + + +@checks_deprecated_behaviour +def test_can_sample_sets_while_deprecated(): + assert sampled_from(set('abc')).example() in 'abc' + + +def test_can_sample_sequence_without_warning(): + sampled_from([1, 2, 3]).example() + + +def test_can_sample_ordereddict_without_warning(): + sampled_from(an_ordereddict).example() + + +@given(sampled_from(an_enum)) +def test_can_sample_enums(member): + assert isinstance(member, an_enum) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_searchstrategy.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_searchstrategy.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_searchstrategy.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_searchstrategy.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,97 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import functools +from collections import namedtuple + +import pytest + +from hypothesis.types import RandomWithSeed +from tests.common.debug import assert_no_examples +from hypothesis.strategies import just, tuples, randoms, booleans, integers +from hypothesis.internal.compat import text_type +from hypothesis.searchstrategy.strategies import one_of_strategies + + +def test_or_errors_when_given_non_strategy(): + bools = tuples(booleans()) + with pytest.raises(ValueError): + bools | u'foo' + + +def test_joining_zero_strategies_fails(): + with pytest.raises(ValueError): + one_of_strategies(()) + + +SomeNamedTuple = namedtuple(u'SomeNamedTuple', (u'a', u'b')) + + +def last(xs): + t = None + for x in xs: + t = x + return t + + +def test_random_repr_has_seed(): + rnd = randoms().example() + seed = rnd.seed + assert text_type(seed) in repr(rnd) + + +def test_random_only_produces_special_random(): + st = randoms() + assert isinstance(st.example(), RandomWithSeed) + + +def test_just_strategy_uses_repr(): + class WeirdRepr(object): + + def __repr__(self): + return u'ABCDEFG' + + assert repr( + just(WeirdRepr()) + ) == u'just(%r)' % (WeirdRepr(),) + + +def test_can_map(): + s = integers().map(pack=lambda t: u'foo') + assert s.example() == u'foo' + + +def test_example_raises_unsatisfiable_when_too_filtered(): + assert_no_examples(integers().filter(lambda x: False)) + + +def nameless_const(x): + def f(u, v): + return u + return functools.partial(f, x) + + +def test_can_map_nameless(): + f = nameless_const(2) + assert repr(f) in repr(integers().map(f)) + + +def test_can_flatmap_nameless(): + f = nameless_const(just(3)) + assert repr(f) in repr(integers().flatmap(f)) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_seed_printing.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_seed_printing.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_seed_printing.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_seed_printing.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,125 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import time + +import pytest + +import hypothesis.core as core +import hypothesis.strategies as st +from hypothesis import Verbosity, given, assume, settings +from hypothesis.errors import FailedHealthCheck +from tests.common.utils import all_values, capture_out +from hypothesis.database import InMemoryExampleDatabase +from hypothesis.internal.compat import hrange + + +@pytest.mark.parametrize('in_pytest', [False, True]) +@pytest.mark.parametrize('fail_healthcheck', [False, True]) +@pytest.mark.parametrize('verbosity', [Verbosity.normal, Verbosity.quiet]) +def test_prints_seed_only_on_healthcheck( + monkeypatch, in_pytest, fail_healthcheck, verbosity +): + monkeypatch.setattr(core, 'running_under_pytest', in_pytest) + + strategy = st.integers() + if fail_healthcheck: + def slow_map(i): + time.sleep(10) + return i + strategy = strategy.map(slow_map) + expected_exc = FailedHealthCheck + else: + expected_exc = AssertionError + + @settings(database=None, verbosity=verbosity) + @given(strategy) + def test(i): + assert fail_healthcheck + + with capture_out() as o: + with pytest.raises(expected_exc): + test() + + output = o.getvalue() + + seed = test._hypothesis_internal_use_generated_seed + assert seed is not None + if fail_healthcheck and verbosity != Verbosity.quiet: + assert '@seed(%d)' % (seed,) in output + contains_pytest_instruction = ( + '--hypothesis-seed=%d' % (seed,)) in output + assert contains_pytest_instruction == in_pytest + else: + assert '@seed' not in output + assert '--hypothesis-seed=%d' % (seed,) not in output + + +def test_uses_global_force(monkeypatch): + monkeypatch.setattr(core, 'global_force_seed', 42) + + @given(st.integers()) + def test(i): + raise ValueError() + + output = [] + + for _ in hrange(2): + with capture_out() as o: + with pytest.raises(ValueError): + test() + output.append(o.getvalue()) + + assert output[0] == output[1] + assert '@seed' not in output[0] + + +def test_does_print_on_reuse_from_database(): + passes_healthcheck = False + + database = InMemoryExampleDatabase() + + @settings(database=database) + @given(st.integers()) + def test(i): + assume(passes_healthcheck) + raise ValueError() + + with capture_out() as o: + with pytest.raises(FailedHealthCheck): + test() + + assert '@seed' in o.getvalue() + + passes_healthcheck = True + + with capture_out() as o: + with pytest.raises(ValueError): + test() + + assert all_values(database) + assert '@seed' not in o.getvalue() + + passes_healthcheck = False + + with capture_out() as o: + with pytest.raises(FailedHealthCheck): + test() + + assert '@seed' in o.getvalue() diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_settings.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_settings.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_settings.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_settings.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,396 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import os +import sys +import subprocess +from tempfile import mkdtemp + +import pytest + +import hypothesis.strategies as st +from hypothesis import given, example, unlimited +from hypothesis.errors import InvalidState, InvalidArgument, \ + HypothesisDeprecationWarning +from tests.common.utils import validate_deprecation, \ + checks_deprecated_behaviour +from hypothesis.database import ExampleDatabase, \ + DirectoryBasedExampleDatabase +from hypothesis._settings import Verbosity, settings, default_variable, \ + note_deprecation +from hypothesis.utils.conventions import not_set + + +def test_has_docstrings(): + assert settings.verbosity.__doc__ + + +original_default = settings.get_profile('default').max_examples + + +def setup_function(fn): + settings.load_profile('default') + settings.register_profile('test_settings', settings()) + settings.load_profile('test_settings') + + +def test_cannot_set_non_settings(): + s = settings() + with pytest.raises(AttributeError): + s.databas_file = u'some_file' + + +def test_settings_uses_defaults(): + s = settings() + assert s.max_examples == settings.default.max_examples + + +def test_raises_attribute_error(): + with pytest.raises(AttributeError): + settings().kittens + + +def test_respects_none_database(): + assert settings(database=None).database is None + + +@checks_deprecated_behaviour +def test_settings_can_be_used_as_context_manager_to_change_defaults(): + with settings(max_examples=12): + assert settings.default.max_examples == 12 + assert settings.default.max_examples == original_default + + +@checks_deprecated_behaviour +def test_can_repeatedly_push_the_same_thing(): + s = settings(max_examples=12) + t = settings(max_examples=17) + assert settings().max_examples == original_default + with s: + assert settings().max_examples == 12 + with t: + assert settings().max_examples == 17 + with s: + assert settings().max_examples == 12 + with t: + assert settings().max_examples == 17 + assert settings().max_examples == 12 + assert settings().max_examples == 17 + assert settings().max_examples == 12 + assert settings().max_examples == original_default + + +def test_cannot_create_settings_with_invalid_options(): + with pytest.raises(InvalidArgument): + settings(a_setting_with_limited_options=u'spoon') + + +def test_cannot_register_with_parent_and_settings_args(): + with pytest.raises(InvalidArgument): + settings.register_profile( + 'conflicted', settings.default, settings=settings.default) + assert 'conflicted' not in settings._profiles + + +@checks_deprecated_behaviour +def test_register_profile_kwarg_settings_is_deprecated(): + settings.register_profile('test', settings=settings(max_examples=10)) + settings.load_profile('test') + assert settings.default.max_examples == 10 + + +@checks_deprecated_behaviour +def test_perform_health_check_setting_is_deprecated(): + s = settings(suppress_health_check=(), perform_health_check=False) + assert s.suppress_health_check + + +@checks_deprecated_behaviour +@given(st.integers(0, 10000)) +def test_max_shrinks_setting_is_deprecated(n): + s = settings(max_shrinks=n) + assert s.max_shrinks == n + + +def test_can_set_verbosity(): + settings(verbosity=Verbosity.quiet) + settings(verbosity=Verbosity.normal) + settings(verbosity=Verbosity.verbose) + + +def test_can_not_set_verbosity_to_non_verbosity(): + with pytest.raises(InvalidArgument): + settings(verbosity='kittens') + + +@checks_deprecated_behaviour +@pytest.mark.parametrize('db', [None, ExampleDatabase()]) +def test_inherits_an_empty_database(db): + assert settings.default.database is not None + s = settings(database=db) + assert s.database is db + with s: + t = settings() + assert t.database is db + + +@pytest.mark.parametrize('db', [None, ExampleDatabase()]) +def test_can_assign_database(db): + x = settings(database=db) + assert x.database is db + + +def test_will_reload_profile_when_default_is_absent(): + original = settings.default + default_variable.value = None + assert settings.default is original + + +def test_load_profile(): + settings.load_profile('default') + assert settings.default.max_examples == original_default + assert settings.default.stateful_step_count == 50 + + settings.register_profile( + 'test', settings(max_examples=10), stateful_step_count=5 + ) + settings.load_profile('test') + + assert settings.default.max_examples == 10 + assert settings.default.stateful_step_count == 5 + + settings.load_profile('default') + + assert settings.default.max_examples == original_default + assert settings.default.stateful_step_count == 50 + + +@checks_deprecated_behaviour +def test_nonstring_profile_names_deprecated(): + settings.register_profile(5, stateful_step_count=5) + settings.load_profile(5) + assert settings.default.stateful_step_count == 5 + + +@checks_deprecated_behaviour +def test_loading_profile_keeps_expected_behaviour(): + settings.register_profile('ci', settings(max_examples=10000)) + settings.load_profile('ci') + assert settings().max_examples == 10000 + with settings(max_examples=5): + assert settings().max_examples == 5 + assert settings().max_examples == 10000 + + +def test_load_non_existent_profile(): + with pytest.raises(InvalidArgument): + settings.get_profile('nonsense') + + +@pytest.mark.skipif( + os.getenv('HYPOTHESIS_PROFILE') not in (None, 'default'), + reason='Defaults have been overridden') +def test_runs_tests_with_defaults_from_conftest(): + assert settings.default.timeout == -1 + + +def test_cannot_delete_a_setting(): + x = settings() + with pytest.raises(AttributeError): + del x.max_examples + x.max_examples + + x = settings() + with pytest.raises(AttributeError): + del x.foo + + +def test_cannot_set_strict(): + with pytest.raises(HypothesisDeprecationWarning): + settings(strict=True) + + +@checks_deprecated_behaviour +def test_set_deprecated_settings(): + assert settings(timeout=3).timeout == 3 + + +def test_setting_to_future_value_gives_future_value_and_no_error(): + assert settings(timeout=unlimited).timeout == -1 + + +def test_cannot_set_settings(): + x = settings() + with pytest.raises(AttributeError): + x.max_examples = 'foo' + with pytest.raises(AttributeError): + x.database = 'foo' + assert x.max_examples != 'foo' + assert x.database != 'foo' + + +def test_can_have_none_database(): + assert settings(database=None).database is None + + +@checks_deprecated_behaviour +@pytest.mark.parametrize('db', [None, ExampleDatabase(':memory:')]) +def test_database_type_must_be_ExampleDatabase(db): + with settings(database=db): + settings_property_db = settings.database + with pytest.raises(InvalidArgument): + settings(database='.hypothesis/examples') + assert settings.database is settings_property_db + + +@checks_deprecated_behaviour +def test_can_have_none_database_file(): + assert settings(database_file=None).database is None + + +@checks_deprecated_behaviour +def test_can_override_database_file(): + f = mkdtemp() + x = settings(database_file=f) + assert isinstance(x.database, DirectoryBasedExampleDatabase) + assert x.database.path == f + + +def test_cannot_define_settings_once_locked(): + with pytest.raises(InvalidState): + settings._define_setting('hi', 'there', 4) + + +def test_cannot_assign_default(): + with pytest.raises(AttributeError): + settings.default = settings(max_examples=3) + assert settings().max_examples != 3 + + +def test_does_not_warn_if_quiet(): + with pytest.warns(None) as rec: + note_deprecation('This is bad', settings(verbosity=Verbosity.quiet)) + assert len(rec) == 0 + + +@settings(max_examples=7) +@given(st.builds(lambda: settings.default)) +def test_settings_in_strategies_are_from_test_scope(s): + assert s.max_examples == 7 + + +@checks_deprecated_behaviour +def test_settings_alone(): + @settings() + def test_nothing(): + pass + test_nothing() + + +@checks_deprecated_behaviour +def test_settings_applied_twice_1(): + @given(st.integers()) + @settings() + @settings() + def test_nothing(x): + pass + test_nothing() + + +@checks_deprecated_behaviour +def test_settings_applied_twice_2(): + @settings() + @given(st.integers()) + @settings() + def test_nothing(x): + pass + test_nothing() + + +@checks_deprecated_behaviour +def test_settings_applied_twice_3(): + @settings() + @settings() + @given(st.integers()) + def test_nothing(x): + pass + test_nothing() + + +@settings() +@given(st.integers()) +def test_outer_ok(x): + pass + + +@given(st.integers()) +@settings() +def test_inner_ok(x): + pass + + +def test_settings_as_decorator_must_be_on_callable(): + with pytest.raises(InvalidArgument): + settings()(1) + + +ASSERT_DATABASE_PATH = """ +import tempfile +from hypothesis import settings +from hypothesis.configuration import set_hypothesis_home_dir +from hypothesis.database import DirectoryBasedExampleDatabase + +settings.default.database + +if __name__ == '__main__': + new_home = tempfile.mkdtemp() + set_hypothesis_home_dir(new_home) + db = settings.default.database + assert isinstance(db, DirectoryBasedExampleDatabase), db + assert db.path.startswith(new_home), (db.path, new_home) +""" + + +def test_puts_the_database_in_the_home_dir_by_default(tmpdir): + script = tmpdir.join('assertlocation.py') + script.write(ASSERT_DATABASE_PATH) + + subprocess.check_call([ + sys.executable, str(script) + ]) + + +def test_database_is_reference_preserved(): + s = settings(database=not_set) + + assert s.database is s.database + + +@pytest.mark.parametrize('value', [False, True]) +def test_setting_use_coverage_is_deprecated(value): + with validate_deprecation(): + settings(use_coverage=value) + + +@settings(verbosity=Verbosity.verbose) +@example(x=99) +@given(st.integers()) +def test_settings_apply_for_explicit_examples(x): + # Regression test for #1521 + assert settings.default.verbosity == Verbosity.verbose diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_setup_teardown.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_setup_teardown.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_setup_teardown.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_setup_teardown.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,133 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import pytest + +from hypothesis import given, assume +from hypothesis.strategies import text, integers + + +class HasSetup(object): + + def setup_example(self): + self.setups = getattr(self, u'setups', 0) + self.setups += 1 + + +class HasTeardown(object): + + def teardown_example(self, ex): + self.teardowns = getattr(self, u'teardowns', 0) + self.teardowns += 1 + + +class SomeGivens(object): + + @given(integers()) + def give_me_an_int(self, x): + pass + + @given(text()) + def give_me_a_string(myself, x): + pass + + @given(integers()) + def give_me_a_positive_int(self, x): + assert x >= 0 + + @given(integers().map(lambda x: x.nope)) + def fail_in_reify(self, x): + pass + + @given(integers()) + def assume_some_stuff(self, x): + assume(x > 0) + + @given(integers().filter(lambda x: x > 0)) + def assume_in_reify(self, x): + pass + + +class HasSetupAndTeardown(HasSetup, HasTeardown, SomeGivens): + pass + + +def test_calls_setup_and_teardown_on_self_as_first_argument(): + x = HasSetupAndTeardown() + x.give_me_an_int() + x.give_me_a_string() + assert x.setups > 0 + assert x.teardowns == x.setups + + +def test_calls_setup_and_teardown_on_self_unbound(): + x = HasSetupAndTeardown() + HasSetupAndTeardown.give_me_an_int(x) + assert x.setups > 0 + assert x.teardowns == x.setups + + +def test_calls_setup_and_teardown_on_failure(): + x = HasSetupAndTeardown() + with pytest.raises(AssertionError): + x.give_me_a_positive_int() + assert x.setups > 0 + assert x.teardowns == x.setups + + +def test_still_tears_down_on_error_in_generation(): + x = HasSetupAndTeardown() + with pytest.raises(AttributeError): + x.fail_in_reify() + assert x.setups > 0 + assert x.teardowns == x.setups + + +def test_still_tears_down_on_failed_assume(): + x = HasSetupAndTeardown() + x.assume_some_stuff() + assert x.setups > 0 + assert x.teardowns == x.setups + + +def test_still_tears_down_on_failed_assume_in_reify(): + x = HasSetupAndTeardown() + x.assume_in_reify() + assert x.setups > 0 + assert x.teardowns == x.setups + + +def test_sets_up_without_teardown(): + class Foo(HasSetup, SomeGivens): + pass + + x = Foo() + x.give_me_an_int() + assert x.setups > 0 + assert not hasattr(x, u'teardowns') + + +def test_tears_down_without_setup(): + class Foo(HasTeardown, SomeGivens): + pass + + x = Foo() + x.give_me_an_int() + assert x.teardowns > 0 + assert not hasattr(x, u'setups') diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_shrink_budgeting.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_shrink_budgeting.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_shrink_budgeting.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_shrink_budgeting.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,51 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import sys +import math +from random import Random + +import pytest + +from hypothesis.internal.compat import ceil +from hypothesis.internal.conjecture.shrinking import Length, Integer, \ + Lexical, Ordering + + +def measure_baseline(cls, value, **kwargs): + shrinker = cls( + value, lambda x: x == value, random=Random(0), **kwargs + ) + shrinker.run() + return shrinker.calls + + +@pytest.mark.parametrize('cls', [Lexical, Length, Ordering]) +@pytest.mark.parametrize('example', [ + [255] * 8, +]) +def test_meets_budgetary_requirements(cls, example): + # Somewhat arbitrary but not unreasonable budget. + n = len(example) + budget = n * ceil(math.log(n, 2)) + 5 + assert measure_baseline(cls, example) <= budget + + +def test_integer_shrinking_is_parsimonious(): + assert measure_baseline(Integer, int(sys.float_info.max)) <= 10 diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_simple_characters.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_simple_characters.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_simple_characters.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_simple_characters.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,145 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import unicodedata + +import pytest + +from hypothesis.errors import InvalidArgument +from tests.common.debug import minimal, find_any, assert_no_examples +from tests.common.utils import checks_deprecated_behaviour +from hypothesis.strategies import characters +from hypothesis.internal.compat import text_type + + +@checks_deprecated_behaviour +def test_nonexistent_category_argument(): + characters(blacklist_categories=['foo']).example() + + +def test_bad_codepoint_arguments(): + with pytest.raises(InvalidArgument): + characters(min_codepoint=42, max_codepoint=24).example() + + +def test_exclude_all_available_range(): + with pytest.raises(InvalidArgument): + characters(min_codepoint=ord('0'), max_codepoint=ord('0'), + blacklist_characters='0').example() + + +def test_when_nothing_could_be_produced(): + with pytest.raises(InvalidArgument): + characters(whitelist_categories=['Cc'], + min_codepoint=ord('0'), max_codepoint=ord('9')).example() + + +def test_characters_of_specific_groups(): + st = characters(whitelist_categories=('Lu', 'Nd')) + + find_any(st, lambda c: unicodedata.category(c) == 'Lu') + find_any(st, lambda c: unicodedata.category(c) == 'Nd') + + assert_no_examples( + st, lambda c: unicodedata.category(c) not in ('Lu', 'Nd')) + + +def test_characters_of_major_categories(): + st = characters(whitelist_categories=('L', 'N')) + find_any(st, lambda c: unicodedata.category(c).startswith('L')) + find_any(st, lambda c: unicodedata.category(c).startswith('N')) + assert_no_examples( + st, lambda c: unicodedata.category(c)[0] not in ('L', 'N')) + + +def test_exclude_characters_of_specific_groups(): + st = characters(blacklist_categories=('Lu', 'Nd')) + + find_any(st, lambda c: unicodedata.category(c) != 'Lu') + find_any(st, lambda c: unicodedata.category(c) != 'Nd') + + assert_no_examples(st, lambda c: unicodedata.category(c) in ('Lu', 'Nd')) + + +def test_exclude_characters_of_major_categories(): + st = characters(blacklist_categories=('L', 'N')) + find_any(st, lambda c: not unicodedata.category(c).startswith('L')) + find_any(st, lambda c: not unicodedata.category(c).startswith('N')) + assert_no_examples(st, lambda c: unicodedata.category(c)[0] in ('L', 'N')) + + +def test_find_one(): + char = minimal(characters(min_codepoint=48, + max_codepoint=48), lambda _: True) + assert char == u'0' + + +def test_find_something_rare(): + st = characters(whitelist_categories=['Zs'], min_codepoint=12288) + + find_any(st, lambda c: unicodedata.category(c) == 'Zs') + + assert_no_examples(st, lambda c: unicodedata.category(c) != 'Zs') + + +def test_whitelisted_characters_alone(): + with pytest.raises(InvalidArgument): + characters(whitelist_characters=u'te02тест49st').example() + + +def test_whitelisted_characters_overlap_blacklisted_characters(): + good_chars = u'te02тест49st' + bad_chars = u'ts94тсет' + with pytest.raises(InvalidArgument) as exc: + characters(min_codepoint=ord('0'), max_codepoint=ord('9'), + whitelist_characters=good_chars, + blacklist_characters=bad_chars).example() + assert repr(good_chars) in text_type(exc) + assert repr(bad_chars) in text_type(exc) + + +def test_whitelisted_characters_override(): + good_characters = u'teтестst' + st = characters(min_codepoint=ord('0'), max_codepoint=ord('9'), + whitelist_characters=good_characters) + + find_any(st, lambda c: c in good_characters) + find_any(st, lambda c: c in '0123456789') + + assert_no_examples(st, lambda c: c not in good_characters + '0123456789') + + +def test_blacklisted_characters(): + bad_chars = u'te02тест49st' + st = characters(min_codepoint=ord('0'), max_codepoint=ord('9'), + blacklist_characters=bad_chars) + + assert '1' == minimal(st, lambda c: True) + + assert_no_examples(st, lambda c: c in bad_chars) + + +def test_whitelist_characters_disjoint_blacklist_characters(): + good_chars = u'123abc' + bad_chars = u'456def' + st = characters(min_codepoint=ord('0'), max_codepoint=ord('9'), + blacklist_characters=bad_chars, + whitelist_characters=good_chars) + + assert_no_examples(st, lambda c: c in bad_chars) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_simple_collections.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_simple_collections.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_simple_collections.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_simple_collections.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,166 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from random import Random + +import pytest + +from hypothesis import given, settings +from tests.common.debug import minimal, find_any +from hypothesis.strategies import none, sets, text, lists, tuples, \ + booleans, integers, frozensets, dictionaries, fixed_dictionaries +from hypothesis.internal.compat import OrderedDict + + +@pytest.mark.parametrize((u'col', u'strat'), [ + ((), tuples()), + ([], lists(none(), max_size=0)), + (set(), sets(none(), max_size=0)), + (frozenset(), frozensets(none(), max_size=0)), + ({}, fixed_dictionaries({})), +]) +def test_find_empty_collection_gives_empty(col, strat): + assert minimal(strat, lambda x: True) == col + + +@pytest.mark.parametrize((u'coltype', u'strat'), [ + (list, lists), + (set, sets), + (frozenset, frozensets), +]) +def test_find_non_empty_collection_gives_single_zero(coltype, strat): + assert minimal( + strat(integers()), bool + ) == coltype((0,)) + + +@pytest.mark.parametrize((u'coltype', u'strat'), [ + (list, lists), + (set, sets), + (frozenset, frozensets), +]) +def test_minimizes_to_empty(coltype, strat): + assert minimal( + strat(integers()), lambda x: True + ) == coltype() + + +def test_minimizes_list_of_lists(): + xs = minimal(lists(lists(booleans())), lambda x: any(x) and not all(x)) + xs.sort() + assert xs == [[], [False]] + + +@given(sets(integers(0, 100), min_size=2, max_size=10)) +@settings(max_examples=100) +def test_sets_are_size_bounded(xs): + assert 2 <= len(xs) <= 10 + + +def test_ordered_dictionaries_preserve_keys(): + r = Random() + keys = list(range(100)) + r.shuffle(keys) + x = fixed_dictionaries( + OrderedDict([(k, booleans()) for k in keys])).example() + assert list(x.keys()) == keys + + +@pytest.mark.parametrize(u'n', range(10)) +def test_lists_of_fixed_length(n): + assert minimal( + lists(integers(), min_size=n, max_size=n), lambda x: True) == [0] * n + + +@pytest.mark.parametrize(u'n', range(10)) +def test_sets_of_fixed_length(n): + x = minimal( + sets(integers(), min_size=n, max_size=n), lambda x: True) + assert len(x) == n + + if not n: + assert x == set() + else: + assert x == set(range(min(x), min(x) + n)) + + +@pytest.mark.parametrize(u'n', range(10)) +def test_dictionaries_of_fixed_length(n): + x = set(minimal( + dictionaries(integers(), booleans(), min_size=n, max_size=n), + lambda x: True).keys()) + + if not n: + assert x == set() + else: + assert x == set(range(min(x), min(x) + n)) + + +@pytest.mark.parametrize(u'n', range(10)) +def test_lists_of_lower_bounded_length(n): + x = minimal( + lists(integers(), min_size=n), lambda x: sum(x) >= 2 * n + ) + assert n <= len(x) <= 2 * n + assert all(t >= 0 for t in x) + assert len(x) == n or all(t > 0 for t in x) + assert sum(x) == 2 * n + + +def test_can_find_unique_lists_of_non_set_order(): + # This test checks that our strategy for unique lists doesn't accidentally + # depend on the iteration order of sets. + # + # Unfortunately, that means that *this* test has to rely on set iteration + # order. That makes it tricky to debug on CPython, because set iteration + # order changes every time the process is launched. + # + # To get around this, define the PYTHONHASHSEED environment variable to + # a consistent value. This could be 0, or it could be the PYTHONHASHSEED + # value listed in a failure log from CI. + + ls = minimal( + lists(text(), unique=True), + lambda x: list(set(reversed(x))) != x + ) + assert len(set(ls)) == len(ls) + assert len(ls) == 2 + + +def test_can_draw_empty_list_from_unsatisfiable_strategy(): + assert find_any(lists(integers().filter(lambda s: False))) == [] + + +def test_can_draw_empty_set_from_unsatisfiable_strategy(): + assert find_any(sets(integers().filter(lambda s: False))) == set() + + +small_set = sets(none()) + + +@given(lists(small_set, min_size=10)) +def test_small_sized_sets(x): + pass + + +def test_minimize_dicts_with_incompatible_keys(): + assert minimal( + fixed_dictionaries({1: booleans(), u'hi': lists(booleans())}), + lambda x: True + ) == {1: False, u'hi': []} diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_simple_strings.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_simple_strings.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_simple_strings.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_simple_strings.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,143 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from random import Random + +import pytest + +from hypothesis import given +from tests.common.debug import minimal +from tests.common.utils import checks_deprecated_behaviour +from hypothesis.strategies import text, binary, tuples, characters + + +def test_can_minimize_up_to_zero(): + s = minimal(text(), lambda x: any(lambda t: t <= u'0' for t in x)) + assert s == u'0' + + +def test_minimizes_towards_ascii_zero(): + s = minimal(text(), lambda x: any(t < u'0' for t in x)) + assert s == chr(ord(u'0') - 1) + + +def test_can_handle_large_codepoints(): + s = minimal(text(), lambda x: x >= u'☃') + assert s == u'☃' + + +def test_can_find_mixed_ascii_and_non_ascii_strings(): + s = minimal( + text(), lambda x: ( + any(t >= u'☃' for t in x) and + any(ord(t) <= 127 for t in x))) + assert len(s) == 2 + assert sorted(s) == [u'0', u'☃'] + + +def test_will_find_ascii_examples_given_the_chance(): + s = minimal( + tuples(text(max_size=1), text(max_size=1)), + lambda x: x[0] and (x[0] < x[1])) + assert ord(s[1]) == ord(s[0]) + 1 + assert u'0' in s + + +def test_finds_single_element_strings(): + assert minimal(text(), bool, random=Random(4)) == u'0' + + +def test_binary_respects_changes_in_size(): + @given(binary()) + def test_foo(x): + assert len(x) <= 5 + with pytest.raises(AssertionError): + test_foo() + + @given(binary(max_size=5)) + def test_foo(x): + assert len(x) <= 5 + test_foo() + + +def test_does_not_simplify_into_surrogates(): + f = minimal(text(), lambda x: x >= u'\udfff') + assert f == u'\ue000' + + size = 5 + + f = minimal( + text(min_size=size), lambda x: sum(t >= u'\udfff' for t in x) >= size) + assert f == u'\ue000' * size + + +@given(text(alphabet=[u'a', u'b'])) +def test_respects_alphabet_if_list(xs): + assert set(xs).issubset(set(u'ab')) + + +@given(text(alphabet=u'cdef')) +def test_respects_alphabet_if_string(xs): + assert set(xs).issubset(set(u'cdef')) + + +@given(text()) +def test_can_encode_as_utf8(s): + s.encode('utf-8') + + +@given(text(characters(blacklist_characters=u'\n'))) +def test_can_blacklist_newlines(s): + assert u'\n' not in s + + +@given(text(characters(blacklist_categories=('Cc', 'Cs')))) +def test_can_exclude_newlines_by_category(s): + assert u'\n' not in s + + +@given(text(characters(max_codepoint=127))) +def test_can_restrict_to_ascii_only(s): + s.encode('ascii') + + +def test_fixed_size_bytes_just_draw_bytes(): + from hypothesis.internal.conjecture.data import ConjectureData + x = ConjectureData.for_buffer(b'foo') + assert x.draw(binary(min_size=3, max_size=3)) == b'foo' + + +@given(text(max_size=10**6)) +def test_can_set_max_size_large(s): + pass + + +@checks_deprecated_behaviour +def test_alphabet_is_not_a_sequence(): + text(alphabet=set('abc')).example() + + +@checks_deprecated_behaviour +def test_alphabet_breaking_size_limit(): + text(['a', 'c', 'ed', 'b', 'abc']).example() + + +@checks_deprecated_behaviour +def test_alphabet_non_string(): + text([1, 2, 3]).example() diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_slippage.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_slippage.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_slippage.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_slippage.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,220 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import pytest + +import hypothesis.strategies as st +from hypothesis import given, settings +from hypothesis.errors import Flaky, MultipleFailures +from tests.common.utils import capture_out, non_covering_examples +from hypothesis.database import InMemoryExampleDatabase + + +def test_raises_multiple_failures_with_varying_type(): + target = [None] + + @settings(database=None) + @given(st.integers()) + def test(i): + if abs(i) < 1000: + return + if target[0] is None: + target[0] = i + exc_class = TypeError if target[0] == i else ValueError + raise exc_class() + + with capture_out() as o: + with pytest.raises(MultipleFailures): + test() + + assert 'TypeError' in o.getvalue() + assert 'ValueError' in o.getvalue() + + +def test_raises_multiple_failures_when_position_varies(): + target = [None] + + @given(st.integers()) + def test(i): + if abs(i) < 1000: + return + if target[0] is None: + target[0] = i + if target[0] == i: + raise ValueError('loc 1') + else: + raise ValueError('loc 2') + + with capture_out() as o: + with pytest.raises(MultipleFailures): + test() + assert 'loc 1' in o.getvalue() + assert 'loc 2' in o.getvalue() + + +def test_replays_both_failing_values(): + target = [None] + + @settings(database=InMemoryExampleDatabase()) + @given(st.integers()) + def test(i): + if abs(i) < 1000: + return + if target[0] is None: + target[0] = i + exc_class = TypeError if target[0] == i else ValueError + raise exc_class() + + with pytest.raises(MultipleFailures): + test() + + with pytest.raises(MultipleFailures): + test() + + +@pytest.mark.parametrize('fix', [TypeError, ValueError]) +def test_replays_slipped_examples_once_initial_bug_is_fixed(fix): + target = [] + bug_fixed = False + + @settings(database=InMemoryExampleDatabase()) + @given(st.integers()) + def test(i): + if abs(i) < 1000: + return + if not target: + target.append(i) + if i == target[0]: + if bug_fixed and fix == TypeError: + return + raise TypeError() + if len(target) == 1: + target.append(i) + if bug_fixed and fix == ValueError: + return + if i == target[1]: + raise ValueError() + + with pytest.raises(MultipleFailures): + test() + + bug_fixed = True + + with pytest.raises(ValueError if fix == TypeError else TypeError): + test() + + +def test_garbage_collects_the_secondary_key(): + target = [] + bug_fixed = False + + db = InMemoryExampleDatabase() + + @settings(database=db) + @given(st.integers()) + def test(i): + if bug_fixed: + return + if abs(i) < 1000: + return + if not target: + target.append(i) + if i == target[0]: + raise TypeError() + if len(target) == 1: + target.append(i) + if i == target[1]: + raise ValueError() + + with pytest.raises(MultipleFailures): + test() + + bug_fixed = True + + def count(): + return len(non_covering_examples(db)) + + prev = count() + while prev > 0: + test() + current = count() + assert current < prev + prev = current + + +def test_shrinks_both_failures(): + first_has_failed = [False] + duds = set() + second_target = [None] + + @settings(database=None) + @given(st.integers(min_value=0)) + def test(i): + if i >= 10000: + first_has_failed[0] = True + assert False + assert i < 10000 + if first_has_failed[0]: + if second_target[0] is None: + for j in range(10000): + if j not in duds: + second_target[0] = j + break + assert i < second_target[0] + else: + duds.add(i) + + with capture_out() as o: + with pytest.raises(MultipleFailures): + test() + + assert 'test(i=10000)' in o.getvalue() + assert 'test(i=%d)' % (second_target[0],) in o.getvalue() + + +def test_handles_flaky_tests_where_only_one_is_flaky(): + flaky_fixed = False + + target = [] + flaky_failed_once = [False] + + @settings(database=InMemoryExampleDatabase()) + @given(st.integers()) + def test(i): + if abs(i) < 1000: + return + if not target: + target.append(i) + if i == target[0]: + raise TypeError() + if flaky_failed_once[0] and not flaky_fixed: + return + if len(target) == 1: + target.append(i) + if i == target[1]: + flaky_failed_once[0] = True + raise ValueError() + + with pytest.raises(Flaky): + test() + + flaky_fixed = True + + with pytest.raises(MultipleFailures): + test() diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_stateful.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_stateful.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_stateful.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_stateful.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,1026 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import inspect +from collections import namedtuple, defaultdict + +import pytest +from _pytest.outcomes import Failed, Skipped + +from hypothesis import assume +from hypothesis import settings as Settings +from hypothesis.errors import Flaky, InvalidArgument, InvalidDefinition +from hypothesis.control import current_build_context +from tests.common.utils import raises, capture_out, \ + checks_deprecated_behaviour +from hypothesis.database import ExampleDatabase +from hypothesis.stateful import Bundle, GenericStateMachine, \ + RuleBasedStateMachine, rule, invariant, initialize, precondition, \ + run_state_machine_as_test +from hypothesis.strategies import just, none, lists, binary, tuples, \ + choices, booleans, integers, sampled_from +from hypothesis.internal.compat import print_unicode + + +class SetStateMachine(GenericStateMachine): + + def __init__(self): + self.elements = [] + + def steps(self): + strat = tuples(just(False), integers(0, 5)) + if self.elements: + strat |= tuples(just(True), sampled_from(self.elements)) + return strat + + def execute_step(self, step): + delete, value = step + if delete: + self.elements.remove(value) + assert value not in self.elements + else: + self.elements.append(value) + + +class OrderedStateMachine(GenericStateMachine): + + def __init__(self): + self.counter = 0 + + def steps(self): + return ( + integers(self.counter - 1, self.counter + 50) + ) + + def execute_step(self, step): + assert step >= self.counter + self.counter = step + + +class GoodSet(GenericStateMachine): + + def __init__(self): + self.stuff = set() + + def steps(self): + return tuples(booleans(), integers()) + + def execute_step(self, step): + delete, value = step + if delete: + self.stuff.discard(value) + else: + self.stuff.add(value) + assert delete == (value not in self.stuff) + + +Leaf = namedtuple(u'Leaf', (u'label',)) +Split = namedtuple(u'Split', (u'left', u'right')) + + +class BalancedTrees(RuleBasedStateMachine): + trees = Bundle(u'BinaryTree') + + @rule(target=trees, x=booleans()) + def leaf(self, x): + return Leaf(x) + + @rule(target=trees, left=trees, right=trees) + def split(self, left, right): + return Split(left, right) + + @rule(tree=trees) + def test_is_balanced(self, tree): + if isinstance(tree, Leaf): + return + else: + assert abs(self.size(tree.left) - self.size(tree.right)) <= 1 + self.test_is_balanced(tree.left) + self.test_is_balanced(tree.right) + + def size(self, tree): + if isinstance(tree, Leaf): + return 1 + else: + return 1 + self.size(tree.left) + self.size(tree.right) + + +class DepthCharge(object): + + def __init__(self, value): + if value is None: + self.depth = 0 + else: + self.depth = value.depth + 1 + + +class DepthMachine(RuleBasedStateMachine): + charges = Bundle(u'charges') + + @rule(targets=(charges,), child=charges) + def charge(self, child): + return DepthCharge(child) + + @rule(targets=(charges,)) + def none_charge(self): + return DepthCharge(None) + + @rule(check=charges) + def is_not_too_deep(self, check): + assert check.depth < 3 + + +class MultipleRulesSameFuncMachine(RuleBasedStateMachine): + + def myfunc(self, data): + print_unicode(data) + + rule1 = rule(data=just(u"rule1data"))(myfunc) + rule2 = rule(data=just(u"rule2data"))(myfunc) + + +class PreconditionMachine(RuleBasedStateMachine): + num = 0 + + @rule() + def add_one(self): + self.num += 1 + + @rule() + def set_to_zero(self): + self.num = 0 + + @rule(num=integers()) + @precondition(lambda self: self.num != 0) + def div_by_precondition_after(self, num): + self.num = num / self.num + + @precondition(lambda self: self.num != 0) + @rule(num=integers()) + def div_by_precondition_before(self, num): + self.num = num / self.num + + +class RoseTreeStateMachine(RuleBasedStateMachine): + nodes = Bundle('nodes') + + @rule(target=nodes, source=lists(nodes)) + def bunch(self, source): + return source + + @rule(source=nodes) + def shallow(self, source): + def d(ls): + if not ls: + return 0 + else: + return 1 + max(map(d, ls)) + assert d(source) <= 5 + + +class NotTheLastMachine(RuleBasedStateMachine): + stuff = Bundle('stuff') + + def __init__(self): + super(NotTheLastMachine, self).__init__() + self.last = None + self.bye_called = False + + @rule(target=stuff) + def hi(self): + result = object() + self.last = result + return result + + @precondition(lambda self: not self.bye_called) + @rule(v=stuff) + def bye(self, v): + assert v == self.last + self.bye_called = True + + +class PopulateMultipleTargets(RuleBasedStateMachine): + b1 = Bundle('b1') + b2 = Bundle('b2') + + @rule(targets=(b1, b2)) + def populate(self): + return 1 + + @rule(x=b1, y=b2) + def fail(self, x, y): + assert False + + +bad_machines = ( + OrderedStateMachine, SetStateMachine, BalancedTrees, + DepthMachine, RoseTreeStateMachine, NotTheLastMachine, + PopulateMultipleTargets, +) + +for m in bad_machines: + m.TestCase.settings = Settings(m.TestCase.settings, max_examples=1000) + + +cheap_bad_machines = list(bad_machines) +cheap_bad_machines.remove(BalancedTrees) + + +with_cheap_bad_machines = pytest.mark.parametrize( + u'machine', + cheap_bad_machines, ids=[t.__name__ for t in cheap_bad_machines] +) + + +@pytest.mark.parametrize( + u'machine', + bad_machines, ids=[t.__name__ for t in bad_machines] +) +def test_bad_machines_fail(machine): + test_class = machine.TestCase + try: + with capture_out() as o: + with raises(AssertionError): + test_class().runTest() + except Exception: + print_unicode(o.getvalue()) + raise + v = o.getvalue() + print_unicode(v) + steps = [l for l in v.splitlines() if 'Step ' in l or 'state.' in l] + assert 1 <= len(steps) <= 50 + + +def test_multiple_rules_same_func(): + test_class = MultipleRulesSameFuncMachine.TestCase + with capture_out() as o: + test_class().runTest() + output = o.getvalue() + assert 'rule1data' in output + assert 'rule2data' in output + + +class GivenLikeStateMachine(GenericStateMachine): + + def steps(self): + return lists(booleans()) + + def execute_step(self, step): + assume(any(step)) + + +def test_can_get_test_case_off_machine_instance(): + assert GoodSet().TestCase is GoodSet().TestCase + assert GoodSet().TestCase is not None + + +class FlakyDrawLessMachine(GenericStateMachine): + + def steps(self): + cb = current_build_context() + if cb.is_final: + return binary(min_size=1, max_size=1) + else: + return binary(min_size=1024, max_size=1024) + + def execute_step(self, step): + cb = current_build_context() + if not cb.is_final: + assert 0 not in bytearray(step) + + +def test_flaky_draw_less_raises_flaky(): + with raises(Flaky): + FlakyDrawLessMachine.TestCase().runTest() + + +class FlakyStateMachine(GenericStateMachine): + + def steps(self): + return just(()) + + def execute_step(self, step): + assert not any( + t[3] == u'find_breaking_runner' + for t in inspect.getouterframes(inspect.currentframe()) + ) + + +def test_flaky_raises_flaky(): + with raises(Flaky): + FlakyStateMachine.TestCase().runTest() + + +class FlakyRatchettingMachine(GenericStateMachine): + ratchet = 0 + + def steps(self): + FlakyRatchettingMachine.ratchet += 1 + n = FlakyRatchettingMachine.ratchet + return lists(integers(), min_size=n, max_size=n) + + def execute_step(self, step): + assert False + + +def test_ratchetting_raises_flaky(): + with raises(Flaky): + FlakyRatchettingMachine.TestCase().runTest() + + +def test_empty_machine_is_invalid(): + class EmptyMachine(RuleBasedStateMachine): + pass + + with raises(InvalidDefinition): + EmptyMachine.TestCase().runTest() + + +def test_machine_with_no_terminals_is_invalid(): + class NonTerminalMachine(RuleBasedStateMachine): + + @rule(value=Bundle(u'hi')) + def bye(self, hi): + pass + + with raises(InvalidDefinition): + NonTerminalMachine.TestCase().runTest() + + +class DynamicMachine(RuleBasedStateMachine): + + @rule(value=Bundle(u'hi')) + def test_stuff(x): + pass + + +DynamicMachine.define_rule( + targets=(), function=lambda self: 1, arguments={} +) + + +class IntAdder(RuleBasedStateMachine): + pass + + +IntAdder.define_rule( + targets=(u'ints',), function=lambda self, x: x, arguments={ + u'x': integers() + } +) + +IntAdder.define_rule( + targets=(u'ints',), function=lambda self, x, y: x, arguments={ + u'x': integers(), u'y': Bundle(u'ints'), + } +) + + +@checks_deprecated_behaviour +def test_can_choose_in_a_machine(): + class ChoosingMachine(GenericStateMachine): + + def steps(self): + return choices() + + def execute_step(self, choices): + choices([1, 2, 3]) + + run_state_machine_as_test(ChoosingMachine) + + +TestGoodSets = GoodSet.TestCase +TestGivenLike = GivenLikeStateMachine.TestCase +TestDynamicMachine = DynamicMachine.TestCase +TestIntAdder = IntAdder.TestCase +TestPrecondition = PreconditionMachine.TestCase + + +for test_case in (TestGoodSets, TestGivenLike, TestDynamicMachine, + TestIntAdder, TestPrecondition): + test_case.settings = Settings(max_examples=10) + + +def test_picks_up_settings_at_first_use_of_testcase(): + assert TestDynamicMachine.settings.max_examples == 10 + + +def test_new_rules_are_picked_up_before_and_after_rules_call(): + class Foo(RuleBasedStateMachine): + pass + Foo.define_rule( + targets=(), function=lambda self: 1, arguments={} + ) + assert len(Foo.rules()) == 1 + Foo.define_rule( + targets=(), function=lambda self: 2, arguments={} + ) + assert len(Foo.rules()) == 2 + + +@checks_deprecated_behaviour +def test_settings_are_independent(): + s = Settings() + orig = s.max_examples + with s: + class Foo(RuleBasedStateMachine): + pass + Foo.define_rule( + targets=(), function=lambda self: 1, arguments={} + ) + Foo.TestCase.settings = Settings( + Foo.TestCase.settings, max_examples=1000000) + assert s.max_examples == orig + + +def test_minimizes_errors_in_teardown(): + class Foo(GenericStateMachine): + + def __init__(self): + self.counter = 0 + + def steps(self): + return tuples() + + def execute_step(self, value): + self.counter += 1 + + def teardown(self): + assert not self.counter + + runner = Foo.find_breaking_runner() + + f = Foo() + with raises(AssertionError): + runner.run(f, print_steps=True) + assert f.counter == 1 + + +class RequiresInit(GenericStateMachine): + + def __init__(self, threshold): + super(RequiresInit, self).__init__() + self.threshold = threshold + + def steps(self): + return integers() + + def execute_step(self, value): + if value > self.threshold: + raise ValueError(u'%d is too high' % (value,)) + + +def test_can_use_factory_for_tests(): + with raises(ValueError): + run_state_machine_as_test(lambda: RequiresInit(42)) + + +class FailsEventually(GenericStateMachine): + + def __init__(self): + super(FailsEventually, self).__init__() + self.counter = 0 + + def steps(self): + return none() + + def execute_step(self, _): + self.counter += 1 + assert self.counter < 10 + + +FailsEventually.TestCase.settings = Settings( + FailsEventually.TestCase.settings, stateful_step_count=5) + +TestDoesNotFail = FailsEventually.TestCase + + +def test_can_explicitly_pass_settings(): + try: + FailsEventually.TestCase.settings = Settings( + FailsEventually.TestCase.settings, stateful_step_count=15) + run_state_machine_as_test( + FailsEventually, settings=Settings( + stateful_step_count=2, + )) + finally: + FailsEventually.TestCase.settings = Settings( + FailsEventually.TestCase.settings, stateful_step_count=5) + + +def test_saves_failing_example_in_database(): + db = ExampleDatabase(':memory:') + with raises(AssertionError): + run_state_machine_as_test( + SetStateMachine, Settings(database=db)) + assert any(list(db.data.values())) + + +def test_can_run_with_no_db(): + with raises(AssertionError): + run_state_machine_as_test( + SetStateMachine, Settings(database=None)) + + +def test_stateful_double_rule_is_forbidden(recwarn): + with pytest.raises(InvalidDefinition): + class DoubleRuleMachine(RuleBasedStateMachine): + + @rule(num=just(1)) + @rule(num=just(2)) + def whatevs(self, num): + pass + + +def test_can_explicitly_call_functions_when_precondition_not_satisfied(): + class BadPrecondition(RuleBasedStateMachine): + + def __init__(self): + super(BadPrecondition, self).__init__() + + @precondition(lambda self: False) + @rule() + def test_blah(self): + raise ValueError() + + @rule() + def test_foo(self): + self.test_blah() + + with pytest.raises(ValueError): + run_state_machine_as_test(BadPrecondition) + + +def test_invariant(): + """If an invariant raise an exception, the exception is propagated.""" + class Invariant(RuleBasedStateMachine): + + def __init__(self): + super(Invariant, self).__init__() + + @invariant() + def test_blah(self): + raise ValueError() + + @rule() + def do_stuff(self): + pass + + with pytest.raises(ValueError): + run_state_machine_as_test(Invariant) + + +def test_no_double_invariant(): + """The invariant decorator can't be applied multiple times to a single + function.""" + with raises(InvalidDefinition): + class Invariant(RuleBasedStateMachine): + + def __init__(self): + super(Invariant, self).__init__() + + @invariant() + @invariant() + def test_blah(self): + pass + + @rule() + def do_stuff(self): + pass + + +def test_invariant_precondition(): + """If an invariant precodition isn't met, the invariant isn't run. + + The precondition decorator can be applied in any order. + """ + class Invariant(RuleBasedStateMachine): + + def __init__(self): + super(Invariant, self).__init__() + + @invariant() + @precondition(lambda _: False) + def an_invariant(self): + raise ValueError() + + @precondition(lambda _: False) + @invariant() + def another_invariant(self): + raise ValueError() + + @rule() + def do_stuff(self): + pass + + run_state_machine_as_test(Invariant) + + +def test_multiple_invariants(): + """If multiple invariants are present, they all get run.""" + class Invariant(RuleBasedStateMachine): + + def __init__(self): + super(Invariant, self).__init__() + self.first_invariant_ran = False + + @invariant() + def invariant_1(self): + self.first_invariant_ran = True + + @precondition(lambda self: self.first_invariant_ran) + @invariant() + def invariant_2(self): + raise ValueError() + + @rule() + def do_stuff(self): + pass + + with pytest.raises(ValueError): + run_state_machine_as_test(Invariant) + + +def test_explicit_invariant_call_with_precondition(): + """Invariants can be called explicitly even if their precondition is not + satisfied.""" + class BadPrecondition(RuleBasedStateMachine): + + def __init__(self): + super(BadPrecondition, self).__init__() + + @precondition(lambda self: False) + @invariant() + def test_blah(self): + raise ValueError() + + @rule() + def test_foo(self): + self.test_blah() + + with pytest.raises(ValueError): + run_state_machine_as_test(BadPrecondition) + + +def test_invariant_checks_initial_state(): + """Invariants are checked before any rules run.""" + class BadPrecondition(RuleBasedStateMachine): + + def __init__(self): + super(BadPrecondition, self).__init__() + self.num = 0 + + @invariant() + def test_blah(self): + if self.num == 0: + raise ValueError() + + @rule() + def test_foo(self): + self.num += 1 + + with pytest.raises(ValueError): + run_state_machine_as_test(BadPrecondition) + + +def test_always_runs_at_least_one_step(): + class CountSteps(RuleBasedStateMachine): + def __init__(self): + super(CountSteps, self).__init__() + self.count = 0 + + @rule() + def do_something(self): + self.count += 1 + + def teardown(self): + assert self.count > 0 + + run_state_machine_as_test(CountSteps) + + +def test_removes_needless_steps(): + """Regression test from an example based on + tests/nocover/test_database_agreement.py, but without the expensive bits. + Comparing two database implementations in which deletion is broken, so as + soon as a key/value pair is successfully deleted the test will now fail if + you ever check that key. + + The main interesting feature of this is that it has a lot of + opportunities to generate keys and values before it actually fails, + but will still fail with very high probability. + """ + class IncorrectDeletion(RuleBasedStateMachine): + def __init__(self): + super(IncorrectDeletion, self).__init__() + self.__saved = defaultdict(set) + self.__deleted = defaultdict(set) + + keys = Bundle('keys') + values = Bundle('values') + + @rule(target=keys, k=binary()) + def k(self, k): + return k + + @rule(target=values, v=binary()) + def v(self, v): + return v + + @rule(k=keys, v=values) + def save(self, k, v): + self.__saved[k].add(v) + + @rule(k=keys, v=values) + def delete(self, k, v): + if v in self.__saved[k]: + self.__deleted[k].add(v) + + @rule(k=keys) + def values_agree(self, k): + assert not self.__deleted[k] + + with capture_out() as o: + with pytest.raises(AssertionError): + run_state_machine_as_test(IncorrectDeletion) + + assert o.getvalue().count(' = state.k(') == 1 + assert o.getvalue().count(' = state.v(') == 1 + + +def test_prints_equal_values_with_correct_variable_name(): + class MovesBetweenBundles(RuleBasedStateMachine): + b1 = Bundle('b1') + b2 = Bundle('b2') + + @rule(target=b1) + def create(self): + return [] + + @rule(target=b2, source=b1) + def transfer(self, source): + return source + + @rule(source=b2) + def fail(self, source): + assert False + + with capture_out() as o: + with pytest.raises(AssertionError): + run_state_machine_as_test(MovesBetweenBundles) + + result = o.getvalue() + for m in ['create', 'transfer', 'fail']: + assert result.count(m) == 1 + assert 'v1 = state.create()' in result + assert 'v2 = state.transfer(source=v1)' in result + assert 'state.fail(source=v2)' in result + + +def test_initialize_rule(): + class WithInitializeRules(RuleBasedStateMachine): + initialized = [] + + @initialize() + def initialize_a(self): + self.initialized.append('a') + + @initialize() + def initialize_b(self): + self.initialized.append('b') + + @initialize() + def initialize_c(self): + self.initialized.append('c') + + @rule() + def fail_fast(self): + assert False + + with capture_out() as o: + with pytest.raises(AssertionError): + run_state_machine_as_test(WithInitializeRules) + + assert set(WithInitializeRules.initialized[-3:]) == {'a', 'b', 'c'} + result = o.getvalue().splitlines() + assert result[0] == 'state = WithInitializeRules()' + # Initialize rules call order is shuffled + assert {result[1], result[2], result[3]} == { + 'state.initialize_a()', 'state.initialize_b()', 'state.initialize_c()' + } + assert result[4] == 'state.fail_fast()' + assert result[5] == 'state.teardown()' + + +def test_initialize_rule_populate_bundle(): + class WithInitializeBundleRules(RuleBasedStateMachine): + a = Bundle('a') + + @initialize(target=a, dep=just('dep')) + def initialize_a(self, dep): + return 'a v1 with (%s)' % dep + + @rule(param=a) + def fail_fast(self, param): + assert False + + with capture_out() as o: + with pytest.raises(AssertionError): + run_state_machine_as_test(WithInitializeBundleRules) + + result = o.getvalue() + assert result == """state = WithInitializeBundleRules() +v1 = state.initialize_a(dep='dep') +state.fail_fast(param=v1) +state.teardown() +""" + + +def test_initialize_rule_dont_mix_with_precondition(): + with pytest.raises(InvalidDefinition) as exc: + class BadStateMachine(RuleBasedStateMachine): + + @precondition(lambda self: True) + @initialize() + def initialize(self): + pass + + assert 'An initialization rule cannot have a precondition.' in str( + exc.value) + + # Also test decorator application in reverse order + + with pytest.raises(InvalidDefinition) as exc: + class BadStateMachineReverseOrder(RuleBasedStateMachine): + + @initialize() + @precondition(lambda self: True) + def initialize(self): + pass + + assert 'An initialization rule cannot have a precondition.' in str( + exc.value) + + +def test_initialize_rule_dont_mix_with_regular_rule(): + with pytest.raises(InvalidDefinition) as exc: + class BadStateMachine(RuleBasedStateMachine): + + @rule() + @initialize() + def initialize(self): + pass + + assert 'A function cannot be used for two distinct rules.' in str( + exc.value) + + +def test_initialize_rule_cannot_be_double_applied(): + with pytest.raises(InvalidDefinition) as exc: + class BadStateMachine(RuleBasedStateMachine): + + @initialize() + @initialize() + def initialize(self): + pass + + assert 'A function cannot be used for two distinct rules.' in str( + exc.value) + + +def test_initialize_rule_in_state_machine_with_inheritance(): + class ParentStateMachine(RuleBasedStateMachine): + initialized = [] + + @initialize() + def initialize_a(self): + self.initialized.append('a') + + class ChildStateMachine(ParentStateMachine): + + @initialize() + def initialize_b(self): + self.initialized.append('b') + + @rule() + def fail_fast(self): + assert False + + with capture_out() as o: + with pytest.raises(AssertionError): + run_state_machine_as_test(ChildStateMachine) + + assert set(ChildStateMachine.initialized[-2:]) == {'a', 'b'} + result = o.getvalue().splitlines() + assert result[0] == 'state = ChildStateMachine()' + # Initialize rules call order is shuffled + assert {result[1], result[2]} == { + 'state.initialize_a()', 'state.initialize_b()'} + assert result[3] == 'state.fail_fast()' + assert result[4] == 'state.teardown()' + + +def test_can_manually_call_initialize_rule(): + class StateMachine(RuleBasedStateMachine): + initialize_called_counter = 0 + + @initialize() + def initialize(self): + self.initialize_called_counter += 1 + return self.initialize_called_counter + + @rule() + def fail_eventually(self): + assert self.initialize() == 2 + + with capture_out() as o: + with pytest.raises(AssertionError): + run_state_machine_as_test(StateMachine) + + result = o.getvalue() + assert result == """state = StateMachine() +state.initialize() +state.fail_eventually() +state.fail_eventually() +state.teardown() +""" + + +def test_new_initialize_rules_are_picked_up_before_and_after_rules_call(): + class Foo(RuleBasedStateMachine): + pass + Foo.define_initialize_rule( + targets=(), function=lambda self: 1, arguments={} + ) + assert len(Foo.initialize_rules()) == 1 + Foo.define_initialize_rule( + targets=(), function=lambda self: 2, arguments={} + ) + assert len(Foo.initialize_rules()) == 2 + + +def test_steps_printed_despite_pytest_fail(capsys): + # Test for https://github.com/HypothesisWorks/hypothesis/issues/1372 + class RaisesProblem(RuleBasedStateMachine): + + @rule() + def oops(self): + pytest.fail() + + with pytest.raises(Failed): + run_state_machine_as_test(RaisesProblem) + out, _ = capsys.readouterr() + assert 'state = RaisesProblem()\nstate.oops()\nstate.teardown()\n' == out + + +def test_steps_not_printed_with_pytest_skip(capsys): + class RaisesProblem(RuleBasedStateMachine): + + @rule() + def skip_whole_test(self): + pytest.skip() + + with pytest.raises(Skipped): + run_state_machine_as_test(RaisesProblem) + out, _ = capsys.readouterr() + assert '' == out + + +@checks_deprecated_behaviour +def test_rule_deprecation_targets_and_target(): + k, v = Bundle('k'), Bundle('v') + rule(targets=(k,), target=v) + + +@checks_deprecated_behaviour +def test_rule_deprecation_bundle_by_name(): + Bundle('k') + rule(target='k') + + +def test_rule_non_bundle_target(): + with pytest.raises(InvalidArgument): + rule(target=integers()) + + +def test_rule_non_bundle_target_oneof(): + k, v = Bundle('k'), Bundle('v') + pattern = r'.+ `one_of(a, b)` or `a | b` .+' + with pytest.raises(InvalidArgument, match=pattern): + rule(target=k | v) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_statistical_events.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_statistical_events.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_statistical_events.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_statistical_events.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,215 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import re +import time +import traceback + +import pytest + +from hypothesis import HealthCheck, event, given, assume, example, settings +from hypothesis import strategies as st +from hypothesis.statistics import Statistics, collector +from hypothesis.internal.conjecture.data import Status +from hypothesis.internal.conjecture.engine import ExitReason, \ + ConjectureRunner + + +def call_for_statistics(test_function): + result = [None] + + def callback(statistics): + result[0] = statistics + + with collector.with_value(callback): + try: + test_function() + except Exception: + traceback.print_exc() + assert result[0] is not None + return result[0] + + +def test_notes_hard_to_satisfy(): + @given(st.integers()) + @settings(suppress_health_check=HealthCheck.all()) + def test(i): + assume(i == 0) + + stats = call_for_statistics(test) + assert 'satisfied assumptions' in stats.exit_reason + + +def test_can_callback_with_a_string(): + @given(st.integers()) + def test(i): + event('hi') + + stats = call_for_statistics(test) + + assert any('hi' in s for s in stats.events) + + +counter = 0 +seen = [] + + +class Foo(object): + + def __eq__(self, other): + return True + + def __ne__(self, other): + return False + + def __hash__(self): + return 0 + + def __str__(self): + seen.append(self) + global counter + counter += 1 + return 'COUNTER %d' % (counter,) + + +def test_formats_are_evaluated_only_once(): + global counter + counter = 0 + + @given(st.integers()) + def test(i): + event(Foo()) + + stats = call_for_statistics(test) + + assert any('COUNTER 1' in s for s in stats.events) + assert not any('COUNTER 2' in s for s in stats.events) + + +def test_does_not_report_on_examples(): + @example('hi') + @given(st.integers()) + def test(i): + if isinstance(i, str): + event('boo') + + stats = call_for_statistics(test) + assert not any('boo' in e for e in stats.events) + + +def test_exact_timing(): + @settings(suppress_health_check=[HealthCheck.too_slow], deadline=None) + @given(st.integers()) + def test(i): + time.sleep(0.5) + + stats = call_for_statistics(test) + assert re.match(r'~ 5\d\dms', stats.runtimes) + + +def test_apparently_instantaneous_tests(): + time.freeze() + + @given(st.integers()) + def test(i): + pass + + stats = call_for_statistics(test) + assert stats.runtimes == '< 1ms' + + +def test_flaky_exit(): + first = [True] + + @given(st.integers()) + def test(i): + if i > 1001: + if first[0]: + first[0] = False + print('Hi') + assert False + + stats = call_for_statistics(test) + assert stats.exit_reason == 'test was flaky' + + +@pytest.mark.parametrize('draw_delay', [False, True]) +@pytest.mark.parametrize('test_delay', [False, True]) +def test_draw_time_percentage(draw_delay, test_delay): + time.freeze() + + @st.composite + def s(draw): + if draw_delay: + time.sleep(0.05) + + @given(s()) + def test(_): + if test_delay: + time.sleep(0.05) + + stats = call_for_statistics(test) + if not draw_delay: + assert stats.draw_time_percentage == '~ 0%' + elif test_delay: + assert stats.draw_time_percentage == '~ 50%' + else: + assert stats.draw_time_percentage == '~ 100%' + + +def test_has_lambdas_in_output(): + @given(st.integers().filter(lambda x: x % 2 == 0)) + def test(i): + pass + + stats = call_for_statistics(test) + assert any( + 'lambda x: x % 2 == 0' in e for e in stats.events + ) + + +def test_stops_after_x_shrinks(monkeypatch): + # the max_shrinks argument is deprecated, but we still stop after some + # number - which we can reduce to zero to check that this works. + from hypothesis.internal.conjecture import engine + monkeypatch.setattr(engine, 'MAX_SHRINKS', 0) + + @given(st.integers()) + def test(n): + assert n < 100 + + stats = call_for_statistics(test) + assert 'shrunk example' in stats.exit_reason + + +@pytest.mark.parametrize('drawtime,runtime', [ + (1, 0), (-1, 0), (0, -1), (-1, -1), +]) +def test_weird_drawtime_issues(drawtime, runtime): + # Regression test for #1346, where we don't have the expected relationship + # 0<=drawtime<= runtime due to changing clocks or floating-point issues. + engine = ConjectureRunner(lambda: None) + engine.exit_reason = ExitReason.finished + engine.status_runtimes[Status.VALID] = [0] + + engine.all_drawtimes.append(drawtime) + engine.all_runtimes.extend([0, runtime]) + + stats = Statistics(engine) + assert stats.draw_time_percentage == 'NaN' diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_streams.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_streams.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_streams.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_streams.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,115 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from itertools import islice + +import pytest + +from hypothesis import find, given +from hypothesis.errors import InvalidArgument +from tests.common.utils import checks_deprecated_behaviour +from hypothesis.strategies import text, lists, booleans, streaming +from hypothesis.searchstrategy.streams import Stream + + +@given(lists(booleans())) +def test_stream_give_lists(xs): + s = Stream(iter(xs)) + assert list(s) == xs + assert list(s) == xs + + +@given(lists(booleans())) +def test_can_zip_streams_with_self(xs): + s = Stream(iter(xs)) + assert list(zip(s, s)) == list(zip(xs, xs)) + + +def loop(x): + while True: + yield x + + +def test_can_stream_infinite(): + s = Stream(loop(False)) + assert list(islice(s, 100)) == [False] * 100 + + +@checks_deprecated_behaviour +def test_fetched_repr_is_in_stream_repr(): + @given(streaming(text())) + def test(s): + assert repr(s) == u'Stream(...)' + assert repr(next(iter(s))) in repr(s) + test() + + +def test_cannot_thunk_past_end_of_list(): + with pytest.raises(IndexError): + Stream([1])._thunk_to(5) + + +def test_thunking_evaluates_initial_list(): + x = Stream([1, 2, 3]) + x._thunk_to(1) + assert len(x.fetched) == 1 + + +def test_thunking_map_evaluates_source(): + x = Stream(loop(False)) + y = x.map(lambda t: True) + y[100] + assert y._thunked() == 101 + assert x._thunked() == 101 + + +def test_wrong_index_raises_type_error(): + with pytest.raises(InvalidArgument): + Stream([])[u'kittens'] + + +def test_can_index_into_unindexed(): + x = Stream(loop(1)) + assert x[100] == 1 + + +def test_can_map(): + x = Stream([1, 2, 3]).map(lambda i: i * 2) + assert isinstance(x, Stream) + assert list(x) == [2, 4, 6] + + +@checks_deprecated_behaviour +def test_streaming_errors_in_find(): + with pytest.raises(InvalidArgument): + find(streaming(booleans()), lambda x: True) + + +def test_default_stream_is_empty(): + assert list(Stream()) == [] + + +def test_can_slice_streams(): + assert list(Stream([1, 2, 3])[:2]) == [1, 2] + + +@checks_deprecated_behaviour +def test_validates_argument(): + with pytest.raises(InvalidArgument): + streaming(bool).example() diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_testdecorators.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_testdecorators.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_testdecorators.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_testdecorators.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,471 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import functools +import threading +from collections import namedtuple + +import hypothesis.reporting as reporting +from hypothesis import Verbosity, HealthCheck, note, given, assume, \ + settings +from tests.common.utils import fails, raises, no_shrink, fails_with, \ + capture_out +from hypothesis.strategies import data, just, sets, text, lists, binary, \ + builds, floats, one_of, booleans, integers, frozensets, sampled_from + + +@given(integers(), integers()) +def test_int_addition_is_commutative(x, y): + assert x + y == y + x + + +@fails +@given(text(), text()) +def test_str_addition_is_commutative(x, y): + assert x + y == y + x + + +@fails +@given(binary(), binary()) +def test_bytes_addition_is_commutative(x, y): + assert x + y == y + x + + +@given(integers(), integers(), integers()) +def test_int_addition_is_associative(x, y, z): + assert x + (y + z) == (x + y) + z + + +@fails +@given(floats(), floats(), floats()) +@settings(max_examples=2000,) +def test_float_addition_is_associative(x, y, z): + assert x + (y + z) == (x + y) + z + + +@given(lists(integers())) +def test_reversing_preserves_integer_addition(xs): + assert sum(xs) == sum(reversed(xs)) + + +def test_still_minimizes_on_non_assertion_failures(): + @settings(max_examples=50) + @given(integers()) + def is_not_too_large(x): + if x >= 10: + raise ValueError('No, %s is just too large. Sorry' % x) + + with raises(ValueError) as exinfo: + is_not_too_large() + + assert ' 10 ' in exinfo.value.args[0] + + +@given(integers()) +def test_integer_division_shrinks_positive_integers(n): + assume(n > 0) + assert n / 2 < n + + +class TestCases(object): + + @given(integers()) + def test_abs_non_negative(self, x): + assert abs(x) >= 0 + assert isinstance(self, TestCases) + + @given(x=integers()) + def test_abs_non_negative_varargs(self, x, *args): + assert abs(x) >= 0 + assert isinstance(self, TestCases) + + @given(x=integers()) + def test_abs_non_negative_varargs_kwargs(self, *args, **kw): + assert abs(kw['x']) >= 0 + assert isinstance(self, TestCases) + + @given(x=integers()) + def test_abs_non_negative_varargs_kwargs_only(*args, **kw): + assert abs(kw['x']) >= 0 + assert isinstance(args[0], TestCases) + + @fails + @given(integers()) + def test_int_is_always_negative(self, x): + assert x < 0 + + @fails + @given(floats(), floats()) + def test_float_addition_cancels(self, x, y): + assert x + (y - x) == y + + +@fails +@given(x=integers(min_value=0, max_value=3), name=text()) +def test_can_be_given_keyword_args(x, name): + assume(x > 0) + assert len(name) < x + + +@fails +@given(one_of(floats(), booleans()), one_of(floats(), booleans())) +def test_one_of_produces_different_values(x, y): + assert type(x) == type(y) + + +@given(just(42)) +def test_is_the_answer(x): + assert x == 42 + + +@fails +@given(text(), text()) +def test_text_addition_is_not_commutative(x, y): + assert x + y == y + x + + +@fails +@given(binary(), binary()) +def test_binary_addition_is_not_commutative(x, y): + assert x + y == y + x + + +@given(integers(1, 10)) +def test_integers_are_in_range(x): + assert 1 <= x <= 10 + + +@given(integers(min_value=100)) +def test_integers_from_are_from(x): + assert x >= 100 + + +def test_does_not_catch_interrupt_during_falsify(): + calls = [0] + + @given(integers()) + def flaky_base_exception(x): + if not calls[0]: + calls[0] = 1 + raise KeyboardInterrupt() + with raises(KeyboardInterrupt): + flaky_base_exception() + + +@given(lists(integers(), unique=True), integers()) +def test_removing_an_element_from_a_unique_list(xs, y): + assume(len(set(xs)) == len(xs)) + + try: + xs.remove(y) + except ValueError: + pass + + assert y not in xs + + +@fails +@given(lists(integers(), min_size=2), data()) +def test_removing_an_element_from_a_non_unique_list(xs, data): + y = data.draw(sampled_from(xs)) + xs.remove(y) + assert y not in xs + + +@given(sets(sampled_from(list(range(10))))) +def test_can_test_sets_sampled_from(xs): + assert all(isinstance(x, int) for x in xs) + assert all(0 <= x < 10 for x in xs) + + +mix = one_of(sampled_from([1, 2, 3]), text()) + + +@fails +@given(mix, mix) +def test_can_mix_sampling_with_generating(x, y): + assert type(x) == type(y) + + +@fails +@given(frozensets(integers())) +def test_can_find_large_sum_frozenset(xs): + assert sum(xs) < 100 + + +def test_prints_on_failure_by_default(): + @given(integers(), integers()) + @settings(max_examples=100) + def test_ints_are_sorted(balthazar, evans): + assume(evans >= 0) + assert balthazar <= evans + with raises(AssertionError): + with capture_out() as out: + with reporting.with_reporter(reporting.default): + test_ints_are_sorted() + out = out.getvalue() + lines = [l.strip() for l in out.split('\n')] + assert ( + 'Falsifying example: test_ints_are_sorted(balthazar=1, evans=0)' + in lines) + + +def test_does_not_print_on_success(): + @settings(verbosity=Verbosity.normal) + @given(integers()) + def test_is_an_int(x): + return + + with capture_out() as out: + test_is_an_int() + out = out.getvalue() + lines = [l.strip() for l in out.split(u'\n')] + assert all(not l for l in lines), lines + + +@given(sampled_from([1])) +def test_can_sample_from_single_element(x): + assert x == 1 + + +@fails +@given(lists(integers())) +def test_list_is_sorted(xs): + assert sorted(xs) == xs + + +@fails +@given(floats(1.0, 2.0)) +def test_is_an_endpoint(x): + assert x == 1.0 or x == 2.0 + + +def test_breaks_bounds(): + @fails + @given(x=integers()) + def test_is_bounded(t, x): + assert x < t + for t in [1, 10, 100, 1000]: + test_is_bounded(t) + + +@given(x=booleans()) +def test_can_test_kwargs_only_methods(**kwargs): + assert isinstance(kwargs['x'], bool) + + +@fails_with(UnicodeEncodeError) +@given(text()) +@settings(max_examples=100) +def test_is_ascii(x): + x.encode('ascii') + + +@fails +@given(text()) +def test_is_not_ascii(x): + try: + x.encode('ascii') + assert False + except UnicodeEncodeError: + pass + + +@fails +@given(text()) +def test_can_find_string_with_duplicates(s): + assert len(set(s)) == len(s) + + +@fails +@given(text()) +def test_has_ascii(x): + if not x: + return + ascii_characters = ( + u'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ \t\n' + ) + assert any(c in ascii_characters for c in x) + + +def test_can_derandomize(): + values = [] + + @fails + @given(integers()) + @settings(derandomize=True, database=None) + def test_blah(x): + values.append(x) + assert x > 0 + + test_blah() + assert values + v1 = values + values = [] + test_blah() + assert v1 == values + + +def test_can_run_without_database(): + @given(integers()) + @settings(database=None) + def test_blah(x): + assert False + with raises(AssertionError): + test_blah() + + +def test_can_run_with_database_in_thread(): + results = [] + + @given(integers()) + def test_blah(x): + raise ValueError() + + def run_test(): + try: + test_blah() + except ValueError: + results.append('success') + + # Run once in the main thread and once in another thread. Execution is + # strictly serial, so no need for locking. + run_test() + assert results == ['success'] + thread = threading.Thread(target=run_test) + thread.start() + thread.join() + assert results == ['success', 'success'] + + +@given(integers()) +def test_can_call_an_argument_f(f): + # See issue https://github.com/HypothesisWorks/hypothesis-python/issues/38 + # for details + pass + + +Litter = namedtuple('Litter', ('kitten1', 'kitten2')) + + +@given(builds(Litter, integers(), integers())) +def test_named_tuples_are_of_right_type(litter): + assert isinstance(litter, Litter) + + +@fails_with(AttributeError) +@given(integers().map(lambda x: x.nope)) +@settings(suppress_health_check=HealthCheck.all()) +def test_fails_in_reify(x): + pass + + +@given(text(u'a')) +def test_a_text(x): + assert set(x).issubset(set(u'a')) + + +@given(text(u'')) +def test_empty_text(x): + assert not x + + +@given(text(u'abcdefg')) +def test_mixed_text(x): + assert set(x).issubset(set(u'abcdefg')) + + +def test_when_set_to_no_simplifies_runs_failing_example_twice(): + failing = [0] + + @given(integers()) + @settings(phases=no_shrink, max_examples=100, verbosity=Verbosity.normal) + def foo(x): + if x > 11: + note('Lo') + failing[0] += 1 + assert False + + with raises(AssertionError): + with capture_out() as out: + foo() + assert failing == [2] + assert 'Falsifying example' in out.getvalue() + assert 'Lo' in out.getvalue() + + +@given(integers().filter(lambda x: x % 4 == 0)) +def test_filtered_values_satisfy_condition(i): + assert i % 4 == 0 + + +def nameless_const(x): + def f(u, v): + return u + return functools.partial(f, x) + + +@given(sets(booleans()).map(nameless_const(2))) +def test_can_map_nameless(x): + assert x == 2 + + +@given( + integers(0, 10).flatmap(nameless_const(just(3)))) +def test_can_flatmap_nameless(x): + assert x == 3 + + +def test_can_be_used_with_none_module(): + def test_is_cool(i): + pass + test_is_cool.__module__ = None + test_is_cool = given(integers())(test_is_cool) + test_is_cool() + + +def test_does_not_print_notes_if_all_succeed(): + @given(integers()) + @settings(verbosity=Verbosity.normal) + def test(i): + note('Hi there') + with capture_out() as out: + with reporting.with_reporter(reporting.default): + test() + assert not out.getvalue() + + +def test_prints_notes_once_on_failure(): + @given(lists(integers())) + @settings(database=None, verbosity=Verbosity.normal) + def test(xs): + note('Hi there') + if sum(xs) <= 100: + raise ValueError() + with capture_out() as out: + with reporting.with_reporter(reporting.default): + with raises(ValueError): + test() + lines = out.getvalue().strip().splitlines() + assert lines.count('Hi there') == 1 + + +@given(lists(integers(), max_size=0)) +def test_empty_lists(xs): + assert xs == [] diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_timeout.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_timeout.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_timeout.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_timeout.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,132 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import time + +import pytest + +from hypothesis import find, given, reject, settings +from hypothesis.errors import Timeout, NoSuchExample +from tests.common.utils import fails, fails_with, validate_deprecation, \ + checks_deprecated_behaviour +from hypothesis.strategies import integers + + +def test_hitting_timeout_is_deprecated(): + with validate_deprecation(): + @settings(timeout=0.1) + @given(integers()) + def test_slow_test_times_out(x): + time.sleep(0.05) + + with validate_deprecation(): + test_slow_test_times_out() + + +def test_slow_unsatisfiable_test(): + with validate_deprecation(): + @settings(timeout=0.1) + @given(integers()) + def test_slow_test_times_out(x): + time.sleep(0.05) + reject() + + with validate_deprecation(): + with pytest.raises(Timeout): + test_slow_test_times_out() + + +# Cheap hack to make test functions which fail on their second invocation +calls = [0, 0, 0, 0] + + +with validate_deprecation(): + timeout_settings = settings(timeout=0.2) + + +# The following tests exist to test that verifiers start their timeout +# from when the test first executes, not from when it is defined. +@checks_deprecated_behaviour +@fails +@given(integers()) +@timeout_settings +def test_slow_failing_test_1(x): + time.sleep(0.05) + assert not calls[0] + calls[0] = 1 + + +@checks_deprecated_behaviour +@fails +@timeout_settings +@given(integers()) +def test_slow_failing_test_2(x): + time.sleep(0.05) + assert not calls[1] + calls[1] = 1 + + +@checks_deprecated_behaviour +@fails +@given(integers()) +@timeout_settings +def test_slow_failing_test_3(x): + time.sleep(0.05) + assert not calls[2] + calls[2] = 1 + + +@checks_deprecated_behaviour +@fails +@timeout_settings +@given(integers()) +def test_slow_failing_test_4(x): + time.sleep(0.05) + assert not calls[3] + calls[3] = 1 + + +with validate_deprecation(): + strict_timeout_settings = settings(timeout=60) + + +@checks_deprecated_behaviour +@strict_timeout_settings +@given(integers()) +def test_deprecated_behaviour(i): + time.sleep(100) + + +@checks_deprecated_behaviour +@fails_with(AssertionError) +@strict_timeout_settings +@given(integers()) +def test_does_not_hide_errors_with_deprecation(i): + time.sleep(100) + assert False + + +def test_can_hit_timeout_in_find(): + def f(x): + time.sleep(100) + return x >= 100 + + with pytest.raises(NoSuchExample): + with validate_deprecation(): + find(integers(), f, settings=timeout_settings) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_type_lookup.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_type_lookup.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_type_lookup.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_type_lookup.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,161 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import enum + +import pytest + +import hypothesis.strategies as st +from hypothesis import given, infer +from hypothesis.errors import InvalidArgument, ResolutionFailed, \ + HypothesisDeprecationWarning +from hypothesis.searchstrategy import types +from hypothesis.internal.compat import PY2, integer_types + +# Build a set of all types output by core strategies +blacklist = [ + 'builds', 'iterables', 'permutations', 'random_module', 'randoms', + 'runner', 'sampled_from', 'streaming', 'choices', +] +types_with_core_strat = set(integer_types) +for thing in (getattr(st, name) for name in sorted(st._strategies) + if name in dir(st) and name not in blacklist): + for n in range(3): + try: + ex = thing(*([st.nothing()] * n)).example() + types_with_core_strat.add(type(ex)) + break + except (TypeError, InvalidArgument, HypothesisDeprecationWarning): + continue + + +@pytest.mark.parametrize('typ', sorted(types_with_core_strat, key=str)) +def test_resolve_core_strategies(typ): + @given(st.from_type(typ)) + def inner(ex): + if PY2 and issubclass(typ, integer_types): + assert isinstance(ex, integer_types) + else: + assert isinstance(ex, typ) + + inner() + + +def test_lookup_knows_about_all_core_strategies(): + cannot_lookup = types_with_core_strat - set(types._global_type_lookup) + assert not cannot_lookup + + +def test_lookup_keys_are_types(): + with pytest.raises(InvalidArgument): + st.register_type_strategy('int', st.integers()) + assert 'int' not in types._global_type_lookup + + +def test_lookup_values_are_strategies(): + with pytest.raises(InvalidArgument): + st.register_type_strategy(int, 42) + assert 42 not in types._global_type_lookup.values() + + +@pytest.mark.parametrize('typ', sorted(types_with_core_strat, key=str)) +def test_lookup_overrides_defaults(typ): + sentinel = object() + try: + strat = types._global_type_lookup[typ] + st.register_type_strategy(typ, st.just(sentinel)) + assert st.from_type(typ).example() is sentinel + finally: + st.register_type_strategy(typ, strat) + st.from_type.__clear_cache() + assert st.from_type(typ).example() is not sentinel + + +class ParentUnknownType(object): + pass + + +class UnknownType(ParentUnknownType): + def __init__(self, arg): + pass + + +def test_custom_type_resolution(): + fails = st.from_type(UnknownType) + with pytest.raises(ResolutionFailed): + fails.example() + sentinel = object() + try: + st.register_type_strategy(UnknownType, st.just(sentinel)) + assert st.from_type(UnknownType).example() is sentinel + # Also covered by registration of child class + assert st.from_type(ParentUnknownType).example() is sentinel + finally: + types._global_type_lookup.pop(UnknownType) + st.from_type.__clear_cache() + fails = st.from_type(UnknownType) + with pytest.raises(ResolutionFailed): + fails.example() + + +def test_errors_if_generic_resolves_empty(): + try: + st.register_type_strategy(UnknownType, lambda _: st.nothing()) + fails_1 = st.from_type(UnknownType) + with pytest.raises(ResolutionFailed): + fails_1.example() + fails_2 = st.from_type(ParentUnknownType) + with pytest.raises(ResolutionFailed): + fails_2.example() + finally: + types._global_type_lookup.pop(UnknownType) + st.from_type.__clear_cache() + + +def test_cannot_register_empty(): + # Cannot register and did not register + with pytest.raises(InvalidArgument): + st.register_type_strategy(UnknownType, st.nothing()) + fails = st.from_type(UnknownType) + with pytest.raises(ResolutionFailed): + fails.example() + assert UnknownType not in types._global_type_lookup + + +def test_pulic_interface_works(): + st.from_type(int).example() + fails = st.from_type('not a type or annotated function') + with pytest.raises(InvalidArgument): + fails.example() + + +def test_given_can_infer_on_py2(): + # Editing annotations before decorating is hilariously awkward, but works! + def inner(a): + pass + inner.__annotations__ = {'a': int} + given(a=infer)(inner)() + + +class EmptyEnum(enum.Enum): + pass + + +def test_error_if_enum_is_empty(): + assert st.from_type(EmptyEnum).is_empty diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_unittest.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_unittest.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_unittest.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_unittest.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,60 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import io +import unittest + +import pytest + +from hypothesis import given +from hypothesis import strategies as st +from hypothesis.errors import FailedHealthCheck, HypothesisWarning +from tests.common.utils import fails_with +from hypothesis.internal.compat import PY2 + + +class Thing_with_a_subThing(unittest.TestCase): + """Example test case using subTest for the actual test below.""" + + @given(st.tuples(st.booleans(), st.booleans())) + def thing(self, lst): + for i, b in enumerate(lst): + with pytest.warns(HypothesisWarning): + with self.subTest((i, b)): + self.assertTrue(b) + + +def test_subTest(): + suite = unittest.TestSuite() + suite.addTest(Thing_with_a_subThing('thing')) + stream = io.BytesIO() if PY2 else io.StringIO() + out = unittest.TextTestRunner(stream=stream).run(suite) + assert len(out.failures) <= out.testsRun, out + + +class test_given_on_setUp_fails_health_check(unittest.TestCase): + + @fails_with(FailedHealthCheck) + @given(st.integers()) + def setUp(self, i): + pass + + def test(self): + """Provide something to set up for, so the setUp method is called.""" + pass diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_validation.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_validation.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_validation.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_validation.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,198 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import pytest + +from hypothesis import find, given +from hypothesis.errors import InvalidArgument +from tests.common.utils import fails_with +from hypothesis.strategies import sets, lists, floats, booleans, \ + integers, recursive, frozensets + + +def test_errors_when_given_varargs(): + @given(integers()) + def has_varargs(*args): + pass + with pytest.raises(InvalidArgument) as e: + has_varargs() + assert u'varargs' in e.value.args[0] + + +def test_varargs_without_positional_arguments_allowed(): + @given(somearg=integers()) + def has_varargs(somearg, *args): + pass + + +def test_errors_when_given_varargs_and_kwargs_with_positional_arguments(): + @given(integers()) + def has_varargs(*args, **kw): + pass + with pytest.raises(InvalidArgument) as e: + has_varargs() + assert u'varargs' in e.value.args[0] + + +def test_varargs_and_kwargs_without_positional_arguments_allowed(): + @given(somearg=integers()) + def has_varargs(*args, **kw): + pass + + +def test_bare_given_errors(): + @given() + def test(): + pass + + with pytest.raises(InvalidArgument): + test() + + +def test_errors_on_unwanted_kwargs(): + @given(hello=int, world=int) + def greet(world): + pass + with pytest.raises(InvalidArgument): + greet() + + +def test_errors_on_too_many_positional_args(): + @given(integers(), int, int) + def foo(x, y): + pass + + with pytest.raises(InvalidArgument): + foo() + + +def test_errors_on_any_varargs(): + @given(integers()) + def oops(*args): + pass + with pytest.raises(InvalidArgument): + oops() + + +def test_can_put_arguments_in_the_middle(): + @given(y=integers()) + def foo(x, y, z): + pass + foo(1, 2) + + +def test_float_ranges(): + with pytest.raises(InvalidArgument): + floats(float(u'nan'), 0).example() + with pytest.raises(InvalidArgument): + floats(1, -1).example() + + +def test_float_range_and_allow_nan_cannot_both_be_enabled(): + with pytest.raises(InvalidArgument): + floats(min_value=1, allow_nan=True).example() + with pytest.raises(InvalidArgument): + floats(max_value=1, allow_nan=True).example() + + +def test_float_finite_range_and_allow_infinity_cannot_both_be_enabled(): + with pytest.raises(InvalidArgument): + floats(0, 1, allow_infinity=True).example() + + +def test_does_not_error_if_min_size_is_bigger_than_default_size(): + lists(integers(), min_size=50).example() + sets(integers(), min_size=50).example() + frozensets(integers(), min_size=50).example() + lists(integers(), min_size=50, unique=True).example() + + +def test_list_unique_and_unique_by_cannot_both_be_enabled(): + @given(lists(integers(), unique=True, unique_by=lambda x: x)) + def boom(t): + pass + with pytest.raises(InvalidArgument) as e: + boom() + assert 'unique ' in e.value.args[0] + assert 'unique_by' in e.value.args[0] + + +def test_min_before_max(): + with pytest.raises(InvalidArgument): + integers(min_value=1, max_value=0).validate() + + +def test_filter_validates(): + with pytest.raises(InvalidArgument): + integers(min_value=1, max_value=0).filter(bool).validate() + + +def test_recursion_validates_base_case(): + with pytest.raises(InvalidArgument): + recursive( + integers(min_value=1, max_value=0), + lists, + ).validate() + + +def test_recursion_validates_recursive_step(): + with pytest.raises(InvalidArgument): + recursive( + integers(), + lambda x: lists(x, min_size=3, max_size=1), + ).validate() + + +@fails_with(InvalidArgument) +@given(x=integers()) +def test_stuff_keyword(x=1): + pass + + +@fails_with(InvalidArgument) +@given(integers()) +def test_stuff_positional(x=1): + pass + + +@fails_with(InvalidArgument) +@given(integers(), integers()) +def test_too_many_positional(x): + pass + + +def test_given_warns_on_use_of_non_strategies(): + @given(bool) + def test(x): + pass + with pytest.raises(InvalidArgument): + test() + + +def test_given_warns_when_mixing_positional_with_keyword(): + @given(booleans(), y=booleans()) + def test(x, y): + pass + with pytest.raises(InvalidArgument): + test() + + +def test_cannot_find_non_strategies(): + with pytest.raises(InvalidArgument): + find(bool, bool) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_verbosity.py python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_verbosity.py --- python-hypothesis-3.44.1/hypothesis-python/tests/cover/test_verbosity.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/cover/test_verbosity.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,135 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import os +import sys +import subprocess +from contextlib import contextmanager + +from hypothesis import find, given +from tests.common.utils import fails, capture_out +from hypothesis._settings import Verbosity, settings +from hypothesis.reporting import default as default_reporter +from hypothesis.reporting import with_reporter +from hypothesis.strategies import lists, booleans, integers + + +@contextmanager +def capture_verbosity(): + with capture_out() as o: + with with_reporter(default_reporter): + yield o + + +def test_prints_intermediate_in_success(): + with capture_verbosity() as o: + @settings(verbosity=Verbosity.verbose) + @given(booleans()) + def test_works(x): + pass + test_works() + assert 'Trying example' in o.getvalue() + + +def test_does_not_log_in_quiet_mode(): + with capture_verbosity() as o: + @fails + @settings(verbosity=Verbosity.quiet) + @given(integers()) + def test_foo(x): + assert False + + test_foo() + assert not o.getvalue() + + +def test_includes_progress_in_verbose_mode(): + with capture_verbosity() as o: + def foo(): + find( + lists(integers()), + lambda x: sum(x) >= 1000000, + settings=settings(verbosity=Verbosity.verbose, database=None)) + + foo() + + out = o.getvalue() + assert out + assert u'Shrunk example' in out + assert u'Found satisfying example' in out + + +def test_prints_initial_attempts_on_find(): + + with capture_verbosity() as o: + def foo(): + seen = [] + + def not_first(x): + if not seen: + seen.append(x) + return False + return x not in seen + find( + integers(), not_first, + settings=settings(verbosity=Verbosity.verbose)) + + foo() + + assert u'Tried non-satisfying example' in o.getvalue() + + +def test_includes_intermediate_results_in_verbose_mode(): + with capture_verbosity() as o: + @fails + @settings(verbosity=Verbosity.verbose, database=None) + @given(lists(integers(), min_size=1)) + def test_foo(x): + assert sum(x) < 1000000 + + test_foo() + lines = o.getvalue().splitlines() + assert len([l for l in lines if u'example' in l]) > 2 + assert [l for l in lines if u'AssertionError' in l] + + +PRINT_VERBOSITY = """ +from __future__ import print_function + +import warnings +warnings.resetwarnings() + +from hypothesis import settings + +if __name__ == '__main__': + print("VERBOSITY=%s" % (settings.default.verbosity.name,)) +""" + + +def test_picks_up_verbosity_from_environment(tmpdir): + script = tmpdir.join('printdebug.py') + script.write(PRINT_VERBOSITY) + environ = dict(os.environ) + + environ['HYPOTHESIS_VERBOSITY_LEVEL'] = 'debug' + output = subprocess.check_output([ + sys.executable, str(script) + ], env=environ).decode('ascii') + + assert 'VERBOSITY=debug' in output diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/datetime/__init__.py python-hypothesis-3.71.11/hypothesis-python/tests/datetime/__init__.py --- python-hypothesis-3.44.1/hypothesis-python/tests/datetime/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/datetime/__init__.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,16 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/datetime/test_dates.py python-hypothesis-3.71.11/hypothesis-python/tests/datetime/test_dates.py --- python-hypothesis-3.44.1/hypothesis-python/tests/datetime/test_dates.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/datetime/test_dates.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,49 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from tests.common.debug import minimal, find_any +from tests.common.utils import checks_deprecated_behaviour +from hypothesis.extra.datetime import dates +from hypothesis.internal.compat import hrange + + +@checks_deprecated_behaviour +def test_can_find_after_the_year_2000(): + assert minimal(dates(), lambda x: x.year > 2000).year == 2001 + + +@checks_deprecated_behaviour +def test_can_find_before_the_year_2000(): + assert minimal(dates(), lambda x: x.year < 2000).year == 1999 + + +@checks_deprecated_behaviour +def test_can_find_each_month(): + for month in hrange(1, 13): + find_any(dates(), lambda x: x.month == month) + + +@checks_deprecated_behaviour +def test_min_year_is_respected(): + assert minimal(dates(min_year=2003)).year == 2003 + + +@checks_deprecated_behaviour +def test_max_year_is_respected(): + assert minimal(dates(max_year=1998)).year == 1998 diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/datetime/test_datetime.py python-hypothesis-3.71.11/hypothesis-python/tests/datetime/test_datetime.py --- python-hypothesis-3.44.1/hypothesis-python/tests/datetime/test_datetime.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/datetime/test_datetime.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,165 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from datetime import MINYEAR + +import pytz +import pytest +from flaky import flaky + +from hypothesis import given, assume, settings, unlimited +from hypothesis.errors import InvalidArgument +from tests.common.debug import minimal, find_any +from tests.common.utils import checks_deprecated_behaviour +from hypothesis.extra.datetime import datetimes +from hypothesis.internal.compat import hrange + + +@checks_deprecated_behaviour +def test_can_find_after_the_year_2000(): + assert minimal(datetimes(), lambda x: x.year > 2000).year == 2001 + + +@checks_deprecated_behaviour +def test_can_find_before_the_year_2000(): + assert minimal(datetimes(), lambda x: x.year < 2000).year == 1999 + + +@checks_deprecated_behaviour +def test_can_find_each_month(): + for month in hrange(1, 13): + find_any(datetimes(), lambda x: x.month == month) + + +@checks_deprecated_behaviour +def test_can_find_midnight(): + datetimes().filter( + lambda x: x.hour == x.minute == x.second == 0 + ).example() + + +@checks_deprecated_behaviour +def test_can_find_non_midnight(): + assert minimal(datetimes(), lambda x: x.hour != 0).hour == 1 + + +@checks_deprecated_behaviour +def test_can_find_off_the_minute(): + find_any(datetimes(), lambda x: x.second != 0) + + +@checks_deprecated_behaviour +def test_can_find_on_the_minute(): + find_any(datetimes(), lambda x: x.second == 0) + + +@checks_deprecated_behaviour +def test_simplifies_towards_midnight(): + d = minimal(datetimes()) + assert d.hour == 0 + assert d.minute == 0 + assert d.second == 0 + assert d.microsecond == 0 + + +@checks_deprecated_behaviour +def test_can_generate_naive_datetime(): + find_any(datetimes(allow_naive=True), lambda d: d.tzinfo is None) + + +@checks_deprecated_behaviour +def test_can_generate_non_naive_datetime(): + assert minimal( + datetimes(allow_naive=True), lambda d: d.tzinfo).tzinfo == pytz.UTC + + +@checks_deprecated_behaviour +def test_can_generate_non_utc(): + datetimes().filter( + lambda d: assume(d.tzinfo) and d.tzinfo.zone != u'UTC' + ).example() + + +@checks_deprecated_behaviour +@given(datetimes(timezones=[])) +def test_naive_datetimes_are_naive(dt): + assert not dt.tzinfo + + +@checks_deprecated_behaviour +@given(datetimes(allow_naive=False)) +def test_timezone_aware_datetimes_are_timezone_aware(dt): + assert dt.tzinfo + + +@checks_deprecated_behaviour +def test_restricts_to_allowed_set_of_timezones(): + timezones = list(map(pytz.timezone, list(pytz.all_timezones)[:3])) + x = minimal(datetimes(timezones=timezones)) + assert any(tz.zone == x.tzinfo.zone for tz in timezones) + + +@checks_deprecated_behaviour +def test_min_year_is_respected(): + assert minimal(datetimes(min_year=2003)).year == 2003 + + +@checks_deprecated_behaviour +def test_max_year_is_respected(): + assert minimal(datetimes(max_year=1998)).year == 1998 + + +@checks_deprecated_behaviour +def test_validates_year_arguments_in_range(): + with pytest.raises(InvalidArgument): + datetimes(min_year=-10 ** 6).example() + with pytest.raises(InvalidArgument): + datetimes(max_year=-10 ** 6).example() + with pytest.raises(InvalidArgument): + datetimes(min_year=10 ** 6).example() + with pytest.raises(InvalidArgument): + datetimes(max_year=10 ** 6).example() + + +@checks_deprecated_behaviour +def test_needs_permission_for_no_timezones(): + with pytest.raises(InvalidArgument): + datetimes(allow_naive=False, timezones=[]).example() + + +@checks_deprecated_behaviour +@flaky(max_runs=3, min_passes=1) +def test_bordering_on_a_leap_year(): + x = minimal( + datetimes(min_year=2002, max_year=2005), + lambda x: x.month == 2 and x.day == 29, + settings=settings( + database=None, max_examples=10 ** 7, timeout=unlimited) + ) + assert x.year == 2004 + + +@checks_deprecated_behaviour +def test_overflow_in_simplify(): + """This is a test that we don't trigger a pytz bug when we're simplifying + around MINYEAR where valid dates can produce an overflow error.""" + minimal( + datetimes(max_year=MINYEAR), + lambda x: x.tzinfo != pytz.UTC + ) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/datetime/test_dateutil_timezones.py python-hypothesis-3.71.11/hypothesis-python/tests/datetime/test_dateutil_timezones.py --- python-hypothesis-3.44.1/hypothesis-python/tests/datetime/test_dateutil_timezones.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/datetime/test_dateutil_timezones.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,89 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import datetime as dt + +import pytest +from dateutil import tz, zoneinfo + +from hypothesis import given, assume +from hypothesis.errors import InvalidArgument +from tests.common.debug import minimal +from hypothesis.strategies import times, datetimes, sampled_from +from hypothesis.extra.dateutil import timezones + + +def test_utc_is_minimal(): + assert tz.UTC is minimal(timezones()) + + +def test_can_generate_non_naive_time(): + assert minimal(times(timezones=timezones()), + lambda d: d.tzinfo).tzinfo == tz.UTC + + +def test_can_generate_non_naive_datetime(): + assert minimal(datetimes(timezones=timezones()), + lambda d: d.tzinfo).tzinfo == tz.UTC + + +@given(datetimes(timezones=timezones())) +def test_timezone_aware_datetimes_are_timezone_aware(dt): + assert dt.tzinfo is not None + + +@given(sampled_from(['min_value', 'max_value']), + datetimes(timezones=timezones())) +def test_datetime_bounds_must_be_naive(name, val): + with pytest.raises(InvalidArgument): + datetimes(**{name: val}).validate() + + +def test_timezones_arg_to_datetimes_must_be_search_strategy(): + all_timezones = zoneinfo.get_zonefile_instance().zones + with pytest.raises(InvalidArgument): + datetimes(timezones=all_timezones).validate() + + +@given(times(timezones=timezones())) +def test_timezone_aware_times_are_timezone_aware(dt): + assert dt.tzinfo is not None + + +def test_can_generate_non_utc(): + times(timezones=timezones()).filter( + lambda d: assume(d.tzinfo) and d.tzinfo.zone != u'UTC' + ).validate() + + +@given(sampled_from(['min_value', 'max_value']), times(timezones=timezones())) +def test_time_bounds_must_be_naive(name, val): + with pytest.raises(InvalidArgument): + times(**{name: val}).validate() + + +def test_should_have_correct_ordering(): + def offset(timezone): + return abs(timezone.utcoffset(dt.datetime(2000, 1, 1))) + + next_interesting_tz = minimal( + timezones(), + lambda tz: offset(tz) > dt.timedelta(0) + ) + assert offset(next_interesting_tz) == dt.timedelta(seconds=3600) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/datetime/test_pytz_timezones.py python-hypothesis-3.71.11/hypothesis-python/tests/datetime/test_pytz_timezones.py --- python-hypothesis-3.44.1/hypothesis-python/tests/datetime/test_pytz_timezones.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/datetime/test_pytz_timezones.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,94 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import datetime as dt + +import pytz +import pytest + +from hypothesis import given, assume +from hypothesis.errors import InvalidArgument +from tests.common.debug import minimal +from hypothesis.extra.pytz import timezones +from hypothesis.strategies import times, datetimes, sampled_from + + +def test_utc_is_minimal(): + assert pytz.UTC is minimal(timezones()) + + +def test_can_generate_non_naive_time(): + assert minimal(times(timezones=timezones()), + lambda d: d.tzinfo).tzinfo == pytz.UTC + + +def test_can_generate_non_naive_datetime(): + assert minimal(datetimes(timezones=timezones()), + lambda d: d.tzinfo).tzinfo == pytz.UTC + + +@given(datetimes(timezones=timezones())) +def test_timezone_aware_datetimes_are_timezone_aware(dt): + assert dt.tzinfo is not None + + +@given(sampled_from(['min_value', 'max_value']), + datetimes(timezones=timezones())) +def test_datetime_bounds_must_be_naive(name, val): + with pytest.raises(InvalidArgument): + datetimes(**{name: val}).validate() + + +def test_underflow_in_simplify(): + # we shouldn't trigger a pytz bug when we're simplifying + minimal(datetimes(max_value=dt.datetime.min + dt.timedelta(days=3), + timezones=timezones()), + lambda x: x.tzinfo != pytz.UTC) + + +def test_overflow_in_simplify(): + # we shouldn't trigger a pytz bug when we're simplifying + minimal(datetimes(min_value=dt.datetime.max - dt.timedelta(days=3), + timezones=timezones()), + lambda x: x.tzinfo != pytz.UTC) + + +def test_timezones_arg_to_datetimes_must_be_search_strategy(): + with pytest.raises(InvalidArgument): + datetimes(timezones=pytz.all_timezones).validate() + with pytest.raises(InvalidArgument): + tz = [pytz.timezone(t) for t in pytz.all_timezones] + datetimes(timezones=tz).validate() + + +@given(times(timezones=timezones())) +def test_timezone_aware_times_are_timezone_aware(dt): + assert dt.tzinfo is not None + + +def test_can_generate_non_utc(): + times(timezones=timezones()).filter( + lambda d: assume(d.tzinfo) and d.tzinfo.zone != u'UTC' + ).validate() + + +@given(sampled_from(['min_value', 'max_value']), times(timezones=timezones())) +def test_time_bounds_must_be_naive(name, val): + with pytest.raises(InvalidArgument): + times(**{name: val}).validate() diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/datetime/test_times.py python-hypothesis-3.71.11/hypothesis-python/tests/datetime/test_times.py --- python-hypothesis-3.44.1/hypothesis-python/tests/datetime/test_times.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/datetime/test_times.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,91 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import pytz + +from hypothesis import given, assume +from tests.common.debug import minimal, find_any +from tests.common.utils import checks_deprecated_behaviour +from hypothesis.extra.datetime import times + + +@checks_deprecated_behaviour +def test_can_find_midnight(): + find_any(times(), lambda x: x.hour == x.minute == x.second == 0) + + +@checks_deprecated_behaviour +def test_can_find_non_midnight(): + assert minimal(times(), lambda x: x.hour != 0).hour == 1 + + +@checks_deprecated_behaviour +def test_can_find_off_the_minute(): + find_any(times(), lambda x: x.second != 0) + + +@checks_deprecated_behaviour +def test_can_find_on_the_minute(): + find_any(times(), lambda x: x.second == 0) + + +@checks_deprecated_behaviour +def test_simplifies_towards_midnight(): + d = minimal(times()) + assert d.hour == 0 + assert d.minute == 0 + assert d.second == 0 + assert d.microsecond == 0 + + +@checks_deprecated_behaviour +def test_can_generate_naive_time(): + find_any(times(allow_naive=True), lambda d: d.tzinfo is not None) + + +@checks_deprecated_behaviour +def test_can_generate_non_naive_time(): + assert minimal( + times(allow_naive=True), lambda d: d.tzinfo).tzinfo == pytz.UTC + + +@checks_deprecated_behaviour +def test_can_generate_non_utc(): + times().filter( + lambda d: assume(d.tzinfo) and d.tzinfo.zone != u'UTC' + ).example() + + +@checks_deprecated_behaviour +@given(times(timezones=[])) +def test_naive_times_are_naive(dt): + assert not dt.tzinfo + + +@checks_deprecated_behaviour +@given(times(allow_naive=False)) +def test_timezone_aware_times_are_timezone_aware(dt): + assert dt.tzinfo + + +@checks_deprecated_behaviour +def test_restricts_to_allowed_set_of_timezones(): + timezones = list(map(pytz.timezone, list(pytz.all_timezones)[:3])) + x = minimal(times(timezones=timezones)) + assert any(tz.zone == x.tzinfo.zone for tz in timezones) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/django/__init__.py python-hypothesis-3.71.11/hypothesis-python/tests/django/__init__.py --- python-hypothesis-3.44.1/hypothesis-python/tests/django/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/django/__init__.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,16 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/django/manage.py python-hypothesis-3.71.11/hypothesis-python/tests/django/manage.py --- python-hypothesis-3.44.1/hypothesis-python/tests/django/manage.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/django/manage.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,41 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import os +import sys + +from hypothesis import HealthCheck, settings, unlimited +from tests.common.setup import run + +if __name__ == u'__main__': + run() + + settings.register_profile('default', settings( + timeout=unlimited, + suppress_health_check=[HealthCheck.too_slow], + )) + + settings.load_profile(os.getenv('HYPOTHESIS_PROFILE', 'default')) + + os.environ.setdefault( + u'DJANGO_SETTINGS_MODULE', u'tests.django.toys.settings') + + from django.core.management import execute_from_command_line + + execute_from_command_line(sys.argv) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/django/toys/__init__.py python-hypothesis-3.71.11/hypothesis-python/tests/django/toys/__init__.py --- python-hypothesis-3.44.1/hypothesis-python/tests/django/toys/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/django/toys/__init__.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,16 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/django/toys/settings.py python-hypothesis-3.71.11/hypothesis-python/tests/django/toys/settings.py --- python-hypothesis-3.44.1/hypothesis-python/tests/django/toys/settings.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/django/toys/settings.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,104 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +"""Django settings for toys project. + +For more information on this file, see +https://docs.djangoproject.com/en/1.7/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/1.7/ref/settings/ +""" + +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) + +from __future__ import division, print_function, absolute_import + +import os + +BASE_DIR = os.path.dirname(os.path.dirname(__file__)) + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/1.7/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = u'o0zlv@74u4e3s+o0^h$+tlalh&$r(7hbx01g4^h5-3gizj%hub' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +TEMPLATE_DEBUG = True + +ALLOWED_HOSTS = [] + + +# Application definition + +INSTALLED_APPS = ( + u'django.contrib.admin', + u'django.contrib.auth', + u'django.contrib.contenttypes', + u'django.contrib.sessions', + u'django.contrib.messages', + u'django.contrib.staticfiles', + u'tests.django.toystore', +) + +MIDDLEWARE_CLASSES = ( + u'django.contrib.sessions.middleware.SessionMiddleware', + u'django.middleware.common.CommonMiddleware', + u'django.middleware.csrf.CsrfViewMiddleware', + u'django.contrib.auth.middleware.AuthenticationMiddleware', + u'django.contrib.auth.middleware.SessionAuthenticationMiddleware', + u'django.contrib.messages.middleware.MessageMiddleware', + u'django.middleware.clickjacking.XFrameOptionsMiddleware', +) + +ROOT_URLCONF = u'tests.django.toys.urls' + +WSGI_APPLICATION = u'tests.django.toys.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/1.7/ref/settings/#databases + +DATABASES = { + u'default': { + u'ENGINE': u'django.db.backends.sqlite3', + u'NAME': os.path.join(BASE_DIR, u'db.sqlite3'), + } +} + +# Internationalization +# https://docs.djangoproject.com/en/1.7/topics/i18n/ + +LANGUAGE_CODE = u'en-us' + +TIME_ZONE = u'UTC' + +USE_I18N = True + +USE_L10N = True + +USE_TZ = os.environ.get('HYPOTHESIS_DJANGO_USETZ', 'TRUE') == 'TRUE' + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/1.7/howto/static-files/ + +STATIC_URL = u'/static/' diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/django/toys/urls.py python-hypothesis-3.71.11/hypothesis-python/tests/django/toys/urls.py --- python-hypothesis-3.44.1/hypothesis-python/tests/django/toys/urls.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/django/toys/urls.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,31 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from django.contrib import admin +from django.conf.urls import url, include + +patterns, namespace, name = admin.site.urls + +urlpatterns = [ + # Examples: + # url(r'^$', 'toys.views.home', name='home'), + # url(r'^blog/', include('blog.urls')), + + url(r'^admin/', include((patterns, name), namespace=namespace)) +] diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/django/toys/wsgi.py python-hypothesis-3.71.11/hypothesis-python/tests/django/toys/wsgi.py --- python-hypothesis-3.44.1/hypothesis-python/tests/django/toys/wsgi.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/django/toys/wsgi.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,35 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +"""WSGI config for toys project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/1.7/howto/deployment/wsgi/ +""" + + +from __future__ import division, print_function, absolute_import + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault(u'DJANGO_SETTINGS_MODULE', u'toys.settings') + +application = get_wsgi_application() diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/django/toystore/admin.py python-hypothesis-3.71.11/hypothesis-python/tests/django/toystore/admin.py --- python-hypothesis-3.44.1/hypothesis-python/tests/django/toystore/admin.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/django/toystore/admin.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,18 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/django/toystore/__init__.py python-hypothesis-3.71.11/hypothesis-python/tests/django/toystore/__init__.py --- python-hypothesis-3.44.1/hypothesis-python/tests/django/toystore/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/django/toystore/__init__.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,16 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/django/toystore/models.py python-hypothesis-3.71.11/hypothesis-python/tests/django/toystore/models.py --- python-hypothesis-3.44.1/hypothesis-python/tests/django/toystore/models.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/django/toystore/models.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,161 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from django.db import models +from django.core.exceptions import ValidationError + + +class Company(models.Model): + name = models.CharField(max_length=100, unique=True) + + +class Store(models.Model): + name = models.CharField(max_length=100, unique=True) + company = models.ForeignKey(Company, null=False, on_delete=models.CASCADE) + + +class CharmField(models.Field): + + def db_type(self, connection): + return u'char(1)' + + +class CustomishField(models.Field): + + def db_type(self, connection): + return u'char(1)' + + +class Customish(models.Model): + customish = CustomishField() + + +class Customer(models.Model): + name = models.CharField(max_length=100, unique=True) + email = models.EmailField(max_length=100, unique=True) + gender = models.CharField(max_length=50, null=True) + age = models.IntegerField() + birthday = models.DateTimeField() + + +class Charming(models.Model): + charm = CharmField() + + +class CouldBeCharming(models.Model): + charm = CharmField(null=True) + + +class SelfLoop(models.Model): + me = models.ForeignKey(u'self', null=True, on_delete=models.SET_NULL) + + +class LoopA(models.Model): + b = models.ForeignKey(u'LoopB', null=False, on_delete=models.CASCADE) + + +class LoopB(models.Model): + a = models.ForeignKey(u'LoopA', null=True, on_delete=models.SET_NULL) + + +class ManyNumerics(models.Model): + i1 = models.IntegerField() + i2 = models.SmallIntegerField() + i3 = models.BigIntegerField() + + p1 = models.PositiveIntegerField() + p2 = models.PositiveSmallIntegerField() + + d = models.DecimalField(decimal_places=2, max_digits=5) + + +class ManyTimes(models.Model): + time = models.TimeField() + date = models.DateField() + duration = models.DurationField() + + +class OddFields(models.Model): + uuid = models.UUIDField() + slug = models.SlugField() + ipv4 = models.GenericIPAddressField(protocol='IPv4') + ipv6 = models.GenericIPAddressField(protocol='IPv6') + + +class CustomishDefault(models.Model): + customish = CustomishField(default=u'b') + + +class MandatoryComputed(models.Model): + name = models.CharField(max_length=100, unique=True) + company = models.ForeignKey(Company, null=False, on_delete=models.CASCADE) + + def __init__(self, **kw): + if u'company' in kw: + raise RuntimeError() + cname = kw[u'name'] + u'_company' + kw[u'company'] = Company.objects.create(name=cname) + super(MandatoryComputed, self).__init__(**kw) + + +def validate_even(value): + if value % 2 != 0: + raise ValidationError('') + + +class RestrictedFields(models.Model): + text_field_4 = models.TextField(max_length=4, blank=True) + char_field_4 = models.CharField(max_length=4, blank=True) + choice_field_text = models.TextField( + choices=(('foo', 'Foo'), ('bar', 'Bar')) + ) + choice_field_int = models.IntegerField( + choices=((1, 'First'), (2, 'Second')) + ) + null_choice_field_int = models.IntegerField( + choices=((1, 'First'), (2, 'Second')), + null=True, blank=True + ) + choice_field_grouped = models.TextField(choices=( + ('Audio', (('vinyl', 'Vinyl'), ('cd', 'CD'),)), + ('Video', (('vhs', 'VHS Tape'), ('dvd', 'DVD'),)), + ('unknown', 'Unknown'), + )) + even_number_field = models.IntegerField( + validators=[validate_even] + ) + non_blank_text_field = models.TextField(blank=False) + + +class SelfModifyingField(models.IntegerField): + def pre_save(self, model_instance, add): + value = getattr(model_instance, self.attname) + value += 1 + setattr(model_instance, self.attname, value) + return value + + +class CompanyExtension(models.Model): + company = models.OneToOneField( + Company, + primary_key=True, + on_delete=models.CASCADE + ) + + self_modifying = SelfModifyingField() diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/django/toystore/test_basic_configuration.py python-hypothesis-3.71.11/hypothesis-python/tests/django/toystore/test_basic_configuration.py --- python-hypothesis-3.44.1/hypothesis-python/tests/django/toystore/test_basic_configuration.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/django/toystore/test_basic_configuration.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,93 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from unittest import TestCase as VanillaTestCase + +import pytest +from django.db import IntegrityError +from django.test import TestCase as DjangoTestCase + +from hypothesis import HealthCheck, given, settings +from hypothesis.errors import InvalidArgument +from hypothesis.strategies import integers +from hypothesis.extra.django import TestCase, TransactionTestCase +from hypothesis.internal.compat import PYPY +from tests.django.toystore.models import Company + + +class SomeStuff(object): + + @settings(suppress_health_check=[HealthCheck.too_slow]) + @given(integers()) + def test_is_blank_slate(self, unused): + Company.objects.create(name=u'MickeyCo') + + def test_normal_test_1(self): + Company.objects.create(name=u'MickeyCo') + + def test_normal_test_2(self): + Company.objects.create(name=u'MickeyCo') + + +class TestConstraintsWithTransactions(SomeStuff, TestCase): + pass + + +if not PYPY: + # xfail + # This is excessively slow in general, but particularly on pypy. We just + # disable it altogether there as it's a niche case. + class TestConstraintsWithoutTransactions(SomeStuff, TransactionTestCase): + pass + + +class TestWorkflow(VanillaTestCase): + + def test_does_not_break_later_tests(self): + def break_the_db(i): + Company.objects.create(name=u'MickeyCo') + Company.objects.create(name=u'MickeyCo') + + class LocalTest(TestCase): + + @given(integers().map(break_the_db)) + @settings(suppress_health_check=HealthCheck.all()) + def test_does_not_break_other_things(self, unused): + pass + + def test_normal_test_1(self): + Company.objects.create(name=u'MickeyCo') + + t = LocalTest(u'test_normal_test_1') + try: + t.test_does_not_break_other_things() + except IntegrityError: + pass + t.test_normal_test_1() + + def test_given_needs_hypothesis_test_case(self): + + class LocalTest(DjangoTestCase): + + @given(integers()) + def tst(self, i): + assert False, 'InvalidArgument should be raised in @given' + + with pytest.raises(InvalidArgument): + LocalTest('tst').tst() diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/django/toystore/test_given_models.py python-hypothesis-3.71.11/hypothesis-python/tests/django/toystore/test_given_models.py --- python-hypothesis-3.44.1/hypothesis-python/tests/django/toystore/test_given_models.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/django/toystore/test_given_models.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,190 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import datetime as dt +from uuid import UUID + +from django.conf import settings as django_settings +from django.contrib.auth.models import User + +from hypothesis import HealthCheck, given, assume, settings +from hypothesis.errors import InvalidArgument, HypothesisException +from hypothesis.control import reject +from hypothesis.strategies import just, lists, binary +from hypothesis.extra.django import TestCase, TransactionTestCase +from hypothesis.internal.compat import text_type +from tests.django.toystore.models import Store, Company, Customer, \ + SelfLoop, Customish, ManyTimes, OddFields, ManyNumerics, \ + CustomishField, CouldBeCharming, CompanyExtension, CustomishDefault, \ + RestrictedFields, MandatoryComputed +from hypothesis.extra.django.models import models, default_value, \ + add_default_field_mapping +from hypothesis.internal.conjecture.data import ConjectureData + +add_default_field_mapping(CustomishField, just(u'a')) + + +class TestGetsBasicModels(TestCase): + + @given(models(Company)) + def test_is_company(self, company): + self.assertIsInstance(company, Company) + self.assertIsNotNone(company.pk) + + @given(models(Store, company=models(Company))) + def test_can_get_a_store(self, store): + assert store.company.pk + + @given(lists(models(Company))) + def test_can_get_multiple_models_with_unique_field(self, companies): + assume(len(companies) > 1) + for c in companies: + self.assertIsNotNone(c.pk) + self.assertEqual( + len({c.pk for c in companies}), len({c.name for c in companies}) + ) + + @settings(suppress_health_check=[HealthCheck.too_slow]) + @given(models(Customer)) + def test_is_customer(self, customer): + self.assertIsInstance(customer, Customer) + self.assertIsNotNone(customer.pk) + self.assertIsNotNone(customer.email) + + @settings(suppress_health_check=[HealthCheck.too_slow]) + @given(models(Customer)) + def test_tz_presence(self, customer): + if django_settings.USE_TZ: + self.assertIsNotNone(customer.birthday.tzinfo) + else: + self.assertIsNone(customer.birthday.tzinfo) + + @given(models(CouldBeCharming)) + def test_is_not_charming(self, not_charming): + self.assertIsInstance(not_charming, CouldBeCharming) + self.assertIsNotNone(not_charming.pk) + self.assertIsNone(not_charming.charm) + + @given(models(SelfLoop)) + def test_sl(self, sl): + self.assertIsNone(sl.me) + + @given(lists(models(ManyNumerics))) + def test_no_overflow_in_integer(self, manyints): + pass + + @given(models(Customish)) + def test_custom_field(self, x): + assert x.customish == u'a' + + def test_mandatory_fields_are_mandatory(self): + self.assertRaises(InvalidArgument, models, Store) + + def test_mandatory_computed_fields_are_mandatory(self): + self.assertRaises(InvalidArgument, models, MandatoryComputed) + + def test_mandatory_computed_fields_may_not_be_provided(self): + mc = models(MandatoryComputed, company=models(Company)) + self.assertRaises(RuntimeError, mc.example) + + @given(models(MandatoryComputed, company=default_value)) + def test_mandatory_computed_field_default(self, x): + assert x.company.name == x.name + u'_company' + + @given(models(CustomishDefault)) + def test_customish_default_generated(self, x): + assert x.customish == u'a' + + @given(models(CustomishDefault, customish=default_value)) + def test_customish_default_not_generated(self, x): + assert x.customish == u'b' + + @given(models(OddFields)) + def test_odd_fields(self, x): + assert isinstance(x.uuid, UUID) + assert isinstance(x.slug, text_type) + assert u' ' not in x.slug + assert isinstance(x.ipv4, str) + assert len(x.ipv4.split('.')) == 4 + assert all(int(i) in range(256) for i in x.ipv4.split('.')) + assert isinstance(x.ipv6, text_type) + assert set(x.ipv6).issubset(set(u'0123456789abcdefABCDEF:.')) + + @given(models(ManyTimes)) + def test_time_fields(self, x): + assert isinstance(x.time, dt.time) + assert isinstance(x.date, dt.date) + assert isinstance(x.duration, dt.timedelta) + + @given(models(Company)) + def test_no_null_in_charfield(self, x): + # regression test for #1045. Company just has a convenient CharField. + assert u'\x00' not in x.name + + @given(binary(min_size=10)) + def test_foreign_key_primary(self, buf): + # Regression test for #1307 + company_strategy = models( + Company, + name=just('test') + ) + strategy = models( + CompanyExtension, + company=company_strategy, + self_modifying=just(2) + ) + try: + ConjectureData.for_buffer(buf).draw(strategy) + except HypothesisException as e: + reject() + # Draw again with the same buffer. This will cause a duplicate + # primary key. + ConjectureData.for_buffer(buf).draw(strategy) + assert CompanyExtension.objects.all().count() == 1 + + +class TestsNeedingRollback(TransactionTestCase): + + def test_can_get_examples(self): + for _ in range(200): + models(Company).example() + + +class TestRestrictedFields(TestCase): + + @given(models(RestrictedFields)) + def test_constructs_valid_instance(self, instance): + self.assertTrue(isinstance(instance, RestrictedFields)) + instance.full_clean() + self.assertLessEqual(len(instance.text_field_4), 4) + self.assertLessEqual(len(instance.char_field_4), 4) + self.assertIn(instance.choice_field_text, ('foo', 'bar')) + self.assertIn(instance.choice_field_int, (1, 2)) + self.assertIn(instance.null_choice_field_int, (1, 2, None)) + self.assertEqual(instance.choice_field_grouped, + instance.choice_field_grouped.lower()) + self.assertEqual(instance.even_number_field % 2, 0) + self.assertTrue(instance.non_blank_text_field) + + +class TestValidatorInference(TestCase): + + @given(models(User)) + def test_user_issue_1112_regression(self, user): + assert user.username diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/django/toystore/views.py python-hypothesis-3.71.11/hypothesis-python/tests/django/toystore/views.py --- python-hypothesis-3.44.1/hypothesis-python/tests/django/toystore/views.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/django/toystore/views.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,18 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/fakefactory/__init__.py python-hypothesis-3.71.11/hypothesis-python/tests/fakefactory/__init__.py --- python-hypothesis-3.44.1/hypothesis-python/tests/fakefactory/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/fakefactory/__init__.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,16 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/fakefactory/test_fake_factory.py python-hypothesis-3.71.11/hypothesis-python/tests/fakefactory/test_fake_factory.py --- python-hypothesis-3.44.1/hypothesis-python/tests/fakefactory/test_fake_factory.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/fakefactory/test_fake_factory.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,109 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import pytest +from faker.providers import BaseProvider + +from hypothesis import given +from tests.common.debug import minimal +from tests.common.utils import checks_deprecated_behaviour +from hypothesis.extra.fakefactory import fake_factory + + +class KittenProvider(BaseProvider): + + def kittens(self): + return u'meow %d' % (self.random_number(digits=10),) + + +@checks_deprecated_behaviour +def test_kittens_meow(): + @given(fake_factory(u'kittens', providers=[KittenProvider])) + def inner(kitten): + assert u'meow' in kitten + + inner() + + +@checks_deprecated_behaviour +def test_email(): + @given(fake_factory(u'email')) + def inner(email): + assert u'@' in email + + inner() + + +@checks_deprecated_behaviour +def test_english_names_are_ascii(): + @given(fake_factory(u'name', locale=u'en_US')) + def inner(name): + name.encode(u'ascii') + + inner() + + +@checks_deprecated_behaviour +def test_french_names_may_have_an_accent(): + minimal( + fake_factory(u'name', locale=u'fr_FR'), + lambda x: u'é' not in x + ) + + +@checks_deprecated_behaviour +def test_fake_factory_errors_with_both_locale_and_locales(): + with pytest.raises(ValueError): + fake_factory( + u'name', locale=u'fr_FR', locales=[u'fr_FR', u'en_US'] + ) + + +@checks_deprecated_behaviour +def test_fake_factory_errors_with_unsupported_locale(): + with pytest.raises(ValueError): + fake_factory( + u'name', locale=u'badger_BADGER' + ) + + +@checks_deprecated_behaviour +def test_factory_errors_with_source_for_unsupported_locale(): + with pytest.raises(ValueError): + fake_factory(u'state', locale=u'ja_JP') + + +@checks_deprecated_behaviour +def test_fake_factory_errors_if_any_locale_is_unsupported(): + with pytest.raises(ValueError): + fake_factory( + u'name', locales=[u'fr_FR', u'en_US', u'mushroom_MUSHROOM'] + ) + + +@checks_deprecated_behaviour +def test_fake_factory_errors_if_unsupported_method(): + with pytest.raises(ValueError): + fake_factory(u'spoon') + + +@checks_deprecated_behaviour +def test_fake_factory_errors_if_private_ish_method(): + with pytest.raises(ValueError): + fake_factory(u'_Generator__config') diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/__init__.py python-hypothesis-3.71.11/hypothesis-python/tests/__init__.py --- python-hypothesis-3.44.1/hypothesis-python/tests/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/__init__.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,16 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/__init__.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/__init__.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/__init__.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,16 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_argument_validation.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_argument_validation.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_argument_validation.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_argument_validation.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,51 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import hypothesis.strategies as st +from tests.common.arguments import e, argument_validation_test + +BAD_ARGS = [] + + +def adjust(ex, **kwargs): + f, a, b = ex + b = dict(b) + b.update(kwargs) + BAD_ARGS.append((f, a, b)) + + +for ex in [ + e(st.lists, st.integers()), + e(st.sets, st.integers()), + e(st.frozensets, st.integers()), + e(st.dictionaries, st.integers(), st.integers()), + e(st.text), + e(st.binary) +]: + adjust(ex, min_size=-1) + adjust(ex, max_size=-1) + adjust(ex, min_size='no') + adjust(ex, max_size='no') + + +BAD_ARGS.extend([ + e(st.lists, st.nothing(), unique=True, min_size=1), +]) + +test_raise_invalid_argument = argument_validation_test(BAD_ARGS) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_bad_repr.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_bad_repr.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_bad_repr.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_bad_repr.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,67 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import pytest + +import hypothesis.strategies as st +from hypothesis import given +from hypothesis.internal.compat import PY3 +from hypothesis.internal.reflection import arg_string + + +class BadRepr(object): + + def __init__(self, value): + self.value = value + + def __repr__(self): + return self.value + + +Frosty = BadRepr('☃') + + +def test_just_frosty(): + assert repr(st.just(Frosty)) == 'just(☃)' + + +def test_sampling_snowmen(): + assert repr(st.sampled_from(( + Frosty, 'hi'))) == 'sampled_from((☃, %s))' % (repr('hi'),) + + +def varargs(*args, **kwargs): + pass + + +@pytest.mark.skipif(PY3, reason='Unicode repr is kosher on python 3') +def test_arg_strings_are_bad_repr_safe(): + assert arg_string(varargs, (Frosty,), {}) == '☃' + + +@pytest.mark.skipif(PY3, reason='Unicode repr is kosher on python 3') +def test_arg_string_kwargs_are_bad_repr_safe(): + assert arg_string(varargs, (), {'x': Frosty}) == 'x=☃' + + +@given(st.sampled_from([ + '✐', '✑', '✒', '✓', '✔', '✕', '✖', '✗', '✘', + '✙', '✚', '✛', '✜', '✝', '✞', '✟', '✠', '✡', '✢', '✣'])) +def test_sampled_from_bad_repr(c): + pass diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_boundary_exploration.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_boundary_exploration.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_boundary_exploration.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_boundary_exploration.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,53 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import pytest + +import hypothesis.strategies as st +from hypothesis import Verbosity, HealthCheck, find, given, reject, \ + settings, unlimited +from hypothesis.errors import NoSuchExample +from tests.common.utils import no_shrink + + +@pytest.mark.parametrize('strat', [st.text(min_size=5)]) +@settings( + phases=no_shrink, deadline=None, + suppress_health_check=HealthCheck.all() +) +@given(st.data()) +def test_explore_arbitrary_function(strat, data): + cache = {} + + def predicate(x): + try: + return cache[x] + except KeyError: + return cache.setdefault(x, data.draw(st.booleans(), label=repr(x))) + + try: + find( + strat, predicate, + settings=settings( + max_examples=10, database=None, timeout=unlimited, + verbosity=Verbosity.quiet, + ) + ) + except NoSuchExample: + reject() diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_cacheable.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_cacheable.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_cacheable.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_cacheable.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,51 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import pytest + +import hypothesis.strategies as st + + +@pytest.mark.parametrize('s', [ + st.floats(), + st.tuples(st.integers()), + st.tuples(), + st.one_of(st.integers(), st.text()), +]) +def test_is_cacheable(s): + assert s.is_cacheable + + +@pytest.mark.parametrize('s', [ + st.just([]), + st.tuples(st.integers(), st.just([])), + st.one_of(st.integers(), st.text(), st.just([])), +]) +def test_is_not_cacheable(s): + assert not s.is_cacheable + + +def test_non_cacheable_things_are_not_cached(): + x = st.just([]) + assert st.tuples(x) != st.tuples(x) + + +def test_cacheable_things_are_cached(): + x = st.just(()) + assert st.tuples(x) == st.tuples(x) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_characters.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_characters.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_characters.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_characters.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,45 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import string + +from hypothesis import given +from hypothesis import strategies as st + +IDENTIFIER_CHARS = string.ascii_letters + string.digits + '_' + + +@given(st.characters(blacklist_characters=IDENTIFIER_CHARS)) +def test_large_blacklist(c): + assert c not in IDENTIFIER_CHARS + + +@given(st.data()) +def test_arbitrary_blacklist(data): + blacklist = data.draw( + st.text(st.characters(max_codepoint=1000), min_size=1)) + ords = list(map(ord, blacklist)) + c = data.draw( + st.characters( + blacklist_characters=blacklist, + min_codepoint=max(0, min(ords) - 1), + max_codepoint=max(0, max(ords) + 1), + ) + ) + assert c not in blacklist diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_choices.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_choices.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_choices.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_choices.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,55 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import hypothesis.strategies as st +from hypothesis import given, settings, unlimited +from tests.common.utils import raises, capture_out, \ + checks_deprecated_behaviour +from hypothesis.database import ExampleDatabase +from hypothesis.internal.compat import hrange + + +@checks_deprecated_behaviour +def test_stability(): + @given( + st.lists(st.integers(0, 1000), unique=True, min_size=5), + st.choices(), + ) + @settings( + database=ExampleDatabase(), max_shrinks=10**6, timeout=unlimited, + ) + def test_choose_and_then_fail(ls, choice): + for _ in hrange(100): + choice(ls) + assert False + + # Run once first for easier debugging + with raises(AssertionError): + test_choose_and_then_fail() + + with capture_out() as o: + with raises(AssertionError): + test_choose_and_then_fail() + out1 = o.getvalue() + with capture_out() as o: + with raises(AssertionError): + test_choose_and_then_fail() + out2 = o.getvalue() + assert out1 == out2 + assert 'Choice #100:' in out1 diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_collective_minimization.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_collective_minimization.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_collective_minimization.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_collective_minimization.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,55 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import pytest +from flaky import flaky + +from hypothesis import settings +from tests.common import standard_types +from hypothesis.errors import NoSuchExample +from tests.common.debug import minimal +from hypothesis.strategies import lists + + +@pytest.mark.parametrize( + u'spec', standard_types, ids=list(map(repr, standard_types))) +@flaky(min_passes=1, max_runs=2) +def test_can_collectively_minimize(spec): + """This should generally exercise strategies' strictly_simpler heuristic by + putting us in a state where example cloning is required to get to the + answer fast enough.""" + n = 10 + + def distinct_reprs(x): + result = set() + for t in x: + result.add(repr(t)) + if len(result) >= 2: + return True + return False + + try: + xs = minimal( + lists(spec, min_size=n, max_size=n), + distinct_reprs, + settings=settings(max_examples=2000)) + assert len(xs) == n + assert 2 <= len(set((map(repr, xs)))) <= 3 + except NoSuchExample: + pass diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_compat.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_compat.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_compat.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_compat.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,138 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import inspect +import warnings + +import pytest + +from hypothesis import given +from hypothesis import strategies as st +from hypothesis.internal.compat import FullArgSpec, ceil, floor, hrange, \ + qualname, int_to_bytes, integer_types, getfullargspec, \ + int_from_bytes + + +def test_small_hrange(): + assert list(hrange(5)) == [0, 1, 2, 3, 4] + assert list(hrange(3, 5)) == [3, 4] + assert list(hrange(1, 10, 2)) == [1, 3, 5, 7, 9] + + +def test_large_hrange(): + n = 1 << 1024 + assert list(hrange(n, n + 5, 2)) == [n, n + 2, n + 4] + assert list(hrange(n, n)) == [] + + with pytest.raises(ValueError): + hrange(n, n, 0) + + +class Foo(): + + def bar(self): + pass + + +def test_qualname(): + assert qualname(Foo.bar) == u'Foo.bar' + assert qualname(Foo().bar) == u'Foo.bar' + assert qualname(qualname) == u'qualname' + + +def a(b, c, d): + pass + + +def b(c, d, *ar): + pass + + +def c(c, d, *ar, **k): + pass + + +def d(a1, a2=1, a3=2, a4=None): + pass + + +@pytest.mark.parametrize('f', [a, b, c, d]) +def test_agrees_on_argspec(f): + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + basic = inspect.getargspec(f) + full = getfullargspec(f) + assert basic.args == full.args + assert basic.varargs == full.varargs + assert basic.keywords == full.varkw + assert basic.defaults == full.defaults + + +@given(st.binary()) +def test_convert_back(bs): + bs = bytearray(bs) + assert int_to_bytes(int_from_bytes(bs), len(bs)) == bs + + +bytes8 = st.builds(bytearray, st.binary(min_size=8, max_size=8)) + + +@given(bytes8, bytes8) +def test_to_int_in_big_endian_order(x, y): + x, y = sorted((x, y)) + assert 0 <= int_from_bytes(x) <= int_from_bytes(y) + + +ints8 = st.integers(min_value=0, max_value=2 ** 63 - 1) + + +@given(ints8, ints8) +def test_to_bytes_in_big_endian_order(x, y): + x, y = sorted((x, y)) + assert int_to_bytes(x, 8) <= int_to_bytes(y, 8) + + +@pytest.mark.skipif(not hasattr(inspect, 'getfullargspec'), + reason='inspect.getfullargspec only exists under Python 3') +def test_inspection_compat(): + assert getfullargspec is inspect.getfullargspec + + +@pytest.mark.skipif(not hasattr(inspect, 'FullArgSpec'), + reason='inspect.FullArgSpec only exists under Python 3') +def test_inspection_result_compat(): + assert FullArgSpec is inspect.FullArgSpec + + +@given(st.fractions()) +def test_ceil(x): + """The compat ceil function always has the Python 3 semantics. + + Under Python 2, math.ceil returns a float, which cannot represent large + integers - for example, `float(2**53) == float(2**53 + 1)` - and this + is obviously incorrect for unlimited-precision integer operations. + """ + assert isinstance(ceil(x), integer_types) + assert x <= ceil(x) < x + 1 + + +@given(st.fractions()) +def test_floor(x): + assert isinstance(floor(x), integer_types) + assert x - 1 < floor(x) <= x diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_completion.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_completion.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_completion.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_completion.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,26 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from hypothesis import given +from hypothesis import strategies as st + + +@given(st.data()) +def test_never_draw_anything(data): + pass diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_conjecture_engine.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_conjecture_engine.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_conjecture_engine.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_conjecture_engine.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,309 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from random import Random + +import pytest + +from hypothesis import HealthCheck, given, settings +from hypothesis import strategies as st +from tests.common.utils import no_shrink, non_covering_examples +from hypothesis.database import InMemoryExampleDatabase +from hypothesis.internal.compat import hbytes, hrange, int_from_bytes +from tests.cover.test_conjecture_engine import shrink, run_to_buffer, \ + shrinking_from +from hypothesis.internal.conjecture.data import Status, ConjectureData +from hypothesis.internal.conjecture.engine import RunIsComplete, \ + ConjectureRunner + + +def test_lot_of_dead_nodes(): + @run_to_buffer + def x(data): + for i in range(4): + if data.draw_bytes(1)[0] != i: + data.mark_invalid() + data.mark_interesting() + assert x == hbytes([0, 1, 2, 3]) + + +def test_saves_data_while_shrinking(monkeypatch): + key = b'hi there' + n = 5 + db = InMemoryExampleDatabase() + assert list(db.fetch(key)) == [] + seen = set() + + monkeypatch.setattr( + ConjectureRunner, 'generate_new_examples', + lambda runner: runner.test_function( + ConjectureData.for_buffer([255] * 10))) + + def f(data): + x = data.draw_bytes(10) + if sum(x) >= 2000 and len(seen) < n: + seen.add(hbytes(x)) + if hbytes(x) in seen: + data.mark_interesting() + runner = ConjectureRunner( + f, settings=settings(database=db), database_key=key) + runner.run() + assert runner.interesting_examples + assert len(seen) == n + in_db = non_covering_examples(db) + assert in_db.issubset(seen) + assert in_db == seen + + +@given(st.randoms(), st.random_module()) +@settings( + phases=no_shrink, deadline=None, + suppress_health_check=[HealthCheck.hung_test] +) +def test_maliciously_bad_generator(rnd, seed): + @run_to_buffer + def x(data): + for _ in range(rnd.randint(1, 100)): + data.draw_bytes(rnd.randint(1, 10)) + if rnd.randint(0, 1): + data.mark_invalid() + else: + data.mark_interesting() + + +def test_can_discard(monkeypatch): + n = 8 + + monkeypatch.setattr( + ConjectureRunner, 'generate_new_examples', + lambda runner: runner.test_function( + ConjectureData.for_buffer([ + v for i in range(n) for v in [i, i] + ]))) + + @run_to_buffer + def x(data): + seen = set() + while len(seen) < n: + seen.add(hbytes(data.draw_bytes(1))) + data.mark_interesting() + assert len(x) == n + + +def test_exhaustive_enumeration_of_partial_buffer(): + seen = set() + + def f(data): + k = data.draw_bytes(2) + assert k[1] == 0 + assert k not in seen + seen.add(k) + + seen_prefixes = set() + + runner = ConjectureRunner( + f, settings=settings(database=None, max_examples=256, buffer_size=2), + random=Random(0), + ) + with pytest.raises(RunIsComplete): + runner.cached_test_function(b'') + for _ in hrange(256): + p = runner.generate_novel_prefix() + assert p not in seen_prefixes + seen_prefixes.add(p) + data = ConjectureData.for_buffer(hbytes(p + hbytes(2))) + runner.test_function(data) + assert data.status == Status.VALID + node = 0 + for b in data.buffer: + node = runner.tree[node][b] + assert node in runner.dead + assert len(seen) == 256 + + +def test_regression_1(): + # This is a really hard to reproduce bug that previously triggered a very + # specific exception inside one of the shrink passes. It's unclear how + # useful this regression test really is, but nothing else caught the + # problem. + @run_to_buffer + def x(data): + data.write(hbytes(b'\x01\x02')) + data.write(hbytes(b'\x01\x00')) + v = data.draw_bits(41) + if v >= 512 or v == 254: + data.mark_interesting() + assert list(x)[:-2] == [1, 2, 1, 0, 0, 0, 0, 0] + + assert int_from_bytes(x[-2:]) in (254, 512) + + +def test_shrink_offset_pairs_handles_block_structure_change(): + """Regression test for a rare error in ``shrink_offset_pairs``. + + This test should run without raising an ``IndexError`` in the + shrinker. + """ + + @shrink([235, 0, 0, 255], 'shrink_offset_pairs') + def f(data): + x = data.draw_bytes(1)[0] + + # Change the block structure in response to a shrink improvement, + # to trigger the bug. + if x == 10: + data.draw_bytes(1) + data.draw_bytes(1) + else: + data.draw_bytes(2) + + y = data.draw_bytes(1)[0] + + # Require the target blocks to be non-trivial and have a fixed + # difference, so that the intended shrinker pass is used. + if x >= 10 and y - x == 20: + data.mark_interesting() + + assert f == [10, 0, 0, 30] + + +def test_retaining_sum_considers_zero_destination_blocks(): + """Explicitly test that this shrink pass will try to move data into blocks + that are currently all-zero.""" + @shrink([100, 0, 0], 'minimize_block_pairs_retaining_sum') + def f(data): + x = data.draw_bytes(1)[0] + data.draw_bytes(1) + y = data.draw_bytes(1)[0] + + if x >= 10 and (x + y) == 100: + data.mark_interesting() + + assert f == [10, 0, 90] + + +@given(st.integers(0, 255), st.integers(0, 255)) +def test_prescreen_with_masked_byte_agrees_with_results(byte_a, byte_b): + def f(data): + data.draw_bits(2) + + runner = ConjectureRunner(f) + + data_a = ConjectureData.for_buffer(hbytes([byte_a])) + data_b = ConjectureData.for_buffer(hbytes([byte_b])) + + runner.test_function(data_a) + prescreen_b = runner.prescreen_buffer(hbytes([byte_b])) + # Always test buffer B, to check whether the prescreen was correct. + runner.test_function(data_b) + + # If the prescreen passed, then the buffers should be different. + # If it failed, then the buffers should be the same. + assert prescreen_b == (data_a.buffer != data_b.buffer) + + +@given(st.integers(0, 255), st.integers(0, 255)) +def test_cached_with_masked_byte_agrees_with_results(byte_a, byte_b): + def f(data): + data.draw_bits(2) + + runner = ConjectureRunner(f) + + cached_a = runner.cached_test_function(hbytes([byte_a])) + cached_b = runner.cached_test_function(hbytes([byte_b])) + + data_b = ConjectureData.for_buffer(hbytes([byte_b])) + runner.test_function(data_b) + + # If the cache found an old result, then it should match the real result. + # If it did not, then it must be because A and B were different. + assert (cached_a is cached_b) == (cached_a.buffer == data_b.buffer) + + +def test_each_pair_of_blocks(): + initial = hbytes([1, 1, 1]) + + @shrinking_from(initial) + def shrinker(data): + data.draw_bits(1) + data.draw_bits(1) + data.draw_bits(1) + data.mark_interesting() + + bounds = [ + (a.bounds, b.bounds) for a, b in shrinker.each_pair_of_blocks( + lambda block: True, + lambda block: True, + ) + ] + + assert bounds == [ + ((0, 1), (1, 2)), + ((0, 1), (2, 3)), + ((1, 2), (2, 3)), + ] + + +def test_each_pair_of_blocks_with_filters(): + initial = hbytes(5) + + @shrinking_from(initial) + def shrinker(data): + for x in range(5): + data.draw_bits(1) + data.mark_interesting() + + blocks = [ + (a.index, b.index) for a, b in shrinker.each_pair_of_blocks( + lambda block: block.index != 1, + lambda block: block.index != 3, + ) + ] + + assert blocks == [ + (0, 1), (0, 2), (0, 4), + (2, 4), + (3, 4), + ] + + +def test_each_pair_of_blocks_handles_change(): + initial = hbytes([9] + [0] * 10) + + @shrinking_from(initial) + def shrinker(data): + x = data.draw_bits(8) + for y in range(x): + data.draw_bits(1) + data.mark_interesting() + + blocks = [] + for a, b in shrinker.each_pair_of_blocks( + lambda block: True, + lambda block: True, + ): + if a.index == 0 and b.index == 6: + shrinker.incorporate_new_buffer(hbytes([3] + [0] * 10)) + blocks.append((a.index, b.index)) + + assert blocks == [ + (0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (0, 6), + (1, 2), (1, 3), + (2, 3), + ] diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_conjecture_length_shrinking.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_conjecture_length_shrinking.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_conjecture_length_shrinking.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_conjecture_length_shrinking.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,40 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from random import Random + +import hypothesis.strategies as st +from hypothesis import given, example +from hypothesis.internal.conjecture.shrinking import Length + +sizes = st.integers(0, 100) + + +@example(m=0, n=1) +@given(sizes, sizes) +def test_shrinks_down_to_size(m, n): + m, n = sorted((m, n)) + assert Length.shrink( + [0] * n + [1], lambda ls: len(ls) >= m + 1 and ls[-1] == 1, + random=Random(0) + ) == (0,) * m + (1,) + + +def test_will_shrink_to_zero(): + assert Length.shrink([1], lambda x: True, random=Random(0)) == () diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_conjecture_utils.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_conjecture_utils.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_conjecture_utils.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_conjecture_utils.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,50 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from fractions import Fraction + +import hypothesis.internal.conjecture.utils as cu +from hypothesis.internal.compat import int_to_bytes +from hypothesis.internal.conjecture.data import StopTest, ConjectureData + + +def test_gives_the_correct_probabilities(): + weights = [Fraction(1), Fraction(9)] + total = sum(weights) + probabilities = [w / total for w in weights] + + sampler = cu.Sampler(probabilities) + + assert cu.Sampler(weights).table == sampler.table + + counts = [0] * len(weights) + + i = 0 + while i < 2 ** 16: + data = ConjectureData.for_buffer(int_to_bytes(i, 2)) + try: + c = sampler.sample(data) + counts[c] += 1 + assert probabilities[c] >= Fraction(counts[c], 2 ** 16) + except StopTest: + pass + if 1 in data.forced_indices: + i += 256 + else: + i += 1 diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_conventions.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_conventions.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_conventions.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_conventions.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,24 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from hypothesis.utils.conventions import UniqueIdentifier + + +def test_unique_identifier_repr(): + assert repr(UniqueIdentifier(u'hello_world')) == u'hello_world' diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_database_agreement.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_database_agreement.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_database_agreement.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_database_agreement.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,90 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import os +import shutil +import tempfile + +import hypothesis.strategies as st +from tests.common.utils import validate_deprecation +from hypothesis.database import SQLiteExampleDatabase, \ + InMemoryExampleDatabase, DirectoryBasedExampleDatabase +from hypothesis.stateful import Bundle, RuleBasedStateMachine, rule + + +class DatabaseComparison(RuleBasedStateMachine): + + def __init__(self): + super(DatabaseComparison, self).__init__() + self.tempd = tempfile.mkdtemp() + exampledir = os.path.join(self.tempd, 'examples') + + self.dbs = [ + DirectoryBasedExampleDatabase(exampledir), + InMemoryExampleDatabase(), + DirectoryBasedExampleDatabase(exampledir), + ] + + with validate_deprecation(): + self.dbs.append(SQLiteExampleDatabase(':memory:')) + + keys = Bundle('keys') + values = Bundle('values') + + @rule(target=keys, k=st.binary()) + def k(self, k): + return k + + @rule(target=values, v=st.binary()) + def v(self, v): + return v + + @rule(k=keys, v=values) + def save(self, k, v): + for db in self.dbs: + db.save(k, v) + + @rule(k=keys, v=values) + def delete(self, k, v): + for db in self.dbs: + db.delete(k, v) + + @rule(k1=keys, k2=keys, v=values) + def move(self, k1, k2, v): + for db in self.dbs: + db.move(k1, k2, v) + + @rule(k=keys) + def values_agree(self, k): + last = None + last_db = None + for db in self.dbs: + keys = set(db.fetch(k)) + if last is not None: + assert last == keys, (last_db, db) + last = keys + last_db = db + + def teardown(self): + for d in self.dbs: + d.close() + shutil.rmtree(self.tempd) + + +TestDBs = DatabaseComparison.TestCase diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_database_usage.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_database_usage.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_database_usage.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_database_usage.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,133 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import hypothesis.strategies as st +from hypothesis import core, find, given, assume, settings +from hypothesis.errors import NoSuchExample, Unsatisfiable +from tests.common.utils import all_values, non_covering_examples +from hypothesis.database import InMemoryExampleDatabase +from hypothesis.internal.compat import hbytes + + +def has_a_non_zero_byte(x): + return any(hbytes(x)) + + +def test_saves_incremental_steps_in_database(): + key = b'a database key' + database = InMemoryExampleDatabase() + find( + st.binary(min_size=10), lambda x: has_a_non_zero_byte(x), + settings=settings(database=database), database_key=key + ) + assert len(all_values(database)) > 1 + + +def test_clears_out_database_as_things_get_boring(): + key = b'a database key' + database = InMemoryExampleDatabase() + do_we_care = True + + def stuff(): + try: + find( + st.binary(min_size=50), + lambda x: do_we_care and has_a_non_zero_byte(x), + settings=settings(database=database, max_examples=10), + database_key=key + ) + except NoSuchExample: + pass + stuff() + assert len(non_covering_examples(database)) > 1 + do_we_care = False + stuff() + initial = len(non_covering_examples(database)) + assert initial > 0 + + for _ in range(initial): + stuff() + keys = len(non_covering_examples(database)) + if not keys: + break + else: + assert False + + +def test_trashes_invalid_examples(): + key = b'a database key' + database = InMemoryExampleDatabase() + finicky = False + + def stuff(): + try: + find( + st.binary(min_size=100), + lambda x: assume(not finicky) and has_a_non_zero_byte(x), + settings=settings(database=database), + database_key=key + ) + except Unsatisfiable: + pass + stuff() + original = len(all_values(database)) + assert original > 1 + finicky = True + stuff() + assert len(all_values(database)) < original + + +def test_respects_max_examples_in_database_usage(): + key = b'a database key' + database = InMemoryExampleDatabase() + do_we_care = True + counter = [0] + + def check(x): + counter[0] += 1 + return do_we_care and has_a_non_zero_byte(x) + + def stuff(): + try: + find( + st.binary(min_size=100), check, + settings=settings(database=database, max_examples=10), + database_key=key + ) + except NoSuchExample: + pass + stuff() + assert len(all_values(database)) > 10 + do_we_care = False + counter[0] = 0 + stuff() + assert counter == [10] + + +def test_does_not_use_database_when_seed_is_forced(monkeypatch): + monkeypatch.setattr(core, 'global_force_seed', 42) + database = InMemoryExampleDatabase() + database.fetch = None + + @settings(database=database) + @given(st.integers()) + def test(i): + pass + + test() diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_deferred_errors.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_deferred_errors.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_deferred_errors.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_deferred_errors.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,74 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import pytest + +import hypothesis.strategies as st +from hypothesis import find, given +from hypothesis.errors import InvalidArgument + + +def test_does_not_error_on_initial_calculation(): + st.floats(max_value=float('nan')) + st.sampled_from([]) + st.lists(st.integers(), min_size=5, max_size=2) + st.floats(min_value=2.0, max_value=1.0) + + +def test_errors_each_time(): + s = st.integers(max_value=1, min_value=3) + with pytest.raises(InvalidArgument): + s.example() + with pytest.raises(InvalidArgument): + s.example() + + +def test_errors_on_test_invocation(): + @given(st.integers(max_value=1, min_value=3)) + def test(x): + pass + with pytest.raises(InvalidArgument): + test() + + +def test_errors_on_find(): + s = st.lists(st.integers(), min_size=5, max_size=2) + with pytest.raises(InvalidArgument): + find(s, lambda x: True) + + +def test_errors_on_example(): + s = st.floats(min_value=2.0, max_value=1.0) + with pytest.raises(InvalidArgument): + s.example() + + +def test_does_not_recalculate_the_strategy(): + calls = [0] + + @st.defines_strategy + def foo(): + calls[0] += 1 + return st.just(1) + f = foo() + assert calls == [0] + f.example() + assert calls == [1] + f.example() + assert calls == [1] diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_duplication.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_duplication.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_duplication.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_duplication.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,70 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from collections import Counter + +import pytest + +from hypothesis import given, settings +from hypothesis.searchstrategy import SearchStrategy + + +class Blocks(SearchStrategy): + def __init__(self, n): + self.n = n + + def do_draw(self, data): + return data.draw_bytes(self.n) + + +@pytest.mark.parametrize('n', range(1, 5)) +def test_does_not_duplicate_blocks(n): + counts = Counter() + + @given(Blocks(n)) + @settings(database=None) + def test(b): + counts[b] += 1 + test() + assert set(counts.values()) == {1} + + +@pytest.mark.parametrize('n', range(1, 5)) +def test_mostly_does_not_duplicate_blocks_even_when_failing(n): + counts = Counter() + + @settings(database=None) + @given(Blocks(n)) + def test(b): + counts[b] += 1 + if len(counts) > 3: + raise ValueError() + try: + test() + except ValueError: + pass + # There are two circumstances in which a duplicate is allowed: We replay + # the failing test once to check for flakiness, and then we replay the + # fully minimized failing test at the end to display the error. The + # complication comes from the fact that these may or may not be the same + # test case, so we can see either two test cases each run twice or one + # test case which has been run three times. + seen_counts = set(counts.values()) + assert seen_counts in ({1, 2}, {1, 3}) + assert len([k for k, v in counts.items() if v > 1]) <= 2 diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_dynamic_variable.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_dynamic_variable.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_dynamic_variable.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_dynamic_variable.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,38 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from hypothesis.utils.dynamicvariables import DynamicVariable + + +def test_can_assign(): + d = DynamicVariable(1) + assert d.value == 1 + with d.with_value(2): + assert d.value == 2 + assert d.value == 1 + + +def test_can_nest(): + d = DynamicVariable(1) + with d.with_value(2): + assert d.value == 2 + with d.with_value(3): + assert d.value == 3 + assert d.value == 2 + assert d.value == 1 diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_emails.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_emails.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_emails.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_emails.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,29 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from hypothesis import given +from hypothesis.strategies import emails + + +@given(emails()) +def test_is_valid_email(address): + local, at_, domain = address.rpartition('@') + assert at_ == '@' + assert local + assert domain diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_eval_as_source.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_eval_as_source.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_eval_as_source.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_eval_as_source.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,43 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from hypothesis.internal.reflection import source_exec_as_module + + +def test_can_eval_as_source(): + assert source_exec_as_module('foo=1').foo == 1 + + +def test_caches(): + x = source_exec_as_module('foo=2') + y = source_exec_as_module('foo=2') + assert x is y + + +RECURSIVE = """ +from hypothesis.internal.reflection import source_exec_as_module + +def test_recurse(): + assert not ( + source_exec_as_module("too_much_recursion = False").too_much_recursion) +""" + + +def test_can_call_self_recursively(): + source_exec_as_module(RECURSIVE).test_recurse() diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_explore_arbitrary_languages.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_explore_arbitrary_languages.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_explore_arbitrary_languages.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_explore_arbitrary_languages.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,144 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import random + +import attr +import pytest + +import hypothesis.strategies as st +import hypothesis.internal.escalation as esc +from hypothesis import Phase, Verbosity, HealthCheck, note, given, \ + assume, settings, unlimited +from hypothesis.internal.compat import hbytes +from hypothesis.internal.conjecture.data import Status +from hypothesis.internal.conjecture.engine import ConjectureRunner + + +def setup_module(module): + esc.PREVENT_ESCALATION = True + + +def teardown_module(module): + esc.PREVENT_ESCALATION = False + + +@attr.s() +class Write(object): + value = attr.ib() + child = attr.ib() + + +@attr.s() +class Branch(object): + bits = attr.ib() + children = attr.ib(default=attr.Factory(dict)) + + +@attr.s() +class Terminal(object): + status = attr.ib() + payload = attr.ib(default=None) + + +nodes = st.deferred(lambda: terminals | writes | branches) + + +# Does not include Status.OVERFLOW by design: That happens because of the size +# of the string, not the input language. +terminals = st.one_of( + st.just(Terminal(Status.VALID)), st.just(Terminal(Status.INVALID)), + st.builds( + Terminal, status=st.just(Status.INTERESTING), + payload=st.integers(0, 10) + ) +) + +branches = st.builds(Branch, bits=st.integers(1, 64)) + +writes = st.builds( + Write, value=st.binary(min_size=1), child=nodes +) + + +def run_language_test_for(root, data, seed): + random.seed(seed) + + def test(local_data): + node = root + while not isinstance(node, Terminal): + if isinstance(node, Write): + local_data.write(hbytes(node.value)) + node = node.child + else: + assert isinstance(node, Branch) + c = local_data.draw_bits(node.bits) + try: + node = node.children[c] + except KeyError: + if data is None: + return + node = node.children.setdefault(c, data.draw(nodes)) + assert isinstance(node, Terminal) + if node.status == Status.INTERESTING: + local_data.mark_interesting(node.payload) + elif node.status == Status.INVALID: + local_data.mark_invalid() + + runner = ConjectureRunner(test, settings=settings( + max_examples=1, max_shrinks=100, buffer_size=512, + database=None, suppress_health_check=HealthCheck.all(), + verbosity=Verbosity.quiet, phases=list(Phase), + )) + try: + runner.run() + finally: + if data is not None: + note(root) + assume(runner.interesting_examples) + + +@settings( + max_examples=100, suppress_health_check=HealthCheck.all(), + deadline=None, timeout=unlimited, + phases=set(Phase) - {Phase.shrink}, +) +@given(st.data()) +def test_explore_an_arbitrary_language(data): + root = data.draw(writes | branches) + seed = data.draw(st.integers(0, 2 ** 64 - 1)) + run_language_test_for(root, data, seed) + + +@pytest.mark.parametrize( + 'seed, language', [ + ] +) +def test_run_specific_example(seed, language): + """This test recreates individual languages generated with the main test. + + These are typically manually pruned down a bit - e.g. it's + OK to remove VALID nodes because KeyError is treated as if it lead to one + in this test (but not in the @given test). + + These tests are likely to be fairly fragile with respect to changes in the + underlying engine. Feel free to delete examples if they start failing after + a change. + """ + run_language_test_for(language, None, seed) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_fancy_repr.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_fancy_repr.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_fancy_repr.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_fancy_repr.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,53 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import hypothesis.strategies as st + + +def test_floats_is_floats(): + assert repr(st.floats()) == u'floats()' + + +def test_includes_non_default_values(): + assert repr(st.floats(max_value=1.0)) == u'floats(max_value=1.0)' + + +def foo(*args, **kwargs): + pass + + +def test_builds_repr(): + assert repr(st.builds(foo, st.just(1), x=st.just(10))) == \ + u'builds(foo, just(1), x=just(10))' + + +def test_map_repr(): + assert repr(st.integers().map(abs)) == u'integers().map(abs)' + assert repr(st.integers().map(lambda x: x * 2)) == \ + u'integers().map(lambda x: x * 2)' + + +def test_filter_repr(): + assert repr(st.integers().filter(lambda x: x != 3)) == \ + u'integers().filter(lambda x: x != 3)' + + +def test_flatmap_repr(): + assert repr(st.integers().flatmap(lambda x: st.booleans())) == \ + u'integers().flatmap(lambda x: st.booleans())' diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_filtering.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_filtering.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_filtering.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_filtering.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,35 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import pytest + +from hypothesis import given +from hypothesis.strategies import lists, integers + + +@pytest.mark.parametrize((u'specifier', u'condition'), [ + (integers(), lambda x: x > 1), + (lists(integers()), bool), +]) +def test_filter_correctly(specifier, condition): + @given(specifier.filter(condition)) + def test_is_filtered(x): + assert condition(x) + + test_is_filtered() diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_find.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_find.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_find.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_find.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,75 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import math + +import pytest + +from hypothesis import find +from hypothesis import settings as Settings +from hypothesis.errors import NoSuchExample +from tests.common.debug import minimal +from hypothesis.strategies import lists, floats, booleans, integers, \ + dictionaries + + +def test_can_find_an_int(): + assert minimal(integers(), lambda x: True) == 0 + assert minimal(integers(), lambda x: x >= 13) == 13 + + +def test_can_find_list(): + x = minimal(lists(integers()), lambda x: sum(x) >= 10) + assert sum(x) == 10 + + +def test_can_find_nan(): + minimal(floats(), math.isnan) + + +def test_can_find_nans(): + x = minimal(lists(floats()), lambda x: math.isnan(sum(x))) + if len(x) == 1: + assert math.isnan(x[0]) + else: + assert 2 <= len(x) <= 3 + + +def test_condition_is_name(): + settings = Settings(max_examples=20) + with pytest.raises(NoSuchExample) as e: + find(booleans(), lambda x: False, settings=settings) + assert 'lambda x:' in e.value.args[0] + + with pytest.raises(NoSuchExample) as e: + find(integers(), lambda x: '☃' in str(x), settings=settings) + assert 'lambda x:' in e.value.args[0] + + def bad(x): + return False + + with pytest.raises(NoSuchExample) as e: + find(integers(), bad, settings=settings) + assert 'bad' in e.value.args[0] + + +def test_find_dictionary(): + assert len(minimal( + dictionaries(keys=integers(), values=integers()), + lambda xs: any(kv[0] > kv[1] for kv in xs.items()))) == 1 diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_fixtures.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_fixtures.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_fixtures.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_fixtures.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,30 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import time + +from tests.common import TIME_INCREMENT + + +def test_time_consistently_increments_in_tests(): + x = time.time() + y = time.time() + z = time.time() + assert y == x + TIME_INCREMENT + assert z == y + TIME_INCREMENT diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_flatmap.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_flatmap.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_flatmap.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_flatmap.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,120 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import pytest + +from hypothesis import given, assume, settings +from tests.common.debug import minimal +from hypothesis.database import ExampleDatabase +from hypothesis.strategies import just, text, lists, builds, floats, \ + tuples, booleans, integers +from hypothesis.internal.compat import Counter + +ConstantLists = integers().flatmap(lambda i: lists(just(i))) + +OrderedPairs = integers(1, 200).flatmap( + lambda e: tuples(integers(0, e - 1), just(e)) +) + + +@settings(max_examples=100) +@given(ConstantLists) +def test_constant_lists_are_constant(x): + assume(len(x) >= 3) + assert len(set(x)) == 1 + + +@settings(max_examples=100) +@given(OrderedPairs) +def test_in_order(x): + assert x[0] < x[1] + + +def test_flatmap_retrieve_from_db(): + constant_float_lists = floats(0, 1).flatmap( + lambda x: lists(just(x)) + ) + + track = [] + + db = ExampleDatabase() + + @given(constant_float_lists) + @settings(database=db) + def record_and_test_size(xs): + if sum(xs) >= 1: + track.append(xs) + assert False + + with pytest.raises(AssertionError): + record_and_test_size() + + assert track + example = track[-1] + track = [] + + with pytest.raises(AssertionError): + record_and_test_size() + + assert track[0] == example + + +def test_flatmap_does_not_reuse_strategies(): + s = builds(list).flatmap(just) + assert s.example() is not s.example() + + +def test_flatmap_has_original_strategy_repr(): + ints = integers() + ints_up = ints.flatmap(lambda n: integers(min_value=n)) + assert repr(ints) in repr(ints_up) + + +def test_mixed_list_flatmap(): + s = lists( + booleans().flatmap(lambda b: booleans() if b else text()) + ) + + def criterion(ls): + c = Counter(type(l) for l in ls) + return len(c) >= 2 and min(c.values()) >= 3 + + result = minimal(s, criterion) + assert len(result) == 6 + assert set(result) == set([False, u'']) + + +@pytest.mark.parametrize('n', range(1, 10)) +def test_can_shrink_through_a_binding(n): + bool_lists = integers(0, 100).flatmap( + lambda k: lists(booleans(), min_size=k, max_size=k)) + + assert minimal( + bool_lists, lambda x: len(list(filter(bool, x))) >= n + ) == [True] * n + + +@pytest.mark.parametrize('n', range(1, 10)) +def test_can_delete_in_middle_of_a_binding(n): + bool_lists = integers(1, 100).flatmap( + lambda k: lists(booleans(), min_size=k, max_size=k)) + + assert minimal( + bool_lists, lambda x: x[0] and x[-1] and x.count(False) >= n + ) == [True] + [False] * n + [True] diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_floating.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_floating.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_floating.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_floating.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,161 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +"""Tests for being able to generate weird and wonderful floating point +numbers.""" + + +from __future__ import division, print_function, absolute_import + +import sys +import math + +from hypothesis import HealthCheck, given, assume, settings +from tests.common.utils import fails +from hypothesis.strategies import data, lists, floats + +TRY_HARDER = settings( + max_examples=1000, + suppress_health_check=[HealthCheck.filter_too_much] +) + + +@given(floats()) +@TRY_HARDER +def test_is_float(x): + assert isinstance(x, float) + + +@fails +@given(floats()) +@TRY_HARDER +def test_inversion_is_imperfect(x): + assume(x != 0.0) + y = 1.0 / x + assert x * y == 1.0 + + +@given(floats(-sys.float_info.max, sys.float_info.max)) +def test_largest_range(x): + assert not math.isinf(x) + + +@given(floats()) +@TRY_HARDER +def test_negation_is_self_inverse(x): + assume(not math.isnan(x)) + y = -x + assert -y == x + + +@fails +@given(lists(floats())) +def test_is_not_nan(xs): + assert not any(math.isnan(x) for x in xs) + + +@fails +@given(floats()) +@TRY_HARDER +def test_is_not_positive_infinite(x): + assume(x > 0) + assert not math.isinf(x) + + +@fails +@given(floats()) +@TRY_HARDER +def test_is_not_negative_infinite(x): + assume(x < 0) + assert not math.isinf(x) + + +@fails +@given(floats()) +@TRY_HARDER +def test_is_int(x): + assume(not (math.isinf(x) or math.isnan(x))) + assert x == int(x) + + +@fails +@given(floats()) +@TRY_HARDER +def test_is_not_int(x): + assume(not (math.isinf(x) or math.isnan(x))) + assert x != int(x) + + +@fails +@given(floats()) +@TRY_HARDER +def test_is_in_exact_int_range(x): + assume(not (math.isinf(x) or math.isnan(x))) + assert x + 1 != x + + +# Tests whether we can represent subnormal floating point numbers. +# This is essentially a function of how the python interpreter +# was compiled. +# Everything is terrible +if math.ldexp(0.25, -1022) > 0: + REALLY_SMALL_FLOAT = sys.float_info.min +else: + REALLY_SMALL_FLOAT = sys.float_info.min * 2 + + +@fails +@given(floats()) +@TRY_HARDER +def test_can_generate_really_small_positive_floats(x): + assume(x > 0) + assert x >= REALLY_SMALL_FLOAT + + +@fails +@given(floats()) +@TRY_HARDER +def test_can_generate_really_small_negative_floats(x): + assume(x < 0) + assert x <= -REALLY_SMALL_FLOAT + + +@fails +@given(floats()) +@TRY_HARDER +def test_can_find_floats_that_do_not_round_trip_through_strings(x): + assert float(str(x)) == x + + +@fails +@given(floats()) +@TRY_HARDER +def test_can_find_floats_that_do_not_round_trip_through_reprs(x): + assert float(repr(x)) == x + + +finite_floats = floats(allow_infinity=False, allow_nan=False) + + +@settings(deadline=None) +@given(finite_floats, finite_floats, data()) +def test_floats_are_in_range(x, y, data): + x, y = sorted((x, y)) + assume(x < y) + + t = data.draw(floats(x, y)) + assert x <= t <= y diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_given_error_conditions.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_given_error_conditions.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_given_error_conditions.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_given_error_conditions.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,34 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import pytest + +from hypothesis import HealthCheck, given, reject, settings +from hypothesis.errors import Unsatisfiable +from hypothesis.strategies import integers + + +def test_raises_unsatisfiable_if_all_false(): + @given(integers()) + @settings(max_examples=50, suppress_health_check=HealthCheck.all()) + def test_assume_false(x): + reject() + + with pytest.raises(Unsatisfiable): + test_assume_false() diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_given_reuse.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_given_reuse.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_given_reuse.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_given_reuse.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,53 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import pytest + +from hypothesis import given +from hypothesis import strategies as st + +given_booleans = given(st.booleans()) + + +@given_booleans +def test_has_an_arg_named_x(x): + pass + + +@given_booleans +def test_has_an_arg_named_y(y): + pass + + +given_named_booleans = given(z=st.text()) + + +def test_fail_independently(): + @given_named_booleans + def test_z1(z): + assert False + + @given_named_booleans + def test_z2(z): + pass + + with pytest.raises(AssertionError): + test_z1() + + test_z2() diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_imports.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_imports.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_imports.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_imports.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,27 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from hypothesis import * +from hypothesis.strategies import * + + +def test_can_star_import_from_hypothesis(): + find(lists(integers()), lambda x: sum(x) > 1, settings=settings( + max_examples=10000, verbosity=Verbosity.quiet + )) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_integer_ranges.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_integer_ranges.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_integer_ranges.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_integer_ranges.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,53 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import pytest + +from tests.common.debug import minimal +from hypothesis.internal.conjecture.utils import integer_range +from hypothesis.searchstrategy.strategies import SearchStrategy + + +class interval(SearchStrategy): + + def __init__(self, lower, upper, center=None): + self.lower = lower + self.upper = upper + self.center = center + + def do_draw(self, data): + return integer_range( + data, self.lower, self.upper, center=self.center, + ) + + +@pytest.mark.parametrize('inter', [ + (0, 5, 10), + (-10, 10, 10), + (0, 1, 1), + (1, 1, 2), +]) +def test_intervals_shrink_to_center(inter): + lower, center, upper = inter + s = interval(lower, upper, center) + assert minimal(s, lambda x: True) == center + if lower < center: + assert minimal(s, lambda x: x < center) == center - 1 + if center < upper: + assert minimal(s, lambda x: x > center) == center + 1 diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_labels.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_labels.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_labels.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_labels.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,58 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import hypothesis.strategies as st + + +def test_labels_are_cached(): + x = st.integers() + assert x.label is x.label + + +def test_labels_are_distinct(): + assert st.integers().label != st.text().label + + +@st.composite +def foo(draw): + pass + + +@st.composite +def bar(draw): + pass + + +def test_different_composites_have_different_labels(): + assert foo().label != bar().label + + +def test_one_of_label_is_distinct(): + a = st.integers() + b = st.booleans() + assert st.one_of(a, b).label != st.one_of(b, a).label + + +def test_lists_label_by_element(): + assert st.lists(st.integers()).label != st.lists(st.booleans()).label + + +def test_label_of_deferred_strategy_is_well_defined(): + recursive = st.deferred(lambda: st.lists(recursive)) + recursive.label diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_large_examples.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_large_examples.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_large_examples.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_large_examples.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,25 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import hypothesis.strategies as st +from tests.common.debug import find_any + + +def test_can_generate_large_lists_with_min_size(): + find_any(st.lists(st.integers(), min_size=400)) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_limits.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_limits.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_limits.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_limits.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,32 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from hypothesis import given, settings +from hypothesis import strategies as st + + +def test_max_examples_are_respected(): + counter = [0] + + @given(st.random_module(), st.integers()) + @settings(max_examples=100) + def test(rnd, i): + counter[0] += 1 + test() + assert counter == [100] diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_modify_inner_test.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_modify_inner_test.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_modify_inner_test.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_modify_inner_test.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,68 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from functools import wraps + +import pytest + +from hypothesis import given +from hypothesis import strategies as st + + +def always_passes(*args, **kwargs): + """Stand-in for a fixed version of an inner test. + + For example, pytest-trio would take the inner test, wrap it in an + async-to-sync converter, and use the new func (not always_passes). + """ + pass + + +@given(st.integers()) +def test_can_replace_inner_test(x): + assert False, 'This should be replaced' + + +test_can_replace_inner_test.hypothesis.inner_test = always_passes + + +def decorator(func): + """An example of a common decorator pattern.""" + @wraps(func) + def inner(*args, **kwargs): + return func(*args, **kwargs) + return inner + + +@decorator +@given(st.integers()) +def test_can_replace_when_decorated(x): + assert False, 'This should be replaced' + + +test_can_replace_when_decorated.hypothesis.inner_test = always_passes + + +@pytest.mark.parametrize('x', [1, 2]) +@given(y=st.integers()) +def test_can_replace_when_parametrized(x, y): + assert False, 'This should be replaced' + + +test_can_replace_when_parametrized.hypothesis.inner_test = always_passes diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_nesting.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_nesting.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_nesting.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_nesting.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,40 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from pytest import raises + +import hypothesis.strategies as st +from hypothesis import Verbosity, given, settings +from tests.common.utils import no_shrink + + +def test_nesting_1(): + @given(st.integers(0, 100)) + @settings(max_examples=5, database=None, deadline=None) + def test_blah(x): + @given(st.integers()) + @settings( + max_examples=100, phases=no_shrink, database=None, + verbosity=Verbosity.quiet) + def test_nest(y): + if y >= x: + raise ValueError() + with raises(ValueError): + test_nest() + test_blah() diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_pretty_repr.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_pretty_repr.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_pretty_repr.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_pretty_repr.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,112 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import hypothesis.strategies as st +from hypothesis import given, settings +from hypothesis.errors import InvalidArgument +from hypothesis.control import reject +from hypothesis.internal.compat import OrderedDict + + +def foo(x): + pass + + +def bar(x): + pass + + +def baz(x): + pass + + +fns = [ + foo, bar, baz +] + + +def builds_ignoring_invalid(target, *args, **kwargs): + def splat(value): + try: + result = target(*value[0], **value[1]) + result.validate() + return result + except InvalidArgument: + reject() + return st.tuples( + st.tuples(*args), st.fixed_dictionaries(kwargs)).map(splat) + + +size_strategies = dict( + min_size=st.integers(min_value=0, max_value=100) | st.none(), + max_size=st.integers(min_value=0, max_value=100) | st.none(), +) + + +values = st.integers() | st.text() + + +Strategies = st.recursive( + st.one_of( + st.sampled_from([ + st.none(), st.booleans(), st.randoms(), st.complex_numbers(), + st.randoms(), st.fractions(), st.decimals(), + ]), + st.builds(st.just, values), + st.builds(st.sampled_from, st.lists(values, min_size=1)), + builds_ignoring_invalid(st.floats, st.floats(), st.floats()), + ), + lambda x: st.one_of( + builds_ignoring_invalid(st.lists, x, **size_strategies), + builds_ignoring_invalid(st.sets, x, **size_strategies), + builds_ignoring_invalid( + lambda v: st.tuples(*v), st.lists(x)), + builds_ignoring_invalid( + lambda v: st.one_of(*v), + st.lists(x, min_size=1)), + builds_ignoring_invalid( + st.dictionaries, x, x, + dict_class=st.sampled_from([dict, OrderedDict]), + **size_strategies + ), + st.builds(lambda s, f: s.map(f), x, st.sampled_from(fns)), + ) +) + + +strategy_globals = dict( + (k, getattr(st, k)) + for k in dir(st) +) + +strategy_globals['OrderedDict'] = OrderedDict +strategy_globals['inf'] = float('inf') +strategy_globals['nan'] = float('nan') +strategy_globals['foo'] = foo +strategy_globals['bar'] = bar +strategy_globals['baz'] = baz + + +@given(Strategies) +@settings(max_examples=2000) +def test_repr_evals_to_thing_with_same_repr(strategy): + r = repr(strategy) + via_eval = eval(r, strategy_globals) + r2 = repr(via_eval) + assert r == r2 diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_randomization.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_randomization.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_randomization.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_randomization.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,50 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import random + +from pytest import raises + +import hypothesis.strategies as st +from hypothesis import Verbosity, find, given, settings +from tests.common.utils import no_shrink + + +def test_seeds_off_random(): + s = settings(phases=no_shrink, database=None) + r = random.getstate() + x = find(st.integers(), lambda x: True, settings=s) + random.setstate(r) + y = find(st.integers(), lambda x: True, settings=s) + assert x == y + + +def test_nesting_with_control_passes_health_check(): + @given(st.integers(0, 100), st.random_module()) + @settings(max_examples=5, database=None, deadline=None) + def test_blah(x, rnd): + @given(st.integers()) + @settings( + max_examples=100, phases=no_shrink, database=None, + verbosity=Verbosity.quiet) + def test_nest(y): + assert y < x + with raises(AssertionError): + test_nest() + test_blah() diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_recursive.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_recursive.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_recursive.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_recursive.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,135 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from flaky import flaky + +import hypothesis.strategies as st +from hypothesis import HealthCheck, given, settings +from tests.common.debug import minimal, find_any +from tests.common.utils import no_shrink + + +def test_can_generate_with_large_branching(): + def flatten(x): + if isinstance(x, list): + return sum(map(flatten, x), []) + else: + return [x] + + size = 20 + + xs = minimal( + st.recursive( + st.integers(), lambda x: st.lists(x, min_size=size // 2), + max_leaves=size * 2), + lambda x: isinstance(x, list) and len(flatten(x)) >= size, + timeout_after=None, + ) + assert flatten(xs) == [0] * size + + +def test_can_generate_some_depth_with_large_branching(): + def depth(x): + if x and isinstance(x, list): + return 1 + max(map(depth, x)) + else: + return 1 + xs = minimal( + st.recursive(st.integers(), st.lists), + lambda x: depth(x) > 1, + timeout_after=None, + ) + assert xs in ([0], [[]]) + + +def test_can_find_quite_broad_lists(): + def breadth(x): + if isinstance(x, list): + return sum(map(breadth, x)) + else: + return 1 + + target = 10 + + broad = minimal( + st.recursive( + st.booleans(), lambda x: st.lists(x, max_size=target // 2)), + lambda x: breadth(x) >= target, + settings=settings(max_examples=10000), + timeout_after=None, + ) + assert breadth(broad) == target + + +def test_drawing_many_near_boundary(): + target = 4 + + ls = minimal( + st.lists(st.recursive( + st.booleans(), + lambda x: st.lists( + x, min_size=2 * (target - 1), max_size=2 * target + ).map(tuple), + max_leaves=2 * target - 1)), + lambda x: len(set(x)) >= target, + timeout_after=None + ) + assert len(ls) == target + + +@given(st.randoms()) +@settings( + max_examples=50, phases=no_shrink, suppress_health_check=HealthCheck.all(), + deadline=None +) +def test_can_use_recursive_data_in_sets(rnd): + nested_sets = st.recursive(st.booleans(), st.frozensets, max_leaves=3) + find_any(nested_sets, random=rnd) + + def flatten(x): + if isinstance(x, bool): + return frozenset((x,)) + else: + result = frozenset() + for t in x: + result |= flatten(t) + if len(result) == 2: + break + return result + assert rnd is not None + x = minimal( + nested_sets, lambda x: len(flatten(x)) == 2, random=rnd + ) + assert x in ( + frozenset((False, True)), + frozenset((False, frozenset((True,)))), + frozenset((frozenset((False, True)),)) + ) + + +@flaky(max_runs=2, min_passes=1) +def test_can_form_sets_of_recursive_data(): + size = 3 + + trees = st.sets(st.recursive( + st.booleans(), + lambda x: st.lists(x, min_size=size).map(tuple), + max_leaves=20)) + xs = minimal(trees, lambda x: len(x) >= size, timeout_after=None) + assert len(xs) == size diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_regex.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_regex.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_regex.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_regex.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,86 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import re +import string + +import hypothesis.strategies as st +from hypothesis import given, assume, reject +from hypothesis.searchstrategy.regex import base_regex_strategy + + +@st.composite +def charset(draw): + negated = draw(st.booleans()) + chars = draw(st.text(string.ascii_letters + string.digits, min_size=1)) + if negated: + return u"[^%s]" % (chars,) + else: + return u"[%s]" % (chars,) + + +COMBINED_MATCHER = re.compile(u"[?+*]{2}") + + +@st.composite +def conservative_regex(draw): + result = draw(st.one_of( + st.just(u"."), + charset(), + CONSERVATIVE_REGEX.map(lambda s: u"(%s)" % (s,)), + CONSERVATIVE_REGEX.map(lambda s: s + u'+'), + CONSERVATIVE_REGEX.map(lambda s: s + u'?'), + CONSERVATIVE_REGEX.map(lambda s: s + u'*'), + st.lists(CONSERVATIVE_REGEX, min_size=1, max_size=3).map(u"|".join), + st.lists(CONSERVATIVE_REGEX, min_size=1, max_size=3).map(u"".join), + )) + assume(COMBINED_MATCHER.search(result) is None) + control = sum( + result.count(c) for c in '?+*' + ) + assume(control <= 3) + return result + + +CONSERVATIVE_REGEX = conservative_regex() + + +@given(st.data()) +def test_conservative_regex_are_correct_by_construction(data): + pattern = re.compile(data.draw(CONSERVATIVE_REGEX)) + pattern = re.compile(pattern) + result = data.draw(base_regex_strategy(pattern)) + assert pattern.search(result) is not None + + +@given(st.data()) +def test_fuzz_stuff(data): + pattern = data.draw( + st.text(min_size=1, max_size=5) | + st.binary(min_size=1, max_size=5) | + CONSERVATIVE_REGEX.filter(bool) + ) + + try: + regex = re.compile(pattern) + except re.error: + reject() + + ex = data.draw(st.from_regex(regex)) + assert regex.search(ex) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_sets.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_sets.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_sets.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_sets.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,41 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from hypothesis import given, settings +from tests.common.debug import find_any +from hypothesis.strategies import sets, floats, randoms, integers + + +@given(randoms()) +@settings(max_examples=5, deadline=None) +def test_can_draw_sets_of_hard_to_find_elements(rnd): + rarebool = floats(0, 1).map(lambda x: x <= 0.05) + find_any( + sets(rarebool, min_size=2), lambda x: True, + random=rnd, settings=settings(database=None)) + + +@given(sets(integers(), max_size=0)) +def test_empty_sets(x): + assert x == set() + + +@given(sets(integers(), max_size=2)) +def test_bounded_size_sets(x): + assert len(x) <= 2 diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_sharing.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_sharing.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_sharing.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_sharing.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,77 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import hypothesis.strategies as st +from hypothesis import given +from tests.common.debug import minimal, find_any + +x = st.shared(st.integers()) + + +@given(x, x) +def test_sharing_is_by_instance_by_default(a, b): + assert a == b + + +@given( + st.shared(st.integers(), key='hi'), st.shared(st.integers(), key='hi')) +def test_different_instances_with_the_same_key_are_shared(a, b): + assert a == b + + +def test_different_instances_are_not_shared(): + find_any( + st.tuples(st.shared(st.integers()), st.shared(st.integers())), + lambda x: x[0] != x[1] + ) + + +def test_different_keys_are_not_shared(): + find_any( + st.tuples( + st.shared(st.integers(), key=1), + st.shared(st.integers(), key=2)), + lambda x: x[0] != x[1] + ) + + +def test_keys_and_default_are_not_shared(): + find_any( + st.tuples( + st.shared(st.integers(), key=1), + st.shared(st.integers())), + lambda x: x[0] != x[1] + ) + + +def test_can_simplify_shared_lists(): + xs = minimal( + st.lists(st.shared(st.integers())), + lambda x: len(x) >= 10 and x[0] != 0 + ) + assert xs == [1] * 10 + + +def test_simplify_shared_linked_to_size(): + xs = minimal( + st.lists(st.shared(st.integers())), + lambda t: sum(t) >= 1000 + ) + assert sum(xs[:-1]) < 1000 + assert (xs[0] - 1) * len(xs) < 1000 diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_simple_numbers.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_simple_numbers.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_simple_numbers.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_simple_numbers.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,237 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import sys +import math + +import pytest + +from hypothesis import given +from tests.common.debug import minimal +from hypothesis.strategies import lists, floats, integers + + +def test_minimize_negative_int(): + assert minimal(integers(), lambda x: x < 0) == -1 + assert minimal(integers(), lambda x: x < -1) == -2 + + +def test_positive_negative_int(): + assert minimal(integers(), lambda x: x > 0) == 1 + assert minimal(integers(), lambda x: x > 1) == 2 + + +boundaries = pytest.mark.parametrize(u'boundary', sorted( + [2 ** i for i in range(10)] + + [2 ** i - 1 for i in range(10)] + + [2 ** i + 1 for i in range(10)] + + [10 ** i for i in range(6)] +)) + + +@boundaries +def test_minimizes_int_down_to_boundary(boundary): + assert minimal(integers(), lambda x: x >= boundary) == boundary + + +@boundaries +def test_minimizes_int_up_to_boundary(boundary): + assert minimal(integers(), lambda x: x <= -boundary) == -boundary + + +@boundaries +def test_minimizes_ints_from_down_to_boundary(boundary): + def is_good(x): + assert x >= boundary - 10 + return x >= boundary + + assert minimal( + integers(min_value=boundary - 10), is_good) == boundary + + assert minimal(integers(min_value=boundary), lambda x: True) == boundary + + +def test_minimizes_negative_integer_range_upwards(): + assert minimal(integers(min_value=-10, max_value=-1)) == -1 + + +@boundaries +def test_minimizes_integer_range_to_boundary(boundary): + assert minimal( + integers(boundary, boundary + 100), lambda x: True + ) == boundary + + +def test_single_integer_range_is_range(): + assert minimal(integers(1, 1), lambda x: True) == 1 + + +def test_minimal_small_number_in_large_range(): + assert minimal( + integers((-2 ** 32), 2 ** 32), lambda x: x >= 101) == 101 + + +def test_minimal_small_sum_float_list(): + xs = minimal( + lists(floats(), min_size=10), + lambda x: sum(x) >= 1.0 + ) + assert sum(xs) <= 2.0 + + +def test_minimals_boundary_floats(): + def f(x): + print(x) + return True + assert -1 <= minimal(floats(min_value=-1, max_value=1), f) <= 1 + + +def test_minimal_non_boundary_float(): + x = minimal(floats(min_value=1, max_value=9), lambda x: x > 2) + assert 2 < x < 3 + + +def test_minimal_float_is_zero(): + assert minimal(floats(), lambda x: True) == 0.0 + + +def test_negative_floats_simplify_to_zero(): + assert minimal(floats(), lambda x: x <= -1.0) == -1.0 + + +def test_minimal_infinite_float_is_positive(): + assert minimal(floats(), math.isinf) == float(u'inf') + + +def test_can_minimal_infinite_negative_float(): + assert minimal(floats(), lambda x: x < -sys.float_info.max) + + +def test_can_minimal_float_on_boundary_of_representable(): + minimal(floats(), lambda x: x + 1 == x and not math.isinf(x)) + + +def test_minimize_nan(): + assert math.isnan(minimal(floats(), math.isnan)) + + +def test_minimize_very_large_float(): + t = sys.float_info.max / 2 + assert t <= minimal(floats(), lambda x: x >= t) < float(u'inf') + + +def is_integral(value): + try: + return int(value) == value + except (OverflowError, ValueError): + return False + + +def test_can_minimal_float_far_from_integral(): + minimal(floats(), lambda x: not ( + math.isnan(x) or + math.isinf(x) or + is_integral(x * (2 ** 32)) + )) + + +def test_list_of_fractional_float(): + assert set(minimal( + lists(floats(), min_size=5), + lambda x: len([t for t in x if t >= 1.5]) >= 5, + timeout_after=60, + )).issubset([1.5, 2.0]) + + +def test_minimal_fractional_float(): + assert minimal(floats(), lambda x: x >= 1.5) in (1.5, 2.0) + + +def test_minimizes_lists_of_negative_ints_up_to_boundary(): + result = minimal( + lists(integers(), min_size=10), + lambda x: len([t for t in x if t <= -1]) >= 10, timeout_after=60) + assert result == [-1] * 10 + + +@pytest.mark.parametrize((u'left', u'right'), [ + (0.0, 5e-324), + (-5e-324, 0.0), + (-5e-324, 5e-324), + (5e-324, 1e-323), +]) +def test_floats_in_constrained_range(left, right): + @given(floats(left, right)) + def test_in_range(r): + assert left <= r <= right + test_in_range() + + +def test_bounds_are_respected(): + assert minimal(floats(min_value=1.0), lambda x: True) == 1.0 + assert minimal(floats(max_value=-1.0), lambda x: True) == -1.0 + + +@pytest.mark.parametrize('k', range(10)) +def test_floats_from_zero_have_reasonable_range(k): + n = 10 ** k + assert minimal(floats(min_value=0.0), lambda x: x >= n) == float(n) + assert minimal(floats(max_value=0.0), lambda x: x <= -n) == float(-n) + + +def test_explicit_allow_nan(): + minimal(floats(allow_nan=True), math.isnan) + + +def test_one_sided_contains_infinity(): + minimal(floats(min_value=1.0), math.isinf) + minimal(floats(max_value=1.0), math.isinf) + + +@given(floats(min_value=0.0, allow_infinity=False)) +def test_no_allow_infinity_upper(x): + assert not math.isinf(x) + + +@given(floats(max_value=0.0, allow_infinity=False)) +def test_no_allow_infinity_lower(x): + assert not math.isinf(x) + + +class TestFloatsAreFloats(object): + + @given(floats()) + def test_unbounded(self, arg): + assert isinstance(arg, float) + + @given(floats(min_value=0, max_value=2 ** 64 - 1)) + def test_int_int(self, arg): + assert isinstance(arg, float) + + @given(floats(min_value=0, max_value=float(2 ** 64 - 1))) + def test_int_float(self, arg): + assert isinstance(arg, float) + + @given(floats(min_value=float(0), max_value=2 ** 64 - 1)) + def test_float_int(self, arg): + assert isinstance(arg, float) + + @given(floats(min_value=float(0), max_value=float(2 ** 64 - 1))) + def test_float_float(self, arg): + assert isinstance(arg, float) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_simple_strings.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_simple_strings.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_simple_strings.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_simple_strings.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,29 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import unicodedata + +from hypothesis import given, settings +from hypothesis.strategies import text + + +@given(text(min_size=1, max_size=1)) +@settings(max_examples=2000) +def test_does_not_generate_surrogates(t): + assert unicodedata.category(t) != u'Cs' diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_skipping.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_skipping.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_skipping.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_skipping.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,48 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import unittest + +import pytest + +from hypothesis import given +from hypothesis.core import EXCEPTIONS_TO_RERAISE +from tests.common.utils import capture_out +from hypothesis.strategies import integers + + +@pytest.mark.parametrize('skip_exception', EXCEPTIONS_TO_RERAISE) +def test_no_falsifying_example_if_unittest_skip(skip_exception): + """If a ``SkipTest`` exception is raised during a test, Hypothesis should + not continue running the test and shrink process, nor should it print + anything about falsifying examples.""" + class DemoTest(unittest.TestCase): + + @given(xs=integers()) + def test_to_be_skipped(self, xs): + if xs == 0: + raise skip_exception + else: + assert xs == 0 + + with capture_out() as o: + suite = unittest.defaultTestLoader.loadTestsFromTestCase(DemoTest) + unittest.TextTestRunner().run(suite) + + assert 'Falsifying example' not in o.getvalue() diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_strategy_state.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_strategy_state.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_strategy_state.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_strategy_state.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,193 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import math +import hashlib +from random import Random + +from hypothesis import Verbosity, assume, settings, unlimited +from hypothesis.database import ExampleDatabase +from hypothesis.stateful import Bundle, RuleBasedStateMachine, rule +from hypothesis.strategies import data, just, none, text, lists, binary, \ + floats, tuples, booleans, decimals, integers, fractions, \ + float_to_int, int_to_float, sampled_from, complex_numbers +from hypothesis.internal.compat import PYPY + +AVERAGE_LIST_LENGTH = 2 + + +def clamp(lower, value, upper): + """Given a value and optional lower/upper bounds, 'clamp' the value so that + it satisfies lower <= value <= upper.""" + if (lower is not None) and (upper is not None) and (lower > upper): + raise ValueError('Cannot clamp with lower > upper: %r > %r' % + (lower, upper)) + if lower is not None: + value = max(lower, value) + if upper is not None: + value = min(value, upper) + return value + + +class HypothesisSpec(RuleBasedStateMachine): + + def __init__(self): + super(HypothesisSpec, self).__init__() + self.database = None + + strategies = Bundle(u'strategy') + strategy_tuples = Bundle(u'tuples') + objects = Bundle(u'objects') + basic_data = Bundle(u'basic') + varied_floats = Bundle(u'varied_floats') + + def teardown(self): + self.clear_database() + + @rule() + def clear_database(self): + if self.database is not None: + self.database.close() + self.database = None + + @rule() + def set_database(self): + self.teardown() + self.database = ExampleDatabase() + + @rule(target=strategies, spec=sampled_from(( + integers(), booleans(), floats(), complex_numbers(), + fractions(), decimals(), text(), binary(), none(), + tuples(), + ))) + def strategy(self, spec): + return spec + + @rule(target=strategies, values=lists(integers() | text(), min_size=1)) + def sampled_from_strategy(self, values): + return sampled_from(values) + + @rule(target=strategies, spec=strategy_tuples) + def strategy_for_tupes(self, spec): + return tuples(*spec) + + @rule( + target=strategies, + source=strategies, + level=integers(1, 10), + mixer=text()) + def filtered_strategy(s, source, level, mixer): + def is_good(x): + return bool(Random( + hashlib.md5((mixer + repr(x)).encode(u'utf-8')).digest() + ).randint(0, level)) + return source.filter(is_good) + + @rule(target=strategies, elements=strategies) + def list_strategy(self, elements): + return lists(elements) + + @rule(target=strategies, left=strategies, right=strategies) + def or_strategy(self, left, right): + return left | right + + @rule(target=varied_floats, source=floats()) + def float(self, source): + return source + + @rule( + target=varied_floats, + source=varied_floats, offset=integers(-100, 100)) + def adjust_float(self, source, offset): + return int_to_float(clamp( + 0, + float_to_int(source) + offset, + 2 ** 64 - 1 + )) + + @rule( + target=strategies, + left=varied_floats, right=varied_floats + ) + def float_range(self, left, right): + for f in (math.isnan, math.isinf): + for x in (left, right): + assume(not f(x)) + left, right = sorted((left, right)) + assert left <= right + return floats(left, right) + + @rule( + target=strategies, + source=strategies, result1=strategies, result2=strategies, + mixer=text(), p=floats(0, 1)) + def flatmapped_strategy(self, source, result1, result2, mixer, p): + assume(result1 is not result2) + + def do_map(value): + rep = repr(value) + random = Random( + hashlib.md5((mixer + rep).encode(u'utf-8')).digest() + ) + if random.random() <= p: + return result1 + else: + return result2 + return source.flatmap(do_map) + + @rule(target=strategies, value=objects) + def just_strategy(self, value): + return just(value) + + @rule(target=strategy_tuples, source=strategies) + def single_tuple(self, source): + return (source,) + + @rule(target=strategy_tuples, left=strategy_tuples, right=strategy_tuples) + def cat_tuples(self, left, right): + return left + right + + @rule(target=objects, strat=strategies, data=data()) + def get_example(self, strat, data): + data.draw(strat) + + @rule(target=strategies, left=integers(), right=integers()) + def integer_range(self, left, right): + left, right = sorted((left, right)) + return integers(left, right) + + @rule(strat=strategies) + def repr_is_good(self, strat): + assert u' at 0x' not in repr(strat) + + +MAIN = __name__ == u'__main__' + +TestHypothesis = HypothesisSpec.TestCase + +TestHypothesis.settings = settings( + TestHypothesis.settings, + stateful_step_count=10 if PYPY else 50, + timeout=unlimited, + verbosity=max(TestHypothesis.settings.verbosity, Verbosity.verbose), + max_examples=10000 if MAIN else 200, +) + +if MAIN: + TestHypothesis().runTest() diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_streams.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_streams.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_streams.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_streams.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,35 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from itertools import islice + +from hypothesis import HealthCheck, given, settings +from tests.common.utils import checks_deprecated_behaviour +from hypothesis.strategies import integers, streaming +from hypothesis.internal.compat import integer_types + + +@checks_deprecated_behaviour +def test_streams_are_arbitrarily_long(): + @settings(suppress_health_check=[HealthCheck.too_slow]) + @given(streaming(integers())) + def test(ss): + for i in islice(ss, 100): + assert isinstance(i, integer_types) + test() diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_testdecorators.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_testdecorators.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_testdecorators.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_testdecorators.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,50 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from hypothesis import HealthCheck, given, reject, settings +from hypothesis.errors import Unsatisfiable +from tests.common.utils import raises +from hypothesis.strategies import integers + + +def test_contains_the_test_function_name_in_the_exception_string(): + look_for_one = settings( + max_examples=1, suppress_health_check=HealthCheck.all()) + + @given(integers()) + @look_for_one + def this_has_a_totally_unique_name(x): + reject() + + with raises(Unsatisfiable) as e: + this_has_a_totally_unique_name() + assert this_has_a_totally_unique_name.__name__ in e.value.args[0] + + class Foo(object): + + @given(integers()) + @look_for_one + def this_has_a_unique_name_and_lives_on_a_class(self, x): + reject() + + with raises(Unsatisfiable) as e: + Foo().this_has_a_unique_name_and_lives_on_a_class() + assert ( + Foo.this_has_a_unique_name_and_lives_on_a_class.__name__ + ) in e.value.args[0] diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_threading.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_threading.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_threading.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_threading.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,36 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import threading + +import hypothesis.strategies as st +from hypothesis import given + + +def test_can_run_given_in_thread(): + has_run_successfully = [False] + + @given(st.integers()) + def test(n): + has_run_successfully[0] = True + + t = threading.Thread(target=test) + t.start() + t.join() + assert has_run_successfully[0] diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_unusual_settings_configs.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_unusual_settings_configs.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_unusual_settings_configs.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_unusual_settings_configs.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,38 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import hypothesis.strategies as st +from hypothesis import Verbosity, HealthCheck, given, assume, settings + + +@settings(max_examples=1, database=None) +@given(st.integers()) +def test_single_example(n): + pass + + +@settings( + max_examples=1, database=None, + suppress_health_check=[HealthCheck.filter_too_much, HealthCheck.too_slow], + verbosity=Verbosity.debug, +) +@given(st.integers()) +def test_hard_to_find_single_example(n): + # Numbers are arbitrary, just deliberately unlikely to hit this too soon. + assume(n % 50 == 11) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_uuids.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_uuids.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_uuids.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_uuids.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,43 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import pytest + +import hypothesis.strategies as st +from hypothesis import given +from tests.common.debug import minimal + + +@given(st.lists(st.uuids())) +def test_are_unique(ls): + assert len(set(ls)) == len(ls) + + +def test_retains_uniqueness_in_simplify(): + ts = minimal(st.lists(st.uuids()), lambda x: len(x) >= 5) + assert len(ts) == len(set(ts)) == 5 + + +@pytest.mark.parametrize('version', (1, 2, 3, 4, 5)) +def test_can_generate_specified_version(version): + @given(st.uuids(version=version)) + def inner(uuid): + assert version == uuid.version + + inner() diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_weird_settings.py python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_weird_settings.py --- python-hypothesis-3.44.1/hypothesis-python/tests/nocover/test_weird_settings.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/nocover/test_weird_settings.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,31 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from hypothesis import given, settings +from hypothesis import strategies as st +from tests.common.utils import checks_deprecated_behaviour + + +@checks_deprecated_behaviour +def test_setting_database_to_none_disables_the_database(): + @given(st.booleans()) + @settings(database_file=None) + def test(b): + pass + test() diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/numpy/__init__.py python-hypothesis-3.71.11/hypothesis-python/tests/numpy/__init__.py --- python-hypothesis-3.44.1/hypothesis-python/tests/numpy/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/numpy/__init__.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,16 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/numpy/test_argument_validation.py python-hypothesis-3.71.11/hypothesis-python/tests/numpy/test_argument_validation.py --- python-hypothesis-3.44.1/hypothesis-python/tests/numpy/test_argument_validation.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/numpy/test_argument_validation.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,65 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import numpy +import pytest + +import hypothesis.strategies as st +import hypothesis.extra.numpy as nps +from hypothesis.errors import InvalidArgument + + +def e(a, **kwargs): + return (a, kwargs) + + +@pytest.mark.parametrize( + ('function', 'kwargs'), [ + e(nps.array_dtypes, min_size=2, max_size=1), + e(nps.array_dtypes, min_size=-1), + e(nps.array_shapes, min_side=2, max_side=1), + e(nps.array_shapes, min_dims=3, max_dims=2), + e(nps.array_shapes, min_dims=0), + e(nps.array_shapes, min_side=0), + e(nps.arrays, dtype=float, shape=(0.5,)), + e(nps.arrays, dtype=object, shape=1), + e(nps.arrays, dtype=object, shape=(), elements=st.none()), + e(nps.arrays, dtype=float, shape=1, fill=3), + e(nps.byte_string_dtypes, min_len=-1), + e(nps.byte_string_dtypes, min_len=2, max_len=1), + e(nps.datetime64_dtypes, max_period=11), + e(nps.datetime64_dtypes, min_period=11), + e(nps.datetime64_dtypes, min_period='Y', max_period='M'), + e(nps.timedelta64_dtypes, max_period=11), + e(nps.timedelta64_dtypes, min_period=11), + e(nps.timedelta64_dtypes, min_period='Y', max_period='M'), + e(nps.unicode_string_dtypes, min_len=-1), + e(nps.unicode_string_dtypes, min_len=2, max_len=1), + e(nps.unsigned_integer_dtypes, endianness=3), + e(nps.unsigned_integer_dtypes, sizes=()), + e(nps.unsigned_integer_dtypes, sizes=(3,)), + e(nps.from_dtype, dtype='float64'), + e(nps.from_dtype, dtype=float), + e(nps.from_dtype, dtype=numpy.int8), + e(nps.from_dtype, dtype=1), + ] +) +def test_raise_invalid_argument(function, kwargs): + with pytest.raises(InvalidArgument): + function(**kwargs).example() diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/numpy/test_fill_values.py python-hypothesis-3.71.11/hypothesis-python/tests/numpy/test_fill_values.py --- python-hypothesis-3.44.1/hypothesis-python/tests/numpy/test_fill_values.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/numpy/test_fill_values.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,61 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import hypothesis.strategies as st +from hypothesis import given +from tests.common.debug import minimal, find_any +from hypothesis.extra.numpy import arrays + + +@given(arrays(object, 100, st.builds(list))) +def test_generated_lists_are_distinct(ls): + assert len(set(map(id, ls))) == len(ls) + + +@st.composite +def distinct_integers(draw): + used = draw(st.shared(st.builds(set), key='distinct_integers.used')) + i = draw(st.integers(0, 2 ** 64 - 1).filter(lambda x: x not in used)) + used.add(i) + return i + + +@given(arrays('uint64', 10, distinct_integers())) +def test_does_not_reuse_distinct_integers(arr): + assert len(set(arr)) == len(arr) + + +def test_may_reuse_distinct_integers_if_asked(): + find_any( + arrays('uint64', 10, distinct_integers(), fill=distinct_integers()), + lambda x: len(set(x)) < len(x) + ) + + +def test_minimizes_to_fill(): + result = minimal(arrays(float, 10, fill=st.just(3.0))) + assert (result == 3.0).all() + + +@given(arrays( + dtype=float, + elements=st.floats().filter(bool), shape=(3, 3, 3,), fill=st.just(1.0)) +) +def test_fills_everything(x): + assert x.all() diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/numpy/test_gen_data.py python-hypothesis-3.71.11/hypothesis-python/tests/numpy/test_gen_data.py --- python-hypothesis-3.44.1/hypothesis-python/tests/numpy/test_gen_data.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/numpy/test_gen_data.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,339 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import sys + +import numpy as np +import pytest +from flaky import flaky + +import hypothesis.strategies as st +import hypothesis.extra.numpy as nps +from hypothesis import given, assume, settings +from hypothesis.errors import InvalidArgument +from tests.common.debug import minimal, find_any +from tests.common.utils import checks_deprecated_behaviour +from hypothesis.searchstrategy import SearchStrategy +from hypothesis.internal.compat import text_type, binary_type + +STANDARD_TYPES = list(map(np.dtype, [ + u'int8', u'int16', u'int32', u'int64', + u'uint8', u'uint16', u'uint32', u'uint64', + u'float', u'float16', u'float32', u'float64', + u'complex64', u'complex128', + u'datetime64', u'timedelta64', + bool, text_type, binary_type +])) + + +@given(nps.nested_dtypes()) +def test_strategies_for_standard_dtypes_have_reusable_values(dtype): + assert nps.from_dtype(dtype).has_reusable_values + + +@pytest.mark.parametrize(u't', STANDARD_TYPES) +def test_produces_instances(t): + @given(nps.from_dtype(t)) + def test_is_t(x): + assert isinstance(x, t.type) + assert x.dtype.kind == t.kind + test_is_t() + + +@given(nps.arrays(float, ())) +def test_empty_dimensions_are_scalars(x): + assert isinstance(x, np.dtype(float).type) + + +@given(nps.arrays(float, (1, 0, 1))) +def test_can_handle_zero_dimensions(x): + assert x.shape == (1, 0, 1) + + +@given(nps.arrays(u'uint32', (5, 5))) +def test_generates_unsigned_ints(x): + assert (x >= 0).all() + + +@given(nps.arrays(int, (1,))) +def test_assert_fits_in_machine_size(x): + pass + + +def test_generates_and_minimizes(): + assert (minimal(nps.arrays(float, (2, 2))) == np.zeros(shape=(2, 2))).all() + + +def test_can_minimize_large_arrays(): + x = minimal( + nps.arrays(u'uint32', 100), lambda x: np.any(x) and not np.all(x), + timeout_after=60 + ) + assert np.logical_or(x == 0, x == 1).all() + assert np.count_nonzero(x) in (1, len(x) - 1) + + +@flaky(max_runs=50, min_passes=1) +def test_can_minimize_float_arrays(): + x = minimal(nps.arrays(float, 50), lambda t: t.sum() >= 1.0) + assert x.sum() in (1, 50) + + +class Foo(object): + pass + + +foos = st.tuples().map(lambda _: Foo()) + + +def test_can_create_arrays_of_composite_types(): + arr = minimal(nps.arrays(object, 100, foos)) + for x in arr: + assert isinstance(x, Foo) + + +def test_can_create_arrays_of_tuples(): + arr = minimal( + nps.arrays(object, 10, st.tuples(st.integers(), st.integers())), + lambda x: all(t0 != t1 for t0, t1 in x)) + assert all(a in ((1, 0), (0, 1)) for a in arr) + + +@given(nps.arrays(object, (2, 2), st.tuples(st.integers()))) +def test_does_not_flatten_arrays_of_tuples(arr): + assert isinstance(arr[0][0], tuple) + + +@given( + nps.arrays(object, (2, 2), st.lists(st.integers(), min_size=1, max_size=1)) +) +def test_does_not_flatten_arrays_of_lists(arr): + assert isinstance(arr[0][0], list) + + +@given(nps.array_shapes()) +def test_can_generate_array_shapes(shape): + assert isinstance(shape, tuple) + assert all(isinstance(i, int) for i in shape) + + +@settings(deadline=None) +@given(st.integers(1, 10), st.integers(0, 9), st.integers(1), st.integers(0)) +def test_minimise_array_shapes(min_dims, dim_range, min_side, side_range): + smallest = minimal(nps.array_shapes(min_dims, min_dims + dim_range, + min_side, min_side + side_range)) + assert len(smallest) == min_dims and all(k == min_side for k in smallest) + + +@given(nps.scalar_dtypes()) +def test_can_generate_scalar_dtypes(dtype): + assert isinstance(dtype, np.dtype) + + +@given(nps.nested_dtypes()) +def test_can_generate_compound_dtypes(dtype): + assert isinstance(dtype, np.dtype) + + +@given(nps.nested_dtypes(max_itemsize=settings.default.buffer_size // 10), + st.data()) +def test_infer_strategy_from_dtype(dtype, data): + # Given a dtype + assert isinstance(dtype, np.dtype) + # We can infer a strategy + strat = nps.from_dtype(dtype) + assert isinstance(strat, SearchStrategy) + # And use it to fill an array of that dtype + data.draw(nps.arrays(dtype, 10, strat)) + + +@given(nps.nested_dtypes()) +def test_np_dtype_is_idempotent(dtype): + assert dtype == np.dtype(dtype) + + +def test_minimise_scalar_dtypes(): + assert minimal(nps.scalar_dtypes()) == np.dtype(u'bool') + + +def test_minimise_nested_types(): + assert minimal(nps.nested_dtypes()) == np.dtype(u'bool') + + +def test_minimise_array_strategy(): + smallest = minimal(nps.arrays( + nps.nested_dtypes(max_itemsize=settings.default.buffer_size // 3**3), + nps.array_shapes(max_dims=3, max_side=3))) + assert smallest.dtype == np.dtype(u'bool') and not smallest.any() + + +@given(nps.array_dtypes(allow_subarrays=False)) +def test_can_turn_off_subarrays(dt): + for field, _ in dt.fields.values(): + assert field.shape == () + + +@pytest.mark.parametrize('byteorder', ['<', '>']) +@given(data=st.data()) +def test_can_restrict_endianness(data, byteorder): + dtype = data.draw(nps.integer_dtypes(byteorder, sizes=(16, 32, 64))) + if byteorder == ('<' if sys.byteorder == 'little' else '>'): + assert dtype.byteorder == '=' + else: + assert dtype.byteorder == byteorder + + +@given(nps.integer_dtypes(sizes=8)) +def test_can_specify_size_as_an_int(dt): + assert dt.itemsize == 1 + + +@given(st.data()) +def test_can_draw_shapeless_from_scalars(data): + dt = data.draw(nps.scalar_dtypes()) + result = data.draw(nps.arrays(dtype=dt, shape=())) + assert isinstance(result, dt.type) + + +@given(st.data()) +def test_unicode_string_dtypes_generate_unicode_strings(data): + dt = data.draw(nps.unicode_string_dtypes()) + result = data.draw(nps.from_dtype(dt)) + assert isinstance(result, text_type) + + +@given(st.data()) +def test_byte_string_dtypes_generate_unicode_strings(data): + dt = data.draw(nps.byte_string_dtypes()) + result = data.draw(nps.from_dtype(dt)) + assert isinstance(result, binary_type) + + +@given(nps.arrays(dtype='int8', shape=st.integers(0, 20), unique=True)) +def test_array_values_are_unique(arr): + assert len(set(arr)) == len(arr) + + +def test_may_fill_with_nan_when_unique_is_set(): + find_any( + nps.arrays( + dtype=float, elements=st.floats(allow_nan=False), shape=10, + unique=True, fill=st.just(float('nan'))), + lambda x: np.isnan(x).any() + ) + + +def test_is_still_unique_with_nan_fill(): + @given(nps.arrays( + dtype=float, elements=st.floats(allow_nan=False), shape=10, + unique=True, fill=st.just(float('nan')))) + def test(xs): + assert len(set(xs)) == len(xs) + + test() + + +def test_may_not_fill_with_non_nan_when_unique_is_set(): + @given(nps.arrays( + dtype=float, elements=st.floats(allow_nan=False), shape=10, + unique=True, fill=st.just(0.0))) + def test(arr): + pass + + with pytest.raises(InvalidArgument): + test() + + +def test_may_not_fill_with_non_nan_when_unique_is_set_and_type_is_not_number(): + @given(nps.arrays( + dtype=bytes, shape=10, + unique=True, fill=st.just(b''))) + def test(arr): + pass + + with pytest.raises(InvalidArgument): + test() + + +@given(st.data(), + st.builds('{}[{}]'.format, + st.sampled_from(('datetime64', 'timedelta64')), + st.sampled_from(nps.TIME_RESOLUTIONS) + ).map(np.dtype) + ) +def test_inferring_from_time_dtypes_gives_same_dtype(data, dtype): + ex = data.draw(nps.from_dtype(dtype)) + assert dtype == ex.dtype + + +@given(st.data(), nps.byte_string_dtypes() | nps.unicode_string_dtypes()) +def test_inferred_string_strategies_roundtrip(data, dtype): + # Check that we never generate too-long or nul-terminated strings, which + # cannot be read back out of an array. + arr = np.zeros(shape=1, dtype=dtype) + ex = data.draw(nps.from_dtype(arr.dtype)) + arr[0] = ex + assert arr[0] == ex + + +@given(st.data(), nps.scalar_dtypes()) +def test_all_inferred_scalar_strategies_roundtrip(data, dtype): + # We only check scalars here, because record/compound/nested dtypes always + # give an array of np.void objects. We're interested in whether scalar + # values are safe, not known type coercion. + arr = np.zeros(shape=1, dtype=dtype) + ex = data.draw(nps.from_dtype(arr.dtype)) + assume(ex == ex) # If not, the roundtrip test *should* fail! (eg NaN) + arr[0] = ex + assert arr[0] == ex + + +@pytest.mark.parametrize('fill', [False, True]) +@checks_deprecated_behaviour +@given(st.data()) +def test_overflowing_integers_are_deprecated(fill, data): + kw = dict(elements=st.just(300)) + if fill: + kw = dict(elements=st.nothing(), fill=kw['elements']) + arr = data.draw(nps.arrays(dtype='int8', shape=(1,), **kw)) + assert arr[0] == (300 % 256) + + +@pytest.mark.parametrize('fill', [False, True]) +@checks_deprecated_behaviour +@given(st.data()) +def test_overflowing_floats_are_deprecated(fill, data): + kw = dict(elements=st.floats(min_value=65520, allow_infinity=False)) + if fill: + kw = dict(elements=st.nothing(), fill=kw['elements']) + arr = data.draw(nps.arrays(dtype='float16', shape=(1,), **kw)) + assert np.isinf(arr[0]) + + +@given(nps.arrays(dtype='float16', shape=(1,))) +def test_inferred_floats_do_not_overflow(arr): + pass + + +@given(nps.arrays( + dtype='float16', shape=10, unique=True, + elements=st.integers(1, 9), fill=st.just(np.nan) +)) +def test_unique_array_with_fill_can_use_all_elements(arr): + assume(len(set(arr)) == arr.size) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/numpy/test_narrow_floats.py python-hypothesis-3.71.11/hypothesis-python/tests/numpy/test_narrow_floats.py --- python-hypothesis-3.44.1/hypothesis-python/tests/numpy/test_narrow_floats.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/numpy/test_narrow_floats.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,41 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import numpy as np + +from hypothesis import given +from hypothesis.strategies import floats + + +@given(floats(width=32)) +def test_float32_exactly_representable(x): + clipped = np.dtype('float32').type(x) + if np.isnan(x): + assert np.isnan(clipped) + else: + assert x == float(clipped) + + +@given(floats(width=16)) +def test_float16_exactly_representable(x): + clipped = np.dtype('float16').type(x) + if np.isnan(x): + assert np.isnan(clipped) + else: + assert x == float(clipped) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/numpy/test_sampled_from.py python-hypothesis-3.71.11/hypothesis-python/tests/numpy/test_sampled_from.py --- python-hypothesis-3.44.1/hypothesis-python/tests/numpy/test_sampled_from.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/numpy/test_sampled_from.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,40 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from hypothesis import given +from hypothesis.extra import numpy as npst +from tests.common.utils import checks_deprecated_behaviour +from hypothesis.strategies import data, sampled_from + + +@given(data(), npst.arrays( + dtype=npst.scalar_dtypes(), + shape=npst.array_shapes(max_dims=1) +)) +def test_can_sample_1D_numpy_array_without_warning(data, arr): + data.draw(sampled_from(arr)) + + +@checks_deprecated_behaviour +@given(data(), npst.arrays( + dtype=npst.scalar_dtypes(), + shape=npst.array_shapes(min_dims=2, max_dims=5) +)) +def test_sampling_multi_dimensional_arrays_is_deprecated(data, arr): + data.draw(sampled_from(arr)) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/pandas/helpers.py python-hypothesis-3.71.11/hypothesis-python/tests/pandas/helpers.py --- python-hypothesis-3.44.1/hypothesis-python/tests/pandas/helpers.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/pandas/helpers.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,45 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import numpy as np + +PANDAS_TIME_DTYPES = tuple(map(np.dtype, [ + 'M8[ns]', '>m8[ns]', +])) + + +def supported_by_pandas(dtype): + """Checks whether the dtype is one that can be correctly handled by + Pandas.""" + # Pandas does not support non-native byte orders and things go amusingly + # wrong in weird places if you try to use them. See + # https://pandas.pydata.org/pandas-docs/stable/gotchas.html#byte-ordering-issues + if dtype.byteorder not in ('|', '='): + return False + + # Pandas only supports a limited range of timedelta and datetime dtypes + # compared to the full range that numpy supports and will convert + # everything to those types (possibly increasing precision in the course of + # doing so, which can cause problems if this results in something which + # does not fit into the desired word type. As a result we want to filter + # out any timedelta or datetime dtypes that are not of the desired types. + if dtype.kind in ('m', 'M'): + return dtype in PANDAS_TIME_DTYPES + return True diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/pandas/__init__.py python-hypothesis-3.71.11/hypothesis-python/tests/pandas/__init__.py --- python-hypothesis-3.44.1/hypothesis-python/tests/pandas/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/pandas/__init__.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,16 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/pandas/test_argument_validation.py python-hypothesis-3.71.11/hypothesis-python/tests/pandas/test_argument_validation.py --- python-hypothesis-3.44.1/hypothesis-python/tests/pandas/test_argument_validation.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/pandas/test_argument_validation.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,71 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import hypothesis.strategies as st +import hypothesis.extra.pandas as pdst +from tests.common.arguments import e, argument_validation_test + +BAD_ARGS = [ + e(pdst.data_frames), + e(pdst.data_frames, pdst.columns(1, dtype='not a dtype')), + e(pdst.data_frames, pdst.columns(1, elements='not a strategy')), + e(pdst.data_frames, pdst.columns([[]])), + e(pdst.data_frames, [], index=[]), + e(pdst.data_frames, [], rows=st.fixed_dictionaries({'A': st.just(1)})), + e(pdst.data_frames, pdst.columns(1)), + e(pdst.data_frames, pdst.columns(1, dtype=float, fill=1)), + e(pdst.data_frames, pdst.columns(1, dtype=float, elements=1)), + e(pdst.data_frames, pdst.columns(1, fill=1, dtype=float)), + e(pdst.data_frames, pdst.columns(['A', 'A'], dtype=float)), + e(pdst.data_frames, pdst.columns(1, elements=st.none(), dtype=int)), + e(pdst.data_frames, 1), + e(pdst.data_frames, [1]), + e(pdst.data_frames, pdst.columns(1, dtype='category')), + e(pdst.data_frames, + pdst.columns(['A'], dtype=bool), + rows=st.tuples(st.booleans(), st.booleans())), + e(pdst.data_frames, + pdst.columns(1, elements=st.booleans()), + rows=st.tuples(st.booleans())), + e(pdst.data_frames, rows=st.integers(), index=pdst.range_indexes(0, 0)), + e(pdst.data_frames, rows=st.integers(), index=pdst.range_indexes(1, 1)), + e(pdst.data_frames, pdst.columns(1, dtype=int), rows=st.integers()), + e(pdst.indexes), + e(pdst.indexes, dtype='category'), + e(pdst.indexes, dtype='not a dtype'), + e(pdst.indexes, elements='not a strategy'), + e(pdst.indexes, elements=st.text(), dtype=float), + e(pdst.indexes, elements=st.none(), dtype=int), + e(pdst.indexes, dtype=int, max_size=0, min_size=1), + e(pdst.indexes, dtype=int, unique='true'), + e(pdst.indexes, dtype=int, min_size='0'), + e(pdst.indexes, dtype=int, max_size='1'), + e(pdst.range_indexes, 1, 0), + e(pdst.range_indexes, min_size='0'), + e(pdst.range_indexes, max_size='1'), + e(pdst.series), + e(pdst.series, dtype='not a dtype'), + e(pdst.series, elements='not a strategy'), + e(pdst.series, elements=st.none(), dtype=int), + e(pdst.series, dtype='category'), + e(pdst.series, index='not a strategy'), +] + + +test_raise_invalid_argument = argument_validation_test(BAD_ARGS) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/pandas/test_data_frame.py python-hypothesis-3.71.11/hypothesis-python/tests/pandas/test_data_frame.py --- python-hypothesis-3.44.1/hypothesis-python/tests/pandas/test_data_frame.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/pandas/test_data_frame.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,243 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import numpy as np +import pytest + +import hypothesis.strategies as st +import hypothesis.extra.numpy as npst +import hypothesis.extra.pandas as pdst +from hypothesis import HealthCheck, given, reject, settings +from hypothesis.types import RandomWithSeed as Random +from tests.common.debug import minimal, find_any +from tests.pandas.helpers import supported_by_pandas + + +@given(pdst.data_frames([ + pdst.column('a', dtype=int), + pdst.column('b', dtype=float), +])) +def test_can_have_columns_of_distinct_types(df): + assert df['a'].dtype == np.dtype(int) + assert df['b'].dtype == np.dtype(float) + + +@given(pdst.data_frames( + [pdst.column(dtype=int)], + index=pdst.range_indexes(min_size=1, max_size=5))) +def test_respects_size_bounds(df): + assert 1 <= len(df) <= 5 + + +@given(pdst.data_frames(pdst.columns(['A', 'B'], dtype=float))) +def test_can_specify_just_column_names(df): + df['A'] + df['B'] + + +@given(pdst.data_frames(pdst.columns(2, dtype=float))) +def test_can_specify_just_column_count(df): + df[0] + df[1] + + +@given(pdst.data_frames( + rows=st.fixed_dictionaries({'A': st.integers(1, 10), 'B': st.floats()})) +) +def test_gets_the_correct_data_shape_for_just_rows(table): + assert table['A'].dtype == np.dtype('int64') + assert table['B'].dtype == np.dtype(float) + + +@given(pdst.data_frames( + columns=pdst.columns(['A', 'B'], dtype=int), + rows=st.lists(st.integers(0, 1000), min_size=2, max_size=2).map(sorted), +)) +def test_can_specify_both_rows_and_columns_list(d): + assert d['A'].dtype == np.dtype(int) + assert d['B'].dtype == np.dtype(int) + for _, r in d.iterrows(): + assert r['A'] <= r['B'] + + +@given(pdst.data_frames( + columns=pdst.columns(['A', 'B'], dtype=int), + rows=st.lists( + st.integers(0, 1000), min_size=2, max_size=2).map(sorted).map(tuple), +)) +def test_can_specify_both_rows_and_columns_tuple(d): + assert d['A'].dtype == np.dtype(int) + assert d['B'].dtype == np.dtype(int) + for _, r in d.iterrows(): + assert r['A'] <= r['B'] + + +@given(pdst.data_frames( + columns=pdst.columns(['A', 'B'], dtype=int), + rows=st.lists(st.integers(0, 1000), min_size=2, max_size=2).map( + lambda x: {'A': min(x), 'B': max(x)}), +)) +def test_can_specify_both_rows_and_columns_dict(d): + assert d['A'].dtype == np.dtype(int) + assert d['B'].dtype == np.dtype(int) + for _, r in d.iterrows(): + assert r['A'] <= r['B'] + + +@given( + pdst.data_frames([pdst.column('A', fill=st.just(float('nan')), + dtype=float, + elements=st.floats(allow_nan=False))], + rows=st.builds(dict))) +def test_can_fill_in_missing_elements_from_dict(df): + assert np.isnan(df['A']).all() + + +subsets = ['', 'A', 'B', 'C', 'AB', 'AC', 'BC', 'ABC'] + + +@pytest.mark.parametrize('disable_fill', subsets) +@pytest.mark.parametrize('non_standard_index', [True, False]) +def test_can_minimize_based_on_two_columns_independently( + disable_fill, non_standard_index +): + columns = [ + pdst.column( + name, dtype=bool, + fill=st.nothing() if name in disable_fill else None, + ) + for name in ['A', 'B', 'C'] + ] + + x = minimal( + pdst.data_frames( + columns, + index=pdst.indexes(dtype=int) if non_standard_index else None, + ), + lambda x: x['A'].any() and x['B'].any() and x['C'].any(), + random=Random(0), + ) + assert len(x['A']) == 1 + assert x['A'][0] == 1 + assert x['B'][0] == 1 + assert x['C'][0] == 1 + + +@st.composite +def column_strategy(draw): + name = draw(st.none() | st.text()) + dtype = draw(npst.scalar_dtypes().filter(supported_by_pandas)) + pass_dtype = not draw(st.booleans()) + if pass_dtype: + pass_elements = not draw(st.booleans()) + else: + pass_elements = True + if pass_elements: + elements = npst.from_dtype(dtype) + else: + elements = None + + unique = draw(st.booleans()) + fill = st.nothing() if draw(st.booleans()) else None + + return pdst.column( + name=name, dtype=dtype, unique=unique, fill=fill, elements=elements) + + +@given(pdst.data_frames(pdst.columns(1, dtype=np.dtype('= '0.19': + assert index.dtype == inferred_dtype + else: + assert index.dtype == converted_dtype + + if unique: + assert len(set(index.values)) == len(index) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/pandas/test_series.py python-hypothesis-3.71.11/hypothesis-python/tests/pandas/test_series.py --- python-hypothesis-3.44.1/hypothesis-python/tests/pandas/test_series.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/pandas/test_series.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,70 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import numpy as np + +import pandas +import hypothesis.strategies as st +import hypothesis.extra.numpy as npst +import hypothesis.extra.pandas as pdst +from hypothesis import given, assume +from tests.common.debug import find_any +from tests.pandas.helpers import supported_by_pandas + + +@given(st.data()) +def test_can_create_a_series_of_any_dtype(data): + dtype = np.dtype(data.draw(npst.scalar_dtypes())) + assume(supported_by_pandas(dtype)) + series = data.draw(pdst.series(dtype=dtype)) + assert series.dtype == pandas.Series([], dtype=dtype).dtype + + +@given(pdst.series( + dtype=float, index=pdst.range_indexes(min_size=2, max_size=5))) +def test_series_respects_size_bounds(s): + assert 2 <= len(s) <= 5 + + +def test_can_fill_series(): + nan_backed = pdst.series( + elements=st.floats(allow_nan=False), fill=st.just(float('nan'))) + find_any( + nan_backed, lambda x: np.isnan(x).any() + ) + + +@given(pdst.series(dtype=int)) +def test_can_generate_integral_series(s): + assert s.dtype == np.dtype(int) + + +@given(pdst.series(elements=st.integers(0, 10))) +def test_will_use_dtype_of_elements(s): + assert s.dtype == np.dtype('int64') + + +@given(pdst.series(elements=st.floats(allow_nan=False))) +def test_will_use_a_provided_elements_strategy(s): + assert not np.isnan(s).any() + + +@given(pdst.series(dtype='int8', unique=True)) +def test_unique_series_are_unique(s): + assert len(s) == len(set(s)) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/py2/__init__.py python-hypothesis-3.71.11/hypothesis-python/tests/py2/__init__.py --- python-hypothesis-3.44.1/hypothesis-python/tests/py2/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/py2/__init__.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,16 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/py2/test_destructuring.py python-hypothesis-3.71.11/hypothesis-python/tests/py2/test_destructuring.py --- python-hypothesis-3.44.1/hypothesis-python/tests/py2/test_destructuring.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/py2/test_destructuring.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,38 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import pytest + +from hypothesis import given +from hypothesis.errors import InvalidArgument +from hypothesis.strategies import integers +from hypothesis.internal.reflection import get_pretty_function_description + + +def test_destructuring_lambdas(): + assert get_pretty_function_description(lambda (x, y): 1) == \ + u'lambda (x, y): ' + + +def test_destructuring_not_allowed(): + @given(integers()) + def foo(a, (b, c)): + pass + with pytest.raises(InvalidArgument): + foo() diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/py2/test_from_type.py python-hypothesis-3.71.11/hypothesis-python/tests/py2/test_from_type.py --- python-hypothesis-3.44.1/hypothesis-python/tests/py2/test_from_type.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/py2/test_from_type.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,31 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import hypothesis.strategies as st +from hypothesis import given + + +@given(st.from_type(int)) +def test_from_int_is_int(x): + assert isinstance(x, int) + + +@given(st.from_type(long)) +def test_from_long_is_long(x): + assert isinstance(x, long) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/py3/__init__.py python-hypothesis-3.71.11/hypothesis-python/tests/py3/__init__.py --- python-hypothesis-3.44.1/hypothesis-python/tests/py3/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/py3/__init__.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,16 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/py3/test_annotations.py python-hypothesis-3.71.11/hypothesis-python/tests/py3/test_annotations.py --- python-hypothesis-3.44.1/hypothesis-python/tests/py3/test_annotations.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/py3/test_annotations.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,149 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import sys + +import attr +import pytest + +import hypothesis.strategies as st +from hypothesis import given +from hypothesis.errors import InvalidArgument +from hypothesis.internal.compat import getfullargspec +from hypothesis.internal.reflection import define_function_signature, \ + convert_positional_arguments, get_pretty_function_description + + +@given(st.integers()) +def test_has_an_annotation(i: int): + pass + + +def universal_acceptor(*args, **kwargs): + return args, kwargs + + +def has_annotation(a: int, *b, c=2) -> None: + pass + + +@pytest.mark.parametrize('f', [ + has_annotation, + lambda *, a: a, + lambda *, a=1: a, +]) +def test_copying_preserves_argspec(f): + af = getfullargspec(f) + t = define_function_signature('foo', 'docstring', af)(universal_acceptor) + at = getfullargspec(t) + assert af.args == at.args[:len(af.args)] + assert af.varargs == at.varargs + assert af.varkw == at.varkw + assert len(af.defaults or ()) == len(at.defaults or ()) + assert af.kwonlyargs == at.kwonlyargs + assert af.kwonlydefaults == at.kwonlydefaults + assert af.annotations == at.annotations + + +@pytest.mark.parametrize('lam,source', [ + ((lambda *z, a: a), + 'lambda *z, a: a'), + ((lambda *z, a=1: a), + 'lambda *z, a=1: a'), + ((lambda *, a: a), + 'lambda *, a: a'), + ((lambda *, a=1: a), + 'lambda *, a=1: a'), +]) +def test_py3only_lambda_formatting(lam, source): + # Testing kwonly lambdas, with and without varargs and default values + assert get_pretty_function_description(lam) == source + + +def test_given_notices_missing_kwonly_args(): + with pytest.raises(InvalidArgument): + @given(a=st.none()) + def reqs_kwonly(*, a, b): + pass + + +def test_converter_handles_kwonly_args(): + def f(*, a, b=2): + pass + + out = convert_positional_arguments(f, (), dict(a=1)) + assert out == ((), dict(a=1, b=2)) + + +def test_converter_notices_missing_kwonly_args(): + def f(*, a, b=2): + pass + + with pytest.raises(TypeError): + assert convert_positional_arguments(f, (), dict()) + + +def pointless_composite(draw: None, strat: bool, nothing: list) -> int: + return 3 + + +def return_annot() -> int: + return 4 # per RFC 1149.5 / xckd 221 + + +def first_annot(draw: None): + pass + + +def test_composite_edits_annotations(): + spec_comp = getfullargspec(st.composite(pointless_composite)) + assert spec_comp.annotations['return'] == int + assert 'nothing' in spec_comp.annotations + assert 'draw' not in spec_comp.annotations + + +@pytest.mark.parametrize('nargs', [1, 2, 3]) +def test_given_edits_annotations(nargs): + spec_given = getfullargspec( + given(*(nargs * [st.none()]))(pointless_composite)) + assert spec_given.annotations.pop('return') is None + assert len(spec_given.annotations) == 3 - nargs + + +def a_converter(x) -> int: + return int(x) + + +@attr.s +class Inferrables(object): + annot_converter = attr.ib(converter=a_converter) + + +@pytest.mark.skipif(sys.version_info[:2] <= (3, 5), + reason="Too-old typing module can't get return value hint") +@given(st.builds(Inferrables)) +def test_attrs_inference_builds(c): + pass + + +@pytest.mark.skipif(sys.version_info[:2] <= (3, 5), + reason="Too-old typing module can't get return value hint") +@given(st.from_type(Inferrables)) +def test_attrs_inference_from_type(c): + pass diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/py3/test_asyncio.py python-hypothesis-3.71.11/hypothesis-python/tests/py3/test_asyncio.py --- python-hypothesis-3.44.1/hypothesis-python/tests/py3/test_asyncio.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/py3/test_asyncio.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,70 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import asyncio +import unittest +from unittest import TestCase + +import pytest + +import hypothesis.strategies as st +from hypothesis import given, assume +from hypothesis.internal.compat import PYPY + + +class TestAsyncio(TestCase): + + timeout = 5 + + def setUp(self): + self.loop = asyncio.new_event_loop() + asyncio.set_event_loop(self.loop) + + def tearDown(self): + self.loop.close() + + def execute_example(self, f): + error = None + + def g(): + nonlocal error + try: + x = f() + if x is not None: + yield from x + except BaseException as e: + error = e + coro = asyncio.coroutine(g) + future = asyncio.wait_for(coro(), + timeout=self.timeout) + self.loop.run_until_complete(future) + if error is not None: + raise error + + @pytest.mark.skipif(PYPY, reason='Error in asyncio.new_event_loop()') + @given(st.text()) + @asyncio.coroutine + def test_foo(self, x): + assume(x) + yield from asyncio.sleep(0.001) + assert x + + +if __name__ == '__main__': + unittest.main() diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/py3/test_lookup.py python-hypothesis-3.71.11/hypothesis-python/tests/py3/test_lookup.py --- python-hypothesis-3.44.1/hypothesis-python/tests/py3/test_lookup.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/py3/test_lookup.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,449 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import io +import sys +import enum +import string +import collections + +import pytest + +import hypothesis.strategies as st +from hypothesis import HealthCheck, given, infer, assume, settings +from hypothesis.errors import NoExamples, InvalidArgument, ResolutionFailed +from tests.common.debug import minimal +from hypothesis.strategies import from_type +from hypothesis.searchstrategy import types +from hypothesis.internal.compat import ForwardRef, integer_types, \ + get_type_hints, typing_root_type + +typing = pytest.importorskip('typing') +sentinel = object() +generics = sorted((t for t in types._global_type_lookup + if isinstance(t, typing_root_type)), key=str) + + +@pytest.mark.parametrize('typ', generics) +def test_resolve_typing_module(typ): + @settings(suppress_health_check=[ + HealthCheck.too_slow, HealthCheck.filter_too_much + ]) + @given(from_type(typ)) + def inner(ex): + if typ in (typing.BinaryIO, typing.TextIO): + assert isinstance(ex, io.IOBase) + elif typ is typing.Tuple: + # isinstance is incompatible with Tuple on early 3.5 + assert ex == () + elif isinstance(typ, typing._ProtocolMeta): + pass + elif typ is typing.Type and not isinstance(typing.Type, type): + assert isinstance(ex, typing.TypeVar) + else: + try: + assert isinstance(ex, typ) + except TypeError: + if sys.version_info[:2] < (3, 6): + pytest.skip() + raise + + inner() + + +@pytest.mark.parametrize('typ', [typing.Any, typing.Union]) +def test_does_not_resolve_special_cases(typ): + with pytest.raises(InvalidArgument): + from_type(typ).example() + + +@pytest.mark.parametrize('typ,instance_of', [ + (typing.Union[int, str], (int, str)), + (typing.Optional[int], (int, type(None))), +]) +def test_specialised_scalar_types(typ, instance_of): + @given(from_type(typ)) + def inner(ex): + assert isinstance(ex, instance_of) + + inner() + + +@pytest.mark.skipif(not hasattr(typing, 'Type'), reason='requires this attr') +def test_typing_Type_int(): + assert from_type(typing.Type[int]).example() is int + + +@pytest.mark.skipif(not hasattr(typing, 'Type'), reason='requires this attr') +def test_typing_Type_Union(): + @given(from_type(typing.Type[typing.Union[str, list]])) + def inner(ex): + assert ex in (str, list) + + inner() + + +@pytest.mark.parametrize('typ,coll_type,instance_of', [ + (typing.Set[int], set, int), + (typing.FrozenSet[int], frozenset, int), + (typing.Dict[int, int], dict, int), + (typing.KeysView[int], type({}.keys()), int), + (typing.ValuesView[int], type({}.values()), int), + (typing.List[int], list, int), + (typing.Tuple[int], tuple, int), + (typing.Tuple[int, ...], tuple, int), + (typing.Iterator[int], typing.Iterator, int), + (typing.Sequence[int], typing.Sequence, int), + (typing.Iterable[int], typing.Iterable, int), + (typing.Mapping[int, None], typing.Mapping, int), + (typing.Container[int], typing.Container, int), + (typing.NamedTuple('A_NamedTuple', (('elem', int),)), tuple, int), +]) +def test_specialised_collection_types(typ, coll_type, instance_of): + @given(from_type(typ)) + def inner(ex): + if sys.version_info[:2] >= (3, 6): + assume(ex) + assert isinstance(ex, coll_type) + assert all(isinstance(elem, instance_of) for elem in ex) + + try: + inner() + except (ResolutionFailed, AssertionError): + if sys.version_info[:2] < (3, 6): + pytest.skip('Hard-to-reproduce bug (early version of typing?)') + raise + + +@pytest.mark.skipif(sys.version_info[:2] < (3, 6), reason='new addition') +def test_36_specialised_collection_types(): + @given(from_type(typing.DefaultDict[int, int])) + def inner(ex): + if sys.version_info[:2] >= (3, 6): + assume(ex) + assert isinstance(ex, collections.defaultdict) + assert all(isinstance(elem, int) for elem in ex) + assert all(isinstance(elem, int) for elem in ex.values()) + + inner() + + +@pytest.mark.skipif(sys.version_info[:3] <= (3, 5, 1), reason='broken') +def test_ItemsView(): + @given(from_type(typing.ItemsView[int, int])) + def inner(ex): + # See https://github.com/python/typing/issues/177 + if sys.version_info[:2] >= (3, 6): + assume(ex) + assert isinstance(ex, type({}.items())) + assert all(isinstance(elem, tuple) and len(elem) == 2 for elem in ex) + assert all(all(isinstance(e, int) for e in elem) for elem in ex) + + inner() + + +def test_Optional_minimises_to_None(): + assert minimal(from_type(typing.Optional[int]), lambda ex: True) is None + + +@pytest.mark.parametrize('n', range(10)) +def test_variable_length_tuples(n): + type_ = typing.Tuple[int, ...] + try: + from_type(type_).filter(lambda ex: len(ex) == n).example() + except NoExamples: + if sys.version_info[:2] < (3, 6): + pytest.skip() + raise + + +@pytest.mark.skipif(sys.version_info[:3] <= (3, 5, 1), reason='broken') +def test_lookup_overrides_defaults(): + sentinel = object() + try: + st.register_type_strategy(int, st.just(sentinel)) + + @given(from_type(typing.List[int])) + def inner_1(ex): + assert all(elem is sentinel for elem in ex) + + inner_1() + finally: + st.register_type_strategy(int, st.integers()) + st.from_type.__clear_cache() + + @given(from_type(typing.List[int])) + def inner_2(ex): + assert all(isinstance(elem, int) for elem in ex) + + inner_2() + + +def test_register_generic_typing_strats(): + # I don't expect anyone to do this, but good to check it works as expected + try: + # We register sets for the abstract sequence type, which masks subtypes + # from supertype resolution but not direct resolution + st.register_type_strategy( + typing.Sequence, + types._global_type_lookup[typing.Set] + ) + + @given(from_type(typing.Sequence[int])) + def inner_1(ex): + assert isinstance(ex, set) + + @given(from_type(typing.Container[int])) + def inner_2(ex): + assert not isinstance(ex, typing.Sequence) + + @given(from_type(typing.List[int])) + def inner_3(ex): + assert isinstance(ex, list) + + inner_1() + inner_2() + inner_3() + finally: + types._global_type_lookup.pop(typing.Sequence) + st.from_type.__clear_cache() + + +@pytest.mark.parametrize('typ', [ + typing.Sequence, typing.Container, typing.Mapping, typing.Reversible, + typing.SupportsBytes, typing.SupportsAbs, typing.SupportsComplex, + typing.SupportsFloat, typing.SupportsInt, typing.SupportsRound, +]) +def test_resolves_weird_types(typ): + from_type(typ).example() + + +@pytest.mark.parametrize('var,expected', [ + (typing.TypeVar('V'), object), + (typing.TypeVar('V', bound=int), int), + (typing.TypeVar('V', int, str), (int, str)), +]) +@given(data=st.data()) +def test_typevar_type_is_consistent(data, var, expected): + strat = st.from_type(var) + v1 = data.draw(strat) + v2 = data.draw(strat) + assume(v1 != v2) # Values may vary, just not types + assert type(v1) == type(v2) + assert isinstance(v1, expected) + + +def annotated_func(a: int, b: int=2, *, c: int, d: int=4): + return a + b + c + d + + +def test_issue_946_regression(): + # Turned type hints into kwargs even if the required posarg was passed + st.builds(annotated_func, st.integers()).example() + + +@pytest.mark.parametrize('thing', [ + annotated_func, # Works via typing.get_type_hints + typing.NamedTuple('N', [('a', int)]), # Falls back to inspection + int, # Fails; returns empty dict +]) +def test_can_get_type_hints(thing): + assert isinstance(get_type_hints(thing), dict) + + +def test_force_builds_to_infer_strategies_for_default_args(): + # By default, leaves args with defaults and minimises to 2+4=6 + assert minimal(st.builds(annotated_func), lambda ex: True) == 6 + # Inferring integers() for args makes it minimise to zero + assert minimal(st.builds(annotated_func, b=infer, d=infer), + lambda ex: True) == 0 + + +def non_annotated_func(a, b=2, *, c, d=4): + pass + + +def test_cannot_pass_infer_as_posarg(): + with pytest.raises(InvalidArgument): + st.builds(annotated_func, infer).example() + + +def test_cannot_force_inference_for_unannotated_arg(): + with pytest.raises(InvalidArgument): + st.builds(non_annotated_func, a=infer, c=st.none()).example() + with pytest.raises(InvalidArgument): + st.builds(non_annotated_func, a=st.none(), c=infer).example() + + +class UnknownType(object): + def __init__(self, arg): + pass + + +class UnknownAnnotatedType(object): + def __init__(self, arg: int): + pass + + +@given(st.from_type(UnknownAnnotatedType)) +def test_builds_for_unknown_annotated_type(ex): + assert isinstance(ex, UnknownAnnotatedType) + + +def unknown_annotated_func(a: UnknownType, b=2, *, c: UnknownType, d=4): + pass + + +def test_raises_for_arg_with_unresolvable_annotation(): + with pytest.raises(ResolutionFailed): + st.builds(unknown_annotated_func).example() + with pytest.raises(ResolutionFailed): + st.builds(unknown_annotated_func, a=st.none(), c=infer).example() + + +@given(a=infer, b=infer) +def test_can_use_type_hints(a: int, b: float): + assert isinstance(a, int) and isinstance(b, float) + + +def test_error_if_has_unresolvable_hints(): + @given(a=infer) + def inner(a: UnknownType): + pass + with pytest.raises(InvalidArgument): + inner() + + +@pytest.mark.skipif(not hasattr(typing, 'NewType'), reason='test for NewType') +def test_resolves_NewType(): + typ = typing.NewType('T', int) + nested = typing.NewType('NestedT', typ) + uni = typing.NewType('UnionT', typing.Optional[int]) + assert isinstance(from_type(typ).example(), integer_types) + assert isinstance(from_type(nested).example(), integer_types) + assert isinstance(from_type(uni).example(), integer_types + (type(None),)) + + +E = enum.Enum('E', 'a b c') + + +@given(from_type(E)) +def test_resolves_enum(ex): + assert isinstance(ex, E) + + +@pytest.mark.skipif(not hasattr(enum, 'Flag'), reason='test for Flag') +@pytest.mark.parametrize('resolver', [from_type, st.sampled_from]) +def test_resolves_flag_enum(resolver): + # Storing all combinations takes O(2^n) memory. Using an enum of 52 + # members in this test ensures that we won't try! + F = enum.Flag('F', ' '.join(string.ascii_letters)) + # Filter to check that we can generate compound members of enum.Flags + + @given(resolver(F).filter(lambda ex: ex not in tuple(F))) + def inner(ex): + assert isinstance(ex, F) + + inner() + + +class AnnotatedTarget(object): + + def __init__(self, a: int, b: int): + pass + + def method(self, a: int, b: int): + pass + + +@pytest.mark.parametrize('target', [ + AnnotatedTarget, AnnotatedTarget(1, 2).method +]) +@pytest.mark.parametrize('args,kwargs', [ + ((), {}), + ((1,), {}), + ((1, 2), {}), + ((), dict(a=1)), + ((), dict(b=2)), + ((), dict(a=1, b=2)), +]) +def test_required_args(target, args, kwargs): + # Mostly checking that `self` (and only self) is correctly excluded + st.builds(target, *map(st.just, args), + **{k: st.just(v) for k, v in kwargs.items()}).example() + + +AnnotatedNamedTuple = typing.NamedTuple('AnnotatedNamedTuple', [('a', str)]) + + +@given(st.builds(AnnotatedNamedTuple)) +def test_infers_args_for_namedtuple_builds(thing): + assert isinstance(thing.a, str) + + +@given(st.from_type(AnnotatedNamedTuple)) +def test_infers_args_for_namedtuple_from_type(thing): + assert isinstance(thing.a, str) + + +@given(st.builds(AnnotatedNamedTuple, a=st.none())) +def test_override_args_for_namedtuple(thing): + assert thing.a is None + + +@pytest.mark.parametrize('thing', [ + typing.Optional, typing.List, getattr(typing, 'Type', typing.Set) +]) # check Type if it's available, otherwise Set is redundant but harmless +def test_cannot_resolve_bare_forward_reference(thing): + with pytest.raises(InvalidArgument): + t = thing['int'] + if type(getattr(t, '__args__', [None])[0]) != ForwardRef: + assert sys.version_info[:2] == (3, 5) + pytest.xfail('python 3.5 typing module is really weird') + st.from_type(t).example() + + +class Tree: + def __init__(self, + left: typing.Optional['Tree'], + right: typing.Optional['Tree']): + self.left = left + self.right = right + + def __repr__(self): + return 'Tree({}, {})'.format(self.left, self.right) + + +def test_resolving_recursive_type(): + try: + assert isinstance(st.builds(Tree).example(), Tree) + except ResolutionFailed: + assert sys.version_info[:2] == (3, 5) + pytest.xfail('python 3.5 typing module may not resolve annotations') + except TypeError: + # TypeError raised if typing.get_type_hints(Tree.__init__) fails; see + # https://github.com/HypothesisWorks/hypothesis-python/issues/1074 + assert sys.version_info[:2] == (3, 5) + pytest.skip('Could not find type hints to resolve') + + +@given(from_type(typing.Tuple[()])) +def test_resolves_empty_Tuple_issue_1583_regression(ex): + # See e.g. https://github.com/python/mypy/commit/71332d58 + assert ex == () diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/py3/test_unicode_identifiers.py python-hypothesis-3.71.11/hypothesis-python/tests/py3/test_unicode_identifiers.py --- python-hypothesis-3.44.1/hypothesis-python/tests/py3/test_unicode_identifiers.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/py3/test_unicode_identifiers.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,42 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from hypothesis.internal.reflection import proxies + + +def test_can_copy_argspec_of_unicode_args(): + def foo(μ): + return μ + + @proxies(foo) + def bar(μ): + return foo(μ) + + assert bar(1) == 1 + + +def test_can_copy_argspec_of_unicode_name(): + def ā(): + return 1 + + @proxies(ā) + def bar(): + return 2 + + assert bar() == 2 diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/pytest/test_capture.py python-hypothesis-3.71.11/hypothesis-python/tests/pytest/test_capture.py --- python-hypothesis-3.44.1/hypothesis-python/tests/pytest/test_capture.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/pytest/test_capture.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,154 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import pytest + +from hypothesis.internal.compat import PY2, WINDOWS, hunichr, \ + escape_unicode_characters + +pytest_plugins = str('pytester') + +TESTSUITE = """ +from hypothesis import given, settings, Verbosity +from hypothesis.strategies import integers + +@settings(verbosity=Verbosity.verbose) +@given(integers()) +def test_should_be_verbose(x): + pass + +""" + + +@pytest.mark.parametrize('capture,expected', [ + ('no', True), + ('fd', False), +]) +def test_output_without_capture(testdir, capture, expected): + script = testdir.makepyfile(TESTSUITE) + result = testdir.runpytest(script, '--verbose', '--capture', capture) + out = '\n'.join(result.stdout.lines) + assert 'test_should_be_verbose' in out + assert ('Trying example' in out) == expected + assert result.ret == 0 + + +UNICODE_EMITTING = """ +import pytest +from hypothesis import given, settings, Verbosity +from hypothesis.strategies import text +from hypothesis.internal.compat import PY3 +import sys + +def test_emits_unicode(): + @settings(verbosity=Verbosity.verbose) + @given(text()) + def test_should_emit_unicode(t): + assert all(ord(c) <= 1000 for c in t) + with pytest.raises(AssertionError): + test_should_emit_unicode() +""" + + +@pytest.mark.xfail( + WINDOWS, + reason=( + "Encoding issues in running the subprocess, possibly py.test's fault")) +@pytest.mark.skipif( + PY2, reason="Output streams don't have encodings in python 2") +def test_output_emitting_unicode(testdir, monkeypatch): + monkeypatch.setenv('LC_ALL', 'C') + monkeypatch.setenv('LANG', 'C') + script = testdir.makepyfile(UNICODE_EMITTING) + result = getattr( + testdir, 'runpytest_subprocess', testdir.runpytest)( + script, '--verbose', '--capture=no') + out = '\n'.join(result.stdout.lines) + assert 'test_emits_unicode' in out + assert hunichr(1001) in out or \ + escape_unicode_characters(hunichr(1001)) in out + assert result.ret == 0 + + +TRACEBACKHIDE_TIMEOUT = """ +from hypothesis import given, settings, reject +from hypothesis.strategies import integers +from hypothesis.errors import HypothesisDeprecationWarning + +import time +import warnings +import pytest + + +def test_timeout_traceback_is_hidden(): + with warnings.catch_warnings(record=True): + warnings.simplefilter('ignore', HypothesisDeprecationWarning) + @given(integers()) + @settings(timeout=1) + def inner(i): + time.sleep(1.1) + reject() + inner() +""" + + +def get_line_num(token, result, skip_n=0): + skipped = 0 + for i, line in enumerate(result.stdout.lines): + if token in line: + if skip_n == skipped: + return i + else: + skipped += 1 + assert False, 'Token %r not found (skipped %r of planned %r skips)' % ( + token, skipped, skip_n) + + +def test_timeout_traceback_is_hidden(testdir): + script = testdir.makepyfile(TRACEBACKHIDE_TIMEOUT) + result = testdir.runpytest(script, '--verbose') + # `def inner` shows up in the output twice: once when pytest shows us the + # source code of the failing test, and once in the traceback. + # It's the 2nd that should be next to the "Timeout: ..." message. + def_line = get_line_num('def inner', result, skip_n=1) + timeout_line = get_line_num('Timeout: Ran out of time', result) + # If __tracebackhide__ works, then the Timeout error message will be + # next to the test name. If it doesn't work, then the message will be + # many lines apart with source code dump between them. + assert timeout_line - def_line == 1 + + +TRACEBACKHIDE_HEALTHCHECK = """ +from hypothesis import given, settings +from hypothesis.strategies import integers +import time +@given(integers().map(lambda x: time.sleep(0.2))) +def test_healthcheck_traceback_is_hidden(x): + pass +""" + + +def test_healthcheck_traceback_is_hidden(testdir): + script = testdir.makepyfile(TRACEBACKHIDE_HEALTHCHECK) + result = testdir.runpytest(script, '--verbose') + def_token = '__ test_healthcheck_traceback_is_hidden __' + timeout_token = ': FailedHealthCheck' + def_line = get_line_num(def_token, result) + timeout_line = get_line_num(timeout_token, result) + assert timeout_line - def_line == 6 diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/pytest/test_compat.py python-hypothesis-3.71.11/hypothesis-python/tests/pytest/test_compat.py --- python-hypothesis-3.44.1/hypothesis-python/tests/pytest/test_compat.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/pytest/test_compat.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,29 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import pytest + +from hypothesis import given +from hypothesis.strategies import booleans + + +@given(booleans()) +@pytest.mark.parametrize('hi', (1, 2, 3)) +def test_parametrize_after_given(hi, i): + pass diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/pytest/test_doctest.py python-hypothesis-3.71.11/hypothesis-python/tests/pytest/test_doctest.py --- python-hypothesis-3.44.1/hypothesis-python/tests/pytest/test_doctest.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/pytest/test_doctest.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,33 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +pytest_plugins = 'pytester' + + +def test_can_run_doctests(testdir): + script = testdir.makepyfile( + 'def hi():\n' + ' """\n' + ' >>> i = 5\n' + ' >>> i-1\n' + ' 4"""' + ) + + result = testdir.runpytest(script, '--doctest-modules') + assert result.ret == 0 diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/pytest/test_fixtures.py python-hypothesis-3.71.11/hypothesis-python/tests/pytest/test_fixtures.py --- python-hypothesis-3.44.1/hypothesis-python/tests/pytest/test_fixtures.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/pytest/test_fixtures.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,81 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import pytest +from mock import Mock, create_autospec + +from hypothesis import given, example +from tests.common.utils import fails +from hypothesis.strategies import integers + + +@pytest.fixture +def infinity(): + return float('inf') + + +@pytest.fixture +def mock_fixture(): + return Mock() + + +@pytest.fixture +def spec_fixture(): + class Foo(): + def __init__(self): + pass + + def bar(self): + return 'baz' + return create_autospec(Foo) + + +@given(integers()) +def test_can_mix_fixture_and_positional_strategy(infinity, xs): + # Hypothesis fills arguments from the right, so if @given() uses + # positional arguments then any strategies need to be on the right. + assert xs <= infinity + + +@given(xs=integers()) +def test_can_mix_fixture_and_keyword_strategy(xs, infinity): + assert xs <= infinity + + +@example(xs=0) +@given(xs=integers()) +def test_can_mix_fixture_example_and_keyword_strategy(xs, infinity): + assert xs <= infinity + + +@fails +@given(integers()) +def test_can_inject_mock_via_fixture(mock_fixture, xs): + """A negative test is better for this one - this condition uncovers a bug + whereby the mock fixture is executed instead of the test body and always + succeeds. If this test fails, then we know we've run the test body instead + of the mock. + """ + assert False + + +@given(integers()) +def test_can_inject_autospecced_mock_via_fixture(spec_fixture, xs): + spec_fixture.bar.return_value = float('inf') + assert xs <= spec_fixture.bar() diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/pytest/test_mark.py python-hypothesis-3.71.11/hypothesis-python/tests/pytest/test_mark.py --- python-hypothesis-3.44.1/hypothesis-python/tests/pytest/test_mark.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/pytest/test_mark.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,64 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +pytest_plugins = str('pytester') + + +TESTSUITE = """ +from hypothesis import given +from hypothesis.strategies import integers + +@given(integers()) +def test_foo(x): + pass + +def test_bar(): + pass +""" + + +def test_can_select_mark(testdir): + script = testdir.makepyfile(TESTSUITE) + result = testdir.runpytest(script, '--verbose', '--strict', '-m', + 'hypothesis') + out = '\n'.join(result.stdout.lines) + assert '1 passed, 1 deselected' in out + + +UNITTEST_TESTSUITE = """ +from hypothesis import given +from hypothesis.strategies import integers +from unittest import TestCase + +class TestStuff(TestCase): + @given(integers()) + def test_foo(self, x): + pass + + def test_bar(self): + pass +""" + + +def test_can_select_mark_on_unittest(testdir): + script = testdir.makepyfile(UNITTEST_TESTSUITE) + result = testdir.runpytest(script, '--verbose', '--strict', '-m', + 'hypothesis') + out = '\n'.join(result.stdout.lines) + assert '1 passed, 1 deselected' in out diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/pytest/test_profiles.py python-hypothesis-3.71.11/hypothesis-python/tests/pytest/test_profiles.py --- python-hypothesis-3.44.1/hypothesis-python/tests/pytest/test_profiles.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/pytest/test_profiles.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,47 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from hypothesis.version import __version__ +from hypothesis.extra.pytestplugin import LOAD_PROFILE_OPTION + +pytest_plugins = str('pytester') + +CONFTEST = """ +from hypothesis._settings import settings +settings.register_profile("test", settings(max_examples=1)) +""" + +TESTSUITE = """ +from hypothesis import given +from hypothesis.strategies import integers +from hypothesis._settings import settings + +def test_this_one_is_ok(): + assert settings().max_examples == 1 +""" + + +def test_runs_reporting_hook(testdir): + script = testdir.makepyfile(TESTSUITE) + testdir.makeconftest(CONFTEST) + result = testdir.runpytest(script, LOAD_PROFILE_OPTION, 'test') + out = '\n'.join(result.stdout.lines) + assert '1 passed' in out + assert 'max_examples=1' in out + assert __version__ in out diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/pytest/test_pytest_detection.py python-hypothesis-3.71.11/hypothesis-python/tests/pytest/test_pytest_detection.py --- python-hypothesis-3.44.1/hypothesis-python/tests/pytest/test_pytest_detection.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/pytest/test_pytest_detection.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,42 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +"""This module provides the core primitives of Hypothesis, such as given.""" + + +from __future__ import division, print_function, absolute_import + +import sys +import subprocess + +import hypothesis.core as core + + +def test_is_running_under_pytest(): + assert core.running_under_pytest + + +FILE_TO_RUN = """ +import hypothesis.core as core +assert not core.running_under_pytest +""" + + +def test_is_not_running_under_pytest(tmpdir): + pyfile = tmpdir.join('test.py') + pyfile.write(FILE_TO_RUN) + subprocess.check_call([sys.executable, str(pyfile)]) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/pytest/test_reporting.py python-hypothesis-3.71.11/hypothesis-python/tests/pytest/test_reporting.py --- python-hypothesis-3.44.1/hypothesis-python/tests/pytest/test_reporting.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/pytest/test_reporting.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,44 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +pytest_plugins = str('pytester') + + +TESTSUITE = """ +from hypothesis import given +from hypothesis.strategies import lists, integers + +@given(integers()) +def test_this_one_is_ok(x): + pass + +@given(lists(integers())) +def test_hi(xs): + assert False +""" + + +def test_runs_reporting_hook(testdir): + script = testdir.makepyfile(TESTSUITE) + result = testdir.runpytest(script, '--verbose') + out = '\n'.join(result.stdout.lines) + assert 'test_this_one_is_ok' in out + assert 'Captured stdout call' not in out + assert 'Falsifying example' in out + assert result.ret != 0 diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/pytest/test_runs.py python-hypothesis-3.71.11/hypothesis-python/tests/pytest/test_runs.py --- python-hypothesis-3.44.1/hypothesis-python/tests/pytest/test_runs.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/pytest/test_runs.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,33 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from hypothesis import given +from tests.common.utils import fails +from hypothesis.strategies import integers + + +@given(integers()) +def test_ints_are_ints(x): + pass + + +@fails +@given(integers()) +def test_ints_are_floats(x): + assert isinstance(x, float) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/pytest/test_seeding.py python-hypothesis-3.71.11/hypothesis-python/tests/pytest/test_seeding.py --- python-hypothesis-3.44.1/hypothesis-python/tests/pytest/test_seeding.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/pytest/test_seeding.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,124 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import re + +import pytest + +from hypothesis.internal.compat import hrange + +pytest_plugins = str('pytester') + + +TEST_SUITE = """ +from hypothesis import given, settings, assume +import hypothesis.strategies as st + + +first = None + +@settings(database=None) +@given(st.integers()) +def test_fails_once(some_int): + assume(abs(some_int) > 10000) + global first + if first is None: + first = some_int + + assert some_int != first +""" + + +CONTAINS_SEED_INSTRUCTION = re.compile(r"--hypothesis-seed=\d+", re.MULTILINE) + + +@pytest.mark.parametrize('seed', [0, 42, 'foo']) +def test_runs_repeatably_when_seed_is_set(seed, testdir): + script = testdir.makepyfile(TEST_SUITE) + + results = [ + testdir.runpytest( + script, '--verbose', '--strict', '--hypothesis-seed', str(seed) + ) + for _ in hrange(2) + ] + + for r in results: + for l in r.stdout.lines: + assert '--hypothesis-seed' not in l + + failure_lines = [ + l + for r in results + for l in r.stdout.lines + if 'some_int=' in l + ] + + assert len(failure_lines) == 2 + assert failure_lines[0] == failure_lines[1] + + +HEALTH_CHECK_FAILURE = """ +import os + +from hypothesis import given, strategies as st, assume, reject + +RECORD_EXAMPLES = + +if os.path.exists(RECORD_EXAMPLES): + target = None + with open(RECORD_EXAMPLES, 'r') as i: + seen = set(map(int, i.read().strip().split("\\n"))) +else: + target = open(RECORD_EXAMPLES, 'w') + +@given(st.integers()) +def test_failure(i): + if target is None: + assume(i not in seen) + else: + target.write("%s\\n" % (i,)) + reject() +""" + + +def test_repeats_healthcheck_when_following_seed_instruction(testdir, tmpdir): + health_check_test = HEALTH_CHECK_FAILURE.replace( + '', repr(str(tmpdir.join('seen')))) + + script = testdir.makepyfile(health_check_test) + + initial = testdir.runpytest(script, '--verbose', '--strict',) + + match = CONTAINS_SEED_INSTRUCTION.search('\n'.join(initial.stdout.lines)) + initial_output = '\n'.join(initial.stdout.lines) + + match = CONTAINS_SEED_INSTRUCTION.search(initial_output) + assert match is not None + + rerun = testdir.runpytest(script, '--verbose', '--strict', match.group(0)) + rerun_output = '\n'.join(rerun.stdout.lines) + + assert 'FailedHealthCheck' in rerun_output + assert '--hypothesis-seed' not in rerun_output + + rerun2 = testdir.runpytest( + script, '--verbose', '--strict', '--hypothesis-seed=10') + rerun2_output = '\n'.join(rerun2.stdout.lines) + assert 'FailedHealthCheck' not in rerun2_output diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/pytest/test_skipping.py python-hypothesis-3.71.11/hypothesis-python/tests/pytest/test_skipping.py --- python-hypothesis-3.44.1/hypothesis-python/tests/pytest/test_skipping.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/pytest/test_skipping.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,45 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +pytest_plugins = str('pytester') + + +PYTEST_TESTSUITE = """ +from hypothesis import given +from hypothesis.strategies import integers +import pytest + +@given(xs=integers()) +def test_to_be_skipped(xs): + if xs == 0: + pytest.skip() + else: + assert xs == 0 +""" + + +def test_no_falsifying_example_if_pytest_skip(testdir): + """If ``pytest.skip() is called during a test, Hypothesis should not + continue running the test and shrink process, nor should it print anything + about falsifying examples.""" + script = testdir.makepyfile(PYTEST_TESTSUITE) + result = testdir.runpytest(script, '--verbose', '--strict', '-m', + 'hypothesis') + out = '\n'.join(result.stdout.lines) + assert 'Falsifying example' not in out diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/pytest/test_statistics.py python-hypothesis-3.71.11/hypothesis-python/tests/pytest/test_statistics.py --- python-hypothesis-3.44.1/hypothesis-python/tests/pytest/test_statistics.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/pytest/test_statistics.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,117 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from hypothesis.extra.pytestplugin import PRINT_STATISTICS_OPTION + +pytest_plugins = 'pytester' + + +TESTSUITE = """ +from hypothesis import HealthCheck, given, settings, assume +from hypothesis.strategies import integers +import time +import warnings +from hypothesis.errors import HypothesisDeprecationWarning + +warnings.simplefilter('always', HypothesisDeprecationWarning) + + +@given(integers()) +def test_all_valid(x): + pass + + +@settings(timeout=0.2) +@given(integers()) +def test_slow(x): + time.sleep(0.1) + + +@settings(max_examples=100, suppress_health_check=HealthCheck.all()) +@given(integers()) +def test_iterations(x): + assume(x == 0) +""" + + +def test_does_not_run_statistics_by_default(testdir): + script = testdir.makepyfile(TESTSUITE) + result = testdir.runpytest(script) + out = '\n'.join(result.stdout.lines) + assert 'Hypothesis Statistics' not in out + + +def test_prints_statistics_given_option(testdir): + script = testdir.makepyfile(TESTSUITE) + result = testdir.runpytest(script, PRINT_STATISTICS_OPTION) + out = '\n'.join(result.stdout.lines) + assert 'Hypothesis Statistics' in out + assert 'timeout=0.2' in out + assert 'max_examples=100' in out + assert '< 10% of examples satisfied assumptions' in out + + +UNITTEST_TESTSUITE = """ + +from hypothesis import given +from hypothesis.strategies import integers +from unittest import TestCase + + +class TestStuff(TestCase): + @given(integers()) + def test_all_valid(self, x): + pass +""" + + +def test_prints_statistics_for_unittest_tests(testdir): + script = testdir.makepyfile(UNITTEST_TESTSUITE) + result = testdir.runpytest(script, PRINT_STATISTICS_OPTION) + out = '\n'.join(result.stdout.lines) + assert 'Hypothesis Statistics' in out + assert 'TestStuff::test_all_valid' in out + assert 'max_examples=100' in out + + +STATEFUL_TESTSUITE = """ + +from hypothesis import given +from hypothesis.strategies import integers +from hypothesis.stateful import GenericStateMachine + + +class Stuff(GenericStateMachine): + def steps(self): + return integers() + + def execute_step(self, step): + pass + +TestStuff = Stuff.TestCase +""" + + +def test_prints_statistics_for_stateful_tests(testdir): + script = testdir.makepyfile(STATEFUL_TESTSUITE) + result = testdir.runpytest(script, PRINT_STATISTICS_OPTION) + out = '\n'.join(result.stdout.lines) + assert 'Hypothesis Statistics' in out + assert 'TestStuff::runTest' in out + assert 'max_examples=100' in out diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/quality/__init__.py python-hypothesis-3.71.11/hypothesis-python/tests/quality/__init__.py --- python-hypothesis-3.44.1/hypothesis-python/tests/quality/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/quality/__init__.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,16 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/quality/test_deferred_strategies.py python-hypothesis-3.71.11/hypothesis-python/tests/quality/test_deferred_strategies.py --- python-hypothesis-3.44.1/hypothesis-python/tests/quality/test_deferred_strategies.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/quality/test_deferred_strategies.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,54 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from hypothesis import strategies as st +from tests.common.debug import minimal + + +def test_large_branching_tree(): + tree = st.deferred( + lambda: st.integers() | st.tuples(tree, tree, tree, tree, tree)) + assert minimal(tree) == 0 + assert minimal(tree, lambda x: isinstance(x, tuple)) == (0,) * 5 + + +def test_non_trivial_json(): + json = st.deferred( + lambda: st.none() | st.floats() | st.text() | lists | objects + ) + + lists = st.lists(json) + objects = st.dictionaries(st.text(), json) + + assert minimal(json) is None + + small_list = minimal(json, lambda x: isinstance(x, list) and x) + assert small_list == [None] + + x = minimal( + json, lambda x: isinstance(x, dict) and isinstance(x.get(''), list)) + + assert x == {'': []} + + +def test_self_recursive_lists(): + x = st.deferred(lambda: st.lists(x)) + assert minimal(x) == [] + assert minimal(x, bool) == [[]] + assert minimal(x, lambda x: len(x) > 1) == [[], []] diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/quality/test_discovery_ability.py python-hypothesis-3.71.11/hypothesis-python/tests/quality/test_discovery_ability.py --- python-hypothesis-3.44.1/hypothesis-python/tests/quality/test_discovery_ability.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/quality/test_discovery_ability.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,408 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +# -*- coding: utf-8 -*- +"""Statistical tests over the forms of the distributions in the standard set of +definitions. + +These tests all take the form of a classic hypothesis test with the null +hypothesis being that the probability of some event occurring when +drawing data from the distribution produced by some specifier is >= +REQUIRED_P +""" + + +from __future__ import division, print_function, absolute_import + +import re +import math +import collections + +import hypothesis.internal.reflection as reflection +from hypothesis import settings as Settings +from hypothesis.errors import UnsatisfiedAssumption +from tests.common.utils import no_shrink +from hypothesis.strategies import just, sets, text, lists, floats, \ + one_of, tuples, booleans, integers, sampled_from +from hypothesis.internal.conjecture.engine import \ + ConjectureRunner as ConConjectureRunner + +RUNS = 100 +REQUIRED_RUNS = 50 + + +INITIAL_LAMBDA = re.compile(u'^lambda[^:]*:\\s*') + + +def strip_lambda(s): + return INITIAL_LAMBDA.sub(u'', s) + + +class HypothesisFalsified(AssertionError): + pass + + +def define_test(specifier, predicate, condition=None): + def run_test(): + if condition is None: + def _condition(x): + return True + condition_string = u'' + else: + _condition = condition + condition_string = strip_lambda( + reflection.get_pretty_function_description(condition)) + + def test_function(data): + try: + value = data.draw(specifier) + except UnsatisfiedAssumption: + data.mark_invalid() + if not _condition(value): + data.mark_invalid() + if predicate(value): + data.mark_interesting() + + successes = 0 + for _ in range(RUNS): + runner = ConConjectureRunner( + test_function, + settings=Settings( + max_examples=100, + phases=no_shrink + )) + runner.run() + if runner.interesting_examples: + successes += 1 + if successes >= REQUIRED_RUNS: + return + event = reflection.get_pretty_function_description(predicate) + if condition is not None: + event += '|' + event += condition_string + + description = ( + u'P(%s) ~ %d / %d = %.2f < %.2f' + ) % ( + event, + successes, RUNS, + successes / RUNS, (REQUIRED_RUNS / RUNS) + ) + raise HypothesisFalsified(description + u' rejected') + return run_test + + +test_can_produce_zero = define_test(integers(), lambda x: x == 0) +test_can_produce_large_magnitude_integers = define_test( + integers(), lambda x: abs(x) > 1000 +) +test_can_produce_large_positive_integers = define_test( + integers(), lambda x: x > 1000 +) +test_can_produce_large_negative_integers = define_test( + integers(), lambda x: x < -1000 +) + + +def long_list(xs): + return len(xs) >= 20 + + +test_can_produce_unstripped_strings = define_test( + text(), lambda x: x != x.strip() +) + +test_can_produce_stripped_strings = define_test( + text(), lambda x: x == x.strip() +) + +test_can_produce_multi_line_strings = define_test( + text(), lambda x: u'\n' in x +) + +test_can_produce_ascii_strings = define_test( + text(), lambda x: all(ord(c) <= 127 for c in x), +) + +test_can_produce_long_strings_with_no_ascii = define_test( + text(min_size=5), lambda x: all(ord(c) > 127 for c in x), +) + +test_can_produce_short_strings_with_some_non_ascii = define_test( + text(), lambda x: any(ord(c) > 127 for c in x), + condition=lambda x: len(x) <= 3 +) + +test_can_produce_positive_infinity = define_test( + floats(), lambda x: x == float(u'inf') +) + +test_can_produce_negative_infinity = define_test( + floats(), lambda x: x == float(u'-inf') +) + +test_can_produce_nan = define_test( + floats(), math.isnan +) + +test_can_produce_floats_near_left = define_test( + floats(0, 1), + lambda t: t < 0.2 +) + +test_can_produce_floats_near_right = define_test( + floats(0, 1), + lambda t: t > 0.8 +) + +test_can_produce_floats_in_middle = define_test( + floats(0, 1), + lambda t: 0.2 <= t <= 0.8 +) + +test_can_produce_long_lists = define_test( + lists(integers()), long_list +) + +test_can_produce_short_lists = define_test( + lists(integers()), lambda x: len(x) <= 10 +) + +test_can_produce_the_same_int_twice = define_test( + lists(integers()), + lambda t: len(set(t)) < len(t) +) + + +def distorted_value(x): + c = collections.Counter(x) + return min(c.values()) * 3 <= max(c.values()) + + +def distorted(x): + return distorted_value(map(type, x)) + + +test_sampled_from_large_number_can_mix = define_test( + lists(sampled_from(range(50)), min_size=50), + lambda x: len(set(x)) >= 25, +) + + +test_sampled_from_often_distorted = define_test( + lists(sampled_from(range(5))), distorted_value, + condition=lambda x: len(x) >= 3, +) + + +test_non_empty_subset_of_two_is_usually_large = define_test( + sets(sampled_from((1, 2))), + lambda t: len(t) == 2 +) + +test_subset_of_ten_is_sometimes_empty = define_test( + sets(integers(1, 10)), lambda t: len(t) == 0 +) + +test_mostly_sensible_floats = define_test( + floats(), + lambda t: t + 1 > t +) + +test_mostly_largish_floats = define_test( + floats(), + lambda t: t + 1 > 1, + condition=lambda x: x > 0, +) + +test_ints_can_occasionally_be_really_large = define_test( + integers(), + lambda t: t >= 2 ** 63 +) + +test_mixing_is_sometimes_distorted = define_test( + lists(booleans() | tuples()), distorted, + condition=lambda x: len(set(map(type, x))) == 2, +) + +test_mixes_2_reasonably_often = define_test( + lists(booleans() | tuples()), + lambda x: len(set(map(type, x))) > 1, + condition=bool, +) + +test_partial_mixes_3_reasonably_often = define_test( + lists(booleans() | tuples() | just(u'hi')), + lambda x: 1 < len(set(map(type, x))) < 3, + condition=bool, +) + +test_mixes_not_too_often = define_test( + lists(booleans() | tuples()), + lambda x: len(set(map(type, x))) == 1, + condition=bool, +) + +test_integers_are_usually_non_zero = define_test( + integers(), lambda x: x != 0 +) + +test_integers_are_sometimes_zero = define_test( + integers(), lambda x: x == 0 +) + +test_integers_are_often_small = define_test( + integers(), lambda x: abs(x) <= 100 +) + + +test_integers_are_often_small_but_not_that_small = define_test( + integers(), lambda x: 50 <= abs(x) <= 255 +) + + +# This series of tests checks that the one_of() strategy flattens branches +# correctly. We assert that the probability of any branch is >= 0.1, +# approximately (1/8 = 0.125), regardless of how heavily nested it is in the +# strategy. + +# This first strategy chooses an integer between 0 and 7 (inclusive). +one_of_nested_strategy = one_of( + just(0), + one_of( + just(1), + just(2), + one_of( + just(3), + just(4), + one_of( + just(5), + just(6), + just(7) + ) + ) + ) +) + +for i in range(8): + exec('''test_one_of_flattens_branches_%d = define_test( + one_of_nested_strategy, lambda x: x == %d + )''' % (i, i)) + + +xor_nested_strategy = ( + just(0) | ( + just(1) | just(2) | ( + just(3) | just(4) | ( + just(5) | just(6) | just(7) + ) + ) + ) +) + +for i in range(8): + exec('''test_xor_flattens_branches_%d = define_test( + xor_nested_strategy, lambda x: x == %d + )''' % (i, i)) + + +# This strategy tests interactions with `map()`. They generate integers +# from the set {1, 4, 6, 16, 20, 24, 28, 32}. +def double(x): + return x * 2 + + +one_of_nested_strategy_with_map = one_of( + just(1), + one_of( + (just(2) | just(3)).map(double), + one_of( + (just(4) | just(5)).map(double), + one_of( + (just(6) | just(7) | just(8)).map(double) + ) + ).map(double) + ) +) + +for i in (1, 4, 6, 16, 20, 24, 28, 32): + exec('''test_one_of_flattens_map_branches_%d = define_test( + one_of_nested_strategy_with_map, lambda x: x == %d + )''' % (i, i)) + + +# This strategy tests interactions with `flatmap()`. It generates lists +# of length 0-7 (inclusive) in which every element is `None`. +one_of_nested_strategy_with_flatmap = just(None).flatmap( + lambda x: one_of( + just([x] * 0), just([x] * 1), one_of( + just([x] * 2), just([x] * 3), one_of( + just([x] * 4), just([x] * 5), one_of( + just([x] * 6), just([x] * 7), + ) + ) + ) + ) +) + +for i in range(8): + exec('''test_one_of_flattens_flatmap_branches_%d = define_test( + one_of_nested_strategy_with_flatmap, lambda x: len(x) == %d + )''' % (i, i)) + + +xor_nested_strategy_with_flatmap = just(None).flatmap( + lambda x: ( + just([x] * 0) | just([x] * 1) | ( + just([x] * 2) | just([x] * 3) | ( + just([x] * 4) | just([x] * 5) | ( + just([x] * 6) | just([x] * 7) + ) + ) + ) + ) +) + +for i in range(8): + exec('''test_xor_flattens_flatmap_branches_%d = define_test( + xor_nested_strategy_with_flatmap, lambda x: len(x) == %d + )''' % (i, i)) + + +# This strategy tests interactions with `filter()`. It generates the even +# integers {0, 2, 4, 6} in equal measures. +one_of_nested_strategy_with_filter = one_of( + just(0), + just(1), + one_of( + just(2), + just(3), + one_of( + just(4), + just(5), + one_of( + just(6), + just(7), + ) + ) + ) +).filter(lambda x: x % 2 == 0) + +for i in range(4): + exec('''test_one_of_flattens_filter_branches_%d = define_test( + one_of_nested_strategy_with_filter, lambda x: x == 2 * %d + )''' % (i, i)) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/quality/test_float_shrinking.py python-hypothesis-3.71.11/hypothesis-python/tests/quality/test_float_shrinking.py --- python-hypothesis-3.44.1/hypothesis-python/tests/quality/test_float_shrinking.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/quality/test_float_shrinking.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,67 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from random import Random + +import pytest + +import hypothesis.strategies as st +from hypothesis import Verbosity, HealthCheck, given, assume, example, \ + settings +from tests.common.debug import minimal +from hypothesis.internal.compat import ceil + + +def test_shrinks_to_simple_floats(): + assert minimal(st.floats(), lambda x: x > 1) == 2.0 + assert minimal(st.floats(), lambda x: x > 0) == 1.0 + + +@pytest.mark.parametrize('n', [1, 2, 3, 8, 10]) +def test_can_shrink_in_variable_sized_context(n): + x = minimal(st.lists(st.floats(), min_size=n), any) + assert len(x) == n + assert x.count(0.0) == n - 1 + assert 1 in x + + +@example(1.7976931348623157e+308) +@example(1.5) +@given(st.floats(min_value=0, allow_infinity=False, allow_nan=False)) +@settings(deadline=None, suppress_health_check=HealthCheck.all()) +def test_shrinks_downwards_to_integers(f): + g = minimal( + st.floats(), lambda x: x >= f, random=Random(0), + settings=settings(verbosity=Verbosity.quiet), + ) + assert g == ceil(f) + + +@example(1) +@given(st.integers(1, 2 ** 16 - 1)) +@settings(deadline=None, + suppress_health_check=HealthCheck.all(), max_examples=10) +def test_shrinks_downwards_to_integers_when_fractional(b): + g = minimal( + st.floats(), + lambda x: assume((0 < x < (2 ** 53)) and int(x) != x) and x >= b, + random=Random(0), + settings=settings(verbosity=Verbosity.quiet), + ) + assert g == b + 0.5 diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/quality/test_integers.py python-hypothesis-3.71.11/hypothesis-python/tests/quality/test_integers.py --- python-hypothesis-3.44.1/hypothesis-python/tests/quality/test_integers.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/quality/test_integers.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,111 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from random import Random + +import hypothesis.strategies as st +from hypothesis import Phase, Verbosity, HealthCheck, given, assume, \ + reject, example, settings, unlimited +from hypothesis.internal.compat import hbytes +from hypothesis.searchstrategy.numbers import WideRangeIntStrategy +from hypothesis.internal.conjecture.data import Status, StopTest, \ + ConjectureData +from hypothesis.internal.conjecture.engine import ConjectureRunner + + +@st.composite +def problems(draw): + while True: + buf = bytearray(draw(st.binary(min_size=16, max_size=16))) + while buf and not buf[-1]: + buf.pop() + try: + d = ConjectureData.for_buffer(buf) + k = d.draw(st.integers()) + stop = d.draw_bits(8) + if stop > 0 and k > 0: + return (draw(st.integers(0, k - 1)), hbytes(d.buffer)) + except (StopTest, IndexError): + pass + + +@example((2, b'\x00\x00\n\x01')) +@example((1, b'\x00\x00\x06\x01')) +@example(problem=(32768, b'\x03\x01\x00\x00\x00\x00\x00\x01\x00\x02\x01')) +@settings( + suppress_health_check=HealthCheck.all(), timeout=unlimited, deadline=None, + max_examples=10, verbosity=Verbosity.normal +) +@given(problems()) +def test_always_reduces_integers_to_smallest_suitable_sizes(problem): + n, blob = problem + blob = hbytes(blob) + try: + d = ConjectureData.for_buffer(blob) + k = d.draw(st.integers()) + stop = blob[len(d.buffer)] + except (StopTest, IndexError): + reject() + + assume(k > n) + assume(stop > 0) + + def f(data): + k = data.draw(st.integers()) + data.output = repr(k) + if data.draw_bits(8) == stop and k >= n: + data.mark_interesting() + + runner = ConjectureRunner(f, random=Random(0), settings=settings( + suppress_health_check=HealthCheck.all(), timeout=unlimited, + phases=(Phase.shrink,), database=None, verbosity=Verbosity.debug + ), database_key=None) + + runner.test_function(ConjectureData.for_buffer(blob)) + + assert runner.interesting_examples + + v, = runner.interesting_examples.values() + + shrinker = runner.new_shrinker(v, lambda x: x.status == Status.INTERESTING) + + shrinker.clear_passes() + shrinker.add_new_pass('minimize_individual_blocks') + + shrinker.shrink() + + v = shrinker.shrink_target + + m = ConjectureData.for_buffer(v.buffer).draw(st.integers()) + assert m == n + + # Upper bound on the length needed is calculated as follows: + # * We have an initial byte at the beginning to decide the length of the + # integer. + # * We have a terminal byte as the stop value. + # * The rest is the integer payload. This should be n. Including the sign + # bit, n needs (1 + n.bit_length()) / 8 bytes (rounded up). But we only + # have power of two sizes, so it may be up to a factor of two more than + # that. + bits_needed = 1 + n.bit_length() + actual_bits_needed = min( + [s for s in WideRangeIntStrategy.sizes if s >= bits_needed]) + bytes_needed = actual_bits_needed // 8 + # 3 extra bytes: two for the sampler, one for the capping value. + assert len(v.buffer) == 3 + bytes_needed diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/quality/test_poisoned_lists.py python-hypothesis-3.71.11/hypothesis-python/tests/quality/test_poisoned_lists.py --- python-hypothesis-3.44.1/hypothesis-python/tests/quality/test_poisoned_lists.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/quality/test_poisoned_lists.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,117 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from random import Random + +import pytest + +import hypothesis.strategies as st +import hypothesis.internal.conjecture.utils as cu +from hypothesis import settings, unlimited +from hypothesis.searchstrategy import SearchStrategy +from hypothesis.internal.compat import ceil, hrange +from hypothesis.internal.conjecture.engine import ConjectureData, \ + ConjectureRunner, uniform + +POISON = 'POISON' + + +class Poisoned(SearchStrategy): + def __init__(self, poison_chance): + SearchStrategy.__init__(self) + self.__poison_chance = poison_chance + self.__ints = st.integers(0, 10) + + def do_draw(self, data): + if cu.biased_coin(data, self.__poison_chance): + return POISON + else: + return data.draw(self.__ints) + + +class LinearLists(SearchStrategy): + def __init__(self, elements, size): + SearchStrategy.__init__(self) + self.__length = st.integers(0, size) + self.__elements = elements + + def do_draw(self, data): + return [ + data.draw(self.__elements) + for _ in hrange(data.draw(self.__length)) + ] + + +class Matrices(SearchStrategy): + def __init__(self, elements, size): + SearchStrategy.__init__(self) + self.__length = st.integers(0, ceil(size ** 0.5)) + self.__elements = elements + + def do_draw(self, data): + n = data.draw(self.__length) + m = data.draw(self.__length) + + return [ + data.draw(self.__elements) for _ in hrange(n * m) + ] + + +class TrialRunner(ConjectureRunner): + def generate_new_examples(self): + def draw_bytes(data, n): + return uniform(self.random, n) + + while not self.interesting_examples: + self.test_function(ConjectureData( + draw_bytes=draw_bytes, max_length=self.settings.buffer_size)) + + +LOTS = 10 ** 6 + +TRIAL_SETTINGS = settings( + max_examples=LOTS, timeout=unlimited, database=None +) + + +@pytest.mark.parametrize('seed', [ + 2282791295271755424, 1284235381287210546, 14202812238092722246, + 26097, +]) +@pytest.mark.parametrize('size', [5, 10, 20]) +@pytest.mark.parametrize('p', [0.01, 0.1]) +@pytest.mark.parametrize('strategy_class', [LinearLists, Matrices]) +def test_minimal_poisoned_containers( + seed, size, p, strategy_class, monkeypatch +): + elements = Poisoned(p) + strategy = strategy_class(elements, size) + + def test_function(data): + v = data.draw(strategy) + data.output = repr(v) + if POISON in v: + data.mark_interesting() + + runner = TrialRunner( + test_function, random=Random(seed), settings=TRIAL_SETTINGS) + runner.run() + v, = runner.interesting_examples.values() + result = ConjectureData.for_buffer(v.buffer).draw(strategy) + assert len(result) == 1 diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/quality/test_poisoned_trees.py python-hypothesis-3.71.11/hypothesis-python/tests/quality/test_poisoned_trees.py --- python-hypothesis-3.44.1/hypothesis-python/tests/quality/test_poisoned_trees.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/quality/test_poisoned_trees.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,138 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from random import Random + +import pytest + +import hypothesis.internal.conjecture.utils as cu +from hypothesis import HealthCheck, settings, unlimited +from hypothesis.searchstrategy import SearchStrategy +from hypothesis.internal.compat import hbytes, hrange +from hypothesis.internal.conjecture.engine import ConjectureData, \ + ConjectureRunner, uniform + +POISON = 'POISON' + +MAX_INT = 2 ** 32 - 1 + + +class PoisonedTree(SearchStrategy): + """Generates variable sized tuples with an implicit tree structure. + + The actual result is flattened out, but the hierarchy is implicit in + the data. + """ + + def __init__(self, p): + SearchStrategy.__init__(self) + self.__p = p + + def do_draw(self, data): + if cu.biased_coin(data, self.__p): + return data.draw(self) + data.draw(self) + else: + # We draw n as two separate calls so that it doesn't show up as a + # single block. If it did, the heuristics that allow us to move + # blocks around would fire and it would move right, which would + # then allow us to shrink it more easily. + n = (data.draw_bits(16) << 16) | data.draw_bits(16) + if n == MAX_INT: + return (POISON,) + else: + return (None,) + + +LOTS = 10 ** 6 + + +TEST_SETTINGS = settings( + database=None, suppress_health_check=HealthCheck.all(), max_examples=LOTS, + deadline=None, timeout=unlimited +) + + +@pytest.mark.parametrize('size', [2, 5, 10]) +@pytest.mark.parametrize('seed', [0, 15993493061449915028]) +def test_can_reduce_poison_from_any_subtree(size, seed): + """This test validates that we can minimize to any leaf node of a binary + tree, regardless of where in the tree the leaf is.""" + random = Random(seed) + + # Initially we create the minimal tree of size n, regardless of whether it + # is poisoned (which it won't be - the poison event essentially never + # happens when drawing uniformly at random). + + # Choose p so that the expected size of the tree is equal to the desired + # size. + p = 1.0 / (2.0 - 1.0 / size) + strat = PoisonedTree(p) + + def test_function(data): + v = data.draw(strat) + if len(v) >= size: + data.mark_interesting() + + runner = ConjectureRunner( + test_function, random=random, settings=TEST_SETTINGS + ) + + while not runner.interesting_examples: + runner.test_function(ConjectureData( + draw_bytes=lambda data, n: uniform(random, n), + max_length=LOTS)) + + runner.shrink_interesting_examples() + + data, = runner.interesting_examples.values() + + assert len(ConjectureData.for_buffer(data.buffer).draw(strat)) == size + + starts = data.block_starts[2] + assert len(starts) % 2 == 0 + + for i in hrange(0, len(starts), 2): + # Now for each leaf position in the tree we try inserting a poison + # value artificially. Additionally, we add a marker to the end that + # must be preserved. The marker means that we are not allow to rely on + # discarding the end of the buffer to get the desired shrink. + u = starts[i] + marker = hbytes([1, 2, 3, 4]) + + poisoned_data = ConjectureData.for_buffer( + data.buffer[:u] + hbytes([255]) * 4 + data.buffer[u + 4:] + + marker + ) + + def test_function(data): + v = data.draw(strat) + m = data.draw_bytes(len(marker)) + if POISON in v and m == marker: + data.mark_interesting() + runner = ConjectureRunner( + test_function, random=random, settings=TEST_SETTINGS) + + runner.test_function(poisoned_data) + assert runner.interesting_examples + runner.shrink_interesting_examples() + + shrunk, = runner.interesting_examples.values() + + assert ConjectureData.for_buffer( + shrunk.buffer).draw(strat) == (POISON,) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/quality/test_shrink_quality.py python-hypothesis-3.71.11/hypothesis-python/tests/quality/test_shrink_quality.py --- python-hypothesis-3.44.1/hypothesis-python/tests/quality/test_shrink_quality.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/quality/test_shrink_quality.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,349 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from random import Random +from fractions import Fraction +from functools import reduce +from collections import namedtuple + +import pytest +from flaky import flaky + +from hypothesis import assume, settings +from tests.common import parametrize +from tests.common.debug import minimal +from hypothesis.strategies import just, none, sets, text, lists, builds, \ + tuples, booleans, integers, fractions, frozensets, dictionaries, \ + sampled_from, fixed_dictionaries +from hypothesis.internal.compat import OrderedDict, hrange + + +def test_integers_from_minimizes_leftwards(): + assert minimal(integers(min_value=101)) == 101 + + +def test_minimal_fractions_1(): + assert minimal(fractions()) == Fraction(0) + + +def test_minimal_fractions_2(): + assert minimal(fractions(), lambda x: x >= 1) == Fraction(1) + + +def test_minimal_fractions_3(): + assert minimal( + lists(fractions()), lambda s: len(s) >= 5) == [Fraction(0)] * 5 + + +def test_minimize_string_to_empty(): + assert minimal(text()) == u'' + + +def test_minimize_one_of(): + for _ in hrange(100): + assert minimal(integers() | text() | booleans()) in ( + 0, u'', False + ) + + +def test_minimize_mixed_list(): + mixed = minimal(lists(integers() | text()), lambda x: len(x) >= 10) + assert set(mixed).issubset(set((0, u''))) + + +def test_minimize_longer_string(): + assert minimal(text(), lambda x: len(x) >= 10) == u'0' * 10 + + +def test_minimize_longer_list_of_strings(): + assert minimal(lists(text()), lambda x: len(x) >= 10) == [u''] * 10 + + +def test_minimize_3_set(): + assert minimal(sets(integers()), lambda x: len(x) >= 3) in ( + set((0, 1, 2)), + set((-1, 0, 1)), + ) + + +def test_minimize_3_set_of_tuples(): + assert minimal( + sets(tuples(integers())), + lambda x: len(x) >= 2) == set(((0,), (1,))) + + +def test_minimize_sets_of_sets(): + elements = integers(1, 100) + size = 8 + set_of_sets = minimal(sets(frozensets(elements), min_size=size)) + assert frozenset() in set_of_sets + assert len(set_of_sets) == size + for s in set_of_sets: + if len(s) > 1: + assert any( + s != t and t.issubset(s) + for t in set_of_sets + ) + + +def test_can_simplify_flatmap_with_bounded_left_hand_size(): + assert minimal( + booleans().flatmap(lambda x: lists(just(x))), + lambda x: len(x) >= 10) == [False] * 10 + + +def test_can_simplify_across_flatmap_of_just(): + assert minimal(integers().flatmap(just)) == 0 + + +def test_can_simplify_on_right_hand_strategy_of_flatmap(): + assert minimal(integers().flatmap(lambda x: lists(just(x)))) == [] + + +@flaky(min_passes=5, max_runs=5) +def test_can_ignore_left_hand_side_of_flatmap(): + assert minimal( + integers().flatmap(lambda x: lists(integers())), + lambda x: len(x) >= 10 + ) == [0] * 10 + + +def test_can_simplify_on_both_sides_of_flatmap(): + assert minimal( + integers().flatmap(lambda x: lists(just(x))), + lambda x: len(x) >= 10 + ) == [0] * 10 + + +def test_flatmap_rectangles(): + lengths = integers(min_value=0, max_value=10) + + def lists_of_length(n): + return lists(sampled_from('ab'), min_size=n, max_size=n) + + xs = minimal(lengths.flatmap( + lambda w: lists(lists_of_length(w))), lambda x: ['a', 'b'] in x, + settings=settings(database=None, max_examples=2000) + ) + assert xs == [['a', 'b']] + + +@flaky(min_passes=5, max_runs=5) +@parametrize(u'dict_class', [dict, OrderedDict]) +def test_dictionary(dict_class): + assert minimal(dictionaries( + keys=integers(), values=text(), + dict_class=dict_class)) == dict_class() + + x = minimal( + dictionaries(keys=integers(), values=text(), dict_class=dict_class), + lambda t: len(t) >= 3) + assert isinstance(x, dict_class) + assert set(x.values()) == set((u'',)) + for k in x: + if k < 0: + assert k + 1 in x + if k > 0: + assert k - 1 in x + + +def test_minimize_single_element_in_silly_large_int_range(): + ir = integers(-(2 ** 256), 2 ** 256) + assert minimal(ir, lambda x: x >= -(2 ** 255)) == 0 + + +def test_minimize_multiple_elements_in_silly_large_int_range(): + desired_result = [0] * 20 + + ir = integers(-(2 ** 256), 2 ** 256) + x = minimal( + lists(ir), + lambda x: len(x) >= 20, + timeout_after=20, + ) + assert x == desired_result + + +def test_minimize_multiple_elements_in_silly_large_int_range_min_is_not_dupe(): + ir = integers(0, 2 ** 256) + target = list(range(20)) + + x = minimal( + lists(ir), + lambda x: ( + assume(len(x) >= 20) and all(x[i] >= target[i] for i in target)), + timeout_after=60, + ) + assert x == target + + +def test_find_large_union_list(): + size = 10 + + def large_mostly_non_overlapping(xs): + union = reduce(set.union, xs) + return len(union) >= size + + result = minimal( + lists(sets(integers(), min_size=1), min_size=1), + large_mostly_non_overlapping, timeout_after=120) + assert len(result) == 1 + union = reduce(set.union, result) + assert len(union) == size + assert max(union) == min(union) + len(union) - 1 + + +@pytest.mark.parametrize('n', [0, 1, 10, 100, 1000]) +@pytest.mark.parametrize( + 'seed', + [13878544811291720918, 15832355027548327468, 12901656430307478246] +) +def test_containment(n, seed): + iv = minimal( + tuples(lists(integers()), integers()), + lambda x: x[1] in x[0] and x[1] >= n, + timeout_after=60, + random=Random(seed), + ) + assert iv == ([n], n) + + +def test_duplicate_containment(): + ls, i = minimal( + tuples(lists(integers()), integers()), + lambda s: s[0].count(s[1]) > 1, timeout_after=100) + assert ls == [0, 0] + assert i == 0 + + +@pytest.mark.parametrize('seed', [11, 28, 37]) +def test_reordering_bytes(seed): + ls = minimal( + lists(integers()), lambda x: sum(x) >= 10 and len(x) >= 3, + random=Random(seed), + ) + + assert ls == sorted(ls) + + +def test_minimize_long_list(): + assert minimal( + lists(booleans(), min_size=50), lambda x: len(x) >= 70 + ) == [False] * 70 + + +def test_minimize_list_of_longish_lists(): + size = 5 + xs = minimal( + lists(lists(booleans())), + lambda x: len([t for t in x if any(t) and len(t) >= 2]) >= size) + assert len(xs) == size + for x in xs: + assert x == [False, True] + + +def test_minimize_list_of_fairly_non_unique_ints(): + xs = minimal(lists(integers()), lambda x: len(set(x)) < len(x)) + assert len(xs) == 2 + + +def test_list_with_complex_sorting_structure(): + xs = minimal( + lists(lists(booleans())), + lambda x: [list(reversed(t)) for t in x] > x and len(x) > 3) + assert len(xs) == 4 + + +def test_list_with_wide_gap(): + xs = minimal(lists(integers()), lambda x: x and (max(x) > min(x) + 10 > 0)) + assert len(xs) == 2 + xs.sort() + assert xs[1] == 11 + xs[0] + + +def test_minimize_namedtuple(): + T = namedtuple(u'T', (u'a', u'b')) + tab = minimal( + builds(T, integers(), integers()), + lambda x: x.a < x.b) + assert tab.b == tab.a + 1 + + +def test_minimize_dict(): + tab = minimal( + fixed_dictionaries({u'a': booleans(), u'b': booleans()}), + lambda x: x[u'a'] or x[u'b'] + ) + assert not (tab[u'a'] and tab[u'b']) + + +def test_minimize_list_of_sets(): + assert minimal( + lists(sets(booleans())), + lambda x: len(list(filter(None, x))) >= 3) == ( + [set((False,))] * 3 + ) + + +def test_minimize_list_of_lists(): + assert minimal( + lists(lists(integers())), + lambda x: len(list(filter(None, x))) >= 3) == ( + [[0]] * 3 + ) + + +def test_minimize_list_of_tuples(): + xs = minimal( + lists(tuples(integers(), integers())), lambda x: len(x) >= 2) + assert xs == [(0, 0), (0, 0)] + + +def test_minimize_multi_key_dicts(): + assert minimal( + dictionaries(keys=booleans(), values=booleans()), + bool + ) == {False: False} + + +def test_multiple_empty_lists_are_independent(): + x = minimal(lists(lists(none(), max_size=0)), lambda t: len(t) >= 2) + u, v = x + assert u is not v + + +def test_can_find_sets_unique_by_incomplete_data(): + size = 5 + ls = minimal( + lists(tuples(integers(), integers()), unique_by=max), + lambda x: len(x) >= size + ) + assert len(ls) == size + values = sorted(list(map(max, ls))) + assert values[-1] - values[0] == size - 1 + for u, v in ls: + assert u <= 0 + + +@pytest.mark.parametrize(u'n', range(10)) +def test_lists_forced_near_top(n): + assert minimal( + lists(integers(), min_size=n, max_size=n + 2), + lambda t: len(t) == n + 2 + ) == [0] * (n + 2) diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/quality/test_zig_zagging.py python-hypothesis-3.71.11/hypothesis-python/tests/quality/test_zig_zagging.py --- python-hypothesis-3.44.1/hypothesis-python/tests/quality/test_zig_zagging.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/quality/test_zig_zagging.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,123 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import random +from math import log + +import hypothesis.strategies as st +from hypothesis import Phase, Verbosity, HealthCheck, given, assume, \ + example, settings, unlimited +from hypothesis.internal.compat import ceil, hbytes, int_from_bytes +from hypothesis.internal.conjecture.data import ConjectureData +from hypothesis.internal.conjecture.engine import ConjectureRunner + + +@st.composite +def problem(draw): + b = hbytes(draw(st.binary(min_size=1, max_size=8))) + m = int_from_bytes(b) * 256 + assume(m > 0) + marker = draw(st.binary(max_size=8)) + bound = draw(st.integers(0, m - 1)) + return (b, marker, bound) + + +base_settings = settings( + database=None, + deadline=None, suppress_health_check=HealthCheck.all(), max_examples=10, + verbosity=Verbosity.normal, timeout=unlimited, + phases=( + Phase.explicit, + Phase.generate + ) +) + + +@example((b'\x10\x00\x00\x00\x00\x00', b'', 2861143707951135)) +@example((b'\x05Cn', b'%\x1b\xa0\xfa', 12394667)) +@example((b'\x179 f', b'\xf5|', 24300326997)) +@example((b'\x05*\xf5\xe5\nh', b'', 1076887621690235)) +@example((b'=', b'', 2508)) +@example((b'\x01\x00', b'', 20048)) +@example((b'\x01', b'', 0)) +@example((b'\x02', b'', 258)) +@example((b'\x08', b'', 1792)) +@example((b'\x0c', b'', 0)) +@example((b'\x01', b'', 1)) +@settings( + base_settings, + verbosity=Verbosity.normal, + phases=( + # We disable shrinking for this test because when it fails it's a sign + # that the shrinker is working really badly, so it ends up very slow! + Phase.explicit, + Phase.generate, + ), + max_examples=20, +) +@given(problem()) +def test_avoids_zig_zag_trap(p): + b, marker, lower_bound = p + + random.seed(0) + + b = hbytes(b) + marker = hbytes(marker) + + n_bits = 8 * (len(b) + 1) + + def test_function(data): + m = data.draw_bits(n_bits) + if m < lower_bound: + data.mark_invalid() + n = data.draw_bits(n_bits) + if data.draw_bytes(len(marker)) != marker: + data.mark_invalid() + if abs(m - n) == 1: + data.mark_interesting() + + runner = ConjectureRunner( + test_function, database_key=None, settings=settings( + base_settings, + phases=(Phase.generate, Phase.shrink) + ) + ) + + runner.test_function(ConjectureData.for_buffer( + b + hbytes([0]) + b + hbytes([1]) + marker)) + + assert runner.interesting_examples + + runner.run() + + v, = runner.interesting_examples.values() + + data = ConjectureData.for_buffer(v.buffer) + + m = data.draw_bits(n_bits) + n = data.draw_bits(n_bits) + assert m == lower_bound + if m == 0: + assert n == 1 + else: + assert n == m - 1 + + budget = 2 * n_bits * ceil(log(n_bits, 2)) + 2 + + assert runner.shrinks <= budget diff -Nru python-hypothesis-3.44.1/hypothesis-python/tests/README.rst python-hypothesis-3.71.11/hypothesis-python/tests/README.rst --- python-hypothesis-3.44.1/hypothesis-python/tests/README.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tests/README.rst 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,123 @@ +=========== +Don't Panic +=========== + +The Hypothesis test suite is large, but we've written these notes to help you +out. It's aimed at contributors (new and old!) who know they need to add tests +*somewhere*, but aren't sure where - or maybe need some hints on what kinds of +tests might be useful. Others might just be interested in how a testing +library tests itself! + + +The very short version +====================== + +- To improve code coverage (eg because ``make check-coverage`` / the Travis + build is failing), go to ``cover/`` +- For longer / system / integration tests, look in ``nocover/`` +- For tests that require an optional dependency, look in the directory + named for that dependency. + +.. note:: + If you get stuck, just ask a maintainer to help out by mentioning + ``@HypothesisWorks/hypothesis-python-contributors`` on GitHub. + We'd love to help - and also get feedback on how this document could + be better! + + +Some scenarios +============== + +**I'm adding or changing a strategy** + Check for a file specific to that strategy (eg ``test_uuids.py`` for + the ``uuids()`` strategy). Write tests for all invalid argument handling + in ``test_direct_strategies.py``. Strategies with optional dependencies + should go in ``hypothesis.extras``, and the tests in their own module + (ie not in ``cover``). When you think you might be done, push and let + Travis point out any failing tests or non-covered code! + +**I've made some internal changes** + That's not very specific - you should probably refer to the test-finding + tips in the next section. Remember that ``tests/cover`` is reasonably + quick unit-test style tests - you should consider writing more intensive + integration tests too, but put them in ``tests/nocover`` with the others. + + +Finding particular tests +======================== + +With the sheer size and variety in this directory finding a specific thing +can be tricky. Tips: + +- Check for filenames that are relevant to your contribution. +- Use ``git grep`` to search for keywords, e.g. the name of a strategy you've changed. +- Deliberately break something related to your code, and see which tests fail. +- Ask a maintainer! Sometimes the structure is just arbitrary, and other tactics + don't work - but we *want* to help! + + +About each group of tests +========================= + +Still here? Here's a note on what to expect in each directory. + +``common/`` + Useful shared testing code, including test setup and a few helper + functions in ``utils.py``. Also read up on + `pytest `_ + features such as ``mark.parametrize``, ``mark.skipif``, and ``raises`` + for other functions that are often useful when writing tests. + +``cover/`` + The home of enough tests to get 100% branch coverage, as quickly as possible + without compromising on test power. This can be an intimidating target, + but it's entirely achievable and the maintainers are (still) here to help. + + This directory alone has around two-thirds of the tests for Hypothesis + (~8k of ~12k lines of code). If you're adding or fixing tests, chances + are therefore good that they're in here! + +``datetime/`` + Tests for the deprecated ``hypothesis.extra.datetime`` module, which + depends on the ``pytz`` package. + +``django/`` + Tests for the Django extra. Includes a toy application, to give us lots + of models to generate. + +``fakefactory/`` + Tests for the deprecated Faker extra. + +``nocover/`` + More expensive and longer-running tests, typically used to test trickier + interactions or check for regressions in expensive bugs. Lots of tests + about how values shrink, databases, compatibility, etc. + + New tests that are not required for full coverage of code branches or + behaviour should also go in ``nocover``, to keep ``cover`` reasonably fast. + +``numpy/`` + Tests for the Numpy extra. + +``pandas/`` + Tests for the Pandas extra. + +``py2/`` + Tests that require Python 2. This is a small group, because almost all + of our code and tests are also compatible with Python 3. + +``py3/`` + Tests that require Python 3. Includes checking that unicode identifiers + and function annotations don't break anything, asyncio tests, and tests + for inference from type hints. + +``pytest/`` + Hypothesis has excellent integration with ``py.test``, though we are careful + to support other test runners including unittest and nose. This is where we + test that our pytest integration is working properly. + +``quality/`` + Tests that various hard-to-find examples do in fact get found by Hypothesis, + as well as some stuff about example shrinking. Mostly intended for tests + of the form "Hypothesis finds an example of this condition" + assertions + about which example it finds. diff -Nru python-hypothesis-3.44.1/hypothesis-python/tox.ini python-hypothesis-3.71.11/hypothesis-python/tox.ini --- python-hypothesis-3.44.1/hypothesis-python/tox.ini 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-python/tox.ini 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,177 @@ +[tox] +envlist = py{27,34,35,36,37,py27}-{brief,prettyquick,full,custom} +toxworkdir={env:TOX_WORK_DIR:.tox} + +[testenv] +deps = + -r../requirements/test.txt +whitelist_externals= + bash +passenv= + HOME + LC_ALL + COVERAGE_FILE + TOXENV + CIRCLECI +setenv= + brief: HYPOTHESIS_PROFILE=speedy +commands = + full: bash scripts/basic-test.sh + brief: python -m pytest tests/cover/test_testdecorators.py {posargs} + prettyquick: python -m pytest tests/cover/ + custom: python -m pytest {posargs} + +[testenv:quality] +deps= + -r../requirements/test.txt +commands= + python -m pytest tests/quality/ -n2 + + +[testenv:quality2] +basepython=python2.7 +deps= + -r../requirements/test.txt +commands= + python -m pytest tests/quality/ + +[testenv:py27typing] +basepython=python2.7 +deps= + -r../requirements/test.txt + -r../requirements/typing.txt +commands= + python -m pytest tests/cover/ -n2 + +[testenv:unicode] +basepython=python2.7 +deps = + unicode-nazi +setenv= + UNICODENAZI=true + PYTHONPATH=. +commands= + python scripts/unicodechecker.py + +[testenv:faker070] +deps = + -r../requirements/test.txt +commands = + pip install --no-binary :all: Faker==0.7.0 + python -m pytest tests/fakefactory + +[testenv:faker-latest] +deps = + -r../requirements/test.txt +commands = + pip install --no-binary :all: Faker + python -m pytest tests/fakefactory + + +[testenv:pandas19] +deps = + -r../requirements/test.txt + pandas~=0.19.2 +commands = + python -m pytest tests/pandas -n2 + +[testenv:pandas20] +deps = + -r../requirements/test.txt + pandas~=0.20.3 +commands = + python -m pytest tests/pandas -n2 + +[testenv:pandas21] +deps = + -r../requirements/test.txt + pandas~=0.21.0 +commands = + python -m pytest tests/pandas -n2 + +[testenv:pandas22] +deps = + -r../requirements/test.txt + pandas~=0.22.0 +commands = + python -m pytest tests/pandas -n2 + +[testenv:pandas23] +deps = + -r../requirements/test.txt + pandas~=0.23.0 +commands = + python -m pytest tests/pandas -n2 + + +[testenv:django111] +commands = + pip install .[pytz] + pip install django~=1.11.7 + python -m tests.django.manage test tests.django + +[testenv:django20] +basepython=python3 +commands = + pip install .[pytz] + pip install django~=2.0.1 + python -m tests.django.manage test tests.django + +[testenv:django21] +basepython=python3 +commands = + pip install .[pytz] + pip install django~=2.1.0 + python -m tests.django.manage test tests.django + +[testenv:nose] +deps = + nose +commands= + nosetests tests/cover/test_testdecorators.py + +[testenv:pytest30] +deps = + -r../requirements/test.txt +commands= + pip install pytest==3.0 + python -m pytest tests/pytest tests/cover/test_testdecorators.py + + +[testenv:coverage] +deps = + -r../requirements/test.txt + -r../requirements/coverage.txt +setenv= + HYPOTHESIS_INTERNAL_COVERAGE=true +commands = + python -m coverage --version + python -m coverage debug sys + python -m coverage run --rcfile=.coveragerc -m pytest -n0 --strict tests/cover tests/datetime tests/py3 tests/numpy tests/pandas --maxfail=1 --ff {posargs} + python -m coverage report -m --fail-under=100 --show-missing + python scripts/validate_branch_check.py + + +[testenv:pypy-with-tracer] +setenv= + HYPOTHESIS_PROFILE=with_coverage +basepython=pypy +deps = + -r../requirements/test.txt +commands = + python -m pytest tests/cover/test_testdecorators.py tests/nocover/test_coverage.py -n 0 {posargs} + + +[testenv:examples3] +deps= + -r../requirements/test.txt +commands= + python -m pytest examples + + +[testenv:examples2] +basepython=python2.7 +deps= + -r../requirements/test.txt +commands= + python -m pytest examples diff -Nru python-hypothesis-3.44.1/hypothesis-ruby/Cargo.toml python-hypothesis-3.71.11/hypothesis-ruby/Cargo.toml --- python-hypothesis-3.44.1/hypothesis-ruby/Cargo.toml 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-ruby/Cargo.toml 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,12 @@ +[package] +name = "hypothesis-ruby" +version = "0.1.0" +authors = ["David R. MacIver "] + +[lib] +crate-type = ["cdylib"] + +[dependencies] +helix = '0.7.5' +rand = '0.3' +conjecture = { path = '../conjecture-rust' } diff -Nru python-hypothesis-3.44.1/hypothesis-ruby/CHANGELOG.md python-hypothesis-3.71.11/hypothesis-ruby/CHANGELOG.md --- python-hypothesis-3.44.1/hypothesis-ruby/CHANGELOG.md 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-ruby/CHANGELOG.md 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,83 @@ +# Hypothesis for Ruby 0.1.1 (2018-08-31) + +This release fixes minor documentation issues. + +Thanks to Tessa Bradbury for this contribution. + +# Hypothesis for Ruby 0.1.0 (2018-07-16) + +This release adds support for reporting multiple exceptions when Hypothesis +finds more than one way for the test to fail. + +# Hypothesis for Ruby 0.0.15 (2018-06-25) + +This release fixes an occasional `RuntimeError` that could occur +when shrinking a failing test. + +# Hypothesis for Ruby 0.0.14 (2018-06-25) + +This release updates the release date to the correct date, as part of fixing a +bug which caused the last couple of releases (0.0.11, 0.0.12, and 0.0.13) to +have an incorrect date. + +# Hypothesis for Ruby 0.0.13 (2018-06-25) + +This release moves the core Rust engine into the separate Conjecture crate. It +should have no user visible effect. + +# Hypothesis for Ruby 0.0.12 (2018-06-23) + +This release is the beginning of splitting out the Rust core of Hypothesis +Ruby into a separate `conjecture` crate for the non-Ruby-specific components +of it. + +It should have no user visible impact. + +# Hypothesis for Ruby 0.0.11 (2018-06-22) + +This release has no user-visible changes other than updating the gemspec's +homepage attribute. + +## Hypothesis for Ruby 0.0.10 (2018-04-26) + +This release is another update to shrinking: + +* Cases where the value may be simplified without necessarily + becoming smaller will have better results. +* Duplicated values can now sometimes be simultaneously shrunk. + +## Hypothesis for Ruby 0.0.9 (2018-04-20) + +This improves Hypothesis for Ruby's shrinking to be much closer +to Hypothesis for Python's. It's still far from complete, and even +in cases where it has the same level of quality it will often be +significantly slower, but examples should now be much more consistent, +especially in cases where you are using e.g. `built_as`. + +## Hypothesis for Ruby 0.0.8 (2018-02-20) + +This release fixes the dependency on Rake to be in a more sensible range. + +## Hypothesis for Ruby 0.0.7 (2018-02-19) + +This release updates an error in the README. + +## Hypothesis for Ruby 0.0.6 (2018-02-19) + +This release just updates the gem description. + +## Hypothesis for Ruby 0.0.5 (2018-02-19) + +This is a trivial release to test the release automation. +It should have no user visible impact. + +## Hypothesis for Ruby 0.0.3 (2018-02-19) + +This is an initial developer preview of Hypothesis for Ruby. +It's ready to use, but isn't yet stable and has significant +limitations. It is mostly released so that people can easily give +feedback on the API and implementation, and is likely to change +substantially before a stable release. + +Note that while there were some earlier release numbers internally, +these were pulled. This is the first official release. diff -Nru python-hypothesis-3.44.1/hypothesis-ruby/docs/debt.md python-hypothesis-3.71.11/hypothesis-ruby/docs/debt.md --- python-hypothesis-3.44.1/hypothesis-ruby/docs/debt.md 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-ruby/docs/debt.md 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,114 @@ +# A Series of Unfortunate Implementation Choices + +## In Which The Narrator Seeks To Justify Himself + +This project is currently in a somewhat expeditionary state, +where its goal is not to produce wonderful software that will +stand the test of time, but instead to prove its concept +valid and get something working enough for me to decide +whether it's worth it to continue down this route, and +to decide whether it's worth it to continue funding it. + +As such, whenever presented with the question "Do we want it +good or do we want it soon?" I am mostly choosing soon. + +BUT I am optimistic about the long-term viability of this +project, and I do not wish to find future-David cursing the +very name of past-David. In aid of squaring this particular +circle, I am choosing to document every terrible thing that +I knowingly do. + +The goals of this documentation are: + +* To make me feel bad, so that I'm less likely to do things + that are awful but not actually needed. +* To explain the reasoning to future-me and those who come + after. +* To make explicit the conditions under which the awful hack + may be removed. + +## Awful Hacks + +### Panicky Clones + +Engine is currently set up to implement Clone but to panic when +you call it. + +This is because [Helix seems to needlessly derive the Clone +trait](https://github.com/tildeio/helix/issues/143). + +Can be removed when: That issue is fixed, or an alternative +workaround is suggested. + +### Threads as a Control Flow Mechanism + +Rather than attempt to encode the generation state machine +explicitly, which was proving to be absolutely awful, I +decided to continue to write it synchronously. The Rust side +of the equation does not control calling the test function, +which makes this tricky (and having the asynchronous interface +as the main API entry point is a long term good anyway). + +The ideal way of doing this would be with something lightweight, +like a coroutines. The ideal way of doing coroutines would be +[Rust generators](https://doc.rust-lang.org/nightly/unstable-book/language-features/generators.html). + +Unfortunately this suffers from two problems: + +* It requires rust nightly. I would be prepared to live with this, + but it's sub-par. +* The current implementation is one-way only: resume does not take + an argument. + +Alternate things tried: + +* [libfringe](https://github.com/edef1c/libfringe) seems lovely, + but also requires rust-nightly and the released version doesn't + actually build on rust nightly +* I didn't really look into [may](https://github.com/Xudong-Huang/may/) + after a) getting vaguely warned off it and b) Honestly having + coroutine implementation exhaustion at this point. + +So at this point I said "Screw it, threads work on stable, and the +context switching overhead isn't going to be *that* large compared +to all the other mess that's in this chain, so..." + +So, yeah, that's why the main loop runs in a separate thread and +communicates with the main thread via a synchronous channel. + +Can be removed when one of: + +* Generators are on stable and support resuming with an argument. +* libfringe works on stable +* Either of the above but on unstable, and my frustration with + threading bugs (but fearless concurrency, David!) outweighs + my desire to not use nightly. + + +### Monkey-patching Helix for our Build + +I was very very bored of Helix's build support [not actually failing +the rake task when the build fails](https://github.com/tildeio/helix/issues/133), +so I've monkey-patched their build system in our Rakefile in order +to make it error properly in this case. + +Can be removed when: The linked issue is fixed. + + +### Stable identifiers from RSpec + +Another "I did terrible things to RSpec" entry, sorry. RSpec's +design here is totally reasonable and sensible and honestly +probably *is* how you should pass state around, but seems +to make it impossible to get access to the Example object from +inside an it block without actually being the definer of the +block. + +See `hypothesis_stable_identifier` for details, but basically I +couldn't figure out how to get the name of a currently executing +spec in RSPec from a helper function without some fairly brutal +hacks where we extract information badly from self.inspect, because +it's there stored as a string that gets passed in for inspection. + +Can be removed when: Someone shows me a better way, or a +feature is added to RSpec to make this easier. diff -Nru python-hypothesis-3.44.1/hypothesis-ruby/docs/design.md python-hypothesis-3.71.11/hypothesis-ruby/docs/design.md --- python-hypothesis-3.44.1/hypothesis-ruby/docs/design.md 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-ruby/docs/design.md 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,123 @@ +# Design Notes + +The current goals of the Hypothesis for Ruby project are: + +* To provide a useful but not wholly feature complete version of + [Hypothesis](http://hypothesis.works) for Ruby, that works with + RSpec (and ideally minitest, but if that at any point proves to + be a lot of work this may be dropped. It's not an explicit + requirement, but supporting it now makes it much easier to find + the right shape of the project design). +* To provide a mostly feature complete version of the Conjecture + engine that powers Hypothesis in Rust, as decoupled from that + Ruby front-end as possible. + +Hypothesis for Ruby is not intended to be an exact feature for +feature copy of the Python version. It will have a lot of the same +underlying functionality, but with a number of changes driven by: + +* Trying to make it feel as "ruby native" as possible. +* The ability to design an API from scratch that lacks many of the + constraints imposed both by the earlier much more limited functionality + of Hypothesis and the specifics of Python decorators and test + frameworks. + +## Differences + +The most fundamental API differences between Hypothesis +for Python and Hypothesis for Ruby are: + +* In Python we do a whole giant song and dance about exposing + functions for the test runner to call, while in Ruby we just + have a function which repeatedly calls a block and then fails. +* In Python you specify a bunch of given parameters up front, + and then if you want values inline in the test you [explicitly + opt in to it](https://hypothesis.readthedocs.io/en/latest/data.html#drawing-interactively-in-tests), + while in Ruby this is not only the default but the only way to + get those values. +* Strategies are called Possibles because strategy is a terrible + name that was originally intended to be internal and then leaked + into the public API because I wasn't thinking hard about naming. +* Many of the Possible implementations have different names than + the corresponding + names in hypothesis-python. There is also a weird dual naming + convention for Possibles where there is both e.g. `integers` and + `integer` as aliases for each other. + +So for example: + +```ruby +RSPec.describe "integer addition" do + it "commutes" do + hypothesis do + m = any integer + n = any integer + expect(m + n).to eq(n + m) + end + end +end +``` + +```python +@given(integers(), integers()) +def test_integers_commute(m, n): + assert m + n == n + m +``` + +The in-line style is slightly more verbose, but vastly more flexible +and (I think) reads better. Also mixing in-line and up-front +styles looks weird, and if we're going to have just one then +the in-line approach is a strict superset of the functionality +of the other. + +The main reason for these differences are: + +* Ruby blocks (and their relation to testing) make this approach + much more natural. +* This functionality was not actually possible when the Hypothesis + for Python API was originally designed, which informed the way + its API looks. + +## Deliberate omissions + +The following are currently *not* part of the intended feature set +of Hypothesis for Ruby: + +* Calls to `hypothesis` may not be nested. +* There will be no equivalent to the [stateful testing](https://hypothesis.readthedocs.io/en/latest/stateful.html) + (but the very interactive nature of tests in the Ruby API means that + the generic state machine stuff is just something you can write in + your normal tests). +* Testing will not be coverage guided (to be fair, it's barely coverage + guided in the Python version right now...) +* There will probably not be a health check system as part of the initial + release, or if there is it will be much more basic. +* Any equivalent to [`@reproduce_failure`](https://hypothesis.readthedocs.io/en/latest/reproducing.html#reproducing-an-example-with-with-reproduce-failure) + +## Possible omissions + +The following will be in this initial project on a "time permitting" basis: +If everything else is going well and we've got plenty of time, I'll do them, +but I'm currently anticipating a tightish schedule so these are probably +for a future release: + +* Reporting multiple failing examples per test (this will definitely be supported + in the core engine, and if it's easy to support it then it will + also be included in the front-end. I currently think it will be + easy, but if it's not it will be dropped). +* [adding explicit examples](https://hypothesis.readthedocs.io/en/latest/reproducing.html#providing-explicit-examples). + +## Current Project State + +The current state is best described as "nascent" - it demonstrates +a lot of the right moving parts, but has rough edges that you will +hit almost immediately if you try to use it. Those rough edges need +to be filed off before it can be built. + +Things that don't work yet but will: + +* The Possible library is limited, and most of what is there is bad. +* The shrinker is *very* primitive in comparison to in Python. +* The example database does not yet exist. +* It can't actually be installed as a gem! Note that even once it is + installable you will need a rust compiler and cargo. diff -Nru python-hypothesis-3.44.1/hypothesis-ruby/ext/extconf.rb python-hypothesis-3.71.11/hypothesis-ruby/ext/extconf.rb --- python-hypothesis-3.44.1/hypothesis-ruby/ext/extconf.rb 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-ruby/ext/extconf.rb 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,5 @@ +if !system('cargo --version') + raise 'Hypothesis requires cargo to be installed (https://www.rust-lang.org/)' +end + +require 'rake' diff -Nru python-hypothesis-3.44.1/hypothesis-ruby/ext/Makefile python-hypothesis-3.71.11/hypothesis-ruby/ext/Makefile --- python-hypothesis-3.44.1/hypothesis-ruby/ext/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-ruby/ext/Makefile 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,7 @@ +all: + cd .. + rake build +clean: + rm -rf ../target + +install: ; diff -Nru python-hypothesis-3.44.1/hypothesis-ruby/Gemfile python-hypothesis-3.71.11/hypothesis-ruby/Gemfile --- python-hypothesis-3.44.1/hypothesis-ruby/Gemfile 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-ruby/Gemfile 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +source 'https://rubygems.org' + +gemspec + +gem 'minitest', '~> 5.8.4' +gem 'rspec', '~> 3.0' +gem 'rubocop', '~> 0.51.0' +gem 'simplecov', '~> 0.15.1' +gem 'yard', '~> 0.9.12' +gem 'redcarpet', '~> 3.4.0' diff -Nru python-hypothesis-3.44.1/hypothesis-ruby/Gemfile.lock python-hypothesis-3.71.11/hypothesis-ruby/Gemfile.lock --- python-hypothesis-3.44.1/hypothesis-ruby/Gemfile.lock 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-ruby/Gemfile.lock 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,72 @@ +PATH + remote: . + specs: + hypothesis-specs (0.1.0) + helix_runtime (~> 0.7.0) + rake (>= 10.0, < 13.0) + +GEM + remote: https://rubygems.org/ + specs: + ast (2.4.0) + diff-lcs (1.3) + docile (1.1.5) + helix_runtime (0.7.5) + rake (>= 10.0) + thor (>= 0.19.4, < 2.0) + tomlrb (~> 1.2.4) + json (2.1.0) + minitest (5.8.5) + parallel (1.12.1) + parser (2.5.1.0) + ast (~> 2.4.0) + powerpack (0.1.1) + rainbow (2.2.2) + rake + rake (12.3.1) + redcarpet (3.4.0) + rspec (3.7.0) + rspec-core (~> 3.7.0) + rspec-expectations (~> 3.7.0) + rspec-mocks (~> 3.7.0) + rspec-core (3.7.1) + rspec-support (~> 3.7.0) + rspec-expectations (3.7.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.7.0) + rspec-mocks (3.7.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.7.0) + rspec-support (3.7.1) + rubocop (0.51.0) + parallel (~> 1.10) + parser (>= 2.3.3.1, < 3.0) + powerpack (~> 0.1) + rainbow (>= 2.2.2, < 3.0) + ruby-progressbar (~> 1.7) + unicode-display_width (~> 1.0, >= 1.0.1) + ruby-progressbar (1.9.0) + simplecov (0.15.1) + docile (~> 1.1.0) + json (>= 1.8, < 3) + simplecov-html (~> 0.10.0) + simplecov-html (0.10.2) + thor (0.20.0) + tomlrb (1.2.7) + unicode-display_width (1.3.2) + yard (0.9.12) + +PLATFORMS + ruby + +DEPENDENCIES + hypothesis-specs! + minitest (~> 5.8.4) + redcarpet (~> 3.4.0) + rspec (~> 3.0) + rubocop (~> 0.51.0) + simplecov (~> 0.15.1) + yard (~> 0.9.12) + +BUNDLED WITH + 1.16.4 diff -Nru python-hypothesis-3.44.1/hypothesis-ruby/.gitignore python-hypothesis-3.71.11/hypothesis-ruby/.gitignore --- python-hypothesis-3.44.1/hypothesis-ruby/.gitignore 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-ruby/.gitignore 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,13 @@ +*.sw* +spec/examples.txt +target/ +**/*.rs.bk +Cargo.lock +*.so +coverage +.yardoc +isolated +doc +*.gem +secrets +secrets.tar diff -Nru python-hypothesis-3.44.1/hypothesis-ruby/hypothesis-specs.gemspec python-hypothesis-3.71.11/hypothesis-ruby/hypothesis-specs.gemspec --- python-hypothesis-3.44.1/hypothesis-ruby/hypothesis-specs.gemspec 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-ruby/hypothesis-specs.gemspec 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +Gem::Specification.new do |s| + s.name = 'hypothesis-specs' + s.version = '0.1.1' + s.date = '2018-08-31' + s.description = <<~DESCRIPTION + Hypothesis is a powerful, flexible, and easy to use library for property-based testing. +DESCRIPTION + s.summary = s.description + s.authors = ['David R. Maciver'] + s.email = 'david@drmaciver.com' + s.files = Dir['{ext/*,src/**/*,lib/**/*}'] + [ + 'Cargo.toml', 'LICENSE.txt', 'README.markdown', 'Rakefile', + 'CHANGELOG.md' + ] + s.homepage = 'https://github.com/HypothesisWorks/hypothesis/tree/master/hypothesis-ruby' + s.license = 'MPL-2.0' + s.extensions = Dir['ext/extconf.rb'] + s.add_dependency 'helix_runtime', '~> 0.7.0' + s.add_runtime_dependency 'rake', '>= 10.0', '< 13.0' +end diff -Nru python-hypothesis-3.44.1/hypothesis-ruby/lib/hypothesis/engine.rb python-hypothesis-3.71.11/hypothesis-ruby/lib/hypothesis/engine.rb --- python-hypothesis-3.44.1/hypothesis-ruby/lib/hypothesis/engine.rb 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-ruby/lib/hypothesis/engine.rb 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,100 @@ +# frozen_string_literal: true + +require 'helix_runtime' +require 'hypothesis-ruby/native' +require 'rspec/expectations' + +module Hypothesis + class Engine + include RSpec::Matchers + + attr_reader :current_source + attr_accessor :is_find + + def initialize(options) + seed = Random.rand(2**64 - 1) + @core_engine = HypothesisCoreEngine.new( + seed, options.fetch(:max_examples) + ) + + @exceptions_to_tags = Hash.new { |h, k| h[k] = h.size } + end + + def run + loop do + core = @core_engine.new_source + break if core.nil? + @current_source = TestCase.new(core) + begin + result = yield(@current_source) + if is_find && result + @core_engine.finish_interesting(core, 0) + else + @core_engine.finish_valid(core) + end + rescue UnsatisfiedAssumption + @core_engine.finish_invalid(core) + rescue DataOverflow + @core_engine.finish_overflow(core) + rescue Exception => e + raise if is_find + key = [ + e.class, + HypothesisJunkDrawer.find_first_relevant_line(e.backtrace) + ] + @core_engine.finish_interesting(core, @exceptions_to_tags[key]) + end + end + if @core_engine.count_failing_examples.zero? + raise Unsatisfiable if @core_engine.was_unsatisfiable + @current_source = nil + return + end + + if is_find + core = @core_engine.failing_example(0) + @current_source = TestCase.new(core, record_draws: true) + yield @current_source + else + exceptions = [] + (0...@core_engine.count_failing_examples).each do |example| + core = @core_engine.failing_example(example) + @current_source = TestCase.new(core, print_draws: true) + + begin + yield @current_source + rescue Exception => e + givens = @current_source.print_log + given_str = givens.each_with_index.map do |(name, s), i| + name = "##{i + 1}" if name.nil? + "Given #{name}: #{s}" + end.to_a + + if e.respond_to? :hypothesis_data + e.hypothesis_data[0] = given_str + else + original_to_s = e.to_s + original_inspect = e.inspect + + class < 0 + # i = any element_of(ls) + # [ls, i] + # end + # ``` + # + # @return [Possible] A Possible whose possible values are + # any result from the passed block. + def built_as(&block) + Hypothesis::Possible::Implementations::CompositePossible.new(block) + end + + alias values_built_as built_as + + # A Possible boolean value + # @return [Possible] + def booleans + integers(min: 0, max: 1).map { |i| i == 1 } + end + + alias boolean booleans + + # A Possible unicode codepoint. + # @return [Possible] + # @param min [Integer] The smallest codepoint to provide + # @param max [Integer] The largest codepoint to provide + def codepoints(min: 1, max: 1_114_111) + base = integers(min: min, max: max) + if min <= 126 + from(integers(min: min, max: [126, max].min), base) + else + base + end + end + + alias codepoint codepoints + + # A Possible String + # @return [Possible] + # @param codepoints [Possible, nil] The Possible codepoints + # that can be found in the string. If nil, + # will default to self.codepoints. These + # will be further filtered to ensure the generated string is + # valid. + # @param min_size [Integer] The smallest valid length for a + # provided string + # @param max_size [Integer] The largest valid length for a + # provided string + def strings(codepoints: nil, min_size: 0, max_size: 10) + codepoints = self.codepoints if codepoints.nil? + codepoints = codepoints.select do |i| + begin + [i].pack('U*').codepoints + true + rescue ArgumentError + false + end + end + arrays(of: codepoints, min_size: min_size, max_size: max_size).map do |ls| + ls.pack('U*') + end + end + + alias string strings + + # A Possible Hash, where all possible values have a fixed + # shape. + # This is used for hashes where you know exactly what the + # keys are, and different keys may have different possible values. + # For example, hashes_of_shape(a: integers, b: booleans) + # will give you values like `{a: 11, b: false}`. + # @return [Possible] + # @param hash [Hash] A hash describing the values to provide. + # The keys will be present unmodified in the provided hashes, + # mapping to their Possible value in the result. + def hashes_of_shape(hash) + built_as do + result = {} + hash.each { |k, v| result[k] = any(v) } + result + end + end + + alias hash_of_shape hashes_of_shape + + # A Possible Hash of variable shape. + # @return [Possible] + # @param keys [Possible] the possible keys + # @param values [Possible] the possible values + def hashes_with(keys:, values:, min_size: 0, max_size: 10) + built_as do + result = {} + rep = HypothesisCoreRepeatValues.new( + min_size, max_size, (min_size + max_size) * 0.5 + ) + source = World.current_engine.current_source + while rep.should_continue(source) + key = any keys + if result.include?(key) + rep.reject + else + result[key] = any values + end + end + result + end + end + + alias hash_with hashes_with + + # A Possible Arrays of a fixed shape. + # This is used for arrays where you know exactly how many + # elements there are, and different values may be possible + # at different positions. + # For example, arrays_of_shape(strings, integers) + # will give you values like ["a", 1] + # @return [Possible] + # @param elements [Array] A variable number of Possible. + # values. The provided array will have this many values, with + # each value possible for the corresponding argument. If elements + # contains an array it will be flattened first, so e.g. + # arrays_of_shape(a, b) is equivalent to arrays_of_shape([a, b]) + def arrays_of_shape(*elements) + elements = elements.flatten + built_as do + elements.map { |e| any e }.to_a + end + end + + alias array_of_shape arrays_of_shape + + # A Possible Array of variable shape. + # This is used for arrays where the size may vary and the same values + # are possible at any position. + # For example, arrays(of: booleans) might provide [false, true, false]. + # @return [Possible] + # @param of [Possible] The possible elements of the array. + # @param min_size [Integer] The smallest valid size of a provided array + # @param max_size [Integer] The largest valid size of a provided array + def arrays(of:, min_size: 0, max_size: 10) + built_as do + result = [] + rep = HypothesisCoreRepeatValues.new( + min_size, max_size, (min_size + max_size) * 0.5 + ) + source = World.current_engine.current_source + result.push any(of) while rep.should_continue(source) + result + end + end + + alias array arrays + + # A Possible where the possible values are any one of a number + # of other possible values. + # For example, from(strings, integers) could provide either of "a" + # or 1. + # @note This has a slightly non-standard aliasing. It reads more + # nicely if you write `any from(a, b, c)` but e.g. + # `arrays(of: mix_of(a, b, c))`. + # + # @return [Possible] + # @param components [Array] A number of Possible values, + # where the result will include any value possible from any of + # them. If components contains an + # array it will be flattened first, so e.g. from(a, b) + # is equivalent to from([a, b]) + def from(*components) + components = components.flatten + indexes = from_hypothesis_core( + HypothesisCoreBoundedIntegers.new(components.size - 1) + ) + built_as do + i = any indexes + any components[i] + end + end + + alias mix_of from + + # A Possible where any one of a fixed array of values is possible. + # @note these values are provided as is, so if the provided + # values are mutated in the test you should be careful to make + # sure each test run gets a fresh value (if you use this Possible + # in line in the test you don't need to worry about this, this + # is only a problem if you define the Possible outside of your + # hypothesis block). + # @return [Possible] + # @param values [Enumerable] A collection of possible values. + def element_of(values) + values = values.to_a + indexes = from_hypothesis_core( + HypothesisCoreBoundedIntegers.new(values.size - 1) + ) + built_as do + values.fetch(any(indexes)) + end + end + + alias elements_of element_of + + # A Possible integer + # @return [Possible] + # @param min [Integer] The smallest value integer to provide. + # @param max [Integer] The largest value integer to provide. + def integers(min: nil, max: nil) + base = from_hypothesis_core HypothesisCoreIntegers.new + if min.nil? && max.nil? + base + elsif min.nil? + built_as { max - any(base).abs } + elsif max.nil? + built_as { min + any(base).abs } + else + bounded = from_hypothesis_core( + HypothesisCoreBoundedIntegers.new(max - min) + ) + if min.zero? + bounded + else + built_as { min + any(bounded) } + end + end + end + + alias integer integers + + private + + def from_hypothesis_core(core) + Hypothesis::Possible::Implementations::PossibleFromCore.new( + core + ) + end + end +end diff -Nru python-hypothesis-3.44.1/hypothesis-ruby/lib/hypothesis/testcase.rb python-hypothesis-3.71.11/hypothesis-ruby/lib/hypothesis/testcase.rb --- python-hypothesis-3.44.1/hypothesis-ruby/lib/hypothesis/testcase.rb 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-ruby/lib/hypothesis/testcase.rb 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +module Hypothesis + # A TestCase class provides a concrete representation of + # an executing test case. You do not normally need to use this + # within the body of the test, but it exists to be used as + # an argument to {Hypothesis::Possibilities::built_as}. + # @!visibility private + class TestCase + # @!visibility private + attr_reader :draws, :print_log, :print_draws, :wrapped_data + + # @!visibility private + def initialize(wrapped_data, print_draws: false, record_draws: false) + @wrapped_data = wrapped_data + + @draws = [] if record_draws + @print_log = [] if print_draws + @depth = 0 + end + + def assume(condition) + raise UnsatisfiedAssumption unless condition + end + + # @!visibility private + def any(possible = nil, name: nil, &block) + top_level = @depth.zero? + + begin + @depth += 1 + possible ||= block + @wrapped_data.start_draw + result = possible.provide(&block) + @wrapped_data.stop_draw + if top_level + draws&.push(result) + print_log&.push([name, result.inspect]) + end + result + ensure + @depth -= 1 + end + end + end +end diff -Nru python-hypothesis-3.44.1/hypothesis-ruby/lib/hypothesis/world.rb python-hypothesis-3.71.11/hypothesis-ruby/lib/hypothesis/world.rb --- python-hypothesis-3.44.1/hypothesis-ruby/lib/hypothesis/world.rb 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-ruby/lib/hypothesis/world.rb 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module Hypothesis + module World + class << self + attr_accessor :current_engine + end + end +end diff -Nru python-hypothesis-3.44.1/hypothesis-ruby/lib/hypothesis.rb python-hypothesis-3.71.11/hypothesis-ruby/lib/hypothesis.rb --- python-hypothesis-3.44.1/hypothesis-ruby/lib/hypothesis.rb 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-ruby/lib/hypothesis.rb 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,224 @@ +# frozen_string_literal: true + +require 'hypothesis/junkdrawer' +require 'hypothesis/errors' +require 'hypothesis/possible' +require 'hypothesis/testcase' +require 'hypothesis/engine' +require 'hypothesis/world' + +# This is the main module for using Hypothesis. +# It is expected that you will include this in your +# tests, but its methods are also available on the +# module itself. +# +# The main entry point for using this is the +# {Hypothesis#hypothesis} method. All of the other +# methods make sense only inside blocks passed to +# it. +module Hypothesis + # @!visibility private + HYPOTHESIS_LOCATION = File.dirname(__FILE__) + + # @!visibility private + def hypothesis_stable_identifier + # Attempt to get a "stable identifier" for any any + # call into hypothesis. We use these to create + # database keys (or will when we have a database) that + # are stable across runs, so that when a test that + # previously failed is rerun, we can fetch and reuse + # the previous examples. + + # Note that essentially any answer to this method is + # "fine" in that the failure mode is that sometiems we + # just won't run the same test, but it's nice to keep + # this as stable as possible if the code isn't changing. + + # Minitest makes it nice and easy to create a stable + # test identifier, because it follows the classic xunit + # pattern where a test is just a method invocation on a + # fresh test class instance and it's easy to find out + # which invocation that was. + return "#{self.class.name}::#{@NAME}" if defined? @NAME + + # If we are running in an rspec example then, sadly, + # rspec take the entirely unreasonable stance that + # the correct way to pass data to a test is by passing + # it as a function argument. Honestly, what is this, + # Haskell? Ahem. Perfectly reasonable design decisions + # on rspec's part, this creates some annoying difficulties + # for us. We solve this through brute force and ignorance + # by relying on the information we want being in the + # inspect for the Example object, even if it's just there + # as a string. + begin + is_rspec = is_a? RSpec::Core::ExampleGroup + # We do our coverage testing inside rspec, so this will + # never trigger! Though we also don't currently have a + # test that covers it outside of rspec... + # :nocov: + rescue NameError + is_rspec = false + end + # :nocov: + + if is_rspec + return [ + self.class.description, + inspect.match(/"([^"]+)"/)[1] + ].join(' ') + end + + # Fallback time! We just walk the stack until we find the + # entry point into code we control. This will typically be + # where "hypothesis" was called. + Thread.current.backtrace.each do |line| + return line unless line.include?(Hypothesis::HYPOTHESIS_LOCATION) + end + # This should never happen unless something very strange is + # going on. + # :nocov: + raise 'BUG: Somehow we have no caller!' + # :nocov: + end + + # Run a test using Hypothesis. + # + # For example: + # + # ```ruby + # hypothesis do + # x = any integer + # y = any integer(min: x) + # expect(y).to be >= x + # end + # ``` + # + # The arguments to `any` are `Possible` instances which + # specify the range of value values for it to return. + # + # Typically you would include this inside some test in your + # normal testing framework - e.g. in an rspec it block or a + # minitest test method. + # + # This will run the block many times with integer values for + # x and y, and each time it will pass because we specified that + # y had a minimum value of x. + # If we changed it to `expect(y).to be > x` we would see output + # like the following: + # + # ``` + # Failure/Error: expect(y).to be > x + # + # Given #1: 0 + # Given #2: 0 + # expected: > 0 + # got: 0 + # ``` + # + # In more detail: + # + # hypothesis calls its provided block many times. Each invocation + # of the block is a *test case*. + # A test case has three important features: + # + # * *givens* are the result of a call to self.any, and are the + # values that make up the test case. These might be values such + # as strings, integers, etc. or they might be values specific to + # your application such as a User object. + # * *assumptions*, where you call `self.assume(some_condition)`. If + # an assumption fails (`some_condition` is false), then the test + # case is considered invalid, and is discarded. + # * *assertions* are anything that will raise an error if the test + # case should be considered a failure. These could be e.g. RSpec + # expectations or minitest matchers, but anything that throws an + # exception will be treated as a failed assertion. + # + # A test case which satisfies all of its assumptions and assertions + # is *valid*. A test-case which satisfies all of its assumptions but + # fails one of its assertions is *failing*. + # + # A call to hypothesis does the following: + # + # 1. It tries to *generate* a failing test case. + # 2. If it succeeded then it will *shrink* that failing test case. + # 3. Finally, it will *display* the shrunk failing test case by + # the error from its failing assertion, modified to show the + # givens of the test case. + # + # Generation consists of randomly trying test cases until one of + # three things has happened: + # + # 1. It has found a failing test case. At this point it will start + # *shrinking* the test case (see below). + # 2. It has found enough valid test cases. At this point it will + # silently stop. + # 3. It has found so many invalid test cases that it seems unlikely + # that it will find any more valid ones in a reasonable amount of + # time. At this point it will either silently stop or raise + # `Hypothesis::Unsatisfiable` depending on how many valid + # examples it found. + # + # *Shrinking* is when Hypothesis takes a failing test case and tries + # to make it easier to understand. It does this by replacing the givens + # in the test case with smaller and simpler values. These givens will + # still come from the possible values, and will obey all the usual + # constraints. + # In general, shrinking is automatic and you shouldn't need to care + # about the details of it. If the test case you're shown at the end + # is messy or needlessly large, please file a bug explaining the problem! + # + # @param max_valid_test_cases [Integer] The maximum number of valid test + # cases to run without finding a failing test case before stopping. + def hypothesis(max_valid_test_cases: 200, &block) + unless World.current_engine.nil? + raise UsageError, 'Cannot nest hypothesis calls' + end + begin + World.current_engine = Engine.new( + max_examples: max_valid_test_cases + ) + World.current_engine.run(&block) + ensure + World.current_engine = nil + end + end + + # Supplies a value to be used in your hypothesis. + # @note It is invalid to call this method outside of a hypothesis block. + # @return [Object] A value provided by the possible argument. + # @param possible [Possible] A possible that specifies the possible values + # to return. + # @param name [String, nil] An optional name to show next to the result on + # failure. This can be helpful if you have a lot of givens in your + # hypothesis, as it makes it easier to keep track of which is which. + def any(possible, name: nil, &block) + if World.current_engine.nil? + raise UsageError, 'Cannot call any outside of a hypothesis block' + end + + World.current_engine.current_source.any( + possible, name: name, &block + ) + end + + # Specify an assumption of your test case. Only test cases which satisfy + # their assumptions will treated as valid, and all others will be + # discarded. + # @note It is invalid to call this method outside of a hypothesis block. + # @note Try to use this only with "easy" conditions. If the condition is + # too hard to satisfy this can make your testing much worse, because + # Hypothesis will have to retry the test many times and will struggle + # to find "interesting" test cases. For example `assume(x != y)` is + # typically fine, and `assume(x == y)` is rarely a good idea. + # @param condition [Boolean] The condition to assume. If this is false, + # the current test case will be treated as invalid and the block will + # exit by throwing an exception. The next test case will then be run + # as normal. + def assume(condition) + if World.current_engine.nil? + raise UsageError, 'Cannot call assume outside of a hypothesis block' + end + World.current_engine.current_source.assume(condition) + end +end diff -Nru python-hypothesis-3.44.1/hypothesis-ruby/LICENSE.txt python-hypothesis-3.71.11/hypothesis-ruby/LICENSE.txt --- python-hypothesis-3.44.1/hypothesis-ruby/LICENSE.txt 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-ruby/LICENSE.txt 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,8 @@ +Copyright (c) 2018, David R. MacIver + +All code in this repository except where explicitly noted otherwise is released +under the Mozilla Public License v 2.0. You can obtain a copy at http://mozilla.org/MPL/2.0/. + +Some code in this repository may come from other projects. Where applicable, the +original copyright and license are noted and any modifications made are released +dual licensed with the original license. diff -Nru python-hypothesis-3.44.1/hypothesis-ruby/minitests/test_multiple_failures.rb python-hypothesis-3.71.11/hypothesis-ruby/minitests/test_multiple_failures.rb --- python-hypothesis-3.44.1/hypothesis-ruby/minitests/test_multiple_failures.rb 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-ruby/minitests/test_multiple_failures.rb 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +require 'minitest/autorun' +require 'hypothesis' + +class TestMultipleFailures < Minitest::Test + include Hypothesis + include Hypothesis::Possibilities + + def test_multiple_failures + assert_raises(Hypothesis::MultipleExceptionError) do + @initial = nil + + hypothesis do + x = any integers + if @initial.nil? + if x >= 1000 + @initial = x + else + next + end + end + + assert(x != @initial) + raise 'Nope' + end + end + end +end diff -Nru python-hypothesis-3.44.1/hypothesis-ruby/minitests/test_stable_identifier.rb python-hypothesis-3.71.11/hypothesis-ruby/minitests/test_stable_identifier.rb --- python-hypothesis-3.44.1/hypothesis-ruby/minitests/test_stable_identifier.rb 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-ruby/minitests/test_stable_identifier.rb 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +require 'minitest/autorun' +require 'hypothesis' + +class TestIdentifiers < Minitest::Test + include Hypothesis + + def test_abc + assert_equal hypothesis_stable_identifier, 'TestIdentifiers::test_abc' + end +end diff -Nru python-hypothesis-3.44.1/hypothesis-ruby/Rakefile python-hypothesis-3.71.11/hypothesis-ruby/Rakefile --- python-hypothesis-3.44.1/hypothesis-ruby/Rakefile 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-ruby/Rakefile 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,94 @@ +# frozen_string_literal: true + +require 'rubygems' +require 'helix_runtime/build_task' +require 'date' +require 'open3' + +begin + require 'rspec/core/rake_task' + RSpec::Core::RakeTask.new(:spec) + + require 'rake/testtask' + + Rake::TestTask.new(minitests: :build) do |t| + t.test_files = FileList['minitests/**/test_*.rb'] + t.verbose = true + end + + task test: %i[build spec minitests] +rescue LoadError +end + +HelixRuntime::BuildTask.new + +def rubocop(fix:) + sh "bundle exec rubocop #{'-a' if fix} lib spec minitests " \ + 'Rakefile hypothesis-specs.gemspec' +end + +task :checkformat do + rubocop(fix: false) +end + +task :format do + rubocop(fix: true) +end + +begin + require 'yard' + + YARD::Rake::YardocTask.new(:runyard) do |t| + t.files = [ + 'lib/hypothesis.rb', 'lib/hypothesis/errors.rb', + 'lib/hypothesis/possible.rb' + ] + t.options = ['--markup=markdown', '--no-private'] + end + + task doc: :runyard do + YARD::Registry.load + + objs = YARD::Registry.select do |o| + is_private = false + t = o + until t.root? + if t.visibility != :public + is_private = true + break + end + t = t.parent + end + + !is_private && o.docstring.blank? + end + + objs.sort_by! { |o| o.name.to_s } + + unless objs.empty? + abort "Undocumented objects: #{objs.map(&:name).join(', ')}" + end + end +rescue LoadError +end + +GEMSPEC = 'hypothesis-specs.gemspec' + +RELEASE_FILE = 'RELEASE.md' +CHANGELOG = 'CHANGELOG.md' + +def run_for_output(*args) + out, result = Open3.capture2(*args) + abort if result.exitstatus != 0 + out.strip +end + +task :clean do + sh 'git clean -fdx lib' + sh 'rm -rf hypothesis-specs*.gem' + sh 'rm -rf ../target' +end + +task gem: :clean do + sh 'gem build hypothesis-specs.gemspec' +end diff -Nru python-hypothesis-3.44.1/hypothesis-ruby/README.markdown python-hypothesis-3.71.11/hypothesis-ruby/README.markdown --- python-hypothesis-3.44.1/hypothesis-ruby/README.markdown 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-ruby/README.markdown 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,86 @@ +# Hypothesis for Ruby + +Hypothesis is a powerful, flexible, and easy to use library for *property-based testing*. + +In property-based testing, +in contrast to traditional *example-based testing*, +a test is written not against a single example but as a statement that should hold for any of a range of possible values. + +## Usage + +In Hypothesis for Ruby, a test looks something like this: + +```ruby +require "hypothesis" + +RSpec.configure do |config| + config.include(Hypothesis) + config.include(Hypothesis::Possibilities) +end + +RSpec.describe "removing an element from a list" do + it "results in the element no longer being in the list" do + hypothesis do + # Or lists(of: integers, min_size: 1), but this lets us + # demonstrate assume. + values = any array(of: integers) + + # If this is not true then the test will stop here. + assume values.size > 0 + + to_remove = any element_of(values) + + values.delete_at(values.index(to_remove)) + + # Will fail if the value ws duplicated in the list. + expect(values.include?(to_remove)).to be false + + end + end +end +``` + +This would then fail with: + +``` + 1) removing an element from a list results in the element no longer being in the list + Failure/Error: expect(values.include?(to_remove)).to be false + + Given #1: [0, 0] + Given #2: 0 + + expected false + got true +``` + +The use of RSpec here is incidental: +Hypothesis for Ruby works just as well with minitest, +and should work with anything else you care to use. + +## Getting Started + +Hypothesis is available on rubygems.org as a developer preview. +If you want to try it today you can use the current development branch by adding the following to your Gemfile: + +```ruby +gem 'hypothesis-specs' +``` + +The API is still in flux, so be warned that you should expect it to break on upgrades! +Right now this is really more to allow you to try it out and provide feedback than something you should expect to rely on. +The more feedback we get, the sooner it will get there! + +Note that in order to use Hypothesis for Ruby, you will need a rust toolchain installed. +Please go to [https://www.rustup.rs](https://www.rustup.rs) and follow the instructions if you do not already have one. + +## Project Status + +Hypothesis for Ruby is currently in an *early alpha* stage. +It works, and has a solid core set of features, but you should expect to find rough edges, +it is far from feature complete, and the API makes no promises of backwards compatibility. + +Right now you should consider it to be more in the spirit of a developer preview. +You can and should try it out, and hopefully you will find all sorts of interesting bugs in your code by doing so! +But you'll probably find interesting bugs in Hypothesis too, +and we'd appreciate you reporting them, +as well as any just general usability issues or points of confusion you have. diff -Nru python-hypothesis-3.44.1/hypothesis-ruby/.rspec python-hypothesis-3.71.11/hypothesis-ruby/.rspec --- python-hypothesis-3.44.1/hypothesis-ruby/.rspec 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-ruby/.rspec 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,2 @@ +--require spec_helper +--color diff -Nru python-hypothesis-3.44.1/hypothesis-ruby/.rubocop.yml python-hypothesis-3.71.11/hypothesis-ruby/.rubocop.yml --- python-hypothesis-3.44.1/hypothesis-ruby/.rubocop.yml 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-ruby/.rubocop.yml 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,30 @@ +Metrics/BlockLength: + ExcludedMethods: ['describe', 'context'] +Documentation: + Enabled: false +Metrics/MethodLength: + Enabled: false +Metrics/CyclomaticComplexity: + Enabled: false +Metrics/PerceivedComplexity: + Enabled: false +Metrics/AbcSize: + Enabled: false +Lint/RescueException: + Enabled: false +Style/MixinUsage: + Enabled: false +Style/MultilineBlockChain: + Enabled: false +Style/MethodMissing: + Enabled: false +Style/MultilineBlockChain: + Enabled: false +Metrics/ModuleLength: + Enabled: false +Metrics/BlockLength: + Enabled: false +Lint/HandleExceptions: + Enabled: false +Style/GuardClause: + Enabled: false diff -Nru python-hypothesis-3.44.1/hypothesis-ruby/.ruby-version python-hypothesis-3.71.11/hypothesis-ruby/.ruby-version --- python-hypothesis-3.44.1/hypothesis-ruby/.ruby-version 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-ruby/.ruby-version 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1 @@ +2.4.2 diff -Nru python-hypothesis-3.44.1/hypothesis-ruby/scripts/run-tests-isolated.sh python-hypothesis-3.71.11/hypothesis-ruby/scripts/run-tests-isolated.sh --- python-hypothesis-3.44.1/hypothesis-ruby/scripts/run-tests-isolated.sh 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-ruby/scripts/run-tests-isolated.sh 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +set -e -o xtrace + +rm -rf isolated +mkdir isolated + +bundle exec rake gem + +mv hypothesis-specs*.gem isolated +cp -Rl .rspec spec isolated + +cd isolated + +mkdir gems +export GEM_HOME="$PWD"/gems +export GEM_PATH="$GEM_HOME" + +gem install ./hypothesis-specs*.gem +gem install rspec simplecov + +gems/bin/rspec spec Binary files /tmp/tmpb30OA4/sdMxCRQenE/python-hypothesis-3.44.1/hypothesis-ruby/secrets.tar.enc and /tmp/tmpb30OA4/16q5ZKICe3/python-hypothesis-3.71.11/hypothesis-ruby/secrets.tar.enc differ diff -Nru python-hypothesis-3.44.1/hypothesis-ruby/spec/arrays_spec.rb python-hypothesis-3.71.11/hypothesis-ruby/spec/arrays_spec.rb --- python-hypothesis-3.44.1/hypothesis-ruby/spec/arrays_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-ruby/spec/arrays_spec.rb 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +RSpec.describe 'fixed arrays' do + they 'are of fixed size and shape' do + hypothesis do + ls = any array_of_shape( + integer, string, integer + ) + expect(ls.size).to eq(3) + expect(ls[0]).to be_a(Integer) + expect(ls[2]).to be_a(Integer) + expect(ls[1]).to be_a(String) + end + end +end diff -Nru python-hypothesis-3.44.1/hypothesis-ruby/spec/backtrace_spec.rb python-hypothesis-3.71.11/hypothesis-ruby/spec/backtrace_spec.rb --- python-hypothesis-3.44.1/hypothesis-ruby/spec/backtrace_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-ruby/spec/backtrace_spec.rb 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +RSpec.describe 'backtrace manipulation' do + JD = Hypothesis::HypothesisJunkDrawer + + it 'identifies the test file as relevant' do + JD.find_first_relevant_line(caller).include?('backtrace_spec.rb') + end + + it 'prunes out hypothesis and rspec related lines' do + hypothesis do + relevant = JD.prune_backtrace(caller) + relevant.each do |e| + expect(e).to_not include(JD::HYPOTHESIS_ROOT) + expect(e).to_not include('/rspec-core/') + end + expect(relevant.grep(/backtrace_spec.rb/)).to_not be_empty + end + end +end diff -Nru python-hypothesis-3.44.1/hypothesis-ruby/spec/bad_usage_spec.rb python-hypothesis-3.71.11/hypothesis-ruby/spec/bad_usage_spec.rb --- python-hypothesis-3.44.1/hypothesis-ruby/spec/bad_usage_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-ruby/spec/bad_usage_spec.rb 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +def bad_usage(&block) + expect(&block).to raise_exception(Hypothesis::UsageError) +end + +RSpec.describe 'Incorrect usage' do + it 'includes nesting hypothesis calls' do + bad_usage do + hypothesis do + hypothesis do + end + end + end + end + + it 'includes using any outside a hypothesis call' do + bad_usage { any integers } + end + + it 'includes using assume outside a hypothesis call' do + bad_usage { assume true } + end + + it 'includes using find inside a hypothesis' do + class <= 0 } + end + end + end +end diff -Nru python-hypothesis-3.44.1/hypothesis-ruby/spec/basic_examples_spec.rb python-hypothesis-3.71.11/hypothesis-ruby/spec/basic_examples_spec.rb --- python-hypothesis-3.44.1/hypothesis-ruby/spec/basic_examples_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-ruby/spec/basic_examples_spec.rb 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +def expect_failure(&block) + expect(&block).to raise_exception(RSpec::Expectations::ExpectationNotMetError) +end + +RSpec.describe 'basic hypothesis tests' do + they 'think integer addition is commutative' do + hypothesis do + x = any integers + y = any integers + expect(x + y).to eq(y + x) + end + end + + they 'are able to find zero values' do + expect_failure do + hypothesis do + x = any integers + expect(x).not_to eq(0) + end + end + end + + they 'are able to filter out values' do + hypothesis do + x = any integers + assume x != 0 + 1 / x + end + end + + they 'find that string addition is not commutative' do + expect_failure do + hypothesis do + x = any strings + y = any strings + expect(x + y).to be == y + x + end + end + end + + they 'raise unsatisfiable when all assumptions fail' do + expect do + hypothesis do + any integers + assume false + end + end.to raise_exception(Hypothesis::Unsatisfiable) + end +end diff -Nru python-hypothesis-3.44.1/hypothesis-ruby/spec/boolean_spec.rb python-hypothesis-3.71.11/hypothesis-ruby/spec/boolean_spec.rb --- python-hypothesis-3.44.1/hypothesis-ruby/spec/boolean_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-ruby/spec/boolean_spec.rb 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +RSpec.describe 'booleans' do + include Hypothesis::Debug + + they 'can be true' do + find_any { any booleans } + end + + they 'can be false' do + find_any { !any(booleans) } + end +end diff -Nru python-hypothesis-3.44.1/hypothesis-ruby/spec/choice_spec.rb python-hypothesis-3.71.11/hypothesis-ruby/spec/choice_spec.rb --- python-hypothesis-3.44.1/hypothesis-ruby/spec/choice_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-ruby/spec/choice_spec.rb 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +RSpec.describe 'element_of possible' do + include Hypothesis::Debug + + it 'includes the first argument' do + find_any do + m = any element_of([0, 1]) + m == 0 + end + end + + it 'includes the last argument' do + find_any do + m = any element_of([0, 1, 2, 3]) + m == 3 + end + end +end diff -Nru python-hypothesis-3.44.1/hypothesis-ruby/spec/debug_spec.rb python-hypothesis-3.71.11/hypothesis-ruby/spec/debug_spec.rb --- python-hypothesis-3.44.1/hypothesis-ruby/spec/debug_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-ruby/spec/debug_spec.rb 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +RSpec.describe 'find' do + include Hypothesis::Debug + + it "raises an error if it can't find anything" do + expect do + find do + any integers + false + end + end.to raise_exception(Hypothesis::Debug::NoSuchExample) + end +end diff -Nru python-hypothesis-3.44.1/hypothesis-ruby/spec/example_discovery_spec.rb python-hypothesis-3.71.11/hypothesis-ruby/spec/example_discovery_spec.rb --- python-hypothesis-3.44.1/hypothesis-ruby/spec/example_discovery_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-ruby/spec/example_discovery_spec.rb 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +RSpec.describe 'hypothesis' do + include Hypothesis::Debug + + it 'can find mid sized integers' do + n, = find do + m = any(integers) + m >= 100 && m <= 1000 + end + expect(n).to eq(100) + end +end diff -Nru python-hypothesis-3.44.1/hypothesis-ruby/spec/example_printing_spec.rb python-hypothesis-3.71.11/hypothesis-ruby/spec/example_printing_spec.rb --- python-hypothesis-3.44.1/hypothesis-ruby/spec/example_printing_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-ruby/spec/example_printing_spec.rb 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,73 @@ +# frozen_string_literal: true + +RSpec.describe 'printing examples' do + it 'adds a statement to the exceptions string' do + expect do + hypothesis do + n = any integers + expect(n).to eq(0) + end + end.to raise_exception(/Given #1/) + end + + it 'adds multiple statements to the exceptions string' do + expect do + hypothesis do + n = any integers + m = any integers + expect(n).to eq(m) + end + end.to raise_exception(/Given #1.+Given #2/m) + end + + it 'includes the name in the Given' do + expect do + hypothesis do + n = any integers, name: 'fred' + expect(n).to eq(1) + end + end.to raise_exception(/Given fred:/) + end + + it 'does not mangle names if you reuse exceptions' do + shared = Exception.new('Stuff') + 3.times do + expect do + hypothesis do + any integers + raise shared + end + end.to raise_exception do |ex| + expect(ex).to equal(shared) + expect(ex.to_s.scan(/Given/).count).to eq(1) + expect(ex.to_s.scan(/Stuff/).count).to eq(1) + end + end + end + + it 'does not include nested anys in printing' do + expect do + hypothesis do + value = any built_as do + any integers + any integers + any integers + end + expect(value).to eq(0) + end + end.to raise_exception(RSpec::Expectations::ExpectationNotMetError) do |ex| + expect(ex.to_s.scan(/Given/).count).to eq(1) + end + end + + it 'includes Given in inspect as well as to_s' do + expect do + hypothesis do + n = any integers + expect(n).to eq(0) + end + end.to raise_exception do |ex| + expect(ex.inspect).to match(/Given #1/) + end + end +end diff -Nru python-hypothesis-3.44.1/hypothesis-ruby/spec/example_shrinking_spec.rb python-hypothesis-3.71.11/hypothesis-ruby/spec/example_shrinking_spec.rb --- python-hypothesis-3.44.1/hypothesis-ruby/spec/example_shrinking_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-ruby/spec/example_shrinking_spec.rb 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,63 @@ +# frozen_string_literal: true + +require 'set' + +RSpec.describe 'shrinking' do + include Hypothesis::Debug + + it 'finds lower bounds on integers' do + n, = find { any(integers) >= 10 } + expect(n).to eq(10) + end + + it 'iterates to a fixed point' do + @original = nil + + a, b = find do + m = any integers + n = any integers + m > n && n > 0 + end + + expect(a).to eq(2) + expect(b).to eq(1) + end + + it 'can shrink through a chain' do + ls, = find do + x = any built_as do + n = any integers(min: 1, max: 100) + any arrays(of: integers(min: 0, max: 10), min_size: n, max_size: n) + end + x.sum >= 50 + end + + expect(ls).to_not include(0) + end + + it 'can shrink through a chain without deleting first element' do + 10.times do + ls, = find do + x = any built_as do + n = any integers(min: 1, max: 100) + any arrays(of: integers(min: 0, max: 10), min_size: n, max_size: n) + end + assume x[0] > 0 + x.sum >= 50 + end + + expect(ls).to_not include(0) + end + end + + it 'can shrink duplicate elements' do + 10.times do + ls, = find do + x = any array(of: integers(min: 0, max: 100)) + significant = x.select { |n| n > 0 } + Set.new(significant).length < significant.length + end + expect(ls).to eq([1, 1]) + end + end +end diff -Nru python-hypothesis-3.44.1/hypothesis-ruby/spec/hashes_spec.rb python-hypothesis-3.71.11/hypothesis-ruby/spec/hashes_spec.rb --- python-hypothesis-3.44.1/hypothesis-ruby/spec/hashes_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-ruby/spec/hashes_spec.rb 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +RSpec.describe 'fixed hash possibles' do + they 'include all the keys' do + hypothesis do + x = any hash_of_shape(a: integers, b: integers) + expect(x.size).to eq(2) + expect(x[:a]).to be_a(Integer) + expect(x[:b]).to be_a(Integer) + end + end +end + +RSpec.describe 'variable hash possibles' do + they 'respect lower bounds' do + hypothesis do + x = any hash_with( + keys: integers(min: 0, max: 4), + values: strings, + min_size: 4 + ) + expect(x.size).to be >= 4 + end + end +end diff -Nru python-hypothesis-3.44.1/hypothesis-ruby/spec/integer_spec.rb python-hypothesis-3.71.11/hypothesis-ruby/spec/integer_spec.rb --- python-hypothesis-3.44.1/hypothesis-ruby/spec/integer_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-ruby/spec/integer_spec.rb 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +RSpec.describe 'integer possibles' do + they 'respect upper bounds' do + hypothesis do + expect(any(integers(max: 100))).to be <= 100 + end + end + + they 'respect lower bounds' do + hypothesis do + expect(any(integers(min: -100))).to be >= -100 + end + end + + they 'respect both bounds at once when lower bound is zero' do + hypothesis do + n = any integers(min: 0, max: 100) + expect(n).to be <= 100 + expect(n).to be >= 0 + end + end + + they 'respect both bounds at once when lower bound is non-zero' do + hypothesis do + n = any integers(min: 1, max: 100) + expect(n).to be <= 100 + expect(n).to be >= 1 + end + end +end diff -Nru python-hypothesis-3.44.1/hypothesis-ruby/spec/mixing_spec.rb python-hypothesis-3.71.11/hypothesis-ruby/spec/mixing_spec.rb --- python-hypothesis-3.44.1/hypothesis-ruby/spec/mixing_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-ruby/spec/mixing_spec.rb 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +RSpec.describe 'from possible' do + include Hypothesis::Debug + + it 'includes the first argument' do + find_any do + any(from(integers, strings)).is_a? Integer + end + end + + it 'includes the second argument' do + find_any do + any(from(integers, strings)).is_a? String + end + end +end diff -Nru python-hypothesis-3.44.1/hypothesis-ruby/spec/multiple_failures_spec.rb python-hypothesis-3.71.11/hypothesis-ruby/spec/multiple_failures_spec.rb --- python-hypothesis-3.44.1/hypothesis-ruby/spec/multiple_failures_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-ruby/spec/multiple_failures_spec.rb 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +RSpec.describe 'tests with multiple failures' do + they 'show multiple failures' do + expect do + @initial = nil + + hypothesis do + x = any integers + if @initial.nil? + if x >= 1000 + @initial = x + else + next + end + end + + expect(x).to_not eq(@initial) + raise 'Nope' + end + end.to raise_exception(Hypothesis::MultipleExceptionError) { |e| + expect(e.all_exceptions.length).to eq(2) + } + end +end + +RSpec.describe Hypothesis::MultipleExceptionError do + it 'includes the message from each exception' do + exceptions = [] + %w[hello world].each do |m| + begin + raise m + rescue Exception => e + exceptions.append(e) + end + end + + e = Hypothesis::MultipleExceptionError.new(*exceptions) + expect(e.message).to include('hello') + expect(e.message).to include('world') + end +end diff -Nru python-hypothesis-3.44.1/hypothesis-ruby/spec/provided_list_spec.rb python-hypothesis-3.71.11/hypothesis-ruby/spec/provided_list_spec.rb --- python-hypothesis-3.44.1/hypothesis-ruby/spec/provided_list_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-ruby/spec/provided_list_spec.rb 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +RSpec.describe 'shrinking' do + include Hypothesis::Debug + include Hypothesis::Possibilities + + it 'finds a small list' do + ls, = find { any(arrays(of: integers)).length >= 2 } + expect(ls).to eq([0, 0]) + end + + it 'shrinks a list to its last element' do + 10.times do + @original_target = nil + + ls, = find do + v = any(arrays(of: integers)) + + if v.length >= 5 && @original_target.nil? && v[-1] > 0 + @original_target = v + end + !@original_target.nil? && v && v[-1] == @original_target[-1] + end + + expect(ls.length).to eq(1) + end + end +end diff -Nru python-hypothesis-3.44.1/hypothesis-ruby/spec/spec_helper.rb python-hypothesis-3.71.11/hypothesis-ruby/spec/spec_helper.rb --- python-hypothesis-3.44.1/hypothesis-ruby/spec/spec_helper.rb 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-ruby/spec/spec_helper.rb 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,114 @@ +# frozen_string_literal: true + +require 'simplecov' +SimpleCov.minimum_coverage 100 + +class PrintingFormatter + # Takes a SimpleCov::Result and generates a string out of it + def format(result) + bad = [] + result.files.each do |file| + bad.push file if file.covered_percent < 100.0 + end + + unless bad.empty? + puts 'Files with missing coverage!' + bad.each do |file| + lines = file.source_lines.select { |l| l.coverage == 0 } + .map(&:line_number).sort + s = lines[0] + groups = [[s, s]] + lines.each do |i| + if i <= groups[-1][-1] + 1 + groups[-1][-1] = i + else + groups.push([i, i]) + end + end + markers = [] + groups.each do |g| + if g[0] == g[1] + markers.push(g[0].to_s) + else + markers.push(g.join('-')) + end + end + puts "#{file.filename}: #{markers.join(', ')}" + end + end + end +end + +SimpleCov.formatters = SimpleCov::Formatter::MultiFormatter.new( + [SimpleCov::Formatter::HTMLFormatter, PrintingFormatter] +) + +SimpleCov.start do + add_filter do |source_file| + name = source_file.filename + !(name.include?('/hypothesis-ruby/lib/') || name.end_with?('hypothesis.rb')) + end +end + +require 'hypothesis' + +module Hypothesis + module Debug + class NoSuchExample < HypothesisError + end + + def find(options = {}, &block) + unless Hypothesis::World.current_engine.nil? + raise UsageError, 'Cannot nest hypothesis calls' + end + begin + Hypothesis::World.current_engine = Hypothesis::Engine.new( + max_examples: options.fetch(:max_examples, 1000) + ) + Hypothesis::World.current_engine.is_find = true + Hypothesis::World.current_engine.run(&block) + source = Hypothesis::World.current_engine.current_source + raise NoSuchExample if source.nil? + source.draws + ensure + Hypothesis::World.current_engine = nil + end + end + + def find_any(options = {}, &block) + # Currently the same as find, but once we have config + # options for shrinking it will turn that off. + find(options, &block) + end + end +end + +RSpec.configure do |config| + config.expect_with :rspec do |expectations| + expectations.include_chain_clauses_in_custom_matcher_descriptions = true + end + + config.alias_example_to :they + + config.mock_with :rspec do |mocks| + mocks.verify_partial_doubles = true + end + + config.shared_context_metadata_behavior = :apply_to_host_groups + + config.example_status_persistence_file_path = 'spec/examples.txt' + config.disable_monkey_patching! + + config.warnings = true + + config.default_formatter = 'doc' + + config.profile_examples = 10 + + config.order = :random + + Kernel.srand config.seed + + config.include(Hypothesis) + config.include(Hypothesis::Possibilities) +end diff -Nru python-hypothesis-3.44.1/hypothesis-ruby/spec/stable_identifier_spec.rb python-hypothesis-3.71.11/hypothesis-ruby/spec/stable_identifier_spec.rb --- python-hypothesis-3.44.1/hypothesis-ruby/spec/stable_identifier_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-ruby/spec/stable_identifier_spec.rb 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +class SomeClass + include Hypothesis + def stuff + hypothesis_stable_identifier + end +end + +RSpec.describe 'stable identifiers' do + it 'are the full rspec string' do + expect(hypothesis_stable_identifier).to eq( + 'stable identifiers are the full rspec string' + ) + end + + it 'fall back to a traceback' do + ident = SomeClass.new.stuff + expect(ident).to include(__FILE__) + expect(ident).to include('6') + end +end diff -Nru python-hypothesis-3.44.1/hypothesis-ruby/spec/strings_spec.rb python-hypothesis-3.71.11/hypothesis-ruby/spec/strings_spec.rb --- python-hypothesis-3.44.1/hypothesis-ruby/spec/strings_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-ruby/spec/strings_spec.rb 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +RSpec.describe 'strings' do + they 'respect a non-ascii lower bound' do + hypothesis do + expect(any(codepoints(min: 127))).to be >= 127 + end + end +end + +RSpec.describe 'strings' do + include Hypothesis::Debug + + they 'can be ascii' do + find_any do + s = any(strings(min_size: 3, max_size: 3)) + s.codepoints.all? { |c| c < 127 } + end + end + + they 'can be non-ascii' do + find_any do + any(strings).codepoints.any? { |c| c > 127 } + end + end + + they 'produce valid strings' do + find do + s = any(strings) + # Shrinking will try and fail to move this into + # an invalid codepoint range. + !s.empty? && s.codepoints[0] >= 56_785 + end + end +end diff -Nru python-hypothesis-3.44.1/hypothesis-ruby/src/lib.rs python-hypothesis-3.71.11/hypothesis-ruby/src/lib.rs --- python-hypothesis-3.44.1/hypothesis-ruby/src/lib.rs 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/hypothesis-ruby/src/lib.rs 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,184 @@ +// "Bridging" root code that exists exclusively to provide +// a ruby -> Hypothesis engine binding. + +#![recursion_limit = "256"] +#![deny(warnings, missing_debug_implementations)] + +extern crate core; +#[macro_use] +extern crate helix; +extern crate rand; +extern crate conjecture; + +use std::mem; + +use conjecture::data::{DataSource, Status, TestResult}; +use conjecture::distributions::Repeat; +use conjecture::distributions; +use conjecture::engine::Engine; + +ruby! { + class HypothesisCoreDataSource { + struct { + source: Option, + } + + def initialize(helix, engine: &mut HypothesisCoreEngine){ + let mut result = HypothesisCoreDataSource{helix, source: None}; + mem::swap(&mut result.source, &mut engine.pending); + return result; + } + + def start_draw(&mut self){ + if let &mut Some(ref mut source) = &mut self.source { + source.start_draw(); + } + } + + def stop_draw(&mut self){ + if let &mut Some(ref mut source) = &mut self.source { + source.stop_draw(); + } + } + } + + class HypothesisCoreEngine { + struct { + engine: Engine, + pending: Option, + interesting_examples: Vec, + } + + def initialize(helix, seed: u64, max_examples: u64){ + let xs: [u32; 2] = [seed as u32, (seed >> 32) as u32]; + HypothesisCoreEngine{ + helix, + engine: Engine::new(max_examples, &xs), + pending: None, + interesting_examples: Vec::new(), + } + } + + def new_source(&mut self) -> Option { + match self.engine.next_source() { + None => { + self.interesting_examples = self.engine.list_minimized_examples(); + None + }, + Some(source) => { + self.pending = Some(source); + Some(HypothesisCoreDataSource::new(self)) + }, + } + } + + def count_failing_examples(&self) -> usize { + self.interesting_examples.len() + } + + def failing_example(&mut self, i: usize) -> HypothesisCoreDataSource { + self.pending = Some( + DataSource::from_vec(self.interesting_examples[i].record.clone()) + ); + HypothesisCoreDataSource::new(self) + } + + def was_unsatisfiable(&mut self) -> bool { + self.engine.was_unsatisfiable() + } + + def finish_overflow(&mut self, child: &mut HypothesisCoreDataSource){ + mark_child_status(&mut self.engine, child, Status::Overflow); + } + + def finish_invalid(&mut self, child: &mut HypothesisCoreDataSource){ + mark_child_status(&mut self.engine, child, Status::Invalid); + } + + def finish_interesting(&mut self, child: &mut HypothesisCoreDataSource, label: u64){ + mark_child_status(&mut self.engine, child, Status::Interesting(label)); + } + + def finish_valid(&mut self, child: &mut HypothesisCoreDataSource){ + mark_child_status(&mut self.engine, child, Status::Valid); + } + } + + class HypothesisCoreBitPossible{ + struct { + n_bits: u64, + } + + def initialize(helix, n_bits: u64){ + return HypothesisCoreBitPossible{helix, n_bits: n_bits}; + } + + def provide(&mut self, data: &mut HypothesisCoreDataSource) -> Option{ + match &mut data.source { + &mut None => None, + &mut Some(ref mut source) => source.bits(self.n_bits).ok(), + } + } + } + + class HypothesisCoreRepeatValues{ + struct { + repeat: Repeat, + } + + def initialize(helix, min_count: u64, max_count: u64, expected_count: f64){ + return HypothesisCoreRepeatValues{ + helix, repeat: Repeat::new(min_count, max_count, expected_count) + } + } + + def _should_continue(&mut self, data: &mut HypothesisCoreDataSource) -> Option{ + return data.source.as_mut().and_then(|ref mut source| { + self.repeat.should_continue(source).ok() + }) + } + + def reject(&mut self){ + self.repeat.reject(); + } + } + + class HypothesisCoreIntegers{ + struct { + bitlengths: distributions::Sampler, + } + def initialize(helix){ + return HypothesisCoreIntegers{helix,bitlengths: distributions::good_bitlengths()}; + } + def provide(&mut self, data: &mut HypothesisCoreDataSource) -> Option{ + data.source.as_mut().and_then(|ref mut source| { + distributions::integer_from_bitlengths(source, &self.bitlengths).ok() + }) + } + } + + class HypothesisCoreBoundedIntegers{ + struct { + max_value: u64, + } + def initialize(helix, max_value: u64){ + return HypothesisCoreBoundedIntegers{helix, max_value: max_value}; + } + + def provide(&mut self, data: &mut HypothesisCoreDataSource) -> Option{ + data.source.as_mut().and_then(|ref mut source| { + distributions::bounded_int(source, self.max_value).ok() + }) + } + } +} + +fn mark_child_status(engine: &mut Engine, child: &mut HypothesisCoreDataSource, status: Status) { + let mut replacement = None; + mem::swap(&mut replacement, &mut child.source); + + match replacement { + Some(source) => engine.mark_finished(source, status), + None => (), + } +} diff -Nru python-hypothesis-3.44.1/.isort.cfg python-hypothesis-3.71.11/.isort.cfg --- python-hypothesis-3.44.1/.isort.cfg 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/.isort.cfg 2018-09-24 10:46:59.000000000 +0000 @@ -1,2 +1,2 @@ [settings] -known_third_party = attr, click, django, faker, flaky, numpy, pytz, scipy +known_third_party = attr, click, dateutil, django, faker, flaky, numpy, pytz, scipy diff -Nru python-hypothesis-3.44.1/Makefile python-hypothesis-3.71.11/Makefile --- python-hypothesis-3.44.1/Makefile 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/Makefile 2018-09-24 10:46:59.000000000 +0000 @@ -1,304 +1,6 @@ -.PHONY: clean documentation +# You don't need to use this Makefile and should use build.sh instead. This is +# just here so that us poor souls who remember the Make based system and keep +# typing "make target" can ease our transition to the new system. - -DEVELOPMENT_DATABASE?=postgres://whereshouldilive@localhost/whereshouldilive_dev -SPHINXBUILD = $(DEV_PYTHON) -m sphinx -SPHINX_BUILDDIR = docs/_build -ALLSPHINXOPTS = -d $(SPHINX_BUILDDIR)/doctrees docs -W - -export BUILD_RUNTIMES?=$(HOME)/.cache/hypothesis-build-runtimes -export TOX_WORK_DIR=$(BUILD_RUNTIMES)/.tox -export COVERAGE_FILE=$(BUILD_RUNTIMES)/.coverage - -PY27=$(BUILD_RUNTIMES)/snakepit/python2.7 -PY273=$(BUILD_RUNTIMES)/snakepit/python2.7.3 -PY34=$(BUILD_RUNTIMES)/snakepit/python3.4 -PY35=$(BUILD_RUNTIMES)/snakepit/python3.5 -PY36=$(BUILD_RUNTIMES)/snakepit/python3.6 -PYPY=$(BUILD_RUNTIMES)/snakepit/pypy - -BEST_PY3=$(PY36) - -TOOLS=$(BUILD_RUNTIMES)/tools - -TOX=$(TOOLS)/tox -SPHINX_BUILD=$(TOOLS)/sphinx-build -ISORT=$(TOOLS)/isort -FLAKE8=$(TOOLS)/flake8 -PYFORMAT=$(TOOLS)/pyformat -RSTLINT=$(TOOLS)/rst-lint -PIPCOMPILE=$(TOOLS)/pip-compile - -TOOL_VIRTUALENV:=$(BUILD_RUNTIMES)/virtualenvs/tools-$(shell scripts/tool-hash.py tools) - -TOOL_PYTHON=$(TOOL_VIRTUALENV)/bin/python -TOOL_PIP=$(TOOL_VIRTUALENV)/bin/pip - -BENCHMARK_VIRTUALENV:=$(BUILD_RUNTIMES)/virtualenvs/benchmark-$(shell scripts/tool-hash.py benchmark) -BENCHMARK_PYTHON=$(BENCHMARK_VIRTUALENV)/bin/python - -FILES_TO_FORMAT=$(BEST_PY3) scripts/files-to-format.py - - -export PATH:=$(BUILD_RUNTIMES)/snakepit:$(TOOLS):$(PATH) -export LC_ALL=en_US.UTF-8 - -$(PY27): - scripts/retry.sh scripts/install.sh 2.7 - -$(PY273): - scripts/retry.sh scripts/install.sh 2.7.3 - -$(PY34): - scripts/retry.sh scripts/install.sh 3.4 - -$(PY35): - scripts/retry.sh scripts/install.sh 3.5 - -$(PY36): - scripts/retry.sh scripts/install.sh 3.6 - - -$(PYPY): - scripts/retry.sh scripts/install.sh pypy - -$(TOOL_VIRTUALENV): $(BEST_PY3) - $(BEST_PY3) -m virtualenv $(TOOL_VIRTUALENV) - $(TOOL_PIP) install -r requirements/tools.txt - -$(BENCHMARK_VIRTUALENV): $(BEST_PY3) - rm -rf $(BUILD_RUNTIMES)/virtualenvs/benchmark-* - $(BEST_PY3) -m virtualenv $(BENCHMARK_VIRTUALENV) - $(BENCHMARK_PYTHON) -m pip install -r requirements/benchmark.txt - -$(TOOLS): $(TOOL_VIRTUALENV) - mkdir -p $(TOOLS) - -install-tools: $(TOOLS) - -format: $(PYFORMAT) $(ISORT) - $(FILES_TO_FORMAT) | xargs $(TOOL_PYTHON) scripts/enforce_header.py - # isort will sort packages differently depending on whether they're installed - $(FILES_TO_FORMAT) | xargs env -i PATH="$(PATH)" $(ISORT) -p hypothesis -ls -m 2 -w 75 \ - -a "from __future__ import absolute_import, print_function, division" \ - -rc src tests examples - $(FILES_TO_FORMAT) | xargs $(PYFORMAT) -i - -lint: $(FLAKE8) - $(FLAKE8) src tests --exclude=compat.py,test_reflection.py,test_imports.py,tests/py2,test_lambda_formatting.py - - -check-pyup-yml: $(TOOL_VIRTUALENV) - $(TOOL_PYTHON) scripts/validate_pyup.py - -check-release-file: $(BEST_PY3) - $(BEST_PY3) scripts/check-release-file.py - -deploy: $(TOOL_VIRTUALENV) - $(TOOL_PYTHON) scripts/deploy.py - -check-format: format - find src tests -name "*.py" | xargs $(TOOL_PYTHON) scripts/check_encoding_header.py - git diff --exit-code - -install-core: $(PY27) $(PYPY) $(BEST_PY3) $(TOX) - -STACK=$(HOME)/.local/bin/stack -GHC=$(HOME)/.local/bin/ghc -SHELLCHECK=$(HOME)/.local/bin/shellcheck - -$(STACK): - mkdir -p ~/.local/bin - curl -L https://www.stackage.org/stack/linux-x86_64 | tar xz --wildcards --strip-components=1 -C $(HOME)/.local/bin '*/stack' - -$(GHC): $(STACK) - $(STACK) setup - -$(SHELLCHECK): $(GHC) - $(STACK) install ShellCheck - -check-shellcheck: $(SHELLCHECK) - shellcheck scripts/*.sh - -check-py27: $(PY27) $(TOX) - $(TOX) --recreate -e py27-full - -check-py273: $(PY273) $(TOX) - $(TOX) --recreate -e oldpy27 - -check-py27-typing: $(PY27) $(TOX) - $(TOX) --recreate -e py27typing - -check-py34: $(PY34) $(TOX) - $(TOX) --recreate -e py34-full - -check-py35: $(PY35) $(TOX) - $(TOX) --recreate -e py35-full - -check-py36: $(BEST_PY3) $(TOX) - $(TOX) --recreate -e py36-full - -check-pypy: $(PYPY) $(TOX) - $(TOX) --recreate -e pypy-full - -check-pypy-with-tracer: $(PYPY) $(TOX) - $(TOX) --recreate -e pypy-with-tracer - -check-nose: $(TOX) - $(TOX) --recreate -e nose - -check-pytest30: $(TOX) - $(TOX) --recreate -e pytest30 - -check-pytest28: $(TOX) - $(TOX) --recreate -e pytest28 - -check-quality: $(TOX) - $(TOX) --recreate -e quality - -check-ancient-pip: $(PY273) - scripts/check-ancient-pip.sh $(PY273) - - -check-pytest: check-pytest28 check-pytest30 - -check-faker070: $(TOX) - $(TOX) --recreate -e faker070 - -check-faker-latest: $(TOX) - $(TOX) --recreate -e faker-latest - -check-django18: $(TOX) - $(TOX) --recreate -e django18 - -check-django110: $(TOX) - $(TOX) --recreate -e django110 - -check-django111: $(TOX) - $(TOX) --recreate -e django111 - -check-django: check-django18 check-django110 check-django111 - -check-pandas18: $(TOX) - $(TOX) --recreate -e pandas18 - -check-pandas19: $(TOX) - $(TOX) --recreate -e pandas19 - -check-pandas20: $(TOX) - $(TOX) --recreate -e pandas20 - -check-pandas21: $(TOX) - $(TOX) --recreate -e pandas21 - -check-examples2: $(TOX) $(PY27) - $(TOX) --recreate -e examples2 - -check-examples3: $(TOX) - $(TOX) --recreate -e examples3 - -check-coverage: $(TOX) - $(TOX) --recreate -e coverage - -check-pure-tracer: $(TOX) - $(TOX) --recreate -e pure-tracer - -check-unicode: $(TOX) $(PY27) - $(TOX) --recreate -e unicode - -check-noformat: check-coverage check-py26 check-py27 check-py34 check-py35 check-pypy check-django check-pytest - -check: check-format check-noformat - -check-fast: lint $(PYPY) $(PY36) $(TOX) - $(TOX) --recreate -e pypy-brief - $(TOX) --recreate -e py36-prettyquick - -check-rst: $(RSTLINT) $(FLAKE8) - $(RSTLINT) CONTRIBUTING.rst README.rst - $(RSTLINT) guides/*.rst - $(FLAKE8) --select=W191,W291,W292,W293,W391 *.rst docs/*.rst - -compile-requirements: $(PIPCOMPILE) - $(PIPCOMPILE) requirements/benchmark.in --output-file requirements/benchmark.txt - $(PIPCOMPILE) requirements/test.in --output-file requirements/test.txt - $(PIPCOMPILE) requirements/tools.in --output-file requirements/tools.txt - $(PIPCOMPILE) requirements/typing.in --output-file requirements/typing.txt - $(PIPCOMPILE) requirements/coverage.in --output-file requirements/coverage.txt - -upgrade-requirements: - $(PIPCOMPILE) --upgrade requirements/benchmark.in --output-file requirements/benchmark.txt - $(PIPCOMPILE) --upgrade requirements/test.in --output-file requirements/test.txt - $(PIPCOMPILE) --upgrade requirements/tools.in --output-file requirements/tools.txt - $(PIPCOMPILE) --upgrade requirements/typing.in --output-file requirements/typing.txt - $(PIPCOMPILE) --upgrade requirements/coverage.in --output-file requirements/coverage.txt - -check-requirements: compile-requirements - git diff --exit-code - -secrets.tar.enc: deploy_key .pypirc - rm -f secrets.tar secrets.tar.enc - tar -cf secrets.tar deploy_key .pypirc - travis encrypt-file secrets.tar - rm secrets.tar - -check-benchmark: $(BENCHMARK_VIRTUALENV) - PYTHONPATH=src $(BENCHMARK_PYTHON) scripts/benchmarks.py --check --nruns=100 - -build-new-benchmark-data: $(BENCHMARK_VIRTUALENV) - PYTHONPATH=src $(BENCHMARK_PYTHON) scripts/benchmarks.py --skip-existing --nruns=1000 - -update-improved-benchmark-data: $(BENCHMARK_VIRTUALENV) - PYTHONPATH=src $(BENCHMARK_PYTHON) scripts/benchmarks.py --update=improved --nruns=1000 - -update-all-benchmark-data: $(BENCHMARK_VIRTUALENV) - PYTHONPATH=src $(BENCHMARK_PYTHON) scripts/benchmarks.py --update=all --nruns=1000 - -update-benchmark-headers: $(BENCHMARK_VIRTUALENV) - PYTHONPATH=src $(BENCHMARK_PYTHON) scripts/benchmarks.py --only-update-headers - -$(TOX): $(BEST_PY3) tox.ini $(TOOLS) - rm -f $(TOX) - ln -sf $(TOOL_VIRTUALENV)/bin/tox $(TOX) - touch $(TOOL_VIRTUALENV)/bin/tox $(TOX) - -$(SPHINX_BUILD): $(TOOLS) - ln -sf $(TOOL_VIRTUALENV)/bin/sphinx-build $(SPHINX_BUILD) - -$(PYFORMAT): $(TOOLS) - ln -sf $(TOOL_VIRTUALENV)/bin/pyformat $(PYFORMAT) - -$(ISORT): $(TOOLS) - ln -sf $(TOOL_VIRTUALENV)/bin/isort $(ISORT) - -$(RSTLINT): $(TOOLS) - ln -sf $(TOOL_VIRTUALENV)/bin/rst-lint $(RSTLINT) - -$(FLAKE8): $(TOOLS) - ln -sf $(TOOL_VIRTUALENV)/bin/flake8 $(FLAKE8) - -$(PIPCOMPILE): $(TOOLS) - ln -sf $(TOOL_VIRTUALENV)/bin/pip-compile $(PIPCOMPILE) - - -clean: - rm -rf .tox - rm -rf .hypothesis - rm -rf docs/_build - rm -rf $(TOOLS) - rm -rf $(BUILD_RUNTIMES)/snakepit - rm -rf $(BUILD_RUNTIMES)/virtualenvs - find src tests -name "*.pyc" -delete - find src tests -name "__pycache__" -delete - -.PHONY: RELEASE.rst -RELEASE.rst: - -documentation: $(SPHINX_BUILD) docs/*.rst RELEASE.rst - scripts/build-documentation.sh $(SPHINX_BUILD) $(PY36) - -doctest: $(SPHINX_BUILD) docs/*.rst - PYTHONPATH=src $(SPHINX_BUILD) -W -b doctest -d docs/_build/doctrees docs docs/_build/html - -fix_doctests: $(TOOL_VIRTUALENV) - PYTHONPATH=src $(TOOL_PYTHON) scripts/fix_doctests.py +%: + ./build.sh $@ diff -Nru python-hypothesis-3.44.1/mypy.ini python-hypothesis-3.71.11/mypy.ini --- python-hypothesis-3.44.1/mypy.ini 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/mypy.ini 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,13 @@ +[mypy] +python_version = 3.6 +platform = linux + +strict_optional = True +disallow_untyped_decorators = True + +follow_imports = silent +ignore_missing_imports = True + +warn_unused_ignores = True +warn_unused_configs = True +warn_redundant_casts = True diff -Nru python-hypothesis-3.44.1/pytest.ini python-hypothesis-3.71.11/pytest.ini --- python-hypothesis-3.44.1/pytest.ini 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/pytest.ini 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,3 @@ +[pytest] + +addopts=--strict --tb=native -p pytester --runpytest=subprocess --durations=20 diff -Nru python-hypothesis-3.44.1/.pyup.yml python-hypothesis-3.71.11/.pyup.yml --- python-hypothesis-3.44.1/.pyup.yml 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/.pyup.yml 2018-09-24 10:46:59.000000000 +0000 @@ -5,9 +5,6 @@ - requirements/test.txt: updates: all pin: True - - requirements/benchmark.txt: - updates: all - pin: True - requirements/coverage.txt: updates: all pin: True diff -Nru python-hypothesis-3.44.1/README.rst python-hypothesis-3.71.11/README.rst --- python-hypothesis-3.44.1/README.rst 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/README.rst 2018-09-24 10:46:59.000000000 +0000 @@ -2,58 +2,31 @@ Hypothesis ========== -Hypothesis is an advanced testing library for Python. It lets you write tests which -are parametrized by a source of examples, and then generates simple and comprehensible -examples that make your tests fail. This lets you find more bugs in your code with less -work. +Hypothesis is family of testing libraries which let you write tests parametrized +by a source of examples. A Hypothesis implementation then generates simple and +comprehensible examples that make your tests fail. +This simplifies writing your tests and makes them more powerful at the same time, +by letting software automate the boring bits and do them to a higher standard than a human would, +freeing you to focus on the higher level test logic. + +This sort of testing is often called "property-based testing", +and the most widely known implementation of the concept is the Haskell +library `QuickCheck `_, +but Hypothesis differs significantly from QuickCheck and is designed to fit +idiomatically and easily into existing styles of testing that you are used to, +with absolutely no familiarity with Haskell or functional programming needed. + +The currently available implementations of Hypothesis are: + +* `Hypothesis for Python `_ is the original implementation, + and the only one that is currently fully production ready. +* `Hypothesis for Ruby `_ + is an ongoing project that we intend to eventually reach parity with + Hypothesis for Python. +* `Hypothesis for Java `_ + is a prototype written some time ago. It's far from feature complete and is + not under active development, but was intended to prove the viability of the + concept. -e.g. - -.. code-block:: python - - @given(st.lists( - st.floats(allow_nan=False, allow_infinity=False), min_size=1)) - def test_mean(xs): - assert min(xs) <= mean(xs) <= max(xs) - -.. code-block:: - - Falsifying example: test_mean( - xs=[1.7976321109618856e+308, 6.102390043022755e+303] - ) - -Hypothesis is extremely practical and advances the state of the art of -unit testing by some way. It's easy to use, stable, and powerful. If -you're not using Hypothesis to test your project then you're missing out. - ------------------------- -Quick Start/Installation ------------------------- -If you just want to get started: - -.. code-block:: - - pip install hypothesis - - ------------------ -Links of interest ------------------ - -The main Hypothesis site is at `hypothesis.works `_, and contains a lot -of good introductory and explanatory material. - -Extensive documentation and examples of usage are `available at readthedocs `_. - -If you want to talk to people about using Hypothesis, `we have both an IRC channel -and a mailing list `_. - -If you want to receive occasional updates about Hypothesis, including useful tips and tricks, there's a -`TinyLetter mailing list to sign up for them `_. - -If you want to contribute to Hypothesis, `instructions are here `_. - -If you want to hear from people who are already using Hypothesis, some of them `have written -about it `_. - -If you want to create a downstream package of Hypothesis, please read `these guidelines for packagers `_. +This repository will eventually house all implementations of Hypothesis, but +we are currently in the process of consolidating the existing repositories into a single one. diff -Nru python-hypothesis-3.44.1/.readthedocs.yml python-hypothesis-3.71.11/.readthedocs.yml --- python-hypothesis-3.44.1/.readthedocs.yml 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/.readthedocs.yml 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1 @@ +requirements_file: .rtfd-reqs.txt diff -Nru python-hypothesis-3.44.1/requirements/benchmark.in python-hypothesis-3.71.11/requirements/benchmark.in --- python-hypothesis-3.44.1/requirements/benchmark.in 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/requirements/benchmark.in 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -attrs -click -numpy -scipy -coverage diff -Nru python-hypothesis-3.44.1/requirements/benchmark.txt python-hypothesis-3.71.11/requirements/benchmark.txt --- python-hypothesis-3.44.1/requirements/benchmark.txt 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/requirements/benchmark.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ -# -# This file is autogenerated by pip-compile -# To update, run: -# -# pip-compile --output-file requirements/benchmark.txt requirements/benchmark.in -# -attrs==17.3.0 -click==6.7 -coverage==4.4.2 -numpy==1.13.3 -scipy==1.0.0 diff -Nru python-hypothesis-3.44.1/requirements/coverage.in python-hypothesis-3.71.11/requirements/coverage.in --- python-hypothesis-3.44.1/requirements/coverage.in 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/requirements/coverage.in 2018-09-24 10:46:59.000000000 +0000 @@ -1,4 +1,4 @@ -numpy coverage -pytz +numpy pandas +pytz diff -Nru python-hypothesis-3.44.1/requirements/coverage.txt python-hypothesis-3.71.11/requirements/coverage.txt --- python-hypothesis-3.44.1/requirements/coverage.txt 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/requirements/coverage.txt 2018-09-24 10:46:59.000000000 +0000 @@ -4,9 +4,9 @@ # # pip-compile --output-file requirements/coverage.txt requirements/coverage.in # -coverage==4.4.2 -numpy==1.13.3 -pandas==0.21.0 -python-dateutil==2.6.1 # via pandas -pytz==2017.3 +coverage==4.5.1 +numpy==1.15.1 +pandas==0.23.4 +python-dateutil==2.7.3 # via pandas +pytz==2018.5 six==1.11.0 # via python-dateutil diff -Nru python-hypothesis-3.44.1/requirements/test.in python-hypothesis-3.71.11/requirements/test.in --- python-hypothesis-3.44.1/requirements/test.in 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/requirements/test.in 2018-09-24 10:46:59.000000000 +0000 @@ -1,5 +1,5 @@ +attrs flaky +mock pytest pytest-xdist -mock -attrs diff -Nru python-hypothesis-3.44.1/requirements/test.txt python-hypothesis-3.71.11/requirements/test.txt --- python-hypothesis-3.44.1/requirements/test.txt 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/requirements/test.txt 2018-09-24 10:46:59.000000000 +0000 @@ -4,15 +4,17 @@ # # pip-compile --output-file requirements/test.txt requirements/test.in # -apipkg==1.4 # via execnet -attrs==17.3.0 +apipkg==1.5 # via execnet +atomicwrites==1.2.1 # via pytest +attrs==18.2.0 execnet==1.5.0 # via pytest-xdist flaky==3.4.0 mock==2.0.0 -pbr==3.1.1 # via mock -pluggy==0.6.0 # via pytest -py==1.5.2 # via pytest +more-itertools==4.3.0 # via pytest +pbr==4.2.0 # via mock +pluggy==0.7.1 # via pytest +py==1.6.0 # via pytest pytest-forked==0.2 # via pytest-xdist -pytest-xdist==1.20.1 -pytest==3.3.1 -six==1.11.0 # via mock, pytest +pytest-xdist==1.23.0 +pytest==3.8.0 +six==1.11.0 # via mock, more-itertools, pytest, pytest-xdist diff -Nru python-hypothesis-3.44.1/requirements/tools.in python-hypothesis-3.71.11/requirements/tools.in --- python-hypothesis-3.44.1/requirements/tools.in 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/requirements/tools.in 2018-09-24 10:46:59.000000000 +0000 @@ -1,13 +1,24 @@ +attrs +bandit +coverage +django flake8 +flake8-docstrings +flaky +ipython isort +mock +mypy +numpy pip-tools pyformat pytest +python-dateutil +pyupio +requests restructuredtext-lint -Sphinx +sphinx sphinx-rtd-theme +toml tox twine -attrs -coverage -pyupio diff -Nru python-hypothesis-3.44.1/requirements/tools.txt python-hypothesis-3.71.11/requirements/tools.txt --- python-hypothesis-3.44.1/requirements/tools.txt 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/requirements/tools.txt 2018-09-24 10:46:59.000000000 +0000 @@ -4,57 +4,91 @@ # # pip-compile --output-file requirements/tools.txt requirements/tools.in # -alabaster==0.7.10 # via sphinx -attrs==17.3.0 -autoflake==1.0 # via pyformat -autopep8==1.3.3 # via pyformat -babel==2.5.1 # via sphinx -certifi==2017.11.5 # via requests +alabaster==0.7.11 # via sphinx +atomicwrites==1.2.1 # via pytest +attrs==18.2.0 +autoflake==1.2 # via pyformat +autopep8==1.4 # via pyformat +babel==2.6.0 # via sphinx +backcall==0.1.0 # via ipython +bandit==1.5.1 +certifi==2018.8.24 # via requests chardet==3.0.4 # via requests click==6.7 # via pip-tools, pyupio, safety -coverage==4.4.2 -docformatter==0.8 # via pyformat +coverage==4.5.1 +decorator==4.3.0 # via ipython, traitlets +deprecated==1.2.3 # via pygithub +django==2.1.1 +docformatter==1.0 # via pyformat docutils==0.14 # via restructuredtext-lint, sphinx -dparse==0.2.1 # via pyupio, safety +dparse==0.4.1 # via pyupio, safety first==2.0.1 # via pip-tools +flake8-docstrings==1.3.0 +flake8-polyfill==1.0.2 # via flake8-docstrings flake8==3.5.0 -hashin-pyup==0.7.2 # via pyupio -idna==2.6 # via requests -imagesize==0.7.1 # via sphinx -isort==4.2.15 +flaky==3.4.0 +gitdb2==2.0.4 # via gitpython +gitpython==2.1.11 # via bandit +idna==2.7 # via requests +imagesize==1.1.0 # via sphinx +ipython-genutils==0.2.0 # via traitlets +ipython==6.5.0 +isort==4.3.4 +jedi==0.12.1 # via ipython jinja2==2.10 # via pyupio, sphinx markupsafe==1.0 # via jinja2 mccabe==0.6.1 # via flake8 -packaging==16.8 # via dparse, pyupio, safety -pip-tools==1.11.0 -pkginfo==1.4.1 # via twine -pluggy==0.6.0 # via pytest, tox -py==1.5.2 # via pytest, tox +mock==2.0.0 +more-itertools==4.3.0 # via pytest +mypy-extensions==0.4.1 # via mypy +mypy==0.630 +numpy==1.15.1 +packaging==17.1 # via dparse, pyupio, safety, sphinx +parso==0.3.1 # via jedi +pbr==4.2.0 # via mock, stevedore +pexpect==4.6.0 # via ipython +pickleshare==0.7.4 # via ipython +pip-tools==2.0.2 +pkginfo==1.4.2 # via twine +pluggy==0.7.1 # via pytest, tox +prompt-toolkit==1.0.15 # via ipython +ptyprocess==0.6.0 # via pexpect +py==1.6.0 # via pytest, tox pycodestyle==2.3.1 # via autopep8, flake8 +pydocstyle==2.1.1 # via flake8-docstrings pyflakes==1.6.0 # via autoflake, flake8 pyformat==0.7 -pygithub==1.35 # via pyupio -pygments==2.2.0 # via sphinx -pyjwt==1.5.3 # via pygithub +pygithub==1.43.2 # via pyupio +pygments==2.2.0 # via ipython, sphinx +pyjwt==1.6.4 # via pygithub pyparsing==2.2.0 # via packaging -pytest==3.3.1 -python-gitlab==1.1.0 # via pyupio -pytz==2017.3 # via babel -pyupio==0.8.2 -pyyaml==3.12 # via dparse, pyupio +pytest==3.8.0 +python-dateutil==2.7.3 +python-gitlab==1.6.0 # via pyupio +pytz==2018.5 # via babel, django +pyupio==1.0.2 +pyyaml==3.13 # via bandit, dparse, pyupio requests-toolbelt==0.8.0 # via twine -requests==2.18.4 # via python-gitlab, pyupio, requests-toolbelt, safety, sphinx, twine -restructuredtext-lint==1.1.2 -safety==1.6.1 # via pyupio -six==1.11.0 # via dparse, packaging, pip-tools, pytest, python-gitlab, pyupio, sphinx, tox -snowballstemmer==1.2.1 # via sphinx -sphinx-rtd-theme==0.2.4 -sphinx==1.6.5 -sphinxcontrib-websupport==1.0.1 # via sphinx -tox==2.9.1 -tqdm==4.19.5 # via pyupio, twine -twine==1.9.1 +requests==2.19.1 +restructuredtext-lint==1.1.3 +safety==1.8.4 # via pyupio +simplegeneric==0.8.1 # via ipython +six==1.11.0 # via bandit, dparse, mock, more-itertools, packaging, pip-tools, prompt-toolkit, pydocstyle, pytest, python-dateutil, python-gitlab, pyupio, sphinx, stevedore, tox, traitlets +smmap2==2.0.4 # via gitdb2 +snowballstemmer==1.2.1 # via pydocstyle, sphinx +sphinx-rtd-theme==0.4.1 +sphinx==1.8.0 +sphinxcontrib-websupport==1.1.0 # via sphinx +stevedore==1.29.0 # via bandit +toml==0.9.6 +tox==3.3.0 +tqdm==4.26.0 # via pyupio, twine +traitlets==4.3.2 # via ipython +twine==1.11.0 +typed-ast==1.1.0 # via mypy unify==0.4 # via pyformat untokenize==0.1.1 # via docformatter, unify -urllib3==1.22 # via requests -virtualenv==15.1.0 # via tox +urllib3==1.23 # via requests +virtualenv==16.0.0 # via tox +wcwidth==0.1.7 # via prompt-toolkit +wrapt==1.10.11 # via deprecated diff -Nru python-hypothesis-3.44.1/requirements/typing.txt python-hypothesis-3.71.11/requirements/typing.txt --- python-hypothesis-3.44.1/requirements/typing.txt 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/requirements/typing.txt 2018-09-24 10:46:59.000000000 +0000 @@ -4,4 +4,4 @@ # # pip-compile --output-file requirements/typing.txt requirements/typing.in # -typing==3.6.2 +typing==3.6.6 diff -Nru python-hypothesis-3.44.1/.rtfd-reqs.txt python-hypothesis-3.71.11/.rtfd-reqs.txt --- python-hypothesis-3.44.1/.rtfd-reqs.txt 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/.rtfd-reqs.txt 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1 @@ +hypothesis-python/[all] diff -Nru python-hypothesis-3.44.1/scripts/basic-test.sh python-hypothesis-3.71.11/scripts/basic-test.sh --- python-hypothesis-3.44.1/scripts/basic-test.sh 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/scripts/basic-test.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,75 +0,0 @@ -#!/bin/bash -set -e -o xtrace - -# We run a reduced set of tests on OSX mostly so the CI runs in vaguely -# reasonable time. -if [[ "$(uname -s)" == 'Darwin' ]]; then - DARWIN=true -else - DARWIN=false -fi - -python -c ' -import os -for k, v in sorted(dict(os.environ).items()): - print("%s=%s" % (k, v)) -' - -pip install . - - -PYTEST="python -m pytest" - -$PYTEST tests/cover - -COVERAGE_TEST_TRACER=timid $PYTEST tests/cover - -if [ "$(python -c 'import sys; print(sys.version_info[0] == 2)')" = "True" ] ; then - $PYTEST tests/py2 -else - $PYTEST tests/py3 -fi - -$PYTEST --runpytest=subprocess tests/pytest - -pip install ".[datetime]" -$PYTEST tests/datetime/ -pip uninstall -y pytz - - -if [ "$DARWIN" = true ]; then - exit 0 -fi - -if [ "$(python -c 'import sys; print(sys.version_info[:2] in ((2, 7), (3, 6)))')" = "False" ] ; then - exit 0 -fi - -for f in tests/nocover/test_*.py; do - $PYTEST "$f" -done - -# fake-factory doesn't have a correct universal wheel -pip install --no-binary :all: faker -$PYTEST tests/fakefactory/ -pip uninstall -y faker - -if [ "$(python -c 'import platform; print(platform.python_implementation())')" != "PyPy" ]; then - if [ "$(python -c 'import sys; print(sys.version_info[0] == 2 or sys.version_info[:2] >= (3, 4))')" == "True" ] ; then - pip install .[django] - HYPOTHESIS_DJANGO_USETZ=TRUE python -m tests.django.manage test tests.django - HYPOTHESIS_DJANGO_USETZ=FALSE python -m tests.django.manage test tests.django - pip uninstall -y django - fi - - if [ "$(python -c 'import sys; print(sys.version_info[:2] in ((2, 7), (3, 6)))')" = "True" ] ; then - pip install numpy - $PYTEST tests/numpy - - pip install pandas - - $PYTEST tests/pandas - - pip uninstall -y numpy pandas - fi -fi diff -Nru python-hypothesis-3.44.1/scripts/benchmarks.py python-hypothesis-3.71.11/scripts/benchmarks.py --- python-hypothesis-3.44.1/scripts/benchmarks.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/scripts/benchmarks.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,546 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -# pylint: skip-file - -from __future__ import division, print_function, absolute_import - -import os -import sys -import json -import zlib -import base64 -import random -import hashlib -from collections import OrderedDict - -import attr -import click -import numpy as np - -import hypothesis.strategies as st -import hypothesis.extra.numpy as npst -from hypothesis import settings, unlimited -from hypothesis.errors import UnsatisfiedAssumption -from hypothesis.internal.conjecture.engine import ConjectureRunner - -ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) - - -DATA_DIR = os.path.join( - ROOT, - 'benchmark-data', -) - - -BENCHMARK_SETTINGS = settings( - max_examples=100, max_iterations=1000, max_shrinks=1000, - database=None, timeout=unlimited, use_coverage=False, - perform_health_check=False, -) - - -BENCHMARKS = OrderedDict() - - -@attr.s() -class Benchmark(object): - name = attr.ib() - strategy = attr.ib() - valid = attr.ib() - interesting = attr.ib() - - -@attr.s() -class BenchmarkData(object): - sizes = attr.ib() - seed = attr.ib(default=0) - - -STRATEGIES = OrderedDict([ - ('ints', st.integers()), - ('intlists', st.lists(st.integers())), - ('sizedintlists', st.integers(0, 10).flatmap( - lambda n: st.lists(st.integers(), min_size=n, max_size=n))), - ('text', st.text()), - ('text5', st.text(min_size=5)), - ('arrays10', npst.arrays('int8', 10)), - ('arraysvar', npst.arrays('int8', st.integers(0, 10))), -]) - - -def define_benchmark(strategy_name, valid, interesting): - name = '%s-valid=%s-interesting=%s' % ( - strategy_name, valid.__name__, interesting.__name__) - assert name not in BENCHMARKS - strategy = STRATEGIES[strategy_name] - BENCHMARKS[name] = Benchmark(name, strategy, valid, interesting) - - -def always(seed, testdata, value): - return True - - -def never(seed, testdata, value): - return False - - -def nontrivial(seed, testdata, value): - return sum(testdata.buffer) >= 255 - - -def sometimes(p, name=None): - def accept(seed, testdata, value): - hasher = hashlib.md5() - hasher.update(testdata.buffer) - hasher.update(seed) - return random.Random(hasher.digest()).random() <= p - accept.__name__ = name or 'sometimes(%r)' % (p,) - return accept - - -def array_average(seed, testdata, value): - if np.prod(value.shape) == 0: - return False - avg = random.Random(seed).randint(0, 255) - return value.mean() >= avg - - -def lower_bound(seed, testdata, value): - """Benchmarking condition for testing the lexicographic minimization aspect - of test case reduction. - - This lets us test for the sort of behaviour that happens when we - e.g. have a lower bound on an integer, but in more generality. - - """ - - # We implicitly define an infinite stream of bytes, and compare the buffer - # of the testdata object with the prefix of the stream of the same length. - # If it is >= that prefix we accept the testdata, if not we reject it. - rnd = random.Random(seed) - for b in testdata.buffer: - c = rnd.randint(0, 255) - if c < b: - return True - if c > b: - return False - return True - - -def size_lower_bound(seed, testdata, value): - rnd = random.Random(seed) - return len(testdata.buffer) >= rnd.randint(1, 50) - - -usually = sometimes(0.9, 'usually') - - -def minsum(seed, testdata, value): - return sum(value) >= 1000 - - -def has_duplicates(seed, testdata, value): - return len(set(value)) < len(value) - - -for k in STRATEGIES: - define_benchmark(k, always, never) - define_benchmark(k, always, always) - define_benchmark(k, always, usually) - define_benchmark(k, always, lower_bound) - - define_benchmark(k, always, size_lower_bound) - define_benchmark(k, usually, size_lower_bound) - - -define_benchmark('intlists', always, minsum) -define_benchmark('intlists', always, has_duplicates) -define_benchmark('intlists', has_duplicates, minsum) - -for p in [always, usually]: - define_benchmark('arrays10', p, array_average) - define_benchmark('arraysvar', p, array_average) - - -def run_benchmark_for_sizes(benchmark, n_runs): - click.echo('Calculating data for %s' % (benchmark.name,)) - total_sizes = [] - - with click.progressbar(range(n_runs)) as runs: - for _ in runs: - sizes = [] - valid_seed = random.getrandbits(64).to_bytes(8, 'big') - interesting_seed = random.getrandbits(64).to_bytes(8, 'big') - - def test_function(data): - try: - try: - value = data.draw(benchmark.strategy) - except UnsatisfiedAssumption: - data.mark_invalid() - if not data.frozen: - if not benchmark.valid(valid_seed, data, value): - data.mark_invalid() - if benchmark.interesting( - interesting_seed, data, value - ): - data.mark_interesting() - finally: - sizes.append(len(data.buffer)) - engine = ConjectureRunner( - test_function, settings=BENCHMARK_SETTINGS, random=random - ) - engine.run() - assert len(sizes) > 0 - total_sizes.append(sum(sizes)) - return total_sizes - - -def benchmark_difference_p_value(existing, recent): - """This is a bootstrapped permutation test for the difference of means. - - Under the null hypothesis that the two sides come from the same - distribution, we can randomly reassign values to different populations and - see how large a difference in mean we get. This gives us a p-value for our - actual observed difference in mean by counting the fraction of times our - resampling got a value that large. - - See https://en.wikipedia.org/wiki/Resampling_(statistics)#Permutation_tests - for details. - - """ - rnd = random.Random(0) - - threshold = abs(np.mean(existing) - np.mean(recent)) - n = len(existing) - - n_runs = 1000 - greater = 0 - - all_values = existing + recent - for _ in range(n_runs): - rnd.shuffle(all_values) - l = all_values[:n] - r = all_values[n:] - score = abs(np.mean(l) - np.mean(r)) - if score >= threshold: - greater += 1 - return greater / n_runs - - -def benchmark_file(name): - return os.path.join(DATA_DIR, name) - - -def have_existing_data(name): - return os.path.exists(benchmark_file(name)) - - -EXISTING_CACHE = {} - - -BLOBSTART = 'START' -BLOBEND = 'END' - - -def existing_data(name): - try: - return EXISTING_CACHE[name] - except KeyError: - pass - - fname = benchmark_file(name) - result = None - with open(fname) as i: - for l in i: - l = l.strip() - if not l: - continue - if l.startswith('#'): - continue - key, blob = l.split(': ', 1) - magic, n = key.split(' ') - assert magic == 'Data' - n = int(n) - assert blob.startswith(BLOBSTART) - assert blob.endswith(BLOBEND), blob[-len(BLOBEND) * 2:] - assert len(blob) == n + len(BLOBSTART) + len(BLOBEND) - blob = blob[len(BLOBSTART):len(blob) - len(BLOBEND)] - assert len(blob) == n - result = blob_to_data(blob) - break - assert result is not None - EXISTING_CACHE[name] = result - return result - - -def data_to_blob(data): - as_json = json.dumps(attr.asdict(data)).encode('utf-8') - compressed = zlib.compress(as_json) - as_base64 = base64.b32encode(compressed) - return as_base64.decode('ascii') - - -def blob_to_data(blob): - from_base64 = base64.b32decode(blob.encode('ascii')) - decompressed = zlib.decompress(from_base64) - parsed = json.loads(decompressed) - return BenchmarkData(**parsed) - - -BENCHMARK_HEADER = """ -# This is an automatically generated file from Hypothesis's benchmarking -# script (scripts/benchmarks.py). -# -# Lines like this starting with a # are designed to be useful for human -# consumption when reviewing, specifically with a goal of producing -# useful diffs so that you can get a sense of the impact of a change. -# -# This benchmark is for %(strategy_name)s [%(strategy)r], with the validity -# condition "%(valid)s" and the interestingness condition "%(interesting)s". -# See the script for the exact definitions of these criteria. -# -# This benchmark was generated with seed %(seed)d -# -# Key statistics for this benchmark: -# -# * %(count)d examples -# * Mean size: %(mean).2f bytes, standard deviation: %(sd).2f bytes -# -# Additional interesting statistics: -# -# * Ranging from %(min)d [%(nmin)s] to %(max)d [%(nmax)s] bytes. -# * Median size: %(median)d -# * 99%% of examples had at least %(lo)d bytes -# * 99%% of examples had at most %(hi)d bytes -# -# All data after this point is an opaque binary blob. You are not expected -# to understand it. -""".strip() - - -def times(n): - assert n > 0 - if n > 1: - return '%d times' % (n,) - else: - return 'once' - - -def write_data(name, new_data): - benchmark = BENCHMARKS[name] - strategy_name = [ - k for k, v in STRATEGIES.items() if v == benchmark.strategy - ][0] - sizes = new_data.sizes - with open(benchmark_file(name), 'w') as o: - o.write(BENCHMARK_HEADER % { - 'strategy_name': strategy_name, - 'strategy': benchmark.strategy, - 'valid': benchmark.valid.__name__, - 'interesting': benchmark.interesting.__name__, - 'seed': new_data.seed, - 'count': len(sizes), - 'min': min(sizes), - 'nmin': times(sizes.count(min(sizes))), - 'nmax': times(sizes.count(max(sizes))), - 'max': max(sizes), - 'mean': np.mean(sizes), - 'sd': np.std(sizes), - 'median': int(np.percentile(sizes, 50, interpolation='lower')), - 'lo': int(np.percentile(sizes, 1, interpolation='lower')), - 'hi': int(np.percentile(sizes, 99, interpolation='higher')), - }) - o.write('\n') - o.write('\n') - blob = data_to_blob(new_data) - assert '\n' not in blob - o.write('Data %d: ' % (len(blob),)) - o.write(BLOBSTART) - o.write(blob) - o.write(BLOBEND) - o.write('\n') - - -NONE = 'none' -NEW = 'new' -ALL = 'all' -CHANGED = 'changed' -IMPROVED = 'improved' - - -@attr.s -class Report(object): - name = attr.ib() - p = attr.ib() - old_mean = attr.ib() - new_mean = attr.ib() - new_data = attr.ib() - new_seed = attr.ib() - - -def seed_by_int(i): - # Get an actually good seed from an integer, as Random() doesn't guarantee - # similar but distinct seeds giving different distributions. - as_bytes = i.to_bytes(i.bit_length() // 8 + 1, 'big') - digest = hashlib.sha1(as_bytes).digest() - seedint = int.from_bytes(digest, 'big') - random.seed(seedint) - - -@click.command() -@click.option( - '--nruns', default=200, type=int, help=""" -Specify the number of runs of each benchmark to perform. If this is larger than -the number of stored runs then this will result in the existing data treated as -if it were non-existing. If it is smaller, the existing data will be sampled. -""") -@click.argument('benchmarks', nargs=-1) -@click.option('--check/--no-check', default=False) -@click.option('--skip-existing/--no-skip-existing', default=False) -@click.option('--fdr', default=0.0001) -@click.option('--update', type=click.Choice([ - NONE, NEW, ALL, CHANGED, IMPROVED -]), default=NEW) -@click.option('--only-update-headers/--full-run', default=False) -def cli( - benchmarks, nruns, check, update, fdr, skip_existing, - only_update_headers, -): - """This is the benchmark runner script for Hypothesis. - - Rather than running benchmarks by *time* this runs benchmarks by - *amount of data*. This is the major determiner of performance in - Hypothesis (other than speed of the end user's tests) and has the - important property that we can benchmark it without reference to the - underlying system's performance. - - """ - - if check: - if update not in [NONE, NEW]: - raise click.UsageError('check and update cannot be used together') - if skip_existing: - raise click.UsageError( - 'check and skip-existing cannot be used together') - if only_update_headers: - raise click.UsageError( - 'check and rewrite-only cannot be used together') - - if only_update_headers: - for name in BENCHMARKS: - if have_existing_data(name): - write_data(name, existing_data(name)) - sys.exit(0) - - for name in benchmarks: - if name not in BENCHMARKS: - raise click.UsageError('Invalid benchmark name %s' % (name,)) - - try: - os.mkdir(DATA_DIR) - except FileExistsError: - pass - - last_seed = 0 - for name in BENCHMARKS: - if have_existing_data(name): - last_seed = max(existing_data(name).seed, last_seed) - - next_seed = last_seed + 1 - - reports = [] - if check: - for name in benchmarks or BENCHMARKS: - if not have_existing_data(name): - click.echo('No existing data for benchmark %s' % ( - name, - )) - sys.exit(1) - - for name in benchmarks or BENCHMARKS: - new_seed = next_seed - next_seed += 1 - seed_by_int(new_seed) - if have_existing_data(name): - if skip_existing: - continue - old_data = existing_data(name) - new_data = run_benchmark_for_sizes(BENCHMARKS[name], nruns) - - pp = benchmark_difference_p_value(old_data.sizes, new_data) - - click.echo( - '%r -> %r. p-value for difference %.5f' % ( - np.mean(old_data.sizes), np.mean(new_data), pp,)) - reports.append(Report( - name, pp, np.mean(old_data.sizes), np.mean(new_data), new_data, - new_seed=new_seed, - )) - if update == ALL: - write_data(name, BenchmarkData(sizes=new_data, seed=next_seed)) - elif update != NONE: - new_data = run_benchmark_for_sizes(BENCHMARKS[name], nruns) - write_data(name, BenchmarkData(sizes=new_data, seed=next_seed)) - - if not reports: - sys.exit(0) - - click.echo('Checking for different means') - - # We now perform a Benjamini Hochberg test. This gives us a list of - # possibly significant differences while controlling the false discovery - # rate. https://en.wikipedia.org/wiki/False_discovery_rate - reports.sort(key=lambda x: x.p) - - threshold = 0 - n = len(reports) - for k, report in enumerate(reports, 1): - if report.p <= k * fdr / n: - assert report.p <= fdr - threshold = k - different = reports[:threshold] - - if threshold > 0: - click.echo(( - 'Found %d benchmark%s with significant difference ' - 'at false discovery rate %r' - ) % ( - threshold, - 's' if threshold > 1 else '', - fdr, - )) - - if different: - for report in different: - click.echo('Different means for %s: %.2f -> %.2f. p=%.5f' % ( - report.name, report.old_mean, report.new_mean, report.p - )) - if check: - sys.exit(1) - for r in different: - if update == CHANGED: - write_data(r.name, BenchmarkData(r.new_data, r.new_seed)) - elif update == IMPROVED and r.new_mean < r.old_mean: - write_data(r.name, BenchmarkData(r.new_data, r.new_seed)) - else: - click.echo('No significant differences') - - -if __name__ == '__main__': - cli() diff -Nru python-hypothesis-3.44.1/scripts/build-documentation.sh python-hypothesis-3.71.11/scripts/build-documentation.sh --- python-hypothesis-3.44.1/scripts/build-documentation.sh 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/scripts/build-documentation.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -u -set -x - -SPHINX_BUILD=$1 -PYTHON=$2 - -HERE="$(dirname "$0")" - -cd "$HERE"/.. - -if [ -e RELEASE.rst ] ; then - trap "git checkout docs/changes.rst src/hypothesis/version.py" EXIT - $PYTHON scripts/update-changelog-for-docs.py -fi - -export PYTHONPATH=src - -$SPHINX_BUILD -W -b html -d docs/_build/doctrees docs docs/_build/html diff -Nru python-hypothesis-3.44.1/scripts/check-ancient-pip.sh python-hypothesis-3.71.11/scripts/check-ancient-pip.sh --- python-hypothesis-3.44.1/scripts/check-ancient-pip.sh 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/scripts/check-ancient-pip.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,25 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -x - -PYTHON=$1 - -BROKEN_VIRTUALENV=$($PYTHON -c'import tempfile; print(tempfile.mkdtemp())') - -trap 'rm -rf $BROKEN_VIRTUALENV' EXIT - -rm -rf tmp-dist-dir - -$PYTHON setup.py sdist --dist-dir=tmp-dist-dir - -$PYTHON -m pip install virtualenv -$PYTHON -m virtualenv "$BROKEN_VIRTUALENV" -"$BROKEN_VIRTUALENV"/bin/pip install -rrequirements/test.txt - -# These are versions from debian stable as of 2017-04-21 -# See https://packages.debian.org/stable/python/ -"$BROKEN_VIRTUALENV"/bin/python -m pip install --upgrade pip==1.5.6 -"$BROKEN_VIRTUALENV"/bin/pip install --upgrade setuptools==5.5.1 -"$BROKEN_VIRTUALENV"/bin/pip install tmp-dist-dir/* -"$BROKEN_VIRTUALENV"/bin/python -m pytest tests/cover/test_testdecorators.py diff -Nru python-hypothesis-3.44.1/scripts/check_encoding_header.py python-hypothesis-3.71.11/scripts/check_encoding_header.py --- python-hypothesis-3.44.1/scripts/check_encoding_header.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/scripts/check_encoding_header.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,36 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -VALID_STARTS = ( - '# coding=utf-8', - '#!/usr/bin/env python', -) - -if __name__ == '__main__': - import sys - n = max(map(len, VALID_STARTS)) - bad = False - for f in sys.argv[1:]: - with open(f, 'r', encoding='utf-8') as i: - start = i.read(n) - if not any(start.startswith(s) for s in VALID_STARTS): - print( - '%s has incorrect start %r' % (f, start), file=sys.stderr) - bad = True - sys.exit(int(bad)) diff -Nru python-hypothesis-3.44.1/scripts/check-release-file.py python-hypothesis-3.71.11/scripts/check-release-file.py --- python-hypothesis-3.44.1/scripts/check-release-file.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/scripts/check-release-file.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,38 +0,0 @@ -#!/usr/bin/env python - -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import os -import sys - -import hypothesistooling as tools - -sys.path.append(os.path.dirname(__file__)) # noqa - - -if __name__ == '__main__': - if tools.has_source_changes(): - if not tools.has_release(): - print( - 'There are source changes but no RELEASE.rst. Please create ' - 'one to describe your changes.' - ) - sys.exit(1) - tools.parse_release_file() diff -Nru python-hypothesis-3.44.1/scripts/deploy.py python-hypothesis-3.71.11/scripts/deploy.py --- python-hypothesis-3.44.1/scripts/deploy.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/scripts/deploy.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,167 +0,0 @@ -#!/usr/bin/env python - -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import os -import sys -import random -import shutil -import subprocess -from time import time, sleep - -import hypothesistooling as tools - -sys.path.append(os.path.dirname(__file__)) # noqa - - -DIST = os.path.join(tools.ROOT, 'dist') - - -PENDING_STATUS = ('started', 'created') - - -if __name__ == '__main__': - last_release = tools.latest_version() - - print('Current version: %s. Latest released version: %s' % ( - tools.__version__, last_release - )) - - HEAD = tools.hash_for_name('HEAD') - MASTER = tools.hash_for_name('origin/master') - print('Current head:', HEAD) - print('Current master:', MASTER) - - on_master = tools.is_ancestor(HEAD, MASTER) - has_release = tools.has_release() - - if has_release: - print('Updating changelog and version') - tools.update_for_pending_release() - - print('Building an sdist...') - - if os.path.exists(DIST): - shutil.rmtree(DIST) - - subprocess.check_output([ - sys.executable, 'setup.py', 'sdist', '--dist-dir', DIST, - ]) - - if not on_master: - print('Not deploying due to not being on master') - sys.exit(0) - - if not has_release: - print('Not deploying due to no release') - sys.exit(0) - - start_time = time() - - prev_pending = None - - # We time out after an hour, which is a stupidly long time and it should - # never actually take that long: A full Travis run only takes about 20-30 - # minutes! This is really just here as a guard in case something goes - # wrong and we're not paying attention so as to not be too mean to Travis.. - while time() <= start_time + 60 * 60: - jobs = tools.build_jobs() - - failed_jobs = [ - (k, v) - for k, vs in jobs.items() - if k not in PENDING_STATUS + ('passed',) - for v in vs - ] - - if failed_jobs: - print('Failing this due to failure of jobs %s' % ( - ', '.join('%s(%s)' % (s, j) for j, s in failed_jobs), - )) - sys.exit(1) - else: - pending = [j for s in PENDING_STATUS for j in jobs.get(s, ())] - try: - # This allows us to test the deploy job for a build locally. - pending.remove('deploy') - except ValueError: - pass - if pending: - still_pending = set(pending) - if prev_pending is None: - print('Waiting for the following jobs to complete:') - for p in sorted(still_pending): - print(' * %s' % (p,)) - print() - else: - completed = prev_pending - still_pending - if completed: - print('%s completed since last check.' % ( - ', '.join(sorted(completed)),)) - prev_pending = still_pending - naptime = 10.0 * (2 + random.random()) - print('Waiting %.2fs for %d more job%s to complete' % ( - naptime, len(pending), 's' if len(pending) > 1 else '',)) - sleep(naptime) - else: - break - else: - print("We've been waiting for an hour. That seems bad. Failing now.") - sys.exit(1) - - print('Looks good to release!') - - if os.environ.get('TRAVIS_SECURE_ENV_VARS', None) != 'true': - print("But we don't have the keys to do it") - sys.exit(0) - - print('Decrypting secrets') - - # We'd normally avoid the use of shell=True, but this is more or less - # intended as an opaque string that was given to us by Travis that happens - # to be a shell command that we run, and there are a number of good reasons - # this particular instance is harmless and would be high effort to - # convert (principally: Lack of programmatic generation of the string and - # extensive use of environment variables in it), so we're making an - # exception here. - subprocess.check_call( - 'openssl aes-256-cbc -K $encrypted_39cb4cc39a80_key ' - '-iv $encrypted_39cb4cc39a80_iv -in secrets.tar.enc ' - '-out secrets.tar -d', - shell=True - ) - - subprocess.check_call([ - 'tar', '-xvf', 'secrets.tar', - ]) - - print('Release seems good. Pushing to github now.') - - tools.create_tag_and_push() - - print('Now uploading to pypi.') - - subprocess.check_call([ - sys.executable, '-m', 'twine', 'upload', - '--config-file', './.pypirc', - os.path.join(DIST, '*'), - ]) - - sys.exit(0) diff -Nru python-hypothesis-3.44.1/scripts/enforce_header.py python-hypothesis-3.71.11/scripts/enforce_header.py --- python-hypothesis-3.44.1/scripts/enforce_header.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/scripts/enforce_header.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,67 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import os -import sys -from datetime import datetime - -HEADER_FILE = 'scripts/header.py' - -CURRENT_YEAR = datetime.utcnow().year - -HEADER_SOURCE = open(HEADER_FILE).read().strip().format(year=CURRENT_YEAR) - - -def main(): - rootdir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) - os.chdir(rootdir) - files = sys.argv[1:] - - for f in files: - print(f) - lines = [] - with open(f, encoding='utf-8') as o: - shebang = None - first = True - header_done = False - for l in o.readlines(): - if first: - first = False - if l[:2] == '#!': - shebang = l - continue - if 'END HEADER' in l and not header_done: - lines = [] - header_done = True - else: - lines.append(l) - source = ''.join(lines).strip() - with open(f, 'w', encoding='utf-8') as o: - if shebang is not None: - o.write(shebang) - o.write('\n') - o.write(HEADER_SOURCE) - if source: - o.write('\n\n') - o.write(source) - o.write('\n') - - -if __name__ == '__main__': - main() diff -Nru python-hypothesis-3.44.1/scripts/files-to-format.py python-hypothesis-3.71.11/scripts/files-to-format.py --- python-hypothesis-3.44.1/scripts/files-to-format.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/scripts/files-to-format.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,52 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import os -import sys - -import hypothesistooling as tools - -sys.path.append(os.path.dirname(__file__)) # noqa - - -def should_format_file(path): - if os.path.basename(path) in ('header.py', 'test_lambda_formatting.py'): - return False - if 'vendor' in path.split(os.path.sep): - return False - return path.endswith('.py') - - -if __name__ == '__main__': - changed = tools.modified_files() - - format_all = os.environ.get('FORMAT_ALL', '').lower() == 'true' - if 'scripts/header.py' in changed: - # We've changed the header, so everything needs its header updated. - format_all = True - if 'requirements/tools.txt' in changed: - # We've changed the tools, which includes a lot of our formatting - # logic, so we need to rerun formatters. - format_all = True - - files = tools.all_files() if format_all else changed - - for f in sorted(files): - if should_format_file(f): - print(f) diff -Nru python-hypothesis-3.44.1/scripts/fix_doctests.py python-hypothesis-3.71.11/scripts/fix_doctests.py --- python-hypothesis-3.44.1/scripts/fix_doctests.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/scripts/fix_doctests.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,126 +0,0 @@ -#!/usr/bin/env python3 - -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import os -import re -import sys -from subprocess import PIPE, run -from collections import defaultdict - -import hypothesistooling as tools - - -class FailingExample(object): - - def __init__(self, chunk): - """Turn a chunk of text into an object representing the test.""" - location, *lines = [l + '\n' for l in chunk.split('\n') if l.strip()] - self.location = location.strip() - pattern = 'File "(.+?)", line (\d+?), in .+' - file, line = re.match(pattern, self.location).groups() - self.file = os.path.join('docs', file) - self.line = int(line) + 1 - got = lines.index('Got:\n') - self.expected_lines = lines[lines.index('Expected:\n') + 1:got] - self.got_lines = lines[got + 1:] - self.checked_ok = None - self.adjust() - - @property - def indices(self): - return slice(self.line, self.line + len(self.expected_lines)) - - def adjust(self): - with open(self.file) as f: - lines = f.readlines() - # The raw line number is the first line of *input*, so adjust to - # first line of output by skipping lines which start with a prompt - while self.line < len(lines): - if lines[self.line].strip()[:4] not in ('>>> ', '... '): - break - self.line += 1 - # Sadly the filename and line number for doctests in docstrings is - # wrong - see https://github.com/sphinx-doc/sphinx/issues/4223 - # Luckily, we can just cheat because they're all in one file for now! - # (good luck if this changes without an upstream fix...) - if lines[self.indices] != self.expected_lines: - self.file = 'src/hypothesis/strategies.py' - with open(self.file) as f: - lines = f.readlines() - self.line = 0 - while self.expected_lines[0] in lines: - self.line = lines[self.line:].index(self.expected_lines[0]) - if lines[self.indices] == self.expected_lines: - break - # Finally, set the flag for location quality - self.checked_ok = lines[self.indices] == self.expected_lines - - def __repr__(self): - return '{}\nExpected: {!r:.60}\nGot: {!r:.60}'.format( - self.location, self.expected, self.got) - - -def get_doctest_output(): - # Return a dict of filename: list of examples, sorted from last to first - # so that replacing them in sequence works - command = run(['sphinx-build', '-b', 'doctest', 'docs', 'docs/_build'], - stdout=PIPE, stderr=PIPE, encoding='utf-8') - output = [FailingExample(c) for c in command.stdout.split('*' * 70) - if c.strip().startswith('File "')] - if not all(ex.checked_ok for ex in output): - broken = '\n'.join(ex.location for ex in output if not ex.checked_ok) - print('Could not find some tests:\n' + broken) - sys.exit(1) - tests = defaultdict(set) - for ex in output: - tests[ex.file].add(ex) - return {fname: sorted(examples, key=lambda x: x.line, reverse=True) - for fname, examples in tests.items()} - - -def main(): - os.chdir(tools.ROOT) - failing = get_doctest_output() - if not failing: - print('All doctests are OK') - sys.exit(0) - if tools.has_uncommitted_changes('.'): - print('Cannot fix doctests in place with uncommited changes') - sys.exit(1) - - for fname, examples in failing.items(): - with open(fname) as f: - lines = f.readlines() - for ex in examples: - lines[ex.indices] = ex.got_lines - with open(fname, 'w') as f: - f.writelines(lines) - - still_failing = get_doctest_output() - if still_failing: - print('Fixes failed: script broken or flaky tests.\n', still_failing) - sys.exit(1) - print('All failing doctests have been fixed.') - sys.exit(0) - - -if __name__ == '__main__': - main() diff -Nru python-hypothesis-3.44.1/scripts/header.py python-hypothesis-3.71.11/scripts/header.py --- python-hypothesis-3.44.1/scripts/header.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/scripts/header.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-{year} David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - - diff -Nru python-hypothesis-3.44.1/scripts/hypothesistooling.py python-hypothesis-3.71.11/scripts/hypothesistooling.py --- python-hypothesis-3.44.1/scripts/hypothesistooling.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/scripts/hypothesistooling.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,402 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import os -import re -import sys -import subprocess -from datetime import datetime, timedelta - - -def current_branch(): - return subprocess.check_output([ - 'git', 'rev-parse', '--abbrev-ref', 'HEAD' - ]).decode('ascii').strip() - - -def tags(): - result = [t.decode('ascii') for t in subprocess.check_output([ - 'git', 'tag' - ]).split(b'\n')] - assert len(set(result)) == len(result) - return set(result) - - -ROOT = subprocess.check_output([ - 'git', 'rev-parse', '--show-toplevel']).decode('ascii').strip() -SRC = os.path.join(ROOT, 'src') - -assert os.path.exists(SRC) - - -__version__ = None -__version_info__ = None - -VERSION_FILE = os.path.join(ROOT, 'src/hypothesis/version.py') - -with open(VERSION_FILE) as o: - exec(o.read()) - -assert __version__ is not None -assert __version_info__ is not None - - -def latest_version(): - versions = [] - - for t in tags(): - # All versions get tags but not all tags are versions (and there are - # a large number of historic tags with a different format for versions) - # so we parse each tag as a triple of ints (MAJOR, MINOR, PATCH) - # and skip any tag that doesn't match that. - assert t == t.strip() - parts = t.split('.') - if len(parts) != 3: - continue - try: - v = tuple(map(int, parts)) - except ValueError: - continue - - versions.append((v, t)) - - _, latest = max(versions) - - assert latest in tags() - return latest - - -def hash_for_name(name): - return subprocess.check_output([ - 'git', 'rev-parse', name - ]).decode('ascii').strip() - - -def is_ancestor(a, b): - check = subprocess.call([ - 'git', 'merge-base', '--is-ancestor', a, b - ]) - assert 0 <= check <= 1 - return check == 0 - - -CHANGELOG_FILE = os.path.join(ROOT, 'docs', 'changes.rst') - - -def changelog(): - with open(CHANGELOG_FILE) as i: - return i.read() - - -def merge_base(a, b): - return subprocess.check_output([ - 'git', 'merge-base', a, b, - ]).strip() - - -def has_source_changes(version=None): - if version is None: - version = latest_version() - - # Check where we branched off from the version. We're only interested - # in whether *we* introduced any source changes, so we check diff from - # there rather than the diff to the other side. - point_of_divergence = merge_base('HEAD', version) - - return subprocess.call([ - 'git', 'diff', '--exit-code', point_of_divergence, 'HEAD', '--', SRC, - ]) != 0 - - -def has_uncommitted_changes(filename): - return subprocess.call([ - 'git', 'diff', '--exit-code', filename - ]) != 0 - - -def git(*args): - subprocess.check_call(('git',) + args) - - -def create_tag_and_push(): - assert __version__ not in tags() - git('config', 'user.name', 'Travis CI on behalf of David R. MacIver') - git('config', 'user.email', 'david@drmaciver.com') - git('config', 'core.sshCommand', 'ssh -i deploy_key') - git( - 'remote', 'add', 'ssh-origin', - 'git@github.com:HypothesisWorks/hypothesis-python.git' - ) - git('tag', __version__) - - subprocess.check_call([ - 'ssh-agent', 'sh', '-c', - 'chmod 0600 deploy_key && ' + - 'ssh-add deploy_key && ' + - 'git push ssh-origin HEAD:master &&' - 'git push ssh-origin --tags' - ]) - - -def build_jobs(): - """Query the Travis API to find out what the state of the other build jobs - is. - - Note: This usage of Travis has been somewhat reverse engineered due - to a certain dearth of documentation as to what values what takes - when. - - """ - import requests - - build_id = os.environ['TRAVIS_BUILD_ID'] - - url = 'https://api.travis-ci.org/builds/%s' % (build_id,) - data = requests.get(url, headers={ - 'Accept': 'application/vnd.travis-ci.2+json' - }).json() - - matrix = data['jobs'] - - jobs = {} - - for m in matrix: - name = m['config']['env'].replace('TASK=', '') - status = m['state'] - jobs.setdefault(status, []).append(name) - return jobs - - -def modified_files(): - files = set() - for command in [ - ['git', 'diff', '--name-only', '--diff-filter=d', - latest_version(), 'HEAD'], - ['git', 'diff', '--name-only'] - ]: - diff_output = subprocess.check_output(command).decode('ascii') - for l in diff_output.split('\n'): - filepath = l.strip() - if filepath: - assert os.path.exists(filepath), filepath - files.add(filepath) - return files - - -def all_files(): - return subprocess.check_output(['git', 'ls-files']).decode( - 'ascii').splitlines() - - -RELEASE_FILE = os.path.join(ROOT, 'RELEASE.rst') - - -def has_release(): - return os.path.exists(RELEASE_FILE) - - -CHANGELOG_BORDER = re.compile(r"^-+$") -CHANGELOG_HEADER = re.compile(r"^\d+\.\d+\.\d+ - \d\d\d\d-\d\d-\d\d$") -RELEASE_TYPE = re.compile(r"^RELEASE_TYPE: +(major|minor|patch)") - - -MAJOR = 'major' -MINOR = 'minor' -PATCH = 'patch' - -VALID_RELEASE_TYPES = (MAJOR, MINOR, PATCH) - - -def parse_release_file(): - with open(RELEASE_FILE) as i: - release_contents = i.read() - - release_lines = release_contents.split('\n') - - m = RELEASE_TYPE.match(release_lines[0]) - if m is not None: - release_type = m.group(1) - if release_type not in VALID_RELEASE_TYPES: - print('Unrecognised release type %r' % (release_type,)) - sys.exit(1) - del release_lines[0] - release_contents = '\n'.join(release_lines).strip() - else: - print( - 'RELEASE.rst does not start by specifying release type. The first ' - 'line of the file should be RELEASE_TYPE: followed by one of ' - 'major, minor, or patch, to specify the type of release that ' - 'this is (i.e. which version number to increment). Instead the ' - 'first line was %r' % (release_lines[0],) - ) - sys.exit(1) - - return release_type, release_contents - - -def update_changelog_and_version(): - global __version_info__ - global __version__ - - with open(CHANGELOG_FILE) as i: - contents = i.read() - assert '\r' not in contents - lines = contents.split('\n') - assert contents == '\n'.join(lines) - for i, l in enumerate(lines): - if CHANGELOG_BORDER.match(l): - assert CHANGELOG_HEADER.match(lines[i + 1]), repr(lines[i + 1]) - assert CHANGELOG_BORDER.match(lines[i + 2]), repr(lines[i + 2]) - beginning = '\n'.join(lines[:i]) - rest = '\n'.join(lines[i:]) - assert '\n'.join((beginning, rest)) == contents - break - - release_type, release_contents = parse_release_file() - - new_version = list(__version_info__) - bump = VALID_RELEASE_TYPES.index(release_type) - new_version[bump] += 1 - for i in range(bump + 1, len(new_version)): - new_version[i] = 0 - new_version = tuple(new_version) - new_version_string = '.'.join(map(str, new_version)) - - __version_info__ = new_version - __version__ = new_version_string - - with open(VERSION_FILE) as i: - version_lines = i.read().split('\n') - - for i, l in enumerate(version_lines): - if 'version_info' in l: - version_lines[i] = '__version_info__ = %r' % (new_version,) - break - - with open(VERSION_FILE, 'w') as o: - o.write('\n'.join(version_lines)) - - now = datetime.utcnow() - - date = max([ - d.strftime('%Y-%m-%d') for d in (now, now + timedelta(hours=1)) - ]) - - heading_for_new_version = ' - '.join((new_version_string, date)) - border_for_new_version = '-' * len(heading_for_new_version) - - new_changelog_parts = [ - beginning.strip(), - '', - border_for_new_version, - heading_for_new_version, - border_for_new_version, - '', - release_contents, - '', - rest - ] - - with open(CHANGELOG_FILE, 'w') as o: - o.write('\n'.join(new_changelog_parts)) - - -def update_for_pending_release(): - update_changelog_and_version() - - git('rm', RELEASE_FILE) - git('add', CHANGELOG_FILE, VERSION_FILE) - - git( - 'commit', '-m', - 'Bump version to %s and update changelog\n\n[skip ci]' % (__version__,) - ) - - -def could_affect_tests(path): - """Does this file have any effect on test results?""" - # RST files are the input to some tests -- in particular, the - # documentation build and doctests. Both of those jobs are always run, - # so we can ignore their effect here. - # - # IPython notebooks aren't currently used in any tests. - if path.endswith(('.rst', '.ipynb')): - return False - - # These files exist but have no effect on tests. - if path in ('CITATION', 'LICENSE.txt', ): - return False - - # We default to marking a file "interesting" unless we know otherwise -- - # it's better to run tests that could have been skipped than skip tests - # when they needed to be run. - return True - - -def changed_files_from_master(): - """Returns a list of files which have changed between a branch and - master.""" - files = set() - command = ['git', 'diff', '--name-only', 'HEAD', 'master'] - diff_output = subprocess.check_output(command).decode('ascii') - for line in diff_output.splitlines(): - filepath = line.strip() - if filepath: - files.add(filepath) - return files - - -def should_run_ci_task(task, is_pull_request): - """Given a task name, should we run this task?""" - if not is_pull_request: - print('We only skip tests if the job is a pull request.') - return True - - # These tests are usually fast; we always run them rather than trying - # to keep up-to-date rules of exactly which changed files mean they - # should run. - if task in [ - 'check-pyup-yml', - 'check-release-file', - 'check-shellcheck', - 'documentation', - 'lint', - ]: - print('We always run the %s task.' % task) - return True - - # The remaining tasks are all some sort of test of Hypothesis - # functionality. Since it's better to run tests when we don't need to - # than skip tests when it was important, we remove any files which we - # know are safe to ignore, and run tests if there's anything left. - changed_files = changed_files_from_master() - - interesting_changed_files = [ - f for f in changed_files if could_affect_tests(f) - ] - - if interesting_changed_files: - print( - 'Changes to the following files mean we need to run tests: %s' % - ', '.join(interesting_changed_files) - ) - return True - else: - print('There are no changes which would need a test run.') - return False diff -Nru python-hypothesis-3.44.1/scripts/install.sh python-hypothesis-3.71.11/scripts/install.sh --- python-hypothesis-3.44.1/scripts/install.sh 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/scripts/install.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,107 +0,0 @@ -#!/usr/bin/env bash - -# Special license: Take literally anything you want out of this file. I don't -# care. Consider it WTFPL licensed if you like. -# Basically there's a lot of suffering encoded here that I don't want you to -# have to go through and you should feel free to use this to avoid some of -# that suffering in advance. - -set -e -set -x - -# OS X seems to have some weird Localse problems on Travis. This attempts to set -# the Locale to known good ones during install - -env | grep UTF - -# This is to guard against multiple builds in parallel. The various installers will tend -# to stomp all over each other if you do this and they haven't previously successfully -# succeeded. We use a lock file to block progress so only one install runs at a time. -# This script should be pretty fast once files are cached, so the lost of concurrency -# is not a major problem. -# This should be using the lockfile command, but that's not available on the -# containerized travis and we can't install it without sudo. -# Is is unclear if this is actually useful. I was seeing behaviour that suggested -# concurrent runs of the installer, but I can't seem to find any evidence of this lock -# ever not being acquired. - -BASE=${BUILD_RUNTIMES-$PWD/.runtimes} - -mkdir -p "$BASE" - -LOCKFILE="$BASE/.install-lockfile" -while true; do - if mkdir "$LOCKFILE" 2>/dev/null; then - echo "Successfully acquired installer." - break - else - echo "Failed to acquire lock. Is another installer running? Waiting a bit." - fi - - sleep $(( ( RANDOM % 10 ) + 1 )).$(( RANDOM % 100 ))s - - if (( $(date '+%s') > 300 + $(stat --format=%X "$LOCKFILE") )); then - echo "We've waited long enough" - rm -rf "$LOCKFILE" - fi -done -trap 'rm -rf $LOCKFILE' EXIT - - -PYENV=$BASE/pyenv - - -if [ ! -d "$PYENV/.git" ]; then - rm -rf "$PYENV" - git clone https://github.com/yyuu/pyenv.git "$BASE/pyenv" -else - back=$PWD - cd "$PYENV" - git fetch || echo "Update failed to complete. Ignoring" - git reset --hard origin/master - cd "$back" -fi - -SNAKEPIT=$BASE/snakepit - -install () { - - VERSION="$1" - ALIAS="$2" - mkdir -p "$BASE/versions" - SOURCE=$BASE/versions/$ALIAS - - if [ ! -e "$SOURCE" ]; then - mkdir -p "$SNAKEPIT" - mkdir -p "$BASE/versions" - "$BASE/pyenv/plugins/python-build/bin/python-build" "$VERSION" "$SOURCE" - fi - rm -f "$SNAKEPIT/$ALIAS" - mkdir -p "$SNAKEPIT" - "$SOURCE/bin/python" -m pip.__main__ install --upgrade pip wheel virtualenv - ln -s "$SOURCE/bin/python" "$SNAKEPIT/$ALIAS" -} - - -for var in "$@"; do - case "${var}" in - 2.7) - install 2.7.11 python2.7 - ;; - 2.7.3) - install 2.7.3 python2.7.3 - ;; - 3.4) - install 3.4.3 python3.4 - ;; - 3.5) - install 3.5.1 python3.5 - ;; - 3.6) - install 3.6.1 python3.6 - ;; - pypy) - install pypy2.7-5.8.0 pypy - ;; - esac -done diff -Nru python-hypothesis-3.44.1/scripts/pyenv-installer python-hypothesis-3.71.11/scripts/pyenv-installer --- python-hypothesis-3.44.1/scripts/pyenv-installer 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/scripts/pyenv-installer 1970-01-01 00:00:00.000000000 +0000 @@ -1,88 +0,0 @@ -#!/usr/bin/env bash - -set -e -[ -n "$PYENV_DEBUG" ] && set -x - -if [ -z "$PYENV_ROOT" ]; then - PYENV_ROOT="${HOME}/.pyenv" -fi - -shell="$1" -if [ -z "$shell" ]; then - shell="$(ps c -p "$PPID" -o 'ucomm=' 2>/dev/null || true)" - shell="${shell##-}" - shell="${shell%% *}" - shell="$(basename "${shell:-$SHELL}")" -fi - -colorize() { - if [ -t 1 ]; then printf "\e[%sm%s\e[m" "$1" "$2" - else echo -n "$2" - fi -} - -checkout() { - [ -d "$2" ] || git clone "$1" "$2" -} - -if ! command -v git 1>/dev/null 2>&1; then - echo "pyenv: Git is not installed, can't continue." >&2 - exit 1 -fi - -if [ -n "${USE_HTTPS}" ]; then - GITHUB="https://github.com" -else - GITHUB="git://github.com" -fi - -checkout "${GITHUB}/yyuu/pyenv.git" "${PYENV_ROOT}" -checkout "${GITHUB}/yyuu/pyenv-doctor.git" "${PYENV_ROOT}/plugins/pyenv-doctor" -checkout "${GITHUB}/yyuu/pyenv-installer.git" "${PYENV_ROOT}/plugins/pyenv-installer" -checkout "${GITHUB}/yyuu/pyenv-pip-rehash.git" "${PYENV_ROOT}/plugins/pyenv-pip-rehash" -checkout "${GITHUB}/yyuu/pyenv-update.git" "${PYENV_ROOT}/plugins/pyenv-update" -checkout "${GITHUB}/yyuu/pyenv-virtualenv.git" "${PYENV_ROOT}/plugins/pyenv-virtualenv" -checkout "${GITHUB}/yyuu/pyenv-which-ext.git" "${PYENV_ROOT}/plugins/pyenv-which-ext" - -if ! command -v pyenv 1>/dev/null; then - { echo - colorize 1 "WARNING" - echo ": seems you still have not added 'pyenv' to the load path." - echo - } >&2 - - case "$shell" in - bash ) - profile="~/.bash_profile" - ;; - zsh ) - profile="~/.zshrc" - ;; - ksh ) - profile="~/.profile" - ;; - fish ) - profile="~/.config/fish/config.fish" - ;; - * ) - profile="your profile" - ;; - esac - - { echo "# Load pyenv automatically by adding" - echo "# the following to ${profile}:" - echo - case "$shell" in - fish ) - echo "set -x PATH \"\$HOME/.pyenv/bin\" \$PATH" - echo 'status --is-interactive; and . (pyenv init -|psub)' - echo 'status --is-interactive; and . (pyenv virtualenv-init -|psub)' - ;; - * ) - echo "export PATH=\"\$HOME/.pyenv/bin:\$PATH\"" - echo "eval \"\$(pyenv init -)\"" - echo "eval \"\$(pyenv virtualenv-init -)\"" - ;; - esac - } >&2 -fi diff -Nru python-hypothesis-3.44.1/scripts/retry.sh python-hypothesis-3.71.11/scripts/retry.sh --- python-hypothesis-3.44.1/scripts/retry.sh 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/scripts/retry.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -#!/usr/bin/env bash - -for _ in $(seq 5); do - if "$@" ; then - exit 0 - fi - echo "Command failed. Retrying..." - sleep $(( ( RANDOM % 10 ) + 1 )).$(( RANDOM % 100 ))s -done - -echo "Command failed five times. Giving up now" - -exit 1 diff -Nru python-hypothesis-3.44.1/scripts/run_circle.py python-hypothesis-3.71.11/scripts/run_circle.py --- python-hypothesis-3.44.1/scripts/run_circle.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/scripts/run_circle.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ -#!/usr/bin/env python - -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import os -import sys -import subprocess - -from hypothesistooling import should_run_ci_task - -if __name__ == '__main__': - - if ( - os.environ['CIRCLE_BRANCH'] != 'master' and - os.environ['CI_PULL_REQUESTS'] == '' - ): - print('We only run CI builds on the master branch or in pull requests') - sys.exit(0) - - is_pull_request = (os.environ['CI_PULL_REQUESTS'] != '') - - for task in ['check-pypy', 'check-py36', 'check-py27']: - if should_run_ci_task(task=task, is_pull_request=is_pull_request): - subprocess.check_call(['make', task]) diff -Nru python-hypothesis-3.44.1/scripts/run_travis_make_task.py python-hypothesis-3.71.11/scripts/run_travis_make_task.py --- python-hypothesis-3.44.1/scripts/run_travis_make_task.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/scripts/run_travis_make_task.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ -#!/usr/bin/env python - -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import os -import subprocess - -from hypothesistooling import should_run_ci_task - -if __name__ == '__main__': - is_pull_request = (os.environ.get('TRAVIS_EVENT_TYPE') == 'pull_request') - task = os.environ['TASK'] - - if should_run_ci_task(task=task, is_pull_request=is_pull_request): - subprocess.check_call(['make', task]) diff -Nru python-hypothesis-3.44.1/scripts/tool-hash.py python-hypothesis-3.71.11/scripts/tool-hash.py --- python-hypothesis-3.44.1/scripts/tool-hash.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/scripts/tool-hash.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ -#!/usr/bin/env python - -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import os -import sys -import hashlib - -SCRIPTS_DIR = os.path.dirname(os.path.abspath(__file__)) -ROOT_DIR = os.path.dirname(SCRIPTS_DIR) - -if __name__ == '__main__': - name = sys.argv[1] - - requirements = os.path.join( - ROOT_DIR, 'requirements', '%s.txt' % (name,) - ) - - assert os.path.exists(requirements) - - with open(requirements, 'rb') as f: - tools = f.read() - print(hashlib.sha1(tools).hexdigest()[:10]) diff -Nru python-hypothesis-3.44.1/scripts/unicodechecker.py python-hypothesis-3.71.11/scripts/unicodechecker.py --- python-hypothesis-3.44.1/scripts/unicodechecker.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/scripts/unicodechecker.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,60 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import os -import sys -import inspect -import warnings -from tempfile import mkdtemp - -import unicodenazi -from hypothesis import settings, unlimited -from hypothesis.errors import HypothesisDeprecationWarning -from hypothesis.configuration import set_hypothesis_home_dir - -warnings.filterwarnings('error', category=UnicodeWarning) -warnings.filterwarnings('error', category=HypothesisDeprecationWarning) -unicodenazi.enable() - - -set_hypothesis_home_dir(mkdtemp()) - -assert isinstance(settings, type) - -settings.register_profile( - 'default', settings(timeout=unlimited) -) -settings.load_profile('default') - - -TESTS = [ - 'test_testdecorators', -] - -sys.path.append(os.path.join( - os.path.dirname(__file__), '..', 'tests', 'cover', -)) - -if __name__ == '__main__': - for t in TESTS: - module = __import__(t) - for k, v in sorted(module.__dict__.items(), key=lambda x: x[0]): - if k.startswith('test_') and inspect.isfunction(v): - print(k) - v() diff -Nru python-hypothesis-3.44.1/scripts/update-changelog-for-docs.py python-hypothesis-3.71.11/scripts/update-changelog-for-docs.py --- python-hypothesis-3.44.1/scripts/update-changelog-for-docs.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/scripts/update-changelog-for-docs.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,39 +0,0 @@ -#!/usr/bin/env python - -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import os -import sys - -import hypothesistooling as tools - -sys.path.append(os.path.dirname(__file__)) # noqa - - -if __name__ == '__main__': - if not tools.has_release(): - sys.exit(0) - if tools.has_uncommitted_changes(tools.CHANGELOG_FILE): - print( - 'Cannot build documentation with uncommitted changes to ' - 'changelog and a pending release. Please commit your changes or ' - 'delete your release file.') - sys.exit(1) - tools.update_changelog_and_version() diff -Nru python-hypothesis-3.44.1/scripts/validate_branch_check.py python-hypothesis-3.71.11/scripts/validate_branch_check.py --- python-hypothesis-3.44.1/scripts/validate_branch_check.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/scripts/validate_branch_check.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,64 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import sys -import json -from collections import defaultdict - -if __name__ == '__main__': - with open('branch-check') as i: - data = [ - json.loads(l) for l in i - ] - - checks = defaultdict(set) - - for d in data: - checks[d['name']].add(d['value']) - - always_true = [] - always_false = [] - - for c, vs in sorted(checks.items()): - if len(vs) < 2: - v = list(vs)[0] - assert v in (False, True) - if v: - always_true.append(c) - else: - always_false.append(c) - - failure = always_true or always_false - - if failure: - print('Some branches were not properly covered.') - print() - - if always_true: - print('The following were always True:') - print() - for c in always_true: - print(' * %s' % (c,)) - if always_false: - print('The following were always False:') - print() - for c in always_false: - print(' * %s' % (c,)) - if failure: - sys.exit(1) diff -Nru python-hypothesis-3.44.1/scripts/validate_pyup.py python-hypothesis-3.71.11/scripts/validate_pyup.py --- python-hypothesis-3.44.1/scripts/validate_pyup.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/scripts/validate_pyup.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ -#!/usr/bin/env python - -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import os -import sys - -import yaml -from pyup.config import Config - -from hypothesistooling import ROOT - -PYUP_FILE = os.path.join(ROOT, '.pyup.yml') - -if __name__ == '__main__': - with open(PYUP_FILE, 'r') as i: - data = yaml.safe_load(i.read()) - config = Config() - config.update_config(data) - - if not config.is_valid_schedule(): - print('Schedule %r is invalid' % (config.schedule,)) - sys.exit(1) Binary files /tmp/tmpb30OA4/sdMxCRQenE/python-hypothesis-3.44.1/secrets.tar.enc and /tmp/tmpb30OA4/16q5ZKICe3/python-hypothesis-3.71.11/secrets.tar.enc differ diff -Nru python-hypothesis-3.44.1/setup.py python-hypothesis-3.71.11/setup.py --- python-hypothesis-3.44.1/setup.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/setup.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,99 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import os -import sys - -from setuptools import setup, find_packages - - -def local_file(name): - return os.path.relpath(os.path.join(os.path.dirname(__file__), name)) - - -SOURCE = local_file('src') -README = local_file('README.rst') - - -# Assignment to placate pyflakes. The actual version is from the exec that -# follows. -__version__ = None - -with open(local_file('src/hypothesis/version.py')) as o: - exec(o.read()) - -assert __version__ is not None - - -extras = { - 'datetime': ['pytz'], - 'pytz': ['pytz'], - 'fakefactory': ['Faker>=0.7'], - 'django': ['pytz', 'django>=1.8,<2'], - 'numpy': ['numpy>=1.9.0'], - 'pytest': ['pytest>=2.8.0'], -} - -extras['faker'] = extras['fakefactory'] - -extras['all'] = sorted(sum(extras.values(), [])) - -extras[":python_version == '2.7'"] = ['enum34'] - -install_requires = ['attrs', 'coverage'] - -if sys.version_info[0] < 3: - install_requires.append('enum34') - -setup( - name='hypothesis', - version=__version__, - author='David R. MacIver', - author_email='david@drmaciver.com', - packages=find_packages(SOURCE), - package_dir={'': SOURCE}, - url='https://github.com/HypothesisWorks/hypothesis-python', - license='MPL v2', - description='A library for property based testing', - zip_safe=False, - extras_require=extras, - install_requires=install_requires, - python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*', - classifiers=[ - 'Development Status :: 5 - Production/Stable', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)', - 'Operating System :: Unix', - 'Operating System :: POSIX', - 'Operating System :: Microsoft :: Windows', - 'Programming Language :: Python', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: Implementation :: CPython', - 'Programming Language :: Python :: Implementation :: PyPy', - 'Topic :: Software Development :: Testing', - ], - entry_points={ - 'pytest11': ['hypothesispytest = hypothesis.extra.pytestplugin'], - }, - long_description=open(README).read(), -) diff -Nru python-hypothesis-3.44.1/src/hypothesis/configuration.py python-hypothesis-3.71.11/src/hypothesis/configuration.py --- python-hypothesis-3.44.1/src/hypothesis/configuration.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/configuration.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,57 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import os - -__hypothesis_home_directory_default = os.path.join(os.getcwd(), '.hypothesis') - -__hypothesis_home_directory = None - - -def set_hypothesis_home_dir(directory): - global __hypothesis_home_directory - __hypothesis_home_directory = directory - - -def mkdir_p(path): - try: - os.makedirs(path) - except OSError: - pass - - -def hypothesis_home_dir(): - global __hypothesis_home_directory - if not __hypothesis_home_directory: - __hypothesis_home_directory = os.getenv( - 'HYPOTHESIS_STORAGE_DIRECTORY') - if not __hypothesis_home_directory: - __hypothesis_home_directory = __hypothesis_home_directory_default - mkdir_p(__hypothesis_home_directory) - return __hypothesis_home_directory - - -def storage_directory(*names): - path = os.path.join(hypothesis_home_dir(), *names) - mkdir_p(path) - return path - - -def tmpdir(): - return storage_directory('tmp') diff -Nru python-hypothesis-3.44.1/src/hypothesis/control.py python-hypothesis-3.71.11/src/hypothesis/control.py --- python-hypothesis-3.44.1/src/hypothesis/control.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/control.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,133 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import traceback - -from hypothesis.errors import CleanupFailed, InvalidArgument, \ - UnsatisfiedAssumption -from hypothesis.reporting import report -from hypothesis.utils.dynamicvariables import DynamicVariable - - -def reject(): - raise UnsatisfiedAssumption() - - -def assume(condition): - """``assume()`` is like an :ref:`assert ` that marks the - example as bad, rather than failing the test. - - This allows you to specify properties that you *assume* will be - true, and let Hypothesis try to avoid similar examples in future. - - """ - if not condition: - raise UnsatisfiedAssumption() - return True - - -_current_build_context = DynamicVariable(None) - - -def current_build_context(): - context = _current_build_context.value - if context is None: - raise InvalidArgument( - u'No build context registered') - return context - - -class BuildContext(object): - - def __init__(self, data, is_final=False, close_on_capture=True): - self.data = data - self.tasks = [] - self.is_final = is_final - self.close_on_capture = close_on_capture - self.close_on_del = False - self.notes = [] - - def __enter__(self): - self.assign_variable = _current_build_context.with_value(self) - self.assign_variable.__enter__() - return self - - def __exit__(self, exc_type, exc_value, tb): - self.assign_variable.__exit__(exc_type, exc_value, tb) - if self.close() and exc_type is None: - raise CleanupFailed() - - def local(self): - return _current_build_context.with_value(self) - - def close(self): - any_failed = False - for task in self.tasks: - try: - task() - except BaseException: - any_failed = True - report(traceback.format_exc()) - return any_failed - - -def cleanup(teardown): - """Register a function to be called when the current test has finished - executing. Any exceptions thrown in teardown will be printed but not - rethrown. - - Inside a test this isn't very interesting, because you can just use - a finally block, but note that you can use this inside map, flatmap, - etc. in order to e.g. insist that a value is closed at the end. - - """ - context = _current_build_context.value - if context is None: - raise InvalidArgument( - u'Cannot register cleanup outside of build context') - context.tasks.append(teardown) - - -def note(value): - """Report this value in the final execution.""" - context = _current_build_context.value - if context is None: - raise InvalidArgument( - 'Cannot make notes outside of a test') - context.notes.append(value) - if context.is_final: - report(value) - - -def event(value): - """Record an event that occurred this test. Statistics on number of test - runs with each event will be reported at the end if you run Hypothesis in - statistics reporting mode. - - Events should be strings or convertible to them. - - """ - - context = _current_build_context.value - if context is None: - raise InvalidArgument( - 'Cannot make record events outside of a test') - - if context.data is not None: - context.data.note_event(value) diff -Nru python-hypothesis-3.44.1/src/hypothesis/core.py python-hypothesis-3.71.11/src/hypothesis/core.py --- python-hypothesis-3.44.1/src/hypothesis/core.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/core.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,1124 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -"""This module provides the core primitives of Hypothesis, such as given.""" - - -from __future__ import division, print_function, absolute_import - -import os -import ast -import sys -import time -import zlib -import base64 -import traceback -from random import Random - -import attr -from coverage import CoverageData -from coverage.files import canonical_filename -from coverage.collector import Collector - -import hypothesis.strategies as st -from hypothesis import __version__ -from hypothesis.errors import Flaky, Timeout, NoSuchExample, \ - Unsatisfiable, DidNotReproduce, InvalidArgument, DeadlineExceeded, \ - MultipleFailures, FailedHealthCheck, UnsatisfiedAssumption, \ - HypothesisDeprecationWarning -from hypothesis.control import BuildContext -from hypothesis._settings import settings as Settings -from hypothesis._settings import Phase, Verbosity, HealthCheck, \ - PrintSettings, note_deprecation -from hypothesis.executors import new_style_executor -from hypothesis.reporting import report, verbose_report, current_verbosity -from hypothesis.statistics import note_engine_for_statistics -from hypothesis.internal.compat import ceil, str_to_bytes, \ - benchmark_time, get_type_hints, getfullargspec, encoded_filepath -from hypothesis.internal.coverage import IN_COVERAGE_TESTS -from hypothesis.utils.conventions import infer, not_set -from hypothesis.internal.escalation import is_hypothesis_file, \ - escalate_hypothesis_internal_error -from hypothesis.internal.reflection import is_mock, proxies, nicerepr, \ - arg_string, impersonate, function_digest, fully_qualified_name, \ - define_function_signature, convert_positional_arguments, \ - get_pretty_function_description -from hypothesis.internal.healthcheck import fail_health_check -from hypothesis.internal.conjecture.data import Status, StopTest, \ - ConjectureData -from hypothesis.searchstrategy.strategies import SearchStrategy -from hypothesis.internal.conjecture.engine import ExitReason, \ - ConjectureRunner, sort_key - -try: - from coverage.tracer import CFileDisposition as FileDisposition -except ImportError: # pragma: no cover - from coverage.collector import FileDisposition - - -running_under_pytest = False -global_force_seed = None - - -def new_random(): - import random - return random.Random(random.getrandbits(128)) - - -@attr.s() -class Example(object): - args = attr.ib() - kwargs = attr.ib() - - -def example(*args, **kwargs): - """A decorator which ensures a specific example is always tested.""" - if args and kwargs: - raise InvalidArgument( - 'Cannot mix positional and keyword arguments for examples' - ) - if not (args or kwargs): - raise InvalidArgument( - 'An example must provide at least one argument' - ) - - def accept(test): - if not hasattr(test, 'hypothesis_explicit_examples'): - test.hypothesis_explicit_examples = [] - test.hypothesis_explicit_examples.append(Example(tuple(args), kwargs)) - return test - return accept - - -def seed(seed): - """seed: Start the test execution from a specific seed. - - May be any hashable object. No exact meaning for seed is provided - other than that for a fixed seed value Hypothesis will try the same - actions (insofar as it can given external sources of non- - determinism. e.g. timing and hash randomization). Overrides the - derandomize setting if it is present. - - """ - - def accept(test): - test._hypothesis_internal_use_seed = seed - return test - return accept - - -def reproduce_failure(version, blob): - """Run the example that corresponds to this data blob in order to reproduce - a failure. - - A test with this decorator *always* runs only one example and always fails. - If the provided example does not cause a failure, or is in some way invalid - for this test, then this will fail with a DidNotReproduce error. - - This decorator is not intended to be a permanent addition to your test - suite. It's simply some code you can add to ease reproduction of a problem - in the event that you don't have access to the test database. Because of - this, *no* compatibility guarantees are made between different versions of - Hypothesis - its API may change arbitrarily from version to version. - - """ - def accept(test): - test._hypothesis_internal_use_reproduce_failure = (version, blob) - return test - return accept - - -def encode_failure(buffer): - buffer = bytes(buffer) - compressed = zlib.compress(buffer) - if len(compressed) < len(buffer): - buffer = b'\1' + compressed - else: - buffer = b'\0' + buffer - return base64.b64encode(buffer) - - -def decode_failure(blob): - try: - buffer = base64.b64decode(blob) - except Exception: - raise InvalidArgument('Invalid base64 encoded string: %r' % (blob,)) - prefix = buffer[:1] - if prefix == b'\0': - return buffer[1:] - elif prefix == b'\1': - return zlib.decompress(buffer[1:]) - else: - raise InvalidArgument( - 'Could not decode blob %r: Invalid start byte %r' % ( - blob, prefix - )) - - -class WithRunner(SearchStrategy): - - def __init__(self, base, runner): - assert runner is not None - self.base = base - self.runner = runner - - def do_draw(self, data): - data.hypothesis_runner = self.runner - return self.base.do_draw(data) - - -def is_invalid_test( - name, original_argspec, generator_arguments, generator_kwargs -): - def invalid(message): - def wrapped_test(*arguments, **kwargs): - raise InvalidArgument(message) - return wrapped_test - - if not (generator_arguments or generator_kwargs): - return invalid( - 'given must be called with at least one argument') - - if generator_arguments and any([original_argspec.varargs, - original_argspec.varkw, - original_argspec.kwonlyargs]): - return invalid( - 'positional arguments to @given are not supported with varargs, ' - 'varkeywords, or keyword-only arguments' - ) - - if len(generator_arguments) > len(original_argspec.args): - return invalid(( - 'Too many positional arguments for %s() (got %d but' - ' expected at most %d') % ( - name, len(generator_arguments), - len(original_argspec.args))) - - if infer in generator_arguments: - return invalid('infer was passed as a positional argument to @given, ' - 'but may only be passed as a keyword argument') - - if generator_arguments and generator_kwargs: - return invalid( - 'cannot mix positional and keyword arguments to @given' - ) - extra_kwargs = [ - k for k in generator_kwargs - if k not in original_argspec.args + original_argspec.kwonlyargs - ] - if extra_kwargs and not original_argspec.varkw: - return invalid( - '%s() got an unexpected keyword argument %r' % ( - name, - extra_kwargs[0] - )) - for a in original_argspec.args: - if isinstance(a, list): # pragma: no cover - return invalid(( - 'Cannot decorate function %s() because it has ' - 'destructuring arguments') % ( - name, - )) - if original_argspec.defaults or original_argspec.kwonlydefaults: - return invalid('Cannot apply @given to a function with defaults.') - missing = [repr(kw) for kw in original_argspec.kwonlyargs - if kw not in generator_kwargs] - if missing: - raise InvalidArgument('Missing required kwarg{}: {}'.format( - 's' if len(missing) > 1 else '', ', '.join(missing))) - - -def execute_explicit_examples( - test_runner, test, wrapped_test, settings, arguments, kwargs -): - original_argspec = getfullargspec(test) - - for example in reversed(getattr( - wrapped_test, 'hypothesis_explicit_examples', () - )): - example_kwargs = dict(original_argspec.kwonlydefaults or {}) - if example.args: - if len(example.args) > len(original_argspec.args): - raise InvalidArgument( - 'example has too many arguments for test. ' - 'Expected at most %d but got %d' % ( - len(original_argspec.args), len(example.args))) - example_kwargs.update(dict(zip( - original_argspec.args[-len(example.args):], - example.args - ))) - else: - example_kwargs.update(example.kwargs) - if Phase.explicit not in settings.phases: - continue - example_kwargs.update(kwargs) - # Note: Test may mutate arguments and we can't rerun explicit - # examples, so we have to calculate the failure message at this - # point rather than than later. - example_string = '%s(%s)' % ( - test.__name__, arg_string(test, arguments, example_kwargs) - ) - try: - with BuildContext(None) as b: - if settings.verbosity >= Verbosity.verbose: - report('Trying example: ' + example_string) - test_runner( - None, - lambda data: test(*arguments, **example_kwargs) - ) - except BaseException: - report('Falsifying example: ' + example_string) - for n in b.notes: - report(n) - raise - - -def get_random_for_wrapped_test(test, wrapped_test): - settings = wrapped_test._hypothesis_internal_use_settings - wrapped_test._hypothesis_internal_use_generated_seed = None - - if wrapped_test._hypothesis_internal_use_seed is not None: - return Random( - wrapped_test._hypothesis_internal_use_seed) - elif settings.derandomize: - return Random(function_digest(test)) - elif global_force_seed is not None: - return Random(global_force_seed) - else: - import random - seed = random.getrandbits(128) - wrapped_test._hypothesis_internal_use_generated_seed = seed - return Random(seed) - - -def process_arguments_to_given( - wrapped_test, arguments, kwargs, generator_arguments, generator_kwargs, - argspec, test, settings -): - selfy = None - arguments, kwargs = convert_positional_arguments( - wrapped_test, arguments, kwargs) - - # If the test function is a method of some kind, the bound object - # will be the first named argument if there are any, otherwise the - # first vararg (if any). - if argspec.args: - selfy = kwargs.get(argspec.args[0]) - elif arguments: - selfy = arguments[0] - - # Ensure that we don't mistake mocks for self here. - # This can cause the mock to be used as the test runner. - if is_mock(selfy): - selfy = None - - test_runner = new_style_executor(selfy) - - arguments = tuple(arguments) - - search_strategy = st.tuples( - st.just(arguments), - st.fixed_dictionaries(generator_kwargs).map( - lambda args: dict(args, **kwargs) - ) - ) - - if selfy is not None: - search_strategy = WithRunner(search_strategy, selfy) - - search_strategy.validate() - - return arguments, kwargs, test_runner, search_strategy - - -def skip_exceptions_to_reraise(): - """Return a tuple of exceptions meaning 'skip this test', to re-raise. - - This is intended to cover most common test runners; if you would - like another to be added please open an issue or pull request. - - """ - import unittest - # This is a set because nose may simply re-export unittest.SkipTest - exceptions = set([unittest.SkipTest]) - - try: # pragma: no cover - from unittest2 import SkipTest - exceptions.add(SkipTest) - except ImportError: - pass - - try: # pragma: no cover - from pytest.runner import Skipped - exceptions.add(Skipped) - except ImportError: - pass - - try: # pragma: no cover - from nose import SkipTest as NoseSkipTest - exceptions.add(NoseSkipTest) - except ImportError: - pass - - return tuple(sorted(exceptions, key=str)) - - -exceptions_to_reraise = skip_exceptions_to_reraise() - - -def new_given_argspec(original_argspec, generator_kwargs): - """Make an updated argspec for the wrapped test.""" - new_args = [a for a in original_argspec.args if a not in generator_kwargs] - new_kwonlyargs = [a for a in original_argspec.kwonlyargs - if a not in generator_kwargs] - annots = {k: v for k, v in original_argspec.annotations.items() - if k in new_args + new_kwonlyargs} - annots['return'] = None - return original_argspec._replace( - args=new_args, kwonlyargs=new_kwonlyargs, annotations=annots) - - -ROOT = os.path.dirname(__file__) - -STDLIB = os.path.dirname(os.__file__) - - -def hypothesis_check_include(filename): # pragma: no cover - if is_hypothesis_file(filename): - return False - return filename.endswith('.py') - - -def escalate_warning(msg, slug=None): # pragma: no cover - if slug is not None: - msg = '%s (%s)' % (msg, slug) - raise AssertionError( - 'Unexpected warning from coverage: %s' % (msg,) - ) - - -class Arc(object): - __slots__ = ('filename', 'source', 'target') - - def __init__(self, filename, source, target): - self.filename = filename - self.source = source - self.target = target - - -ARC_CACHE = {} - - -def arc(filename, source, target): - try: - return ARC_CACHE[filename][source][target] - except KeyError: - result = Arc(filename, source, target) - ARC_CACHE.setdefault( - filename, {}).setdefault(source, {})[target] = result - return result - - -in_given = False - -FORCE_PURE_TRACER = os.getenv('HYPOTHESIS_FORCE_PURE_TRACER') == 'true' - - -class StateForActualGivenExecution(object): - - def __init__( - self, test_runner, search_strategy, test, settings, random, had_seed - ): - self.test_runner = test_runner - self.search_strategy = search_strategy - self.settings = settings - self.at_least_one_success = False - self.last_exception = None - self.falsifying_examples = () - self.__was_flaky = False - self.random = random - self.__warned_deadline = False - self.__existing_collector = None - self.__test_runtime = None - self.__had_seed = had_seed - - self.test = test - - self.coverage_data = CoverageData() - self.files_to_propagate = set() - self.failed_normally = False - - self.used_examples_from_database = False - - if settings.use_coverage and not IN_COVERAGE_TESTS: # pragma: no cover - if Collector._collectors: - parent = Collector._collectors[-1] - - # We include any files the collector has already decided to - # trace whether or not on re-investigation we still think it - # wants to trace them. The reason for this is that in some - # cases coverage gets the wrong answer when we run it - # ourselves due to reasons that are our fault but are hard to - # fix (we lie about where certain functions come from). - # This causes us to not record the actual test bodies as - # covered. But if we intended to trace test bodies then the - # file must already have been traced when getting to this point - # and so will already be in the collector's data. Hence we can - # use that information to get the correct answer here. - # See issue 997 for more context. - self.files_to_propagate = set(parent.data) - self.hijack_collector(parent) - - self.collector = Collector( - branch=True, - timid=FORCE_PURE_TRACER, - should_trace=self.should_trace, - check_include=hypothesis_check_include, - concurrency='thread', - warn=escalate_warning, - ) - self.collector.reset() - - # Hide the other collectors from this one so it doesn't attempt to - # pause them (we're doing trace function management ourselves so - # this will just cause problems). - self.collector._collectors = [] - else: - self.collector = None - - def execute( - self, data, - print_example=False, - is_final=False, - expected_failure=None, collect=False, - ): - text_repr = [None] - if self.settings.deadline is None: - test = self.test - else: - @proxies(self.test) - def test(*args, **kwargs): - self.__test_runtime = None - initial_draws = len(data.draw_times) - start = benchmark_time() - result = self.test(*args, **kwargs) - finish = benchmark_time() - internal_draw_time = sum(data.draw_times[initial_draws:]) - runtime = (finish - start - internal_draw_time) * 1000 - self.__test_runtime = runtime - if self.settings.deadline is not_set: - if ( - not self.__warned_deadline and - runtime >= 200 - ): - self.__warned_deadline = True - note_deprecation(( - 'Test took %.2fms to run. In future the default ' - 'deadline setting will be 200ms, which will ' - 'make this an error. You can set deadline to ' - 'an explicit value of e.g. %d to turn tests ' - 'slower than this into an error, or you can set ' - 'it to None to disable this check entirely.') % ( - runtime, ceil(runtime / 100) * 100, - )) - else: - current_deadline = self.settings.deadline - if not is_final: - current_deadline *= 1.25 - if runtime >= current_deadline: - raise DeadlineExceeded(runtime, self.settings.deadline) - return result - - def run(data): - if not hasattr(data, 'can_reproduce_example_from_repr'): - data.can_reproduce_example_from_repr = True - with self.settings: - with BuildContext(data, is_final=is_final): - import random as rnd_module - rnd_module.seed(0) - args, kwargs = data.draw(self.search_strategy) - if expected_failure is not None: - text_repr[0] = arg_string(test, args, kwargs) - - if print_example: - example = '%s(%s)' % ( - test.__name__, arg_string(test, args, kwargs)) - try: - ast.parse(example) - except SyntaxError: - data.can_reproduce_example_from_repr = False - report('Falsifying example: %s' % (example,)) - elif current_verbosity() >= Verbosity.verbose: - report( - lambda: 'Trying example: %s(%s)' % ( - test.__name__, arg_string(test, args, kwargs))) - - if self.collector is None or not collect: - return test(*args, **kwargs) - else: # pragma: no cover - try: - self.collector.start() - return test(*args, **kwargs) - finally: - self.collector.stop() - - result = self.test_runner(data, run) - if expected_failure is not None: - exception, traceback = expected_failure - if ( - isinstance( - exception, - DeadlineExceeded - ) and self.__test_runtime is not None - ): - report(( - 'Unreliable test timings! On an initial run, this ' - 'test took %.2fms, which exceeded the deadline of ' - '%.2fms, but on a subsequent run it took %.2f ms, ' - 'which did not. If you expect this sort of ' - 'variability in your test timings, consider turning ' - 'deadlines off for this test by setting deadline=None.' - ) % ( - exception.runtime, - self.settings.deadline, self.__test_runtime - )) - else: - report( - 'Failed to reproduce exception. Expected: \n' + - traceback, - ) - self.__flaky(( - 'Hypothesis %s(%s) produces unreliable results: Falsified' - ' on the first call but did not on a subsequent one' - ) % (test.__name__, text_repr[0],)) - return result - - def should_trace(self, original_filename, frame): # pragma: no cover - disp = FileDisposition() - assert original_filename is not None - disp.original_filename = original_filename - disp.canonical_filename = encoded_filepath( - canonical_filename(original_filename)) - disp.source_filename = disp.canonical_filename - disp.reason = '' - disp.file_tracer = None - disp.has_dynamic_filename = False - disp.trace = hypothesis_check_include(disp.canonical_filename) - if not disp.trace: - disp.reason = 'hypothesis internal reasons' - elif self.__existing_collector is not None: - check = self.__existing_collector.should_trace( - original_filename, frame) - if check.trace: - self.files_to_propagate.add(check.canonical_filename) - return disp - - def hijack_collector(self, collector): # pragma: no cover - self.__existing_collector = collector - original_save_data = collector.save_data - - def save_data(covdata): - original_save_data(covdata) - if collector.branch: - covdata.add_arcs({ - filename: { - arc: None - for arc in self.coverage_data.arcs(filename) or ()} - for filename in self.files_to_propagate - }) - else: - covdata.add_lines({ - filename: { - line: None - for line in self.coverage_data.lines(filename) or ()} - for filename in self.files_to_propagate - }) - collector.save_data = original_save_data - collector.save_data = save_data - - def evaluate_test_data(self, data): - try: - if self.collector is None: - result = self.execute(data) - else: # pragma: no cover - # This should always be a no-op, but the coverage tracer has - # a bad habit of resurrecting itself. - original = sys.gettrace() - sys.settrace(None) - try: - self.collector.data = {} - result = self.execute(data, collect=True) - finally: - sys.settrace(original) - covdata = CoverageData() - self.collector.save_data(covdata) - self.coverage_data.update(covdata) - for filename in covdata.measured_files(): - if is_hypothesis_file(filename): - continue - data.tags.update( - arc(filename, source, target) - for source, target in covdata.arcs(filename) - ) - if result is not None and self.settings.perform_health_check: - fail_health_check(self.settings, ( - 'Tests run under @given should return None, but ' - '%s returned %r instead.' - ) % (self.test.__name__, result), HealthCheck.return_value) - self.at_least_one_success = True - return False - except UnsatisfiedAssumption: - data.mark_invalid() - except ( - HypothesisDeprecationWarning, FailedHealthCheck, - StopTest, - ) + exceptions_to_reraise: - raise - except Exception as e: - escalate_hypothesis_internal_error() - data.__expected_traceback = traceback.format_exc() - data.__expected_exception = e - verbose_report(data.__expected_traceback) - - error_class, _, tb = sys.exc_info() - - origin = traceback.extract_tb(tb)[-1] - filename = origin[0] - lineno = origin[1] - data.mark_interesting((error_class, filename, lineno)) - - def run(self): - # Tell pytest to omit the body of this function from tracebacks - __tracebackhide__ = True - if global_force_seed is None: - database_key = str_to_bytes(fully_qualified_name(self.test)) - else: - database_key = None - self.start_time = time.time() - global in_given - runner = ConjectureRunner( - self.evaluate_test_data, - settings=self.settings, random=self.random, - database_key=database_key, - ) - - try: - if in_given or self.collector is None: - runner.run() - else: # pragma: no cover - in_given = True - original_trace = sys.gettrace() - try: - sys.settrace(None) - runner.run() - finally: - in_given = False - sys.settrace(original_trace) - note_engine_for_statistics(runner) - run_time = time.time() - self.start_time - finally: - self.used_examples_from_database = \ - runner.used_examples_from_database - - if runner.used_examples_from_database: - if self.settings.derandomize: - note_deprecation( - 'In future derandomize will imply database=None, but your ' - 'test is currently using examples from the database. To ' - 'get the future behaviour, update your settings to ' - 'include database=None.' - ) - if self.__had_seed: - note_deprecation( - 'In future use of @seed will imply database=None in your ' - 'settings, but your test is currently using examples from ' - 'the database. To get the future behaviour, update your ' - 'settings for this test to include database=None.' - ) - - timed_out = runner.exit_reason == ExitReason.timeout - if runner.last_data is None: - return - if runner.interesting_examples: - self.falsifying_examples = sorted( - [d for d in runner.interesting_examples.values()], - key=lambda d: sort_key(d.buffer), reverse=True - ) - else: - if timed_out: - note_deprecation(( - 'Your tests are hitting the settings timeout (%.2fs). ' - 'This functionality will go away in a future release ' - 'and you should not rely on it. Instead, try setting ' - 'max_examples to be some value lower than %d (the number ' - 'of examples your test successfully ran here). Or, if you ' - 'would prefer your tests to run to completion, regardless ' - 'of how long they take, you can set the timeout value to ' - 'hypothesis.unlimited.' - ) % ( - self.settings.timeout, runner.valid_examples), - self.settings) - if runner.valid_examples < min( - self.settings.min_satisfying_examples, - self.settings.max_examples, - ) and not ( - runner.exit_reason == ExitReason.finished and - self.at_least_one_success - ): - if timed_out: - raise Timeout(( - 'Ran out of time before finding a satisfying ' - 'example for ' - '%s. Only found %d examples in ' + - '%.2fs.' - ) % ( - get_pretty_function_description(self.test), - runner.valid_examples, run_time - )) - else: - raise Unsatisfiable(( - 'Unable to satisfy assumptions of hypothesis ' - '%s. Only %d examples considered ' - 'satisfied assumptions' - ) % ( - get_pretty_function_description(self.test), - runner.valid_examples,)) - - if not self.falsifying_examples: - return - - self.failed_normally = True - - flaky = 0 - - for falsifying_example in self.falsifying_examples: - ran_example = ConjectureData.for_buffer(falsifying_example.buffer) - self.__was_flaky = False - assert falsifying_example.__expected_exception is not None - try: - self.execute( - ran_example, - print_example=True, is_final=True, - expected_failure=( - falsifying_example.__expected_exception, - falsifying_example.__expected_traceback, - ) - ) - except (UnsatisfiedAssumption, StopTest): - report(traceback.format_exc()) - self.__flaky( - 'Unreliable assumption: An example which satisfied ' - 'assumptions on the first run now fails it.' - ) - except BaseException: - if len(self.falsifying_examples) <= 1: - raise - report(traceback.format_exc()) - finally: # pragma: no cover - # This section is in fact entirely covered by the tests in - # test_reproduce_failure, but it seems to trigger a lovely set - # of coverage bugs: The branches show up as uncovered (despite - # definitely being covered - you can add an assert False else - # branch to verify this and see it fail - and additionally the - # second branch still complains about lack of coverage even if - # you add a pragma: no cover to it! - # See https://bitbucket.org/ned/coveragepy/issues/623/ - if self.settings.print_blob is not PrintSettings.NEVER: - failure_blob = encode_failure(falsifying_example.buffer) - # Have to use the example we actually ran, not the original - # falsifying example! Otherwise we won't catch problems - # where the repr of the generated example doesn't parse. - can_use_repr = ran_example.can_reproduce_example_from_repr - if ( - self.settings.print_blob is PrintSettings.ALWAYS or ( - self.settings.print_blob is PrintSettings.INFER and - not can_use_repr and - len(failure_blob) < 200 - ) - ): - report(( - '\n' - 'You can reproduce this example by temporarily ' - 'adding @reproduce_failure(%r, %r) as a decorator ' - 'on your test case') % ( - __version__, failure_blob,)) - if self.__was_flaky: - flaky += 1 - - # If we only have one example then we should have raised an error or - # flaky prior to this point. - assert len(self.falsifying_examples) > 1 - - if flaky > 0: - raise Flaky(( - 'Hypothesis found %d distinct failures, but %d of them ' - 'exhibited some sort of flaky behaviour.') % ( - len(self.falsifying_examples), flaky)) - else: - raise MultipleFailures(( - 'Hypothesis found %d distinct failures.') % ( - len(self.falsifying_examples,))) - - def __flaky(self, message): - if len(self.falsifying_examples) <= 1: - raise Flaky(message) - else: - self.__was_flaky = True - report('Flaky example! ' + message) - - -def given(*given_arguments, **given_kwargs): - """A decorator for turning a test function that accepts arguments into a - randomized test. - - This is the main entry point to Hypothesis. - - """ - def run_test_with_generator(test): - generator_arguments = tuple(given_arguments) - generator_kwargs = dict(given_kwargs) - - original_argspec = getfullargspec(test) - - check_invalid = is_invalid_test( - test.__name__, original_argspec, - generator_arguments, generator_kwargs) - - if check_invalid is not None: - return check_invalid - - for name, strategy in zip(reversed(original_argspec.args), - reversed(generator_arguments)): - generator_kwargs[name] = strategy - - argspec = new_given_argspec(original_argspec, generator_kwargs) - - @impersonate(test) - @define_function_signature( - test.__name__, test.__doc__, argspec - ) - def wrapped_test(*arguments, **kwargs): - # Tell pytest to omit the body of this function from tracebacks - __tracebackhide__ = True - - if getattr(test, 'is_hypothesis_test', False): - note_deprecation(( - 'You have applied @given to a test more than once. In ' - 'future this will be an error. Applying @given twice ' - 'wraps the test twice, which can be extremely slow. A ' - 'similar effect can be gained by combining the arguments ' - 'to the two calls to given. For example, instead of ' - '@given(booleans()) @given(integers()), you could write ' - '@given(booleans(), integers())' - )) - - settings = wrapped_test._hypothesis_internal_use_settings - - random = get_random_for_wrapped_test(test, wrapped_test) - - if infer in generator_kwargs.values(): - hints = get_type_hints(test) - for name in [name for name, value in generator_kwargs.items() - if value is infer]: - if name not in hints: - raise InvalidArgument( - 'passed %s=infer for %s, but %s has no type annotation' - % (name, test.__name__, name)) - generator_kwargs[name] = st.from_type(hints[name]) - - processed_args = process_arguments_to_given( - wrapped_test, arguments, kwargs, generator_arguments, - generator_kwargs, argspec, test, settings - ) - arguments, kwargs, test_runner, search_strategy = processed_args - - state = StateForActualGivenExecution( - test_runner, search_strategy, test, settings, random, - had_seed=wrapped_test._hypothesis_internal_use_seed - ) - - reproduce_failure = \ - wrapped_test._hypothesis_internal_use_reproduce_failure - - if reproduce_failure is not None: - expected_version, failure = reproduce_failure - if expected_version != __version__: - raise InvalidArgument(( - 'Attempting to reproduce a failure from a different ' - 'version of Hypothesis. This failure is from %s, but ' - 'you are currently running %r. Please change your ' - 'Hypothesis version to a matching one.' - ) % (expected_version, __version__)) - try: - state.execute(ConjectureData.for_buffer( - decode_failure(failure)), - print_example=True, is_final=True, - ) - raise DidNotReproduce( - 'Expected the test to raise an error, but it ' - 'completed successfully.' - ) - except StopTest: - raise DidNotReproduce( - 'The shape of the test data has changed in some way ' - 'from where this blob was defined. Are you sure ' - "you're running the same test?" - ) - except UnsatisfiedAssumption: - raise DidNotReproduce( - 'The test data failed to satisfy an assumption in the ' - 'test. Have you added it since this blob was ' - 'generated?' - ) - - execute_explicit_examples( - test_runner, test, wrapped_test, settings, arguments, kwargs - ) - - if settings.max_examples <= 0: - return - - if not ( - Phase.reuse in settings.phases or - Phase.generate in settings.phases - ): - return - - try: - state.run() - except BaseException: - generated_seed = \ - wrapped_test._hypothesis_internal_use_generated_seed - if generated_seed is not None and not state.failed_normally: - if running_under_pytest: - report(( - 'You can add @seed(%(seed)d) to this test or run ' - 'pytest with --hypothesis-seed=%(seed)d to ' - 'reproduce this failure.') % { - 'seed': generated_seed},) - else: - report(( - 'You can add @seed(%d) to this test to reproduce ' - 'this failure.') % (generated_seed,)) - raise - - for attrib in dir(test): - if not (attrib.startswith('_') or hasattr(wrapped_test, attrib)): - setattr(wrapped_test, attrib, getattr(test, attrib)) - wrapped_test.is_hypothesis_test = True - wrapped_test._hypothesis_internal_use_seed = getattr( - test, '_hypothesis_internal_use_seed', None - ) - wrapped_test._hypothesis_internal_use_settings = getattr( - test, '_hypothesis_internal_use_settings', None - ) or Settings.default - wrapped_test._hypothesis_internal_use_reproduce_failure = getattr( - test, '_hypothesis_internal_use_reproduce_failure', None - ) - return wrapped_test - return run_test_with_generator - - -def find(specifier, condition, settings=None, random=None, database_key=None): - """Returns the minimal example from the given strategy ``specifier`` that - matches the predicate function ``condition``.""" - settings = settings or Settings( - max_examples=2000, - min_satisfying_examples=0, - max_shrinks=2000, - ) - settings = Settings(settings, perform_health_check=False) - - if database_key is None and settings.database is not None: - database_key = function_digest(condition) - - if not isinstance(specifier, SearchStrategy): - raise InvalidArgument( - 'Expected SearchStrategy but got %r of type %s' % ( - specifier, type(specifier).__name__ - )) - specifier.validate() - - search = specifier - - random = random or new_random() - successful_examples = [0] - last_data = [None] - - def template_condition(data): - with BuildContext(data): - try: - data.is_find = True - result = data.draw(search) - data.note(result) - success = condition(result) - except UnsatisfiedAssumption: - data.mark_invalid() - - if success: - successful_examples[0] += 1 - - if settings.verbosity == Verbosity.verbose: - if not successful_examples[0]: - report(lambda: u'Trying example %s' % ( - nicerepr(result), - )) - elif success: - if successful_examples[0] == 1: - report(lambda: u'Found satisfying example %s' % ( - nicerepr(result), - )) - else: - report(lambda: u'Shrunk example to %s' % ( - nicerepr(result), - )) - last_data[0] = data - if success and not data.frozen: - data.mark_interesting() - start = time.time() - runner = ConjectureRunner( - template_condition, settings=settings, random=random, - database_key=database_key, - ) - runner.run() - note_engine_for_statistics(runner) - run_time = time.time() - start - if runner.last_data.status == Status.INTERESTING: - data = ConjectureData.for_buffer(runner.last_data.buffer) - with BuildContext(data): - return data.draw(search) - if ( - runner.valid_examples <= settings.min_satisfying_examples and - runner.exit_reason != ExitReason.finished - ): - if settings.timeout > 0 and run_time > settings.timeout: - raise Timeout(( - 'Ran out of time before finding enough valid examples for ' - '%s. Only %d valid examples found in %.2f seconds.' - ) % ( - get_pretty_function_description(condition), - runner.valid_examples, run_time)) - - else: - raise Unsatisfiable(( - 'Unable to satisfy assumptions of ' - '%s. Only %d examples considered satisfied assumptions' - ) % ( - get_pretty_function_description(condition), - runner.valid_examples,)) - - raise NoSuchExample(get_pretty_function_description(condition)) diff -Nru python-hypothesis-3.44.1/src/hypothesis/database.py python-hypothesis-3.71.11/src/hypothesis/database.py --- python-hypothesis-3.44.1/src/hypothesis/database.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/database.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,308 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import os -import re -import binascii -import threading -from hashlib import sha1 -from contextlib import contextmanager - -from hypothesis._settings import note_deprecation -from hypothesis.internal.compat import FileNotFoundError, hbytes, \ - b64decode, b64encode - -sqlite3 = None -SQLITE_PATH = re.compile(r"\.\(db|sqlite|sqlite3\)$") - - -def _db_for_path(path=None): - if path in (None, ':memory:'): - return InMemoryExampleDatabase() - path = str(path) - if os.path.isdir(path): - return DirectoryBasedExampleDatabase(path) - if os.path.exists(path): - return SQLiteExampleDatabase(path) - if SQLITE_PATH.search(path): - return SQLiteExampleDatabase(path) - else: - return DirectoryBasedExampleDatabase(path) - - -class EDMeta(type): - - def __call__(self, *args, **kwargs): - if self is ExampleDatabase: - return _db_for_path(*args, **kwargs) - return super(EDMeta, self).__call__(*args, **kwargs) - - -class ExampleDatabase(EDMeta('ExampleDatabase', (object,), {})): - """Interface class for storage systems. - - A key -> multiple distinct values mapping. - - Keys and values are binary data. - - """ - - def save(self, key, value): - """save this value under this key. - - If this value is already present for this key, silently do - nothing - - """ - raise NotImplementedError('%s.save' % (type(self).__name__)) - - def delete(self, key, value): - """Remove this value from this key. - - If this value is not present, silently do nothing. - - """ - raise NotImplementedError('%s.delete' % (type(self).__name__)) - - def move(self, src, dest, value): - """Move value from key src to key dest. Equivalent to delete(src, - value) followed by save(src, value) but may have a more efficient - implementation. - - Note that value will be inserted at dest regardless of whether - it is currently present at src. - - """ - if src == dest: - self.save(src, value) - return - self.delete(src, value) - self.save(dest, value) - - def fetch(self, key): - """Return all values matching this key.""" - raise NotImplementedError('%s.fetch' % (type(self).__name__)) - - def close(self): - """Clear up any resources associated with this database.""" - raise NotImplementedError('%s.close' % (type(self).__name__)) - - -class InMemoryExampleDatabase(ExampleDatabase): - - def __init__(self): - self.data = {} - - def __repr__(self): - return 'InMemoryExampleDatabase(%r)' % (self.data,) - - def fetch(self, key): - for v in self.data.get(key, ()): - yield v - - def save(self, key, value): - self.data.setdefault(key, set()).add(hbytes(value)) - - def delete(self, key, value): - self.data.get(key, set()).discard(hbytes(value)) - - def close(self): - pass - - -class SQLiteExampleDatabase(ExampleDatabase): - - def __init__(self, path=u':memory:'): - self.path = path - self.db_created = False - self.current_connection = threading.local() - global sqlite3 - import sqlite3 - - if path == u':memory:': - note_deprecation( - 'The SQLite database backend has been deprecated. ' - 'Use InMemoryExampleDatabase or set database_file=":memory:" ' - 'instead.' - ) - else: - note_deprecation( - 'The SQLite database backend has been deprecated. ' - 'Set database_file to some path name not ending in .db, ' - '.sqlite or .sqlite3 to get the new directory based database ' - 'backend instead.' - ) - - def connection(self): - if not hasattr(self.current_connection, 'connection'): - self.current_connection.connection = sqlite3.connect(self.path) - return self.current_connection.connection - - def close(self): - if hasattr(self.current_connection, 'connection'): - try: - self.connection().close() - finally: - del self.current_connection.connection - - def __repr__(self): - return u'%s(%s)' % (self.__class__.__name__, self.path) - - @contextmanager - def cursor(self): - conn = self.connection() - cursor = conn.cursor() - try: - try: - yield cursor - finally: - cursor.close() - except BaseException: - conn.rollback() - raise - else: - conn.commit() - - def save(self, key, value): - self.create_db_if_needed() - with self.cursor() as cursor: - try: - cursor.execute(""" - insert into hypothesis_data_mapping(key, value) - values(?, ?) - """, (b64encode(key), b64encode(value))) - except sqlite3.IntegrityError: - pass - - def delete(self, key, value): - self.create_db_if_needed() - with self.cursor() as cursor: - cursor.execute(""" - delete from hypothesis_data_mapping - where key = ? and value = ? - """, (b64encode(key), b64encode(value))) - - def fetch(self, key): - self.create_db_if_needed() - with self.cursor() as cursor: - cursor.execute(""" - select value from hypothesis_data_mapping - where key = ? - """, (b64encode(key),)) - for (value,) in cursor: - try: - yield b64decode(value) - except (binascii.Error, TypeError): - pass - - def create_db_if_needed(self): - if self.db_created: - return - with self.cursor() as cursor: - cursor.execute(""" - create table if not exists hypothesis_data_mapping( - key text, - value text, - unique(key, value) - ) - """) - self.db_created = True - - -def mkdirp(path): - try: - os.makedirs(path) - except OSError: - pass - return path - - -def _hash(key): - return sha1(key).hexdigest()[:16] - - -class DirectoryBasedExampleDatabase(ExampleDatabase): - - def __init__(self, path): - self.path = path - self.keypaths = {} - - def __repr__(self): - return 'DirectoryBasedExampleDatabase(%r)' % (self.path,) - - def close(self): - pass - - def _key_path(self, key): - try: - return self.keypaths[key] - except KeyError: - pass - directory = os.path.join(self.path, _hash(key)) - mkdirp(directory) - self.keypaths[key] = directory - return directory - - def _value_path(self, key, value): - return os.path.join( - self._key_path(key), - sha1(value).hexdigest()[:16] - ) - - def fetch(self, key): - kp = self._key_path(key) - for path in os.listdir(kp): - try: - with open(os.path.join(kp, path), 'rb') as i: - yield hbytes(i.read()) - except FileNotFoundError: - pass - - def save(self, key, value): - path = self._value_path(key, value) - if not os.path.exists(path): - suffix = binascii.hexlify(os.urandom(16)) - if not isinstance(suffix, str): # pragma: no branch - # On Python 3, binascii.hexlify returns bytes - suffix = suffix.decode('ascii') - tmpname = path + '.' + suffix - with open(tmpname, 'wb') as o: - o.write(value) - try: - os.rename(tmpname, path) - except OSError: # pragma: no cover - os.unlink(tmpname) - assert not os.path.exists(tmpname) - - def move(self, src, dest, value): - if src == dest: - self.save(src, value) - return - try: - os.rename( - self._value_path(src, value), self._value_path(dest, value)) - except OSError: - self.delete(src, value) - self.save(dest, value) - - def delete(self, key, value): - try: - os.unlink(self._value_path(key, value)) - except OSError: - pass diff -Nru python-hypothesis-3.44.1/src/hypothesis/errors.py python-hypothesis-3.71.11/src/hypothesis/errors.py --- python-hypothesis-3.44.1/src/hypothesis/errors.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/errors.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,214 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - - -class HypothesisException(Exception): - - """Generic parent class for exceptions thrown by Hypothesis.""" - - -class CleanupFailed(HypothesisException): - - """At least one cleanup task failed and no other exception was raised.""" - - -class UnsatisfiedAssumption(HypothesisException): - - """An internal error raised by assume. - - If you're seeing this error something has gone wrong. - - """ - - -class BadTemplateDraw(HypothesisException): - - """An internal error raised when something unfortunate happened during - template generation and you should restart the draw, preferably with a new - parameter. - - This is not an error condition internally, but if you ever see this - in your code it's probably a Hypothesis bug - - """ - - -class NoSuchExample(HypothesisException): - - """The condition we have been asked to satisfy appears to be always false. - - This does not guarantee that no example exists, only that we were - unable to find one. - - """ - - def __init__(self, condition_string, extra=''): - super(NoSuchExample, self).__init__( - 'No examples found of condition %s%s' % ( - condition_string, extra) - ) - - -class DefinitelyNoSuchExample(NoSuchExample): # pragma: no cover - """Hypothesis used to be able to detect exhaustive coverage of a search - space and no longer can. - - This exception remains for compatibility reasons for now but can - never actually be thrown. - - """ - - -class NoExamples(HypothesisException): - - """Raised when example() is called on a strategy but we cannot find any - examples after enough tries that we really should have been able to if this - was ever going to work.""" - - -class Unsatisfiable(HypothesisException): - - """We ran out of time or examples before we could find enough examples - which satisfy the assumptions of this hypothesis. - - This could be because the function is too slow. If so, try upping - the timeout. It could also be because the function is using assume - in a way that is too hard to satisfy. If so, try writing a custom - strategy or using a better starting point (e.g if you are requiring - a list has unique values you could instead filter out all duplicate - values from the list) - - """ - - -class Flaky(HypothesisException): - - """This function appears to fail non-deterministically: We have seen it - fail when passed this example at least once, but a subsequent invocation - did not fail. - - Common causes for this problem are: - 1. The function depends on external state. e.g. it uses an external - random number generator. Try to make a version that passes all the - relevant state in from Hypothesis. - 2. The function is suffering from too much recursion and its failure - depends sensitively on where it's been called from. - 3. The function is timing sensitive and can fail or pass depending on - how long it takes. Try breaking it up into smaller functions which - don't do that and testing those instead. - - """ - - -class Timeout(Unsatisfiable): - - """We were unable to find enough examples that satisfied the preconditions - of this hypothesis in the amount of time allotted to us.""" - - -class WrongFormat(HypothesisException, ValueError): - - """An exception indicating you have attempted to serialize a value that - does not match the type described by this format.""" - - -class BadData(HypothesisException, ValueError): - - """The data that we got out of the database does not seem to match the data - we could have put into the database given this schema.""" - - -class InvalidArgument(HypothesisException, TypeError): - - """Used to indicate that the arguments to a Hypothesis function were in - some manner incorrect.""" - - -class ResolutionFailed(InvalidArgument): - - """Hypothesis had to resolve a type to a strategy, but this failed. - - Type inference is best-effort, so this only happens when an - annotation exists but could not be resolved for a required argument - to the target of ``builds()``, or where the user passed ``infer``. - - """ - - -class InvalidState(HypothesisException): - - """The system is not in a state where you were allowed to do that.""" - - -class InvalidDefinition(HypothesisException, TypeError): - - """Used to indicate that a class definition was not well put together and - has something wrong with it.""" - - -class AbnormalExit(HypothesisException): - - """Raised when a test running in a child process exits without returning or - raising an exception.""" - - -class FailedHealthCheck(HypothesisException, Warning): - """Raised when a test fails a preliminary healthcheck that occurs before - execution.""" - - def __init__(self, message, check): - super(FailedHealthCheck, self).__init__(message) - self.health_check = check - - -class HypothesisDeprecationWarning(HypothesisException, FutureWarning): - pass - - -class Frozen(HypothesisException): - - """Raised when a mutation method has been called on a ConjectureData object - after freeze() has been called.""" - - -class MultipleFailures(HypothesisException): - """Indicates that Hypothesis found more than one distinct bug when testing - your code.""" - - -class DeadlineExceeded(HypothesisException): - """Raised when an individual test body has taken too long to run.""" - - def __init__(self, runtime, deadline): - super(DeadlineExceeded, self).__init__(( - 'Test took %.2fms, which exceeds the deadline of ' - '%.2fms') % (runtime, deadline)) - self.runtime = runtime - self.deadline = deadline - - -class StopTest(BaseException): - - def __init__(self, testcounter): - super(StopTest, self).__init__(repr(testcounter)) - self.testcounter = testcounter - - -class DidNotReproduce(HypothesisException): - pass diff -Nru python-hypothesis-3.44.1/src/hypothesis/executors.py python-hypothesis-3.71.11/src/hypothesis/executors.py --- python-hypothesis-3.44.1/src/hypothesis/executors.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/executors.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,79 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - - -def default_executor(function): # pragma: nocover - raise NotImplementedError() # We don't actually use this any more - - -def setup_teardown_executor(setup, teardown): - setup = setup or (lambda: None) - teardown = teardown or (lambda ex: None) - - def execute(function): - token = None - try: - token = setup() - return function() - finally: - teardown(token) - return execute - - -def executor(runner): - try: - return runner.execute_example - except AttributeError: - pass - - if ( - hasattr(runner, 'setup_example') or - hasattr(runner, 'teardown_example') - ): - return setup_teardown_executor( - getattr(runner, 'setup_example', None), - getattr(runner, 'teardown_example', None), - ) - - return default_executor - - -def default_new_style_executor(data, function): - return function(data) - - -class ConjectureRunner(object): - - def hypothesis_execute_example_with_data(self, data, function): - return function(data) - - -def new_style_executor(runner): - if runner is None: - return default_new_style_executor - if isinstance(runner, ConjectureRunner): - return runner.hypothesis_execute_example_with_data - - old_school = executor(runner) - if old_school is default_executor: - return default_new_style_executor - else: - return lambda data, function: old_school( - lambda: function(data) - ) diff -Nru python-hypothesis-3.44.1/src/hypothesis/extra/datetime.py python-hypothesis-3.71.11/src/hypothesis/extra/datetime.py --- python-hypothesis-3.44.1/src/hypothesis/extra/datetime.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/extra/datetime.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,116 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -"""This module provides deprecated time and date related strategies. - -It depends on the ``pytz`` package, which is stable enough that almost any -version should be compatible - most updates are for the timezone database. - -""" - -from __future__ import division, print_function, absolute_import - -import datetime as dt - -import pytz - -import hypothesis.strategies as st -from hypothesis.errors import InvalidArgument -from hypothesis._settings import note_deprecation -from hypothesis.extra.pytz import timezones as timezones_strategy - -__all__ = ['datetimes', 'dates', 'times'] - - -def tz_args_strat(allow_naive, tz_list, name): - if tz_list is None: - tz_strat = timezones_strategy() - else: - tz_strat = st.sampled_from([ - tz if isinstance(tz, dt.tzinfo) else pytz.timezone(tz) - for tz in tz_list - ]) - if allow_naive or (allow_naive is None and tz_strat.is_empty): - tz_strat = st.none() | tz_strat - if tz_strat.is_empty: - raise InvalidArgument( - 'Cannot create non-naive %s with no timezones allowed.' % name) - return tz_strat - - -def convert_year_bound(val, default): - if val is None: - return default - try: - return default.replace(val) - except ValueError: - raise InvalidArgument('Invalid year=%r' % (val,)) - - -@st.defines_strategy -def datetimes(allow_naive=None, timezones=None, min_year=None, max_year=None): - """Return a strategy for generating datetimes. - - .. deprecated:: 3.9.0 - use :py:func:`hypothesis.strategies.datetimes` instead. - - allow_naive=True will cause the values to sometimes be naive. - timezones is the set of permissible timezones. If set to an empty - collection all datetimes will be naive. If set to None all timezones - available via pytz will be used. - - All generated datetimes will be between min_year and max_year, inclusive. - - """ - note_deprecation('Use hypothesis.strategies.datetimes, which supports ' - 'full-precision bounds and has a simpler API.') - min_dt = convert_year_bound(min_year, dt.datetime.min) - max_dt = convert_year_bound(max_year, dt.datetime.max) - tzs = tz_args_strat(allow_naive, timezones, 'datetimes') - return st.datetimes(min_dt, max_dt, tzs) - - -@st.defines_strategy -def dates(min_year=None, max_year=None): - """Return a strategy for generating dates. - - .. deprecated:: 3.9.0 - use :py:func:`hypothesis.strategies.dates` instead. - - All generated dates will be between min_year and max_year, inclusive. - - """ - note_deprecation('Use hypothesis.strategies.dates, which supports bounds ' - 'given as date objects for single-day resolution.') - return st.dates(convert_year_bound(min_year, dt.date.min), - convert_year_bound(max_year, dt.date.max)) - - -@st.defines_strategy -def times(allow_naive=None, timezones=None): - """Return a strategy for generating times. - - .. deprecated:: 3.9.0 - use :py:func:`hypothesis.strategies.times` instead. - - The allow_naive and timezones arguments act the same as the datetimes - strategy above. - - """ - note_deprecation('Use hypothesis.strategies.times, which supports ' - 'min_time and max_time arguments.') - return st.times(timezones=tz_args_strat(allow_naive, timezones, 'times')) diff -Nru python-hypothesis-3.44.1/src/hypothesis/extra/django/__init__.py python-hypothesis-3.71.11/src/hypothesis/extra/django/__init__.py --- python-hypothesis-3.44.1/src/hypothesis/extra/django/__init__.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/extra/django/__init__.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,44 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -import unittest - -import django.test as dt - - -class HypothesisTestCase(object): - - def setup_example(self): - self._pre_setup() - - def teardown_example(self, example): - self._post_teardown() - - def __call__(self, result=None): - testMethod = getattr(self, self._testMethodName) - if getattr(testMethod, u'is_hypothesis_test', False): - return unittest.TestCase.__call__(self, result) - else: - return dt.SimpleTestCase.__call__(self, result) - - -class TestCase(HypothesisTestCase, dt.TestCase): - pass - - -class TransactionTestCase(HypothesisTestCase, dt.TransactionTestCase): - pass diff -Nru python-hypothesis-3.44.1/src/hypothesis/extra/django/models.py python-hypothesis-3.71.11/src/hypothesis/extra/django/models.py --- python-hypothesis-3.44.1/src/hypothesis/extra/django/models.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/extra/django/models.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,163 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import string -from decimal import Decimal -from datetime import timedelta - -import django.db.models as dm -from django.db import IntegrityError -from django.conf import settings as django_settings -from django.core.exceptions import ValidationError - -import hypothesis.strategies as st -from hypothesis import reject -from hypothesis.errors import InvalidArgument -from hypothesis.extra.pytz import timezones -from hypothesis.provisional import emails, ip4_addr_strings, \ - ip6_addr_strings -from hypothesis.utils.conventions import UniqueIdentifier - - -def get_tz_strat(): - if getattr(django_settings, 'USE_TZ', False): - return timezones() - return st.none() - - -__default_field_mappings = None - - -def field_mappings(): - global __default_field_mappings - - if __default_field_mappings is None: - # Sized fields are handled in _get_strategy_for_field() - # URL fields are not yet handled - __default_field_mappings = { - dm.SmallIntegerField: st.integers(-32768, 32767), - dm.IntegerField: st.integers(-2147483648, 2147483647), - dm.BigIntegerField: - st.integers(-9223372036854775808, 9223372036854775807), - dm.PositiveIntegerField: st.integers(0, 2147483647), - dm.PositiveSmallIntegerField: st.integers(0, 32767), - dm.BinaryField: st.binary(), - dm.BooleanField: st.booleans(), - dm.DateField: st.dates(), - dm.DateTimeField: st.datetimes(timezones=get_tz_strat()), - dm.DurationField: st.timedeltas(), - dm.EmailField: emails(), - dm.FloatField: st.floats(), - dm.NullBooleanField: st.one_of(st.none(), st.booleans()), - dm.TimeField: st.times(timezones=get_tz_strat()), - dm.UUIDField: st.uuids(), - } - - # SQLite does not support timezone-aware times, or timedeltas that - # don't fit in six bytes of microseconds, so we override those - db = getattr(django_settings, 'DATABASES', {}).get('default', {}) - if db.get('ENGINE', '').endswith('.sqlite3'): # pragma: no branch - sqlite_delta = timedelta(microseconds=2 ** 47 - 1) - __default_field_mappings.update({ - dm.TimeField: st.times(), - dm.DurationField: st.timedeltas(-sqlite_delta, sqlite_delta), - }) - - return __default_field_mappings - - -def add_default_field_mapping(field_type, strategy): - field_mappings()[field_type] = strategy - - -default_value = UniqueIdentifier(u'default_value') - - -def validator_to_filter(f): - """Converts the field run_validators method to something suitable for use - in filter.""" - - def validate(value): - try: - f.run_validators(value) - return True - except ValidationError: - return False - - return validate - - -def _get_strategy_for_field(f): - if f.choices: - choices = [] - for value, name_or_optgroup in f.choices: - if isinstance(name_or_optgroup, (list, tuple)): - choices.extend(key for key, _ in name_or_optgroup) - else: - choices.append(value) - if isinstance(f, (dm.CharField, dm.TextField)) and f.blank: - choices.insert(0, u'') - strategy = st.sampled_from(choices) - elif type(f) == dm.SlugField: - strategy = st.text(alphabet=string.ascii_letters + string.digits, - min_size=(None if f.blank else 1), - max_size=f.max_length) - elif type(f) == dm.GenericIPAddressField: - lookup = {'both': ip4_addr_strings() | ip6_addr_strings(), - 'ipv4': ip4_addr_strings(), 'ipv6': ip6_addr_strings()} - strategy = lookup[f.protocol.lower()] - elif type(f) in (dm.TextField, dm.CharField): - strategy = st.text(min_size=(None if f.blank else 1), - max_size=f.max_length) - elif type(f) == dm.DecimalField: - bound = Decimal(10 ** f.max_digits - 1) / (10 ** f.decimal_places) - strategy = st.decimals(min_value=-bound, max_value=bound, - places=f.decimal_places) - else: - strategy = field_mappings().get(type(f), st.nothing()) - if f.validators: - strategy = strategy.filter(validator_to_filter(f)) - if f.null: - strategy = st.one_of(st.none(), strategy) - return strategy - - -def models(model, **extra): - """Return a strategy for instances of a model.""" - result = {k: v for k, v in extra.items() if v is not default_value} - missed = [] - for f in model._meta.concrete_fields: - if not (f.name in extra or isinstance(f, dm.AutoField)): - result[f.name] = _get_strategy_for_field(f) - if result[f.name].is_empty: - missed.append(f.name) - if missed: - raise InvalidArgument( - u'Missing arguments for mandatory field%s %s for model %s' - % (u's' if missed else u'', u', '.join(missed), model.__name__)) - return _models_impl(st.builds(model.objects.get_or_create, **result)) - - -@st.composite -def _models_impl(draw, strat): - """Handle the nasty part of drawing a value for models()""" - try: - return draw(strat)[0] - except IntegrityError: - reject() diff -Nru python-hypothesis-3.44.1/src/hypothesis/extra/fakefactory.py python-hypothesis-3.71.11/src/hypothesis/extra/fakefactory.py --- python-hypothesis-3.44.1/src/hypothesis/extra/fakefactory.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/extra/fakefactory.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,105 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import random as globalrandom -from random import Random - -import faker -from faker.factory import AVAILABLE_LOCALES - -from hypothesis._settings import note_deprecation -from hypothesis.internal.compat import text_type -from hypothesis.internal.reflection import check_valid_identifier -from hypothesis.searchstrategy.strategies import SearchStrategy - - -def fake_factory(source, locale=None, locales=None, providers=()): - note_deprecation( - 'hypothesis.extra.fakefactory has been deprecated, because it does ' - 'not support example discovery or shrinking. Consider using a lower-' - 'level strategy (such as st.text()) instead.' - ) - check_valid_identifier(source) - if source[0] == u'_': - raise ValueError(u'Bad source name %s' % (source,)) - - if locale is not None and locales is not None: - raise ValueError(u'Cannot specify both single and multiple locales') - if locale: - locales = (locale,) - elif locales: - locales = tuple(locales) - else: - locales = None - for l in (locales or ()): - if l not in AVAILABLE_LOCALES: - raise ValueError(u'Unsupported locale %r' % (l,)) - - def supports_source(locale): - test_faker = faker.Faker(locale) - for provider in providers: - test_faker.add_provider(provider) - return hasattr(test_faker, source) - - if locales is None: - locales = list(filter(supports_source, AVAILABLE_LOCALES)) - if not locales: - raise ValueError(u'No such source %r' % (source,)) - else: - for l in locales: - if not supports_source(locale): - raise ValueError(u'Unsupported source %s for locale %s' % ( - source, l - )) - return FakeFactoryStrategy(source, providers, locales) - - -class FakeFactoryStrategy(SearchStrategy): - - def __init__(self, source, providers, locales): - self.source = source - self.providers = tuple(providers) - self.locales = tuple(locales) - self.factories = {} - - def do_draw(self, data): - seed = data.draw_bytes(4) - random = Random(bytes(seed)) - return self.gen_example(random) - - def factory_for(self, locale): - try: - return self.factories[locale] - except KeyError: - pass - factory = faker.Faker(locale=locale) - self.factories[locale] = factory - for p in self.providers: - factory.add_provider(p) - return factory - - def gen_example(self, random): - factory = self.factory_for(random.choice(self.locales)) - original = globalrandom.getstate() - seed = random.getrandbits(128) - try: - factory.seed(seed) - return text_type(getattr(factory, self.source)()) - finally: - globalrandom.setstate(original) diff -Nru python-hypothesis-3.44.1/src/hypothesis/extra/__init__.py python-hypothesis-3.71.11/src/hypothesis/extra/__init__.py --- python-hypothesis-3.44.1/src/hypothesis/extra/__init__.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/extra/__init__.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER diff -Nru python-hypothesis-3.44.1/src/hypothesis/extra/numpy.py python-hypothesis-3.71.11/src/hypothesis/extra/numpy.py --- python-hypothesis-3.44.1/src/hypothesis/extra/numpy.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/extra/numpy.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,511 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import math - -import numpy as np - -import hypothesis.strategies as st -import hypothesis.internal.conjecture.utils as cu -from hypothesis.errors import InvalidArgument -from hypothesis.searchstrategy import SearchStrategy -from hypothesis.internal.compat import hrange, text_type -from hypothesis.internal.coverage import check_function -from hypothesis.internal.reflection import proxies - -TIME_RESOLUTIONS = tuple('Y M D h m s ms us ns ps fs as'.split()) - - -@st.defines_strategy_with_reusable_values -def from_dtype(dtype): - # Compound datatypes, eg 'f4,f4,f4' - if dtype.names is not None: - # mapping np.void.type over a strategy is nonsense, so return now. - return st.tuples( - *[from_dtype(dtype.fields[name][0]) for name in dtype.names]) - - # Subarray datatypes, eg '(2, 3)i4' - if dtype.subdtype is not None: - subtype, shape = dtype.subdtype - return arrays(subtype, shape) - - # Scalar datatypes - if dtype.kind == u'b': - result = st.booleans() - elif dtype.kind == u'f': - result = st.floats() - elif dtype.kind == u'c': - result = st.complex_numbers() - elif dtype.kind in (u'S', u'a'): - # Numpy strings are null-terminated; only allow round-trippable values. - # `itemsize == 0` means 'fixed length determined at array creation' - result = st.binary(max_size=dtype.itemsize or None - ).filter(lambda b: b[-1:] != b'\0') - elif dtype.kind == u'u': - result = st.integers(min_value=0, - max_value=2 ** (8 * dtype.itemsize) - 1) - elif dtype.kind == u'i': - overflow = 2 ** (8 * dtype.itemsize - 1) - result = st.integers(min_value=-overflow, max_value=overflow - 1) - elif dtype.kind == u'U': - # Encoded in UTF-32 (four bytes/codepoint) and null-terminated - result = st.text(max_size=(dtype.itemsize or 0) // 4 or None - ).filter(lambda b: b[-1:] != u'\0') - elif dtype.kind in (u'm', u'M'): - if '[' in dtype.str: - res = st.just(dtype.str.split('[')[-1][:-1]) - else: - res = st.sampled_from(TIME_RESOLUTIONS) - result = st.builds(dtype.type, st.integers(-2**63, 2**63 - 1), res) - else: - raise InvalidArgument(u'No strategy inference for {}'.format(dtype)) - return result.map(dtype.type) - - -@check_function -def check_argument(condition, fail_message, *f_args, **f_kwargs): - if not condition: - raise InvalidArgument(fail_message.format(*f_args, **f_kwargs)) - - -@check_function -def order_check(name, floor, small, large): - check_argument( - floor <= small, u'min_{name} must be at least {} but was {}', - floor, small, name=name - ) - check_argument( - small <= large, u'min_{name}={} is larger than max_{name}={}', - small, large, name=name - ) - - -class ArrayStrategy(SearchStrategy): - - def __init__(self, element_strategy, shape, dtype, fill, unique): - self.shape = tuple(shape) - self.fill = fill - check_argument(shape, - u'Array shape must have at least one dimension, ' - u'provided shape was {}', shape) - check_argument(all(isinstance(s, int) for s in shape), - u'Array shape must be integer in each dimension, ' - u'provided shape was {}', shape) - self.array_size = int(np.prod(shape)) - self.dtype = dtype - self.element_strategy = element_strategy - self.unique = unique - - def do_draw(self, data): - if 0 in self.shape: - return np.zeros(dtype=self.dtype, shape=self.shape) - - # This could legitimately be a np.empty, but the performance gains for - # that would be so marginal that there's really not much point risking - # undefined behaviour shenanigans. - result = np.zeros(shape=self.array_size, dtype=self.dtype) - - if self.fill.is_empty: - # We have no fill value (either because the user explicitly - # disabled it or because the default behaviour was used and our - # elements strategy does not produce reusable values), so we must - # generate a fully dense array with a freshly drawn value for each - # entry. - if self.unique: - seen = set() - elements = cu.many( - data, - min_size=self.array_size, max_size=self.array_size, - average_size=self.array_size - ) - i = 0 - while elements.more(): - # We assign first because this means we check for - # uniqueness after numpy has converted it to the relevant - # type for us. Because we don't increment the counter on - # a duplicate we will overwrite it on the next draw. - result[i] = data.draw(self.element_strategy) - if result[i] not in seen: - seen.add(result[i]) - i += 1 - else: - elements.reject() - else: - for i in hrange(len(result)): - result[i] = data.draw(self.element_strategy) - else: - # We draw numpy arrays as "sparse with an offset". We draw a - # collection of index assignments within the array and assign - # fresh values from our elements strategy to those indices. If at - # the end we have not assigned every element then we draw a single - # value from our fill strategy and use that to populate the - # remaining positions with that strategy. - - elements = cu.many( - data, - min_size=0, max_size=self.array_size, - # sqrt isn't chosen for any particularly principled reason. It - # just grows reasonably quickly but sublinearly, and for small - # arrays it represents a decent fraction of the array size. - average_size=math.sqrt(self.array_size), - ) - - needs_fill = np.full(self.array_size, True) - seen = set() - - while elements.more(): - i = cu.integer_range(data, 0, self.array_size - 1) - if not needs_fill[i]: - elements.reject() - continue - result[i] = data.draw(self.element_strategy) - if self.unique: - if result[i] in seen: - elements.reject() - continue - else: - seen.add(result[i]) - needs_fill[i] = False - if needs_fill.any(): - # We didn't fill all of the indices in the early loop, so we - # put a fill value into the rest. - - # We have to do this hilarious little song and dance to work - # around numpy's special handling of iterable values. If the - # value here were e.g. a tuple then neither array creation - # nor putmask would do the right thing. But by creating an - # array of size one and then assigning the fill value as a - # single element, we both get an array with the right value in - # it and putmask will do the right thing by repeating the - # values of the array across the mask. - one_element = np.zeros(shape=1, dtype=self.dtype) - one_element[0] = data.draw(self.fill) - fill_value = one_element[0] - if self.unique: - try: - is_nan = np.isnan(fill_value) - except TypeError: - is_nan = False - - if not is_nan: - raise InvalidArgument( - 'Cannot fill unique array with non-NaN ' - 'value %r' % (fill_value,)) - - np.putmask(result, needs_fill, one_element) - - return result.reshape(self.shape) - - -@check_function -def fill_for(elements, unique, fill, name=''): - if fill is None: - if unique or not elements.has_reusable_values: - fill = st.nothing() - else: - fill = elements - else: - st.check_strategy(fill, '%s.fill' % (name,) if name else 'fill') - return fill - - -@st.composite -def arrays( - draw, dtype, shape, elements=None, fill=None, unique=False -): - """Returns a strategy for generating :class:`numpy's - ndarrays`. - - * ``dtype`` may be any valid input to :class:`numpy.dtype ` - (this includes ``dtype`` objects), or a strategy that generates such - values. - * ``shape`` may be an integer >= 0, a tuple of length >= 0 of such - integers, or a strategy that generates such values. - * ``elements`` is a strategy for generating values to put in the array. - If it is None a suitable value will be inferred based on the dtype, - which may give any legal value (including eg ``NaN`` for floats). - If you have more specific requirements, you should supply your own - elements strategy. - * ``fill`` is a strategy that may be used to generate a single background - value for the array. If None, a suitable default will be inferred - based on the other arguments. If set to - :func:`st.nothing() ` then filling - behaviour will be disabled entirely and every element will be generated - independently. - * ``unique`` specifies if the elements of the array should all be - distinct from one another. Note that in this case multiple NaN values - may still be allowed. If fill is also set, the only valid values for - it to return are NaN values (anything for which :func:`numpy.isnan` - returns True. So e.g. for complex numbers (nan+1j) is also a valid fill). - Note that if unique is set to True the generated values must be hashable. - - Arrays of specified ``dtype`` and ``shape`` are generated for example - like this: - - .. code-block:: pycon - - >>> import numpy as np - >>> arrays(np.int8, (2, 3)).example() - array([[-8, 6, 3], - [-6, 4, 6]], dtype=int8) - - - See :doc:`What you can generate and how `. - - .. code-block:: pycon - - >>> import numpy as np - >>> from hypothesis.strategies import floats - >>> arrays(np.float, 3, elements=floats(0, 1)).example() - array([ 0.88974794, 0.77387938, 0.1977879 ]) - - Array values are generated in two parts: - - 1. Some subset of the coordinates of the array are populated with a value - drawn from the elements strategy (or its inferred form). - 2. If any coordinates were not assigned in the previous step, a single - value is drawn from the fill strategy and is assigned to all remaining - places. - - You can set fill to :func:`~hypothesis.strategies.nothing` if you want to - disable this behaviour and draw a value for every element. - - If fill is set to None then it will attempt to infer the correct behaviour - automatically: If unique is True, no filling will occur by default. - Otherwise, if it looks safe to reuse the values of elements across - multiple coordinates (this will be the case for any inferred strategy, and - for most of the builtins, but is not the case for mutable values or - strategies built with flatmap, map, composite, etc) then it will use the - elements strategy as the fill, else it will default to having no fill. - - Having a fill helps Hypothesis craft high quality examples, but its - main importance is when the array generated is large: Hypothesis is - primarily designed around testing small examples. If you have arrays with - hundreds or more elements, having a fill value is essential if you want - your tests to run in reasonable time. - - """ - if isinstance(dtype, SearchStrategy): - dtype = draw(dtype) - dtype = np.dtype(dtype) - if elements is None: - elements = from_dtype(dtype) - if isinstance(shape, SearchStrategy): - shape = draw(shape) - if isinstance(shape, int): - shape = (shape,) - shape = tuple(shape) - if not shape: - if dtype.kind != u'O': - return draw(elements) - fill = fill_for( - elements=elements, unique=unique, fill=fill - ) - return draw(ArrayStrategy(elements, shape, dtype, fill, unique)) - - -@st.defines_strategy -def array_shapes(min_dims=1, max_dims=3, min_side=1, max_side=10): - """Return a strategy for array shapes (tuples of int >= 1).""" - order_check('dims', 1, min_dims, max_dims) - order_check('side', 1, min_side, max_side) - return st.lists(st.integers(min_side, max_side), - min_size=min_dims, max_size=max_dims).map(tuple) - - -@st.defines_strategy -def scalar_dtypes(): - """Return a strategy that can return any non-flexible scalar dtype.""" - return st.one_of(boolean_dtypes(), - integer_dtypes(), unsigned_integer_dtypes(), - floating_dtypes(), complex_number_dtypes(), - datetime64_dtypes(), timedelta64_dtypes()) - - -def defines_dtype_strategy(strat): - @st.defines_strategy - @proxies(strat) - def inner(*args, **kwargs): - return strat(*args, **kwargs).map(np.dtype) - return inner - - -@defines_dtype_strategy -def boolean_dtypes(): - return st.just('?') - - -def dtype_factory(kind, sizes, valid_sizes, endianness): - # Utility function, shared logic for most integer and string types - valid_endian = ('?', '<', '=', '>') - check_argument(endianness in valid_endian, - u'Unknown endianness: was {}, must be in {}', - endianness, valid_endian) - if valid_sizes is not None: - if isinstance(sizes, int): - sizes = (sizes,) - check_argument(sizes, 'Dtype must have at least one possible size.') - check_argument(all(s in valid_sizes for s in sizes), - u'Invalid sizes: was {} must be an item or sequence ' - u'in {}', sizes, valid_sizes) - if all(isinstance(s, int) for s in sizes): - sizes = sorted(set(s // 8 for s in sizes)) - strat = st.sampled_from(sizes) - if '{}' not in kind: - kind += '{}' - if endianness == '?': - return strat.map(('<' + kind).format) | strat.map(('>' + kind).format) - return strat.map((endianness + kind).format) - - -@defines_dtype_strategy -def unsigned_integer_dtypes(endianness='?', sizes=(8, 16, 32, 64)): - """Return a strategy for unsigned integer dtypes. - - endianness may be ``<`` for little-endian, ``>`` for big-endian, - ``=`` for native byte order, or ``?`` to allow either byte order. - This argument only applies to dtypes of more than one byte. - - sizes must be a collection of integer sizes in bits. The default - (8, 16, 32, 64) covers the full range of sizes. - - """ - return dtype_factory('u', sizes, (8, 16, 32, 64), endianness) - - -@defines_dtype_strategy -def integer_dtypes(endianness='?', sizes=(8, 16, 32, 64)): - """Return a strategy for signed integer dtypes. - - endianness and sizes are treated as for - :func:`unsigned_integer_dtypes`. - - """ - return dtype_factory('i', sizes, (8, 16, 32, 64), endianness) - - -@defines_dtype_strategy -def floating_dtypes(endianness='?', sizes=(16, 32, 64)): - """Return a strategy for floating-point dtypes. - - sizes is the size in bits of floating-point number. Some machines support - 96- or 128-bit floats, but these are not generated by default. - - Larger floats (96 and 128 bit real parts) are not supported on all - platforms and therefore disabled by default. To generate these dtypes, - include these values in the sizes argument. - - """ - return dtype_factory('f', sizes, (16, 32, 64, 96, 128), endianness) - - -@defines_dtype_strategy -def complex_number_dtypes(endianness='?', sizes=(64, 128)): - """Return a strategy for complex-number dtypes. - - sizes is the total size in bits of a complex number, which consists - of two floats. Complex halfs (a 16-bit real part) are not supported - by numpy and will not be generated by this strategy. - - """ - return dtype_factory('c', sizes, (64, 128, 192, 256), endianness) - - -@check_function -def validate_time_slice(max_period, min_period): - check_argument(max_period in TIME_RESOLUTIONS, - u'max_period {} must be a valid resolution in {}', - max_period, TIME_RESOLUTIONS) - check_argument(min_period in TIME_RESOLUTIONS, - u'min_period {} must be a valid resolution in {}', - min_period, TIME_RESOLUTIONS) - start = TIME_RESOLUTIONS.index(max_period) - end = TIME_RESOLUTIONS.index(min_period) + 1 - check_argument(start < end, - u'max_period {} must be earlier in sequence {} than ' - u'min_period {}', max_period, TIME_RESOLUTIONS, min_period) - return TIME_RESOLUTIONS[start:end] - - -@defines_dtype_strategy -def datetime64_dtypes(max_period='Y', min_period='ns', endianness='?'): - """Return a strategy for datetime64 dtypes, with various precisions from - year to attosecond.""" - return dtype_factory('datetime64[{}]', - validate_time_slice(max_period, min_period), - TIME_RESOLUTIONS, endianness) - - -@defines_dtype_strategy -def timedelta64_dtypes(max_period='Y', min_period='ns', endianness='?'): - """Return a strategy for timedelta64 dtypes, with various precisions from - year to attosecond.""" - return dtype_factory('timedelta64[{}]', - validate_time_slice(max_period, min_period), - TIME_RESOLUTIONS, endianness) - - -@defines_dtype_strategy -def byte_string_dtypes(endianness='?', min_len=0, max_len=16): - """Return a strategy for generating bytestring dtypes, of various lengths - and byteorder.""" - order_check('len', 0, min_len, max_len) - return dtype_factory('S', list(range(min_len, max_len + 1)), - None, endianness) - - -@defines_dtype_strategy -def unicode_string_dtypes(endianness='?', min_len=0, max_len=16): - """Return a strategy for generating unicode string dtypes, of various - lengths and byteorder.""" - order_check('len', 0, min_len, max_len) - return dtype_factory('U', list(range(min_len, max_len + 1)), - None, endianness) - - -@defines_dtype_strategy -def array_dtypes(subtype_strategy=scalar_dtypes(), - min_size=1, max_size=5, allow_subarrays=False): - """Return a strategy for generating array (compound) dtypes, with members - drawn from the given subtype strategy.""" - order_check('size', 0, min_size, max_size) - native_strings = st.text if text_type is str else st.binary - elements = st.tuples(native_strings(), subtype_strategy) - if allow_subarrays: - elements |= st.tuples(native_strings(), subtype_strategy, - array_shapes(max_dims=2, max_side=2)) - return st.lists(elements=elements, min_size=min_size, max_size=max_size, - unique_by=lambda d: d[0]) - - -@st.defines_strategy -def nested_dtypes(subtype_strategy=scalar_dtypes(), - max_leaves=10, max_itemsize=None): - """Return the most-general dtype strategy. - - Elements drawn from this strategy may be simple (from the - subtype_strategy), or several such values drawn from - :func:`array_dtypes` with ``allow_subarrays=True``. Subdtypes in an - array dtype may be nested to any depth, subject to the max_leaves - argument. - - """ - return st.recursive(subtype_strategy, - lambda x: array_dtypes(x, allow_subarrays=True), - max_leaves).filter( - lambda d: max_itemsize is None or d.itemsize <= max_itemsize) diff -Nru python-hypothesis-3.44.1/src/hypothesis/extra/pandas/impl.py python-hypothesis-3.71.11/src/hypothesis/extra/pandas/impl.py --- python-hypothesis-3.44.1/src/hypothesis/extra/pandas/impl.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/extra/pandas/impl.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,645 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from copy import copy -from collections import Iterable, OrderedDict - -import attr -import numpy as np - -import pandas -import hypothesis.strategies as st -import hypothesis.extra.numpy as npst -import hypothesis.internal.conjecture.utils as cu -from hypothesis.errors import InvalidArgument -from hypothesis.control import reject -from hypothesis.internal.compat import hrange -from hypothesis.internal.coverage import check, check_function -from hypothesis.internal.validation import check_type, try_convert, \ - check_strategy, check_valid_size, check_valid_interval - -try: - from pandas.api.types import is_categorical_dtype -except ImportError: # pragma: no cover - def is_categorical_dtype(dt): - if isinstance(dt, np.dtype): - return False - return dt == 'category' - - -def dtype_for_elements_strategy(s): - return st.shared( - s.map(lambda x: pandas.Series([x]).dtype), - key=('hypothesis.extra.pandas.dtype_for_elements_strategy', s), - ) - - -def infer_dtype_if_necessary(dtype, values, elements, draw): - if dtype is None and not values: - return draw(dtype_for_elements_strategy(elements)) - return dtype - - -@check_function -def elements_and_dtype(elements, dtype, source=None): - - if source is None: - prefix = '' - else: - prefix = '%s.' % (source,) - - if elements is not None: - check_strategy(elements, '%selements' % (prefix,)) - else: - with check('dtype is not None'): - if dtype is None: - raise InvalidArgument(( - 'At least one of %(prefix)selements or %(prefix)sdtype ' - 'must be provided.') % {'prefix': prefix}) - - with check('is_categorical_dtype'): - if is_categorical_dtype(dtype): - raise InvalidArgument( - '%sdtype is categorical, which is currently unsupported' % ( - prefix, - )) - - dtype = try_convert(np.dtype, dtype, 'dtype') - - if elements is None: - elements = npst.from_dtype(dtype) - elif dtype is not None: - def convert_element(value): - name = 'draw(%selements)' % (prefix,) - try: - return np.array([value], dtype=dtype)[0] - except TypeError: - raise InvalidArgument( - 'Cannot convert %s=%r of type %s to dtype %s' % ( - name, value, type(value).__name__, dtype.str - ) - ) - except ValueError: - raise InvalidArgument( - 'Cannot convert %s=%r to type %s' % ( - name, value, dtype.str, - ) - ) - elements = elements.map(convert_element) - assert elements is not None - - return elements, dtype - - -class ValueIndexStrategy(st.SearchStrategy): - def __init__(self, elements, dtype, min_size, max_size, unique): - super(ValueIndexStrategy, self).__init__() - self.elements = elements - self.dtype = dtype - self.min_size = min_size - self.max_size = max_size - self.unique = unique - - def do_draw(self, data): - result = [] - seen = set() - - iterator = cu.many( - data, min_size=self.min_size, max_size=self.max_size, - average_size=(self.min_size + self.max_size) / 2 - ) - - while iterator.more(): - elt = data.draw(self.elements) - - if self.unique: - if elt in seen: - iterator.reject() - continue - seen.add(elt) - result.append(elt) - - dtype = infer_dtype_if_necessary( - dtype=self.dtype, values=result, elements=self.elements, - draw=data.draw - ) - return pandas.Index(result, dtype=dtype, tupleize_cols=False) - - -DEFAULT_MAX_SIZE = 10 - - -@st.cacheable -@st.defines_strategy -def range_indexes(min_size=0, max_size=None): - """Provides a strategy which generates an :class:`~pandas.Index` whose - values are 0, 1, ..., n for some n. - - Arguments: - - * min_size is the smallest number of elements the index can have. - * max_size is the largest number of elements the index can have. If None - it will default to some suitable value based on min_size. - - """ - check_valid_size(min_size, 'min_size') - check_valid_size(max_size, 'max_size') - if max_size is None: - max_size = min([min_size + DEFAULT_MAX_SIZE, 2 ** 63 - 1]) - check_valid_interval(min_size, max_size, 'min_size', 'max_size') - return st.integers(min_size, max_size).map(pandas.RangeIndex) - - -@st.cacheable -@st.defines_strategy -def indexes( - elements=None, dtype=None, min_size=0, max_size=None, unique=True, -): - """Provides a strategy for producing a :class:`pandas.Index`. - - Arguments: - - * elements is a strategy which will be used to generate the individual - values of the index. If None, it will be inferred from the dtype. Note: - even if the elements strategy produces tuples, the generated value - will not be a MultiIndex, but instead be a normal index whose elements - are tuples. - * dtype is the dtype of the resulting index. If None, it will be inferred - from the elements strategy. At least one of dtype or elements must be - provided. - * min_size is the minimum number of elements in the index. - * max_size is the maximum number of elements in the index. If None then it - will default to a suitable small size. If you want larger indexes you - should pass a max_size explicitly. - * unique specifies whether all of the elements in the resulting index - should be distinct. - - """ - check_valid_size(min_size, 'min_size') - check_valid_size(max_size, 'max_size') - check_valid_interval(min_size, max_size, 'min_size', 'max_size') - check_type(bool, unique, 'unique') - - elements, dtype = elements_and_dtype(elements, dtype) - - if max_size is None: - max_size = min_size + DEFAULT_MAX_SIZE - return ValueIndexStrategy( - elements, dtype, min_size, max_size, unique) - - -@st.defines_strategy -def series(elements=None, dtype=None, index=None, fill=None, unique=False): - """Provides a strategy for producing a :class:`pandas.Series`. - - Arguments: - - * elements: a strategy that will be used to generate the individual - values in the series. If None, we will attempt to infer a suitable - default from the dtype. - - * dtype: the dtype of the resulting series and may be any value - that can be passed to :class:`numpy.dtype`. If None, will use - pandas's standard behaviour to infer it from the type of the elements - values. Note that if the type of values that comes out of your - elements strategy varies, then so will the resulting dtype of the - series. - - * index: If not None, a strategy for generating indexes for the - resulting Series. This can generate either :class:`pandas.Index` - objects or any sequence of values (which will be passed to the - Index constructor). - - You will probably find it most convenient to use the - :func:`~hypothesis.extra.pandas.indexes` or - :func:`~hypothesis.extra.pandas.range_indexes` function to produce - values for this argument. - - Usage: - - .. code-block:: pycon - - >>> series(dtype=int).example() - 0 -2001747478 - 1 1153062837 - - """ - if index is None: - index = range_indexes() - else: - check_strategy(index) - - elements, dtype = elements_and_dtype(elements, dtype) - index_strategy = index - - @st.composite - def result(draw): - index = draw(index_strategy) - - if len(index) > 0: - if dtype is not None: - result_data = draw(npst.arrays( - dtype=dtype, elements=elements, shape=len(index), - fill=fill, unique=unique, - )) - else: - result_data = list(draw(npst.arrays( - dtype=object, elements=elements, shape=len(index), - fill=fill, unique=unique, - ))) - - return pandas.Series( - result_data, index=index, dtype=dtype - ) - else: - return pandas.Series( - (), index=index, - dtype=dtype if dtype is not None else draw( - dtype_for_elements_strategy(elements))) - - return result() - - -@attr.s(slots=True) -class column(object): - """Data object for describing a column in a DataFrame. - - Arguments: - - * name: the column name, or None to default to the column position. Must - be hashable, but can otherwise be any value supported as a pandas column - name. - * elements: the strategy for generating values in this column, or None - to infer it from the dtype. - * dtype: the dtype of the column, or None to infer it from the element - strategy. At least one of dtype or elements must be provided. - * fill: A default value for elements of the column. See - :func:`~hypothesis.extra.numpy.arrays` for a full explanation. - * unique: If all values in this column should be distinct. - - """ - - name = attr.ib(default=None) - elements = attr.ib(default=None) - dtype = attr.ib(default=None) - fill = attr.ib(default=None) - unique = attr.ib(default=False) - - -def columns( - names_or_number, dtype=None, elements=None, fill=None, unique=False -): - """A convenience function for producing a list of :class:`column` objects - of the same general shape. - - The names_or_number argument is either a sequence of values, the - elements of which will be used as the name for individual column - objects, or a number, in which case that many unnamed columns will - be created. All other arguments are passed through verbatim to - create the columns. - - """ - try: - names = list(names_or_number) - except TypeError: - names = [None] * names_or_number - return [ - column( - name=n, dtype=dtype, elements=elements, fill=fill, unique=unique - ) for n in names - ] - - -@st.defines_strategy -def data_frames( - columns=None, rows=None, index=None -): - """Provides a strategy for producing a :class:`pandas.DataFrame`. - - Arguments: - - * columns: An iterable of :class:`column` objects describing the shape - of the generated DataFrame. - - * rows: A strategy for generating a row object. Should generate - either dicts mapping column names to values or a sequence mapping - column position to the value in that position (note that unlike the - :class:`pandas.DataFrame` constructor, single values are not allowed - here. Passing e.g. an integer is an error, even if there is only one - column). - - At least one of rows and columns must be provided. If both are - provided then the generated rows will be validated against the - columns and an error will be raised if they don't match. - - Caveats on using rows: - - * In general you should prefer using columns to rows, and only use - rows if the columns interface is insufficiently flexible to - describe what you need - you will get better performance and - example quality that way. - * If you provide rows and not columns, then the shape and dtype of - the resulting DataFrame may vary. e.g. if you have a mix of int - and float in the values for one column in your row entries, the - column will sometimes have an integral dtype and sometimes a float. - - * index: If not None, a strategy for generating indexes for the - resulting DataFrame. This can generate either :class:`pandas.Index` - objects or any sequence of values (which will be passed to the - Index constructor). - - You will probably find it most convenient to use the - :func:`~hypothesis.extra.pandas.indexes` or - :func:`~hypothesis.extra.pandas.range_indexes` function to produce - values for this argument. - - Usage: - - The expected usage pattern is that you use :class:`column` and - :func:`columns` to specify a fixed shape of the DataFrame you want as - follows. For example the following gives a two column data frame: - - .. code-block:: pycon - - >>> from hypothesis.extra.pandas import column, data_frames - >>> data_frames([ - ... column('A', dtype=int), column('B', dtype=float)]).example() - A B - 0 2021915903 1.793898e+232 - 1 1146643993 inf - 2 -2096165693 1.000000e+07 - - If you want the values in different columns to interact in some way you - can use the rows argument. For example the following gives a two column - DataFrame where the value in the first column is always at most the value - in the second: - - .. code-block:: pycon - - >>> from hypothesis.extra.pandas import column, data_frames - >>> import hypothesis.strategies as st - >>> data_frames( - ... rows=st.tuples(st.floats(allow_nan=False), - ... st.floats(allow_nan=False)).map(sorted) - ... ).example() - 0 1 - 0 -3.402823e+38 9.007199e+15 - 1 -1.562796e-298 5.000000e-01 - - You can also combine the two: - - .. code-block:: pycon - - >>> from hypothesis.extra.pandas import columns, data_frames - >>> import hypothesis.strategies as st - >>> data_frames( - ... columns=columns(["lo", "hi"], dtype=float), - ... rows=st.tuples(st.floats(allow_nan=False), - ... st.floats(allow_nan=False)).map(sorted) - ... ).example() - lo hi - 0 9.314723e-49 4.353037e+45 - 1 -9.999900e-01 1.000000e+07 - 2 -2.152861e+134 -1.069317e-73 - - (Note that the column dtype must still be specified and will not be - inferred from the rows. This restriction may be lifted in future). - - Combining rows and columns has the following behaviour: - - * The column names and dtypes will be used. - * If the column is required to be unique, this will be enforced. - * Any values missing from the generated rows will be provided using the - column's fill. - * Any values in the row not present in the column specification (if - dicts are passed, if there are keys with no corresponding column name, - if sequences are passed if there are too many items) will result in - InvalidArgument being raised. - - """ - - if index is None: - index = range_indexes() - else: - check_strategy(index) - - index_strategy = index - - if columns is None: - if rows is None: - raise InvalidArgument( - 'At least one of rows and columns must be provided' - ) - else: - @st.composite - def rows_only(draw): - index = draw(index_strategy) - - @check_function - def row(): - result = draw(rows) - check_type(Iterable, result, 'draw(row)') - return result - - if len(index) > 0: - return pandas.DataFrame( - [row() for _ in index], - index=index - ) - else: - # If we haven't drawn any rows we need to draw one row and - # then discard it so that we get a consistent shape for the - # DataFrame. - base = pandas.DataFrame([row()]) - return base.drop(0) - return rows_only() - - assert columns is not None - columns = try_convert(tuple, columns, 'columns') - - rewritten_columns = [] - column_names = set() - - for i, c in enumerate(columns): - check_type(column, c, 'columns[%d]' % (i,)) - - c = copy(c) - if c.name is None: - label = 'columns[%d]' % (i,) - c.name = i - else: - label = c.name - try: - hash(c.name) - except TypeError: - raise InvalidArgument( - 'Column names must be hashable, but columns[%d].name was ' - '%r of type %s, which cannot be hashed.' % ( - i, c.name, type(c.name).__name__,)) - - if c.name in column_names: - raise InvalidArgument( - 'duplicate definition of column name %r' % (c.name,)) - - column_names.add(c.name) - - c.elements, c.dtype = elements_and_dtype( - c.elements, c.dtype, label - ) - - if c.dtype is None and rows is not None: - raise InvalidArgument( - 'Must specify a dtype for all columns when combining rows with' - ' columns.' - ) - - c.fill = npst.fill_for( - fill=c.fill, elements=c.elements, unique=c.unique, - name=label - ) - - rewritten_columns.append(c) - - if rows is None: - @st.composite - def just_draw_columns(draw): - index = draw(index_strategy) - local_index_strategy = st.just(index) - - data = OrderedDict((c.name, None) for c in rewritten_columns) - - # Depending on how the columns are going to be generated we group - # them differently to get better shrinking. For columns with fill - # enabled, the elements can be shrunk independently of the size, - # so we can just shrink by shrinking the index then shrinking the - # length and are generally much more free to move data around. - - # For columns with no filling the problem is harder, and drawing - # them like that would result in rows being very far apart from - # each other in the underlying data stream, which gets in the way - # of shrinking. So what we do is reorder and draw those columns - # row wise, so that the values of each row are next to each other. - # This makes life easier for the shrinker when deleting blocks of - # data. - columns_without_fill = [ - c for c in rewritten_columns if c.fill.is_empty] - - if columns_without_fill: - for c in columns_without_fill: - data[c.name] = pandas.Series( - np.zeros(shape=len(index), dtype=c.dtype), - index=index, - ) - seen = { - c.name: set() for c in columns_without_fill if c.unique} - - for i in hrange(len(index)): - for c in columns_without_fill: - if c.unique: - for _ in range(5): - value = draw(c.elements) - if value not in seen[c.name]: - seen[c.name].add(value) - break - else: - reject() - else: - value = draw(c.elements) - data[c.name][i] = value - - for c in rewritten_columns: - if not c.fill.is_empty: - data[c.name] = draw(series( - index=local_index_strategy, dtype=c.dtype, - elements=c.elements, fill=c.fill, unique=c.unique)) - - return pandas.DataFrame(data, index=index) - return just_draw_columns() - else: - @st.composite - def assign_rows(draw): - index = draw(index_strategy) - - result = pandas.DataFrame(OrderedDict( - (c.name, pandas.Series( - np.zeros(dtype=c.dtype, shape=len(index)), dtype=c.dtype)) - for c in rewritten_columns - ), index=index) - - fills = {} - - any_unique = any(c.unique for c in rewritten_columns) - - if any_unique: - all_seen = [ - set() if c.unique else None for c in rewritten_columns] - while all_seen[-1] is None: - all_seen.pop() - - for row_index in hrange(len(index)): - for _ in hrange(5): - original_row = draw(rows) - row = original_row - if isinstance(row, dict): - as_list = [None] * len(rewritten_columns) - for i, c in enumerate(rewritten_columns): - try: - as_list[i] = row[c.name] - except KeyError: - try: - as_list[i] = fills[i] - except KeyError: - fills[i] = draw(c.fill) - as_list[i] = fills[i] - for k in row: - if k not in column_names: - raise InvalidArgument(( - 'Row %r contains column %r not in ' - 'columns %r)' % ( - row, k, [ - c.name for c in rewritten_columns - ]))) - row = as_list - if any_unique: - has_duplicate = False - for seen, value in zip(all_seen, row): - if seen is None: - continue - if value in seen: - has_duplicate = True - break - seen.add(value) - if has_duplicate: - continue - row = list(try_convert(tuple, row, 'draw(rows)')) - - if len(row) > len(rewritten_columns): - raise InvalidArgument(( - 'Row %r contains too many entries. Has %d but ' - 'expected at most %d') % ( - original_row, len(row), len(rewritten_columns) - )) - while len(row) < len(rewritten_columns): - row.append(draw(rewritten_columns[len(row)].fill)) - result.iloc[row_index] = row - break - else: - reject() - return result - return assign_rows() diff -Nru python-hypothesis-3.44.1/src/hypothesis/extra/pandas/__init__.py python-hypothesis-3.71.11/src/hypothesis/extra/pandas/__init__.py --- python-hypothesis-3.44.1/src/hypothesis/extra/pandas/__init__.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/extra/pandas/__init__.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from hypothesis.extra.pandas.impl import series, data_frames, column, columns,\ - indexes, range_indexes - -__all__ = [ - 'indexes', 'range_indexes', - 'series', - 'column', 'columns', - 'data_frames', -] diff -Nru python-hypothesis-3.44.1/src/hypothesis/extra/pytestplugin.py python-hypothesis-3.71.11/src/hypothesis/extra/pytestplugin.py --- python-hypothesis-3.44.1/src/hypothesis/extra/pytestplugin.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/extra/pytestplugin.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,161 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import pytest - -import hypothesis.core as core -from hypothesis.reporting import default as default_reporter -from hypothesis.reporting import with_reporter -from hypothesis.statistics import collector -from hypothesis.internal.compat import OrderedDict, text_type -from hypothesis.internal.detection import is_hypothesis_test - -LOAD_PROFILE_OPTION = '--hypothesis-profile' -PRINT_STATISTICS_OPTION = '--hypothesis-show-statistics' -SEED_OPTION = '--hypothesis-seed' - - -class StoringReporter(object): - - def __init__(self, config): - self.config = config - self.results = [] - - def __call__(self, msg): - if self.config.getoption('capture', 'fd') == 'no': - default_reporter(msg) - if not isinstance(msg, text_type): - msg = repr(msg) - self.results.append(msg) - - -def pytest_addoption(parser): - group = parser.getgroup('hypothesis', 'Hypothesis') - group.addoption( - LOAD_PROFILE_OPTION, - action='store', - help='Load in a registered hypothesis.settings profile' - ) - group.addoption( - PRINT_STATISTICS_OPTION, - action='store_true', - help='Configure when statistics are printed', - default=False - ) - group.addoption( - SEED_OPTION, - action='store', - help='Set a seed to use for all Hypothesis tests' - ) - - -def pytest_configure(config): - core.running_under_pytest = True - from hypothesis import settings - profile = config.getoption(LOAD_PROFILE_OPTION) - if profile: - settings.load_profile(profile) - seed = config.getoption(SEED_OPTION) - if seed is not None: - try: - seed = int(seed) - except ValueError: - pass - core.global_force_seed = seed - config.addinivalue_line( - 'markers', - 'hypothesis: Tests which use hypothesis.') - - -gathered_statistics = OrderedDict() - - -@pytest.mark.hookwrapper -def pytest_runtest_call(item): - if not (hasattr(item, 'obj') and is_hypothesis_test(item.obj)): - yield - else: - store = StoringReporter(item.config) - - def note_statistics(stats): - gathered_statistics[item.nodeid] = stats - - with collector.with_value(note_statistics): - with with_reporter(store): - yield - if store.results: - item.hypothesis_report_information = list(store.results) - - -@pytest.mark.hookwrapper -def pytest_runtest_makereport(item, call): - report = (yield).get_result() - if hasattr(item, 'hypothesis_report_information'): - report.sections.append(( - 'Hypothesis', - '\n'.join(item.hypothesis_report_information) - )) - - -def pytest_terminal_summary(terminalreporter): - if not terminalreporter.config.getoption(PRINT_STATISTICS_OPTION): - return - terminalreporter.section('Hypothesis Statistics') - for name, statistics in gathered_statistics.items(): - terminalreporter.write_line(name + ':') - terminalreporter.write_line('') - - if not statistics.has_runs: - terminalreporter.write_line(' - Test was never run') - continue - - terminalreporter.write_line(( - ' - %d passing examples, %d failing examples,' - ' %d invalid examples') % ( - statistics.passing_examples, statistics.failing_examples, - statistics.invalid_examples, - )) - terminalreporter.write_line( - ' - Typical runtimes: %s' % (statistics.runtimes,) - ) - terminalreporter.write_line( - ' - Fraction of time spent in data generation: %s' % ( - statistics.draw_time_percentage,)) - terminalreporter.write_line( - ' - Stopped because %s' % (statistics.exit_reason,) - ) - if statistics.events: - terminalreporter.write_line(' - Events:') - for event in statistics.events: - terminalreporter.write_line( - ' * %s' % (event,) - ) - terminalreporter.write_line('') - - -def pytest_collection_modifyitems(items): - for item in items: - if not isinstance(item, pytest.Function): - continue - if getattr(item.function, 'is_hypothesis_test', False): - item.add_marker('hypothesis') - - -def load(): - pass diff -Nru python-hypothesis-3.44.1/src/hypothesis/extra/pytz.py python-hypothesis-3.71.11/src/hypothesis/extra/pytz.py --- python-hypothesis-3.44.1/src/hypothesis/extra/pytz.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/extra/pytz.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,57 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -"""This module provides ``pytz`` timezones. - -You can use this strategy to make -:py:func:`hypothesis.strategies.datetimes` and -:py:func:`hypothesis.strategies.times` produce timezone-aware values. - -""" - -from __future__ import division, print_function, absolute_import - -import datetime as dt - -import pytz - -import hypothesis.strategies as st - -__all__ = ['timezones'] - - -@st.cacheable -@st.defines_strategy -def timezones(): - """Any timezone in the Olsen database, as a pytz tzinfo object. - - This strategy minimises to UTC, or the smallest possible fixed - offset, and is designed for use with - :py:func:`hypothesis.strategies.datetimes`. - - """ - all_timezones = [pytz.timezone(tz) for tz in pytz.all_timezones] - # Some timezones have always had a constant offset from UTC. This makes - # them simpler than timezones with daylight savings, and the smaller the - # absolute offset the simpler they are. Of course, UTC is even simpler! - static = [pytz.UTC] + sorted( - (t for t in all_timezones if isinstance(t, pytz.tzfile.StaticTzInfo)), - key=lambda tz: abs(tz.utcoffset(dt.datetime(2000, 1, 1))) - ) - # Timezones which have changed UTC offset; best ordered by name. - dynamic = [tz for tz in all_timezones if tz not in static] - return st.sampled_from(static + dynamic) diff -Nru python-hypothesis-3.44.1/src/hypothesis/__init__.py python-hypothesis-3.71.11/src/hypothesis/__init__.py --- python-hypothesis-3.44.1/src/hypothesis/__init__.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/__init__.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,55 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -"""Hypothesis is a library for writing unit tests which are parametrized by -some source of data. - -It verifies your code against a wide range of input and minimizes any -failing examples it finds. - -""" - - -from hypothesis._settings import settings, Verbosity, Phase, HealthCheck, \ - unlimited -from hypothesis.version import __version_info__, __version__ -from hypothesis.control import assume, note, reject, event -from hypothesis.core import given, find, example, seed, reproduce_failure, \ - PrintSettings -from hypothesis.utils.conventions import infer - - -__all__ = [ - 'settings', - 'Verbosity', - 'HealthCheck', - 'Phase', - 'PrintSettings', - 'assume', - 'reject', - 'seed', - 'given', - 'unlimited', - 'reproduce_failure', - 'find', - 'example', - 'note', - 'event', - 'infer', - '__version__', - '__version_info__', -] diff -Nru python-hypothesis-3.44.1/src/hypothesis/internal/cache.py python-hypothesis-3.71.11/src/hypothesis/internal/cache.py --- python-hypothesis-3.44.1/src/hypothesis/internal/cache.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/internal/cache.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,228 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import attr - - -@attr.s(slots=True) -class Entry(object): - key = attr.ib() - value = attr.ib() - score = attr.ib() - - -class GenericCache(object): - """Generic supertype for cache implementations. - - Defines a dict-like mapping with a maximum size, where as well as mapping - to a value, each key also maps to a score. When a write would cause the - dict to exceed its maximum size, it first evicts the existing key with - the smallest score, then adds the new key to the map. - - A key has the following lifecycle: - - 1. key is written for the first time, the key is given the score - self.new_entry(key, value) - 2. whenever an existing key is read or written, self.on_access(key, value, - score) is called. This returns a new score for the key. - 3. When a key is evicted, self.on_evict(key, value, score) is called. - - The cache will be in a valid state in all of these cases. - - Implementations are expected to implement new_entry and optionally - on_access and on_evict to implement a specific scoring strategy. - - """ - __slots__ = ('keys_to_indices', 'data', 'max_size') - - def __init__(self, max_size): - self.max_size = max_size - - # Implementation: We store a binary heap of Entry objects in self.data, - # with the heap property requiring that a parent's score is <= that of - # its children. keys_to_index then maps keys to their index in the - # heap. We keep these two in sync automatically - the heap is never - # reordered without updating the index. - self.keys_to_indices = {} - self.data = [] - - def __len__(self): - assert len(self.keys_to_indices) == len(self.data) - return len(self.data) - - def __getitem__(self, key): - i = self.keys_to_indices[key] - result = self.data[i] - self.on_access(result.key, result.value, result.score) - self.__balance(i) - return result.value - - def __setitem__(self, key, value): - if self.max_size == 0: - return - evicted = None - try: - i = self.keys_to_indices[key] - except KeyError: - entry = Entry(key, value, self.new_entry(key, value)) - if len(self.data) >= self.max_size: - evicted = self.data[0] - del self.keys_to_indices[evicted.key] - i = 0 - self.data[0] = entry - else: - i = len(self.data) - self.data.append(entry) - self.keys_to_indices[key] = i - else: - entry = self.data[i] - assert entry.key == key - entry.value = value - entry.score = self.on_access(entry.key, entry.value, entry.score) - - self.__balance(i) - - if evicted is not None: - if self.data[0] is not entry: - assert evicted.score <= self.data[0].score - self.on_evict(evicted.key, evicted.value, evicted.score) - - def clear(self): - del self.data[:] - self.keys_to_indices.clear() - - def __repr__(self): - return '{%s}' % (', '.join( - '%r: %r' % (e.key, e.value) for e in self.data),) - - def new_entry(self, key, value): - """Called when a key is written that does not currently appear in the - map. - - Returns the score to associate with the key. - - """ - raise NotImplementedError() - - def on_access(self, key, value, score): - """Called every time a key that is already in the map is read or - written. - - Returns the new score for the key. - - """ - return score - - def on_evict(self, key, value, score): - """Called after a key has been evicted, with the score it had had at - the point of eviction.""" - pass - - def check_valid(self): - """Debugging method for use in tests. - - Asserts that all of the cache's invariants hold. When everything - is working correctly this should be an expensive no-op. - - """ - - for i, e in enumerate(self.data): - assert self.keys_to_indices[e.key] == i - for j in [i * 2 + 1, i * 2 + 2]: - if j < len(self.data): - assert e.score <= self.data[j].score, self.data - - def __swap(self, i, j): - assert i < j - assert self.data[j].score < self.data[i].score - self.data[i], self.data[j] = self.data[j], self.data[i] - self.keys_to_indices[self.data[i].key] = i - self.keys_to_indices[self.data[j].key] = j - - def __balance(self, i): - """When we have made a modification to the heap such that means that - the heap property has been violated locally around i but previously - held for all other indexes (and no other values have been modified), - this fixes the heap so that the heap property holds everywhere.""" - - while i > 0: - parent = (i - 1) // 2 - if self.__out_of_order(parent, i): - self.__swap(parent, i) - i = parent - else: - break - while True: - children = [ - j for j in (2 * i + 1, 2 * i + 2) - if j < len(self.data) - ] - if len(children) == 2: - children.sort(key=lambda j: self.data[j].score) - for j in children: - if self.__out_of_order(i, j): - self.__swap(i, j) - i = j - break - else: - break - - def __out_of_order(self, i, j): - """Returns True if the indices i, j are in the wrong order. - - i must be the parent of j. - - """ - - assert i == (j - 1) // 2 - return self.data[j].score < self.data[i].score - - -class LRUReusedCache(GenericCache): - """The only concrete implementation of GenericCache we use outside of tests - currently. - - Adopts a modified least-frequently used eviction policy: It evicts the key - that has been used least recently, but it will always preferentially evict - keys that have only ever been accessed once. Among keys that have been - accessed more than once, it ignores the number of accesses. - - This retains most of the benefits of an LRU cache, but adds an element of - scan-resistance to the process: If we end up scanning through a large - number of keys without reusing them, this does not evict the existing - entries in preference for the new ones. - - """ - __slots__ = ('__tick',) - - def __init__(self, max_size, ): - super(LRUReusedCache, self).__init__(max_size) - self.__tick = 0 - - def tick(self): - self.__tick += 1 - return self.__tick - - def new_entry(self, key, value): - return [1, self.tick()] - - def on_access(self, key, value, score): - score[0] = 2 - score[1] = self.tick() - return score diff -Nru python-hypothesis-3.44.1/src/hypothesis/internal/charmap.py python-hypothesis-3.71.11/src/hypothesis/internal/charmap.py --- python-hypothesis-3.44.1/src/hypothesis/internal/charmap.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/internal/charmap.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,336 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import os -import sys -import gzip -import pickle -import tempfile -import unicodedata - -from hypothesis.configuration import tmpdir, storage_directory -from hypothesis.internal.compat import hunichr - - -def charmap_file(): - return os.path.join( - storage_directory('unicodedata', unicodedata.unidata_version), - 'charmap.pickle.gz' - ) - - -_charmap = None - - -def charmap(): - """Return a dict that maps a Unicode category, to a tuple of 2-tuples - covering the codepoint intervals for characters in that category. - - >>> charmap()['Co'] - ((57344, 63743), (983040, 1048573), (1048576, 1114109)) - - """ - global _charmap - # Best-effort caching in the face of missing files and/or unwritable - # filesystems is fairly simple: check if loaded, else try loading, - # else calculate and try writing the cache. - if _charmap is None: - f = charmap_file() - try: - with gzip.GzipFile(f, 'rb') as i: - _charmap = dict(pickle.load(i)) - - except Exception: - tmp_charmap = {} - for i in range(0, sys.maxunicode + 1): - cat = unicodedata.category(hunichr(i)) - rs = tmp_charmap.setdefault(cat, []) - if rs and rs[-1][-1] == i - 1: - rs[-1][-1] += 1 - else: - rs.append([i, i]) - _charmap = {k: tuple(tuple(pair) for pair in pairs) - for k, pairs in tmp_charmap.items()} - - try: - # Write the Unicode table atomically - fd, tmpfile = tempfile.mkstemp(dir=tmpdir()) - os.close(fd) - # Explicitly set the mtime to get reproducible output - with gzip.GzipFile(tmpfile, 'wb', mtime=1) as o: - pickle.dump(sorted(_charmap.items()), o, - pickle.HIGHEST_PROTOCOL) - os.rename(tmpfile, f) - except Exception: # pragma: no cover - pass - assert _charmap is not None - return _charmap - - -_categories = None - - -def categories(): - """Return a tuple of Unicode categories in a normalised order. - - >>> categories() # doctest: +ELLIPSIS - ('Zl', 'Zp', 'Co', 'Me', 'Pc', ..., 'Cc', 'Cs') - - """ - global _categories - if _categories is None: - cm = charmap() - _categories = sorted( - cm.keys(), key=lambda c: len(cm[c]) - ) - _categories.remove('Cc') # Other, Control - _categories.remove('Cs') # Other, Surrogate - _categories.append('Cc') - _categories.append('Cs') - return tuple(_categories) - - -def _union_intervals(x, y): - """Merge two sequences of intervals into a single tuple of intervals. - - Any integer bounded by `x` or `y` is also bounded by the result. - - >>> _union_intervals([(3, 10)], [(1, 2), (5, 17)]) - ((1, 17),) - - """ - if not x: - return tuple((u, v) for u, v in y) - if not y: - return tuple((u, v) for u, v in x) - intervals = sorted(x + y, reverse=True) - result = [intervals.pop()] - while intervals: - # 1. intervals is in descending order - # 2. pop() takes from the RHS. - # 3. (a, b) was popped 1st, then (u, v) was popped 2nd - # 4. Therefore: a <= u - # 5. We assume that u <= v and a <= b - # 6. So we need to handle 2 cases of overlap, and one disjoint case - # | u--v | u----v | u--v | - # | a----b | a--b | a--b | - u, v = intervals.pop() - a, b = result[-1] - if u <= b + 1: - # Overlap cases - result[-1] = (a, max(v, b)) - else: - # Disjoint case - result.append((u, v)) - return tuple(result) - - -def _subtract_intervals(x, y): - """Set difference for lists of intervals. That is, returns a list of - intervals that bounds all values bounded by x that are not also bounded by - y. x and y are expected to be in sorted order. - - For example _subtract_intervals([(1, 10)], [(2, 3), (9, 15)]) would - return [(1, 1), (4, 8)], removing the values 2, 3, 9 and 10 from the - interval. - - """ - if not y: - return tuple(x) - x = list(map(list, x)) - i = 0 - j = 0 - result = [] - while i < len(x) and j < len(y): - # Iterate in parallel over x and y. j stays pointing at the smallest - # interval in the left hand side that could still overlap with some - # element of x at index >= i. - # Similarly, i is not incremented until we know that it does not - # overlap with any element of y at index >= j. - - xl, xr = x[i] - assert xl <= xr - yl, yr = y[j] - assert yl <= yr - - if yr < xl: - # The interval at y[j] is strictly to the left of the interval at - # x[i], so will not overlap with it or any later interval of x. - j += 1 - elif yl > xr: - # The interval at y[j] is strictly to the right of the interval at - # x[i], so all of x[i] goes into the result as no further intervals - # in y will intersect it. - result.append(x[i]) - i += 1 - elif yl <= xl: - if yr >= xr: - # x[i] is contained entirely in y[j], so we just skip over it - # without adding it to the result. - i += 1 - else: - # The beginning of x[i] is contained in y[j], so we update the - # left endpoint of x[i] to remove this, and increment j as we - # now have moved past it. Note that this is not added to the - # result as is, as more intervals from y may intersect it so it - # may need updating further. - x[i][0] = yr + 1 - j += 1 - else: - # yl > xl, so the left hand part of x[i] is not contained in y[j], - # so there are some values we should add to the result. - result.append((xl, yl - 1)) - - if yr + 1 <= xr: - # If y[j] finishes before x[i] does, there may be some values - # in x[i] left that should go in the result (or they may be - # removed by a later interval in y), so we update x[i] to - # reflect that and increment j because it no longer overlaps - # with any remaining element of x. - x[i][0] = yr + 1 - j += 1 - else: - # Every element of x[i] other than the initial part we have - # already added is contained in y[j], so we move to the next - # interval. - i += 1 - # Any remaining intervals in x do not overlap with any of y, as if they did - # we would not have incremented j to the end, so can be added to the result - # as they are. - result.extend(x[i:]) - return tuple(map(tuple, result)) - - -def _intervals(s): - """Return a tuple of intervals, covering the codepoints of characters in - `s`. - - >>> _intervals('abcdef0123456789') - ((48, 57), (97, 102)) - - """ - intervals = tuple((ord(c), ord(c)) for c in sorted(s)) - return _union_intervals(intervals, intervals) - - -category_index_cache = { - (): (), -} - - -def _category_key(exclude, include): - """Return a normalised tuple of all Unicode categories that are in - `include`, but not in `exclude`. - - If include is None then default to including all categories. - Any item in include that is not a unicode character will be excluded. - - >>> _category_key(exclude=['So'], include=['Lu', 'Me', 'Cs', 'So', 'Xx']) - ('Me', 'Lu', 'Cs') - - """ - cs = categories() - if include is None: - include = set(cs) - else: - include = set(include) - exclude = set(exclude or ()) - include -= exclude - result = tuple(c for c in cs if c in include) - return result - - -def _query_for_key(key): - """Return a tuple of codepoint intervals covering characters that match one - or more categories in the tuple of categories `key`. - - >>> _query_for_key(categories()) - ((0, 1114111),) - >>> _query_for_key(('Zl', 'Zp', 'Co')) - ((8232, 8233), (57344, 63743), (983040, 1048573), (1048576, 1114109)) - - """ - try: - return category_index_cache[key] - except KeyError: - pass - assert key - if set(key) == set(categories()): - result = ((0, sys.maxunicode),) - else: - result = _union_intervals( - _query_for_key(key[:-1]), charmap()[key[-1]] - ) - category_index_cache[key] = result - return result - - -limited_category_index_cache = {} - - -def query( - exclude_categories=(), include_categories=None, - min_codepoint=None, - max_codepoint=None, - include_characters='', - exclude_characters='', -): - """Return a tuple of intervals covering the codepoints for all characters - that meet the critera (min_codepoint <= codepoint(c) <= max_codepoint and - any(cat in include_categories for cat in categories(c)) and all(cat not in - exclude_categories for cat in categories(c)) or (c in include_characters) - - >>> query() - ((0, 1114111),) - >>> query(min_codepoint=0, max_codepoint=128) - ((0, 128),) - >>> query(min_codepoint=0, max_codepoint=128, include_categories=['Lu']) - ((65, 90),) - >>> query(min_codepoint=0, max_codepoint=128, include_categories=['Lu'], - ... include_characters=u'☃') - ((65, 90), (9731, 9731)) - - """ - if min_codepoint is None: - min_codepoint = 0 - if max_codepoint is None: - max_codepoint = sys.maxunicode - catkey = _category_key(exclude_categories, include_categories) - character_intervals = _intervals(include_characters or '') - exclude_intervals = _intervals(exclude_characters or '') - qkey = ( - catkey, min_codepoint, max_codepoint, - character_intervals, exclude_intervals - ) - try: - return limited_category_index_cache[qkey] - except KeyError: - pass - base = _query_for_key(catkey) - result = [] - for u, v in base: - if v >= min_codepoint and u <= max_codepoint: - result.append(( - max(u, min_codepoint), min(v, max_codepoint) - )) - result = tuple(result) - result = _union_intervals(result, character_intervals) - result = _subtract_intervals(result, exclude_intervals) - limited_category_index_cache[qkey] = result - return result diff -Nru python-hypothesis-3.44.1/src/hypothesis/internal/compat.py python-hypothesis-3.71.11/src/hypothesis/internal/compat.py --- python-hypothesis-3.44.1/src/hypothesis/internal/compat.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/internal/compat.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,517 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -# pylint: skip-file - -from __future__ import division, print_function, absolute_import - -import re -import sys -import math -import time -import codecs -import platform -import importlib -from base64 import b64encode -from collections import namedtuple - -try: - from collections import OrderedDict, Counter -except ImportError: # pragma: no cover - from ordereddict import OrderedDict - from counter import Counter - - -PY2 = sys.version_info[0] == 2 -PY3 = sys.version_info[0] == 3 -PYPY = platform.python_implementation() == 'PyPy' -CAN_UNPACK_BYTE_ARRAY = sys.version_info[:3] >= (2, 7, 4) - -WINDOWS = platform.system() == 'Windows' - -if sys.version_info[:2] <= (2, 6): - raise ImportError( - 'Hypothesis is not supported on Python versions before 2.7' - ) - - -def bit_length(n): - return n.bit_length() - - -if PY3: - def str_to_bytes(s): - return s.encode(a_good_encoding()) - - def int_to_text(i): - return str(i) - - text_type = str - binary_type = bytes - hrange = range - ARG_NAME_ATTRIBUTE = 'arg' - integer_types = (int,) - hunichr = chr - - def unicode_safe_repr(x): - return repr(x) - - def isidentifier(s): - return s.isidentifier() - - def escape_unicode_characters(s): - return codecs.encode(s, 'unicode_escape').decode('ascii') - - def print_unicode(x): - print(x) - - exec(""" -def quiet_raise(exc): - raise exc from None -""") - - def int_from_bytes(data): - return int.from_bytes(data, 'big') - - def int_to_bytes(i, size): - return i.to_bytes(size, 'big') - - def to_bytes_sequence(ls): - return bytes(ls) - - def int_to_byte(i): - return bytes([i]) - - import struct - - struct_pack = struct.pack - struct_unpack = struct.unpack - - def benchmark_time(): - return time.monotonic() -else: - import struct - - def struct_pack(*args): - return hbytes(struct.pack(*args)) - - if CAN_UNPACK_BYTE_ARRAY: - def struct_unpack(fmt, string): - return struct.unpack(fmt, string) - else: - def struct_unpack(fmt, string): - return struct.unpack(fmt, str(string)) - - def int_from_bytes(data): - assert isinstance(data, bytearray) - if CAN_UNPACK_BYTE_ARRAY: - unpackable_data = data - else: - unpackable_data = bytes(data) - result = 0 - i = 0 - while i + 4 <= len(data): - result <<= 32 - result |= struct.unpack('>I', unpackable_data[i:i + 4])[0] - i += 4 - while i < len(data): - result <<= 8 - result |= data[i] - i += 1 - return int(result) - - def int_to_bytes(i, size): - assert i >= 0 - result = bytearray(size) - j = size - 1 - while i and j >= 0: - result[j] = i & 255 - i >>= 8 - j -= 1 - if i: - raise OverflowError('int too big to convert') - return hbytes(result) - - int_to_byte = chr - - def to_bytes_sequence(ls): - return bytearray(ls) - - def str_to_bytes(s): - return s - - def int_to_text(i): - return str(i).decode('ascii') - - VALID_PYTHON_IDENTIFIER = re.compile( - r"^[a-zA-Z_][a-zA-Z0-9_]*$" - ) - - def isidentifier(s): - return VALID_PYTHON_IDENTIFIER.match(s) - - def unicode_safe_repr(x): - r = repr(x) - assert isinstance(r, str) - return r.decode(a_good_encoding()) - - text_type = unicode - binary_type = str - - def hrange(start_or_finish, finish=None, step=None): - try: - if step is None: - if finish is None: - return xrange(start_or_finish) - else: - return xrange(start_or_finish, finish) - else: - return xrange(start_or_finish, finish, step) - except OverflowError: - if step == 0: - raise ValueError(u'step argument may not be zero') - if step is None: - step = 1 - if finish is not None: - start = start_or_finish - else: - start = 0 - finish = start_or_finish - assert step != 0 - if step > 0: - def shimrange(): - i = start - while i < finish: - yield i - i += step - else: - def shimrange(): - i = start - while i > finish: - yield i - i += step - return shimrange() - - ARG_NAME_ATTRIBUTE = 'id' - integer_types = (int, long) - hunichr = unichr - - def escape_unicode_characters(s): - return codecs.encode(s, 'string_escape') - - def print_unicode(x): - if isinstance(x, unicode): - x = x.encode(a_good_encoding()) - print(x) - - def quiet_raise(exc): - raise exc - - def benchmark_time(): - return time.time() - - -# coverage mixes unicode and str filepaths on Python 2, which causes us -# problems if we're running under unicodenazi (it might also cause problems -# when not running under unicodenazi, but hard to say for sure). This method -# exists to work around that: If we're given a unicode filepath, we turn it -# into a string file path using the appropriate encoding. See -# https://bitbucket.org/ned/coveragepy/issues/602/ for more information. -if PY2: - def encoded_filepath(filepath): - if isinstance(filepath, text_type): - return filepath.encode(sys.getfilesystemencoding()) - else: - return filepath -else: - def encoded_filepath(filepath): - return filepath - - -def a_good_encoding(): - return 'utf-8' - - -def to_unicode(x): - if isinstance(x, text_type): - return x - else: - return x.decode(a_good_encoding()) - - -def qualname(f): - try: - return f.__qualname__ - except AttributeError: - pass - try: - return f.im_class.__name__ + '.' + f.__name__ - except AttributeError: - return f.__name__ - - -if PY2: - FullArgSpec = namedtuple('FullArgSpec', 'args, varargs, varkw, defaults, ' - 'kwonlyargs, kwonlydefaults, annotations') - - def getfullargspec(func): - import inspect - args, varargs, varkw, defaults = inspect.getargspec(func) - return FullArgSpec(args, varargs, varkw, defaults, [], None, - getattr(func, '__annotations__', {})) -else: - from inspect import getfullargspec, FullArgSpec - - -if sys.version_info[:2] < (3, 6): - def get_type_hints(thing): - try: - spec = getfullargspec(thing) - return { - k: v for k, v in spec.annotations.items() - if k in (spec.args + spec.kwonlyargs) and isinstance(v, type) - } - except TypeError: - return {} -else: - def get_type_hints(thing): - try: - import typing - return typing.get_type_hints(thing) - except TypeError: - return {} - - -importlib_invalidate_caches = getattr( - importlib, 'invalidate_caches', lambda: ()) - - -if PY2: - CODE_FIELD_ORDER = [ - 'co_argcount', - 'co_nlocals', - 'co_stacksize', - 'co_flags', - 'co_code', - 'co_consts', - 'co_names', - 'co_varnames', - 'co_filename', - 'co_name', - 'co_firstlineno', - 'co_lnotab', - 'co_freevars', - 'co_cellvars', - ] -else: - CODE_FIELD_ORDER = [ - 'co_argcount', - 'co_kwonlyargcount', - 'co_nlocals', - 'co_stacksize', - 'co_flags', - 'co_code', - 'co_consts', - 'co_names', - 'co_varnames', - 'co_filename', - 'co_name', - 'co_firstlineno', - 'co_lnotab', - 'co_freevars', - 'co_cellvars', - ] - - -def update_code_location(code, newfile, newlineno): - """Take a code object and lie shamelessly about where it comes from. - - Why do we want to do this? It's for really shallow reasons involving - hiding the hypothesis_temporary_module code from test runners like - py.test's verbose mode. This is a vastly disproportionate terrible - hack that I've done purely for vanity, and if you're reading this - code you're probably here because it's broken something and now - you're angry at me. Sorry. - - """ - unpacked = [ - getattr(code, name) for name in CODE_FIELD_ORDER - ] - unpacked[CODE_FIELD_ORDER.index('co_filename')] = newfile - unpacked[CODE_FIELD_ORDER.index('co_firstlineno')] = newlineno - return type(code)(*unpacked) - - -class compatbytes(bytearray): - __name__ = 'bytes' - - def __init__(self, *args, **kwargs): - bytearray.__init__(self, *args, **kwargs) - self.__hash = None - - def __str__(self): - return bytearray.__str__(self) - - def __repr__(self): - return 'compatbytes(b%r)' % (str(self),) - - def __hash__(self): - if self.__hash is None: - self.__hash = hash(str(self)) - return self.__hash - - def count(self, value): - c = 0 - for w in self: - if w == value: - c += 1 - return c - - def index(self, value): - for i, v in enumerate(self): - if v == value: - return i - raise ValueError('Value %r not in sequence %r' % (value, self)) - - def __add__(self, value): - assert isinstance(value, compatbytes) - return compatbytes(bytearray.__add__(self, value)) - - def __radd__(self, value): - assert isinstance(value, compatbytes) - return compatbytes(bytearray.__add__(value, self)) - - def __mul__(self, value): - return compatbytes(bytearray.__mul__(self, value)) - - def __rmul__(self, value): - return compatbytes(bytearray.__rmul__(self, value)) - - def __getitem__(self, *args, **kwargs): - r = bytearray.__getitem__(self, *args, **kwargs) - if isinstance(r, bytearray): - return compatbytes(r) - else: - return r - - __setitem__ = None - - def join(self, parts): - result = bytearray() - first = True - for p in parts: - if not first: - result.extend(self) - first = False - result.extend(p) - return compatbytes(result) - - def __contains__(self, value): - return any(v == value for v in self) - - -if PY2: - hbytes = compatbytes - reasonable_byte_type = bytearray - string_types = (str, unicode) -else: - hbytes = bytes - reasonable_byte_type = bytes - string_types = (str,) - - -EMPTY_BYTES = hbytes(b'') - -if PY2: - def to_str(s): - if isinstance(s, unicode): - return s.encode(a_good_encoding()) - assert isinstance(s, str) - return s -else: - def to_str(s): - return s - - -def cast_unicode(s, encoding=None): - if isinstance(s, bytes): - return s.decode(encoding or a_good_encoding(), 'replace') - return s - - -def get_stream_enc(stream, default=None): - return getattr(stream, 'encoding', None) or default - - -def implements_iterator(it): - """Turn things with a __next__ attribute into iterators on Python 2.""" - if PY2 and not hasattr(it, 'next') and hasattr(it, '__next__'): - it.next = it.__next__ - return it - - -if PY3: - FileNotFoundError = FileNotFoundError -else: - FileNotFoundError = IOError - -# We need to know what sort of exception gets thrown when you try to write over -# an existing file where you're not allowed to. This is rather less consistent -# between versions than might be hoped. -if PY3: - FileExistsError = FileExistsError - -elif WINDOWS: - FileExistsError = WindowsError - -else: - # This doesn't happen in this case: We're not on windows and don't support - # the x flag because it's Python 2, so there are no places where this can - # be thrown. - FileExistsError = None - - -if PY2: - # Under Python 2, math.floor and math.ceil return floats, which cannot - # represent large integers - eg `float(2**53) == float(2**53 + 1)`. - # We therefore implement them entirely in (long) integer operations. - def floor(x): - if int(x) != x and x < 0: - return int(x) - 1 - return int(x) - - def ceil(x): - if int(x) != x and x > 0: - return int(x) + 1 - return int(x) -else: - floor = math.floor - ceil = math.ceil - - -try: - from math import gcd -except ImportError: - from fractions import gcd - - -if PY2: - def b64decode(s): - from base64 import b64decode as base - return hbytes(base(s)) -else: - from base64 import b64decode diff -Nru python-hypothesis-3.44.1/src/hypothesis/internal/conjecture/data.py python-hypothesis-3.71.11/src/hypothesis/internal/conjecture/data.py --- python-hypothesis-3.44.1/src/hypothesis/internal/conjecture/data.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/internal/conjecture/data.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,261 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import sys -from enum import IntEnum - -from hypothesis.errors import Frozen, StopTest, InvalidArgument -from hypothesis.internal.compat import hbytes, hrange, text_type, \ - bit_length, benchmark_time, int_from_bytes, unicode_safe_repr -from hypothesis.internal.coverage import IN_COVERAGE_TESTS -from hypothesis.internal.escalation import mark_for_escalation - - -class Status(IntEnum): - OVERRUN = 0 - INVALID = 1 - VALID = 2 - INTERESTING = 3 - - -global_test_counter = 0 - - -MAX_DEPTH = 100 - - -class ConjectureData(object): - - @classmethod - def for_buffer(self, buffer): - buffer = hbytes(buffer) - return ConjectureData( - max_length=len(buffer), - draw_bytes=lambda data, n: - hbytes(buffer[data.index:data.index + n]) - ) - - def __init__(self, max_length, draw_bytes): - self.max_length = max_length - self.is_find = False - self._draw_bytes = draw_bytes - self.overdraw = 0 - self.level = 0 - self.block_starts = {} - self.blocks = [] - self.buffer = bytearray() - self.output = u'' - self.status = Status.VALID - self.frozen = False - self.intervals_by_level = [] - self.interval_stack = [] - global global_test_counter - self.testcounter = global_test_counter - global_test_counter += 1 - self.start_time = benchmark_time() - self.events = set() - self.forced_indices = set() - self.capped_indices = {} - self.interesting_origin = None - self.tags = set() - self.draw_times = [] - self.__intervals = None - - def __assert_not_frozen(self, name): - if self.frozen: - raise Frozen( - 'Cannot call %s on frozen ConjectureData' % ( - name,)) - - def add_tag(self, tag): - self.tags.add(tag) - - @property - def depth(self): - return len(self.interval_stack) - - @property - def index(self): - return len(self.buffer) - - def note(self, value): - self.__assert_not_frozen('note') - if not isinstance(value, text_type): - value = unicode_safe_repr(value) - self.output += value - - def draw(self, strategy): - if self.is_find and not strategy.supports_find: - raise InvalidArgument(( - 'Cannot use strategy %r within a call to find (presumably ' - 'because it would be invalid after the call had ended).' - ) % (strategy,)) - - if strategy.is_empty: - self.mark_invalid() - - if self.depth >= MAX_DEPTH: - self.mark_invalid() - - if self.depth == 0 and not IN_COVERAGE_TESTS: # pragma: no cover - original_tracer = sys.gettrace() - try: - sys.settrace(None) - return self.__draw(strategy) - finally: - sys.settrace(original_tracer) - else: - return self.__draw(strategy) - - def __draw(self, strategy): - at_top_level = self.depth == 0 - self.start_example() - try: - if not at_top_level: - return strategy.do_draw(self) - else: - start_time = benchmark_time() - try: - return strategy.do_draw(self) - except BaseException as e: - mark_for_escalation(e) - raise - finally: - self.draw_times.append(benchmark_time() - start_time) - finally: - if not self.frozen: - self.stop_example() - - def start_example(self): - self.__assert_not_frozen('start_example') - self.interval_stack.append(self.index) - self.level += 1 - - def stop_example(self): - if self.frozen: - return - self.level -= 1 - while self.level >= len(self.intervals_by_level): - self.intervals_by_level.append([]) - k = self.interval_stack.pop() - if k != self.index: - t = (k, self.index) - self.intervals_by_level[self.level].append(t) - - def note_event(self, event): - self.events.add(event) - - @property - def intervals(self): - assert self.frozen - if self.__intervals is None: - intervals = set(self.blocks) - for l in self.intervals_by_level: - intervals.update(l) - for i in hrange(len(l) - 1): - if l[i][1] == l[i + 1][0]: - intervals.add((l[i][0], l[i + 1][1])) - for i in hrange(len(self.blocks) - 1): - intervals.add((self.blocks[i][0], self.blocks[i + 1][1])) - # Intervals are sorted as longest first, then by interval start. - self.__intervals = tuple(sorted( - set(intervals), - key=lambda se: (se[0] - se[1], se[0]) - )) - del self.intervals_by_level - return self.__intervals - - def freeze(self): - if self.frozen: - assert isinstance(self.buffer, hbytes) - return - self.frozen = True - self.finish_time = benchmark_time() - - self.buffer = hbytes(self.buffer) - self.events = frozenset(self.events) - del self._draw_bytes - - def draw_bits(self, n): - self.__assert_not_frozen('draw_bits') - if n == 0: - result = 0 - elif n % 8 == 0: - return int_from_bytes(self.draw_bytes(n // 8)) - else: - n_bytes = (n // 8) + 1 - self.__check_capacity(n_bytes) - buf = bytearray(self._draw_bytes(self, n_bytes)) - assert len(buf) == n_bytes - mask = (1 << (n % 8)) - 1 - buf[0] &= mask - self.capped_indices[self.index] = mask - buf = hbytes(buf) - self.__write(buf) - result = int_from_bytes(buf) - assert bit_length(result) <= n - return result - - def write(self, string): - self.__assert_not_frozen('write') - self.__check_capacity(len(string)) - assert isinstance(string, hbytes) - original = self.index - self.__write(string) - self.forced_indices.update(hrange(original, self.index)) - return string - - def __check_capacity(self, n): - if self.index + n > self.max_length: - self.overdraw = self.index + n - self.max_length - self.status = Status.OVERRUN - self.freeze() - raise StopTest(self.testcounter) - - def __write(self, result): - initial = self.index - n = len(result) - self.block_starts.setdefault(n, []).append(initial) - self.blocks.append((initial, initial + n)) - assert len(result) == n - assert self.index == initial - self.buffer.extend(result) - - def draw_bytes(self, n): - self.__assert_not_frozen('draw_bytes') - if n == 0: - return hbytes(b'') - self.__check_capacity(n) - result = self._draw_bytes(self, n) - assert len(result) == n - self.__write(result) - return hbytes(result) - - def mark_interesting(self, interesting_origin=None): - self.__assert_not_frozen('mark_interesting') - self.interesting_origin = interesting_origin - self.status = Status.INTERESTING - self.freeze() - raise StopTest(self.testcounter) - - def mark_invalid(self): - self.__assert_not_frozen('mark_invalid') - self.status = Status.INVALID - self.freeze() - raise StopTest(self.testcounter) diff -Nru python-hypothesis-3.44.1/src/hypothesis/internal/conjecture/engine.py python-hypothesis-3.71.11/src/hypothesis/internal/conjecture/engine.py --- python-hypothesis-3.44.1/src/hypothesis/internal/conjecture/engine.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/internal/conjecture/engine.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,1420 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import heapq -from enum import Enum -from random import Random, getrandbits -from weakref import WeakKeyDictionary -from collections import defaultdict - -import attr - -from hypothesis import settings as Settings -from hypothesis import Phase, HealthCheck -from hypothesis.reporting import debug_report -from hypothesis.internal.compat import EMPTY_BYTES, Counter, ceil, \ - hbytes, hrange, int_to_text, int_to_bytes, benchmark_time, \ - to_bytes_sequence, unicode_safe_repr -from hypothesis.utils.conventions import UniqueIdentifier -from hypothesis.internal.healthcheck import fail_health_check -from hypothesis.internal.conjecture.data import MAX_DEPTH, Status, \ - StopTest, ConjectureData -from hypothesis.internal.conjecture.minimizer import minimize - -# Tell pytest to omit the body of this module from tracebacks -# http://doc.pytest.org/en/latest/example/simple.html#writing-well-integrated-assertion-helpers -__tracebackhide__ = True - - -HUNG_TEST_TIME_LIMIT = 5 * 60 - - -@attr.s -class HealthCheckState(object): - valid_examples = attr.ib(default=0) - invalid_examples = attr.ib(default=0) - overrun_examples = attr.ib(default=0) - draw_times = attr.ib(default=attr.Factory(list)) - - -class ExitReason(Enum): - max_examples = 0 - max_iterations = 1 - timeout = 2 - max_shrinks = 3 - finished = 4 - flaky = 5 - - -class RunIsComplete(Exception): - pass - - -class ConjectureRunner(object): - - def __init__( - self, test_function, settings=None, random=None, - database_key=None, - ): - self._test_function = test_function - self.settings = settings or Settings() - self.last_data = None - self.shrinks = 0 - self.call_count = 0 - self.event_call_counts = Counter() - self.valid_examples = 0 - self.start_time = benchmark_time() - self.random = random or Random(getrandbits(128)) - self.database_key = database_key - self.status_runtimes = {} - - self.all_drawtimes = [] - self.all_runtimes = [] - - self.events_to_strings = WeakKeyDictionary() - - self.target_selector = TargetSelector(self.random) - - # Tree nodes are stored in an array to prevent heavy nesting of data - # structures. Branches are dicts mapping bytes to child nodes (which - # will in general only be partially populated). Leaves are - # ConjectureData objects that have been previously seen as the result - # of following that path. - self.tree = [{}] - - # A node is dead if there is nothing left to explore past that point. - # Recursively, a node is dead if either it is a leaf or every byte - # leads to a dead node when starting from here. - self.dead = set() - - # We rewrite the byte stream at various points during parsing, to one - # that will produce an equivalent result but is in some sense more - # canonical. We keep track of these so that when walking the tree we - # can identify nodes where the exact byte value doesn't matter and - # treat all bytes there as equivalent. This significantly reduces the - # size of the search space and removes a lot of redundant examples. - - # Maps tree indices where to the unique byte that is valid at that - # point. Corresponds to data.write() calls. - self.forced = {} - - # Maps tree indices to the maximum byte that is valid at that point. - # Currently this is only used inside draw_bits, but it potentially - # could get used elsewhere. - self.capped = {} - - # Where a tree node consists of the beginning of a block we track the - # size of said block. This allows us to tell when an example is too - # short even if it goes off the unexplored region of the tree - if it - # is at the beginning of a block of size 4 but only has 3 bytes left, - # it's going to overrun the end of the buffer regardless of the - # buffer contents. - self.block_sizes = {} - - self.interesting_examples = {} - self.covering_examples = {} - - self.shrunk_examples = set() - - self.tag_intern_table = {} - - self.health_check_state = None - - self.used_examples_from_database = False - - def __tree_is_exhausted(self): - return 0 in self.dead - - def test_function(self, data): - if benchmark_time() - self.start_time >= HUNG_TEST_TIME_LIMIT: - fail_health_check(self.settings, ( - 'Your test has been running for at least five minutes. This ' - 'is probably not what you intended, so by default Hypothesis ' - 'turns it into an error.' - ), HealthCheck.hung_test) - - self.call_count += 1 - try: - self._test_function(data) - data.freeze() - except StopTest as e: - if e.testcounter != data.testcounter: - self.save_buffer(data.buffer) - raise e - except BaseException: - self.save_buffer(data.buffer) - raise - finally: - data.freeze() - self.note_details(data) - - self.target_selector.add(data) - - self.debug_data(data) - - tags = frozenset(data.tags) - data.tags = self.tag_intern_table.setdefault(tags, tags) - - if data.status == Status.VALID: - self.valid_examples += 1 - for t in data.tags: - existing = self.covering_examples.get(t) - if ( - existing is None or - sort_key(data.buffer) < sort_key(existing.buffer) - ): - self.covering_examples[t] = data - if self.database is not None: - self.database.save(self.covering_key, data.buffer) - if existing is not None: - self.database.delete( - self.covering_key, existing.buffer) - - tree_node = self.tree[0] - indices = [] - node_index = 0 - for i, b in enumerate(data.buffer): - indices.append(node_index) - if i in data.forced_indices: - self.forced[node_index] = b - try: - self.capped[node_index] = data.capped_indices[i] - except KeyError: - pass - try: - node_index = tree_node[b] - except KeyError: - node_index = len(self.tree) - self.tree.append({}) - tree_node[b] = node_index - tree_node = self.tree[node_index] - if node_index in self.dead: - break - - for u, v in data.blocks: - # This can happen if we hit a dead node when walking the buffer. - # In that case we alrady have this section of the tree mapped. - if u >= len(indices): - break - self.block_sizes[indices[u]] = v - u - - if data.status != Status.OVERRUN and node_index not in self.dead: - self.dead.add(node_index) - self.tree[node_index] = data - - for j in reversed(indices): - if ( - len(self.tree[j]) < self.capped.get(j, 255) + 1 and - j not in self.forced - ): - break - if set(self.tree[j].values()).issubset(self.dead): - self.dead.add(j) - else: - break - - last_data_is_interesting = ( - self.last_data is not None and - self.last_data.status == Status.INTERESTING - ) - - if data.status == Status.INTERESTING: - first_call = len(self.interesting_examples) == 0 - - key = data.interesting_origin - changed = False - try: - existing = self.interesting_examples[key] - except KeyError: - changed = True - else: - if sort_key(data.buffer) < sort_key(existing.buffer): - self.downgrade_buffer(existing.buffer) - changed = True - - if changed: - self.save_buffer(data.buffer) - self.interesting_examples[key] = data - self.shrunk_examples.discard(key) - if last_data_is_interesting and not first_call: - self.shrinks += 1 - - if not last_data_is_interesting or ( - sort_key(data.buffer) < sort_key(self.last_data.buffer) and - data.interesting_origin == - self.last_data.interesting_origin - ): - self.last_data = data - - if self.shrinks >= self.settings.max_shrinks: - self.exit_with(ExitReason.max_shrinks) - elif ( - self.last_data is None or - self.last_data.status < Status.INTERESTING - ): - self.last_data = data - if ( - self.settings.timeout > 0 and - benchmark_time() >= self.start_time + self.settings.timeout - ): - self.exit_with(ExitReason.timeout) - - if not self.interesting_examples: - if self.valid_examples >= self.settings.max_examples: - self.exit_with(ExitReason.max_examples) - if self.call_count >= max( - self.settings.max_iterations, self.settings.max_examples - ): - self.exit_with(ExitReason.max_iterations) - - if self.__tree_is_exhausted(): - self.exit_with(ExitReason.finished) - - self.record_for_health_check(data) - - def record_for_health_check(self, data): - # Once we've actually found a bug, there's no point in trying to run - # health checks - they'll just mask the actually important information. - if data.status == Status.INTERESTING: - self.health_check_state = None - - state = self.health_check_state - - if state is None: - return - - state.draw_times.extend(data.draw_times) - - if data.status == Status.VALID: - state.valid_examples += 1 - elif data.status == Status.INVALID: - state.invalid_examples += 1 - else: - assert data.status == Status.OVERRUN - state.overrun_examples += 1 - - max_valid_draws = 10 - max_invalid_draws = 50 - max_overrun_draws = 20 - - assert state.valid_examples <= max_valid_draws - - if state.valid_examples == max_valid_draws: - self.health_check_state = None - return - - if state.overrun_examples == max_overrun_draws: - fail_health_check(self.settings, ( - 'Examples routinely exceeded the max allowable size. ' - '(%d examples overran while generating %d valid ones)' - '. Generating examples this large will usually lead to' - ' bad results. You could try setting max_size parameters ' - 'on your collections and turning ' - 'max_leaves down on recursive() calls.') % ( - state.overrun_examples, state.valid_examples - ), HealthCheck.data_too_large) - if state.invalid_examples == max_invalid_draws: - fail_health_check(self.settings, ( - 'It looks like your strategy is filtering out a lot ' - 'of data. Health check found %d filtered examples but ' - 'only %d good ones. This will make your tests much ' - 'slower, and also will probably distort the data ' - 'generation quite a lot. You should adapt your ' - 'strategy to filter less. This can also be caused by ' - 'a low max_leaves parameter in recursive() calls') % ( - state.invalid_examples, state.valid_examples - ), HealthCheck.filter_too_much) - - draw_time = sum(state.draw_times) - - if draw_time > 1.0: - fail_health_check(self.settings, ( - 'Data generation is extremely slow: Only produced ' - '%d valid examples in %.2f seconds (%d invalid ones ' - 'and %d exceeded maximum size). Try decreasing ' - "size of the data you're generating (with e.g." - 'max_size or max_leaves parameters).' - ) % ( - state.valid_examples, draw_time, state.invalid_examples, - state.overrun_examples), HealthCheck.too_slow,) - - def save_buffer(self, buffer): - if self.settings.database is not None: - key = self.database_key - if key is None: - return - self.settings.database.save(key, hbytes(buffer)) - - def downgrade_buffer(self, buffer): - if self.settings.database is not None: - self.settings.database.move( - self.database_key, self.secondary_key, buffer) - - @property - def secondary_key(self): - return b'.'.join((self.database_key, b'secondary')) - - @property - def covering_key(self): - return b'.'.join((self.database_key, b'coverage')) - - def note_details(self, data): - runtime = max(data.finish_time - data.start_time, 0.0) - self.all_runtimes.append(runtime) - self.all_drawtimes.extend(data.draw_times) - self.status_runtimes.setdefault(data.status, []).append(runtime) - for event in set(map(self.event_to_string, data.events)): - self.event_call_counts[event] += 1 - - def debug(self, message): - with self.settings: - debug_report(message) - - def debug_data(self, data): - buffer_parts = [u"["] - for i, (u, v) in enumerate(data.blocks): - if i > 0: - buffer_parts.append(u" || ") - buffer_parts.append( - u', '.join(int_to_text(int(i)) for i in data.buffer[u:v])) - buffer_parts.append(u']') - - status = unicode_safe_repr(data.status) - - if data.status == Status.INTERESTING: - status = u'%s (%s)' % ( - status, unicode_safe_repr(data.interesting_origin,)) - - self.debug(u'%d bytes %s -> %s, %s' % ( - data.index, - u''.join(buffer_parts), - status, - data.output, - )) - - def prescreen_buffer(self, buffer): - """Attempt to rule out buffer as a possible interesting candidate. - - Returns False if we know for sure that running this buffer will not - produce an interesting result. Returns True if it might (because it - explores territory we have not previously tried). - - This is purely an optimisation to try to reduce the number of tests we - run. "return True" would be a valid but inefficient implementation. - - """ - node_index = 0 - n = len(buffer) - for k, b in enumerate(buffer): - if node_index in self.dead: - return False - try: - # The block size at that point provides a lower bound on how - # many more bytes are required. If the buffer does not have - # enough bytes to fulfill that block size then we can rule out - # this buffer. - if k + self.block_sizes[node_index] > n: - return False - except KeyError: - pass - try: - b = self.forced[node_index] - except KeyError: - pass - try: - b = min(b, self.capped[node_index]) - except KeyError: - pass - try: - node_index = self.tree[node_index][b] - except KeyError: - return True - else: - return False - - def incorporate_new_buffer(self, buffer): - assert self.last_data.status == Status.INTERESTING - start = self.last_data.interesting_origin - - buffer = hbytes(buffer[:self.last_data.index]) - assert sort_key(buffer) < sort_key(self.last_data.buffer) - - if not self.prescreen_buffer(buffer): - return False - - assert sort_key(buffer) <= sort_key(self.last_data.buffer) - data = ConjectureData.for_buffer(buffer) - self.test_function(data) - assert self.last_data.interesting_origin == start - return data is self.last_data - - def run(self): - with self.settings: - try: - self._run() - except RunIsComplete: - pass - if self.interesting_examples: - self.last_data = max( - self.interesting_examples.values(), - key=lambda d: sort_key(d.buffer)) - if self.last_data is not None: - self.debug_data(self.last_data) - self.debug( - u'Run complete after %d examples (%d valid) and %d shrinks' % ( - self.call_count, self.valid_examples, self.shrinks, - )) - - def _new_mutator(self): - def draw_new(data, n): - return uniform(self.random, n) - - def draw_existing(data, n): - return self.last_data.buffer[data.index:data.index + n] - - def draw_smaller(data, n): - existing = self.last_data.buffer[data.index:data.index + n] - r = uniform(self.random, n) - if r <= existing: - return r - return _draw_predecessor(self.random, existing) - - def draw_larger(data, n): - existing = self.last_data.buffer[data.index:data.index + n] - r = uniform(self.random, n) - if r >= existing: - return r - return _draw_successor(self.random, existing) - - def reuse_existing(data, n): - choices = data.block_starts.get(n, []) or \ - self.last_data.block_starts.get(n, []) - if choices: - i = self.random.choice(choices) - return self.last_data.buffer[i:i + n] - else: - result = uniform(self.random, n) - assert isinstance(result, hbytes) - return result - - def flip_bit(data, n): - buf = bytearray( - self.last_data.buffer[data.index:data.index + n]) - i = self.random.randint(0, n - 1) - k = self.random.randint(0, 7) - buf[i] ^= (1 << k) - return hbytes(buf) - - def draw_zero(data, n): - return hbytes(b'\0' * n) - - def draw_max(data, n): - return hbytes([255]) * n - - def draw_constant(data, n): - return hbytes([self.random.randint(0, 255)]) * n - - def redraw_last(data, n): - u = self.last_data.blocks[-1][0] - if data.index + n <= u: - return self.last_data.buffer[data.index:data.index + n] - else: - return uniform(self.random, n) - - options = [ - draw_new, - redraw_last, redraw_last, - reuse_existing, reuse_existing, - draw_existing, draw_smaller, draw_larger, - flip_bit, - draw_zero, draw_max, draw_zero, draw_max, - draw_constant, - ] - - bits = [ - self.random.choice(options) for _ in hrange(3) - ] - - def draw_mutated(data, n): - if data.index + n > len(self.last_data.buffer): - result = uniform(self.random, n) - else: - result = self.random.choice(bits)(data, n) - - return self.__rewrite_for_novelty( - data, self.__zero_bound(data, result)) - - return draw_mutated - - def __rewrite(self, data, result): - return self.__rewrite_for_novelty( - data, self.__zero_bound(data, result) - ) - - def __zero_bound(self, data, result): - """This tries to get the size of the generated data under control by - replacing the result with zero if we are too deep or have already - generated too much data. - - This causes us to enter "shrinking mode" there and thus reduce - the size of the generated data. - - """ - if ( - data.depth * 2 >= MAX_DEPTH or - (data.index + len(result)) * 2 >= self.settings.buffer_size - ): - if any(result): - data.hit_zero_bound = True - return hbytes(len(result)) - else: - return result - - def __rewrite_for_novelty(self, data, result): - """Take a block that is about to be added to data as the result of a - draw_bytes call and rewrite it a small amount to ensure that the result - will be novel: that is, not hit a part of the tree that we have fully - explored. - - This is mostly useful for test functions which draw a small - number of blocks. - - """ - assert isinstance(result, hbytes) - try: - node_index = data.__current_node_index - except AttributeError: - node_index = 0 - data.__current_node_index = node_index - data.__hit_novelty = False - data.__evaluated_to = 0 - - if data.__hit_novelty: - return result - - node = self.tree[node_index] - - for i in hrange(data.__evaluated_to, len(data.buffer)): - node = self.tree[node_index] - try: - node_index = node[data.buffer[i]] - assert node_index not in self.dead - node = self.tree[node_index] - except KeyError: # pragma: no cover - assert False, ( - 'This should be impossible. If you see this error, please ' - 'report it as a bug (ideally with a reproducible test ' - 'case).' - ) - - for i, b in enumerate(result): - assert isinstance(b, int) - try: - new_node_index = node[b] - except KeyError: - data.__hit_novelty = True - return result - - new_node = self.tree[new_node_index] - - if new_node_index in self.dead: - if isinstance(result, hbytes): - result = bytearray(result) - for c in range(256): - if c not in node: - assert c <= self.capped.get(node_index, c) - result[i] = c - data.__hit_novelty = True - return hbytes(result) - else: - new_node_index = node[c] - new_node = self.tree[new_node_index] - if new_node_index not in self.dead: - result[i] = c - break - else: # pragma: no cover - assert False, ( - 'Found a tree node which is live despite all its ' - 'children being dead.') - node_index = new_node_index - node = new_node - assert node_index not in self.dead - data.__current_node_index = node_index - data.__evaluated_to = data.index + len(result) - return hbytes(result) - - @property - def database(self): - if self.database_key is None: - return None - return self.settings.database - - def has_existing_examples(self): - return ( - self.database is not None and - Phase.reuse in self.settings.phases - ) - - def reuse_existing_examples(self): - """If appropriate (we have a database and have been told to use it), - try to reload existing examples from the database. - - If there are a lot we don't try all of them. We always try the - smallest example in the database (which is guaranteed to be the - last failure) and the largest (which is usually the seed example - which the last failure came from but we don't enforce that). We - then take a random sampling of the remainder and try those. Any - examples that are no longer interesting are cleared out. - - """ - if self.has_existing_examples(): - self.debug('Reusing examples from database') - # We have to do some careful juggling here. We have two database - # corpora: The primary and secondary. The primary corpus is a - # small set of minimized examples each of which has at one point - # demonstrated a distinct bug. We want to retry all of these. - - # We also have a secondary corpus of examples that have at some - # point demonstrated interestingness (currently only ones that - # were previously non-minimal examples of a bug, but this will - # likely expand in future). These are a good source of potentially - # interesting examples, but there are a lot of them, so we down - # sample the secondary corpus to a more manageable size. - - corpus = sorted( - self.settings.database.fetch(self.database_key), - key=sort_key - ) - desired_size = max(2, ceil(0.1 * self.settings.max_examples)) - - for extra_key in [self.secondary_key, self.covering_key]: - if len(corpus) < desired_size: - extra_corpus = list( - self.settings.database.fetch(extra_key), - ) - - shortfall = desired_size - len(corpus) - - if len(extra_corpus) <= shortfall: - extra = extra_corpus - else: - extra = self.random.sample(extra_corpus, shortfall) - extra.sort(key=sort_key) - corpus.extend(extra) - - self.used_examples_from_database = len(corpus) > 0 - - for existing in corpus: - self.last_data = ConjectureData.for_buffer(existing) - try: - self.test_function(self.last_data) - finally: - if self.last_data.status != Status.INTERESTING: - self.settings.database.delete( - self.database_key, existing) - self.settings.database.delete( - self.secondary_key, existing) - - def exit_with(self, reason): - self.exit_reason = reason - raise RunIsComplete() - - def generate_new_examples(self): - if Phase.generate not in self.settings.phases: - return - - zero_data = self.cached_test_function( - hbytes(self.settings.buffer_size)) - if zero_data.status == Status.OVERRUN or ( - zero_data.status == Status.VALID and - len(zero_data.buffer) * 2 > self.settings.buffer_size - ): - fail_health_check( - self.settings, - 'The smallest natural example for your test is extremely ' - 'large. This makes it difficult for Hypothesis to generate ' - 'good examples, especially when trying to reduce failing ones ' - 'at the end. Consider reducing the size of your data if it is ' - 'of a fixed size. You could also fix this by improving how ' - 'your data shrinks (see https://hypothesis.readthedocs.io/en/' - 'latest/data.html#shrinking for details), or by introducing ' - 'default values inside your strategy. e.g. could you replace ' - 'some arguments with their defaults by using ' - 'one_of(none(), some_complex_strategy)?', - HealthCheck.large_base_example - ) - - if self.settings.perform_health_check: - self.health_check_state = HealthCheckState() - - count = 0 - while not self.interesting_examples and ( - count < 10 or self.health_check_state is not None - ): - def draw_bytes(data, n): - return self.__rewrite_for_novelty( - data, self.__zero_bound(data, uniform(self.random, n)) - ) - - targets_found = len(self.covering_examples) - - self.last_data = ConjectureData( - max_length=self.settings.buffer_size, - draw_bytes=draw_bytes - ) - self.test_function(self.last_data) - self.last_data.freeze() - - if len(self.covering_examples) > targets_found: - count = 0 - else: - count += 1 - - mutations = 0 - mutator = self._new_mutator() - - zero_bound_queue = [] - - while not self.interesting_examples: - if zero_bound_queue: - # Whenever we generated an example and it hits a bound - # which forces zero blocks into it, this creates a weird - # distortion effect by making certain parts of the data - # stream (especially ones to the right) much more likely - # to be zero. We fix this by redistributing the generated - # data by shuffling it randomly. This results in the - # zero data being spread evenly throughout the buffer. - # Hopefully the shrinking this causes will cause us to - # naturally fail to hit the bound. - # If it doesn't then we will queue the new version up again - # (now with more zeros) and try again. - overdrawn = zero_bound_queue.pop() - buffer = bytearray(overdrawn.buffer) - - # These will have values written to them that are different - # from what's in them anyway, so the value there doesn't - # really "count" for distributional purposes, and if we - # leave them in then they can cause the fraction of non - # zero bytes to increase on redraw instead of decrease. - for i in overdrawn.forced_indices: - buffer[i] = 0 - - self.random.shuffle(buffer) - buffer = hbytes(buffer) - - def draw_bytes(data, n): - result = buffer[data.index:data.index + n] - if len(result) < n: - result += hbytes(n - len(result)) - return self.__rewrite(data, result) - - data = ConjectureData( - draw_bytes=draw_bytes, - max_length=self.settings.buffer_size, - ) - self.test_function(data) - data.freeze() - else: - target, last_data = self.target_selector.select() - mutations += 1 - targets_found = len(self.covering_examples) - prev_data = self.last_data - data = ConjectureData( - draw_bytes=mutator, - max_length=self.settings.buffer_size - ) - self.test_function(data) - data.freeze() - if ( - data.status > prev_data.status or - len(self.covering_examples) > targets_found - ): - mutations = 0 - elif ( - data.status < prev_data.status or - not self.target_selector.has_tag(target, data) or - mutations >= 10 - ): - # Cap the variations of a single example and move on to - # an entirely fresh start. Ten is an entirely arbitrary - # constant, but it's been working well for years. - mutations = 0 - mutator = self._new_mutator() - if getattr(data, 'hit_zero_bound', False): - zero_bound_queue.append(data) - mutations += 1 - - def _run(self): - self.last_data = None - self.start_time = benchmark_time() - - self.reuse_existing_examples() - self.generate_new_examples() - - if ( - Phase.shrink not in self.settings.phases or - not self.interesting_examples - ): - self.exit_with(ExitReason.finished) - - for prev_data in sorted( - self.interesting_examples.values(), - key=lambda d: sort_key(d.buffer) - ): - assert prev_data.status == Status.INTERESTING - data = ConjectureData.for_buffer(prev_data.buffer) - self.test_function(data) - if data.status != Status.INTERESTING: - self.exit_with(ExitReason.flaky) - - while len(self.shrunk_examples) < len(self.interesting_examples): - target, self.last_data = min([ - (k, v) for k, v in self.interesting_examples.items() - if k not in self.shrunk_examples], - key=lambda kv: (sort_key(kv[1].buffer), sort_key(repr(kv[0]))), - ) - self.debug('Shrinking %r' % (target,)) - assert self.last_data.interesting_origin == target - self.shrink() - self.shrunk_examples.add(target) - self.exit_with(ExitReason.finished) - - def cached_test_function(self, buffer): - node_index = 0 - for i in hrange(self.settings.buffer_size): - try: - c = self.forced[node_index] - except KeyError: - if i < len(buffer): - c = buffer[i] - else: - c = 0 - try: - node_index = self.tree[node_index][c] - except KeyError: - break - node = self.tree[node_index] - if isinstance(node, ConjectureData): - return node - result = ConjectureData.for_buffer(buffer) - self.test_function(result) - return result - - def try_buffer_with_rewriting_from(self, initial_attempt, v): - initial_data = self.cached_test_function(initial_attempt) - - if initial_data.status == Status.INTERESTING: - return initial_data is self.last_data - - # If this produced something completely invalid we ditch it - # here rather than trying to persevere. - if initial_data.status < Status.VALID: - return False - - if len(initial_data.buffer) < v: - return False - - lost_data = len(self.last_data.buffer) - len(initial_data.buffer) - - # If this did not in fact cause the data size to shrink we - # bail here because it's not worth trying to delete stuff from - # the remainder. - if lost_data <= 0: - return False - - try_with_deleted = bytearray(initial_attempt) - del try_with_deleted[v:v + lost_data] - try_with_deleted.extend(hbytes(lost_data - 1)) - if self.incorporate_new_buffer(try_with_deleted): - return True - - for r, s in self.last_data.intervals: - if ( - r >= v and - s - r <= lost_data and - r < len(initial_data.buffer) - ): - try_with_deleted = bytearray(initial_attempt) - del try_with_deleted[r:s] - try_with_deleted.extend(hbytes(s - r - 1)) - if self.incorporate_new_buffer(try_with_deleted): - return True - return False - - def delta_interval_deletion(self): - """Attempt to delete every interval in the example.""" - - self.debug('delta interval deletes') - - # We do a delta-debugging style thing here where we initially try to - # delete many intervals at once and prune it down exponentially to - # eventually only trying to delete one interval at a time. - - # I'm a little skeptical that this is helpful in general, but we've - # got at least one benchmark where it does help. - k = len(self.last_data.intervals) // 2 - while k > 0: - i = 0 - while i + k <= len(self.last_data.intervals): - bitmask = [True] * len(self.last_data.buffer) - - for u, v in self.last_data.intervals[i:i + k]: - for t in range(u, v): - bitmask[t] = False - - if not self.incorporate_new_buffer(hbytes( - b for b, v in zip(self.last_data.buffer, bitmask) - if v - )): - i += k - k //= 2 - - def greedy_interval_deletion(self): - """Attempt to delete every interval in the example.""" - self.debug('greedy interval deletes') - i = 0 - while i < len(self.last_data.intervals): - u, v = self.last_data.intervals[i] - if not self.incorporate_new_buffer( - self.last_data.buffer[:u] + self.last_data.buffer[v:] - ): - i += 1 - - def coarse_block_replacement(self): - """Attempts to zero every block. This is a very coarse pass that we - only run once to attempt to remove some irrelevant detail. The main - purpose of it is that if we manage to zero a lot of data then many - attempted deletes become duplicates of each other, so we run fewer - tests. - - If more blocks become possible to zero later that will be - handled by minimize_individual_blocks. The point of this is - simply to provide a fairly fast initial pass. - - """ - self.debug('Zeroing blocks') - i = 0 - while i < len(self.last_data.blocks): - buf = self.last_data.buffer - u, v = self.last_data.blocks[i] - assert u < v - block = buf[u:v] - if any(block): - self.incorporate_new_buffer(buf[:u] + hbytes(v - u) + buf[v:]) - i += 1 - - def minimize_duplicated_blocks(self): - """Find blocks that have been duplicated in multiple places and attempt - to minimize all of the duplicates simultaneously.""" - - self.debug('Simultaneous shrinking of duplicated blocks') - counts = Counter( - self.last_data.buffer[u:v] for u, v in self.last_data.blocks - ) - blocks = [buffer for buffer, count in counts.items() if count > 1] - - thresholds = {} - for u, v in self.last_data.blocks: - b = self.last_data.buffer[u:v] - thresholds[b] = v - - blocks.sort(reverse=True) - blocks.sort(key=lambda b: counts[b] * len(b), reverse=True) - for block in blocks: - parts = [ - self.last_data.buffer[r:s] - for r, s in self.last_data.blocks - ] - - def replace(b): - return hbytes(EMPTY_BYTES.join( - hbytes(b if c == block else c) for c in parts - )) - - threshold = thresholds[block] - - minimize( - block, - lambda b: self.try_buffer_with_rewriting_from( - replace(b), threshold), - random=self.random, full=False - ) - - def minimize_individual_blocks(self): - self.debug('Shrinking of individual blocks') - i = 0 - while i < len(self.last_data.blocks): - u, v = self.last_data.blocks[i] - minimize( - self.last_data.buffer[u:v], - lambda b: self.try_buffer_with_rewriting_from( - self.last_data.buffer[:u] + b + - self.last_data.buffer[v:], v - ), - random=self.random, full=False, - ) - i += 1 - - def reorder_blocks(self): - self.debug('Reordering blocks') - block_lengths = sorted(self.last_data.block_starts, reverse=True) - for n in block_lengths: - i = 1 - while i < len(self.last_data.block_starts.get(n, ())): - j = i - while j > 0: - buf = self.last_data.buffer - blocks = self.last_data.block_starts[n] - a_start = blocks[j - 1] - b_start = blocks[j] - a = buf[a_start:a_start + n] - b = buf[b_start:b_start + n] - if a <= b: - break - swapped = ( - buf[:a_start] + b + buf[a_start + n:b_start] + - a + buf[b_start + n:]) - assert len(swapped) == len(buf) - assert swapped < buf - if self.incorporate_new_buffer(swapped): - j -= 1 - else: - break - i += 1 - - def shrink(self): - # We assume that if an all-zero block of bytes is an interesting - # example then we're not going to do better than that. - # This might not technically be true: e.g. for integers() | booleans() - # the simplest example is actually [1, 0]. Missing this case is fairly - # harmless and this allows us to make various simplifying assumptions - # about the structure of the data (principally that we're never - # operating on a block of all zero bytes so can use non-zeroness as a - # signpost of complexity). - if ( - not any(self.last_data.buffer) or - self.incorporate_new_buffer(hbytes(len(self.last_data.buffer))) - ): - return - - if self.has_existing_examples(): - # If we have any smaller examples in the secondary corpus, now is - # a good time to try them to see if they work as shrinks. They - # probably won't, but it's worth a shot and gives us a good - # opportunity to clear out the database. - - # It's not worth trying the primary corpus because we already - # tried all of those in the initial phase. - corpus = sorted( - self.settings.database.fetch(self.secondary_key), - key=sort_key - ) - for c in corpus: - if sort_key(c) >= sort_key(self.last_data.buffer): - break - elif self.incorporate_new_buffer(c): - break - else: - self.settings.database.delete(self.secondary_key, c) - - # Coarse passes that are worth running once when the example is likely - # to be "far from shrunk" but not worth repeating in a loop because - # they are subsumed by more fine grained passes. - self.delta_interval_deletion() - self.coarse_block_replacement() - - change_counter = -1 - - while self.shrinks > change_counter: - change_counter = self.shrinks - - self.minimize_duplicated_blocks() - self.minimize_individual_blocks() - self.reorder_blocks() - self.greedy_interval_deletion() - - def event_to_string(self, event): - if isinstance(event, str): - return event - try: - return self.events_to_strings[event] - except KeyError: - pass - result = str(event) - self.events_to_strings[event] = result - return result - - -def _draw_predecessor(rnd, xs): - r = bytearray() - any_strict = False - for x in to_bytes_sequence(xs): - if not any_strict: - c = rnd.randint(0, x) - if c < x: - any_strict = True - else: - c = rnd.randint(0, 255) - r.append(c) - return hbytes(r) - - -def _draw_successor(rnd, xs): - r = bytearray() - any_strict = False - for x in to_bytes_sequence(xs): - if not any_strict: - c = rnd.randint(x, 255) - if c > x: - any_strict = True - else: - c = rnd.randint(0, 255) - r.append(c) - return hbytes(r) - - -def sort_key(buffer): - return (len(buffer), buffer) - - -def uniform(random, n): - return int_to_bytes(random.getrandbits(n * 8), n) - - -class SampleSet(object): - """Set data type with the ability to sample uniformly at random from it. - - The mechanism is that we store the set in two parts: A mapping of - values to their index in an array. Sampling uniformly at random then - becomes simply a matter of sampling from the array, but we can use - the index for efficient lookup to add and remove values. - - """ - __slots__ = ('__values', '__index') - - def __init__(self): - self.__values = [] - self.__index = {} - - def __len__(self): - return len(self.__values) - - def __repr__(self): - return 'SampleSet(%r)' % (self.__values,) - - def add(self, value): - assert value not in self.__index - # Adding simply consists of adding the value to the end of the array - # and updating the index. - self.__index[value] = len(self.__values) - self.__values.append(value) - - def remove(self, value): - # To remove a value we first remove it from the index. But this leaves - # us with the value still in the array, so we have to fix that. We - # can't simply remove the value from the array, as that would a) Be an - # O(n) operation and b) Leave the index completely wrong for every - # value after that index. - # So what we do is we take the last element of the array and place it - # in the position of the value we just deleted (if the value was not - # already the last element of the array. If it was then we don't have - # to do anything extra). This reorders the array, but that's OK because - # we don't care about its order, we just need to sample from it. - i = self.__index.pop(value) - last = self.__values.pop() - if i < len(self.__values): - self.__values[i] = last - self.__index[last] = i - - def choice(self, random): - return random.choice(self.__values) - - -class Negated(object): - __slots__ = ('tag',) - - def __init__(self, tag): - self.tag = tag - - -NEGATED_CACHE = {} - - -def negated(tag): - try: - return NEGATED_CACHE[tag] - except KeyError: - result = Negated(tag) - NEGATED_CACHE[tag] = result - return result - - -universal = UniqueIdentifier('universal') - - -class TargetSelector(object): - """Data structure for selecting targets to use for mutation. - - The goal is to do a good job of exploiting novelty in examples without - getting too obsessed with any particular novel factor. - - Roughly speaking what we want to do is give each distinct coverage target - equal amounts of time. However some coverage targets may be harder to fuzz - than others, or may only appear in a very small minority of examples, so we - don't want to let those dominate the testing. - - Targets are selected according to the following rules: - - 1. We ideally want valid examples as our starting point. We ignore - interesting examples entirely, and other than that we restrict ourselves - to the best example status we've seen so far. If we've only seen - OVERRUN examples we use those. If we've seen INVALID but not VALID - examples we use those. Otherwise we use VALID examples. - 2. Among the examples we've seen with the right status, when asked to - select a target, we select a coverage target and return that along with - an example exhibiting that target uniformly at random. - - Coverage target selection proceeds as follows: - - 1. Whenever we return an example from select, we update the usage count of - each of its tags. - 2. Whenever we see an example, we add it to the list of examples for all of - its tags. - 3. When selecting a tag, we select one with a minimal usage count. Among - those of minimal usage count we select one with the fewest examples. - Among those, we select one uniformly at random. - - This has the following desirable properties: - - 1. When two coverage targets are intrinsically linked (e.g. when you have - multiple lines in a conditional so that either all or none of them will - be covered in a conditional) they are naturally deduplicated. - 2. Popular coverage targets will largely be ignored for considering what - test to run - if every example exhibits a coverage target, picking an - example because of that target is rather pointless. - 3. When we discover new coverage targets we immediately exploit them until - we get to the point where we've spent about as much time on them as the - existing targets. - 4. Among the interesting deduplicated coverage targets we essentially - round-robin between them, but with a more consistent distribution than - uniformly at random, which is important particularly for short runs. - - """ - - def __init__(self, random): - self.random = random - self.best_status = Status.OVERRUN - self.reset() - - def reset(self): - self.examples_by_tags = defaultdict(list) - self.tag_usage_counts = Counter() - self.tags_by_score = defaultdict(SampleSet) - self.scores_by_tag = {} - self.scores = [] - self.mutation_counts = 0 - self.example_counts = 0 - self.non_universal_tags = set() - self.universal_tags = None - - def add(self, data): - if data.status == Status.INTERESTING: - return - if data.status < self.best_status: - return - if data.status > self.best_status: - self.best_status = data.status - self.reset() - - if self.universal_tags is None: - self.universal_tags = set(data.tags) - else: - not_actually_universal = self.universal_tags - data.tags - for t in not_actually_universal: - self.universal_tags.remove(t) - self.non_universal_tags.add(t) - self.examples_by_tags[t] = list( - self.examples_by_tags[universal] - ) - - new_tags = data.tags - self.non_universal_tags - - for t in new_tags: - self.non_universal_tags.add(t) - self.examples_by_tags[negated(t)] = list( - self.examples_by_tags[universal] - ) - - self.example_counts += 1 - for t in self.tags_for(data): - self.examples_by_tags[t].append(data) - self.rescore(t) - - def has_tag(self, tag, data): - if tag is universal: - return True - if isinstance(tag, Negated): - return tag.tag not in data.tags - return tag in data.tags - - def tags_for(self, data): - yield universal - for t in data.tags: - yield t - for t in self.non_universal_tags: - if t not in data.tags: - yield negated(t) - - def rescore(self, tag): - new_score = ( - self.tag_usage_counts[tag], len(self.examples_by_tags[tag])) - try: - old_score = self.scores_by_tag[tag] - except KeyError: - pass - else: - self.tags_by_score[old_score].remove(tag) - self.scores_by_tag[tag] = new_score - - sample = self.tags_by_score[new_score] - if len(sample) == 0: - heapq.heappush(self.scores, new_score) - sample.add(tag) - - def select_tag(self): - while True: - peek = self.scores[0] - sample = self.tags_by_score[peek] - if len(sample) == 0: - heapq.heappop(self.scores) - else: - return sample.choice(self.random) - - def select_example_for_tag(self, t): - return self.random.choice(self.examples_by_tags[t]) - - def select(self): - t = self.select_tag() - self.mutation_counts += 1 - result = self.select_example_for_tag(t) - assert self.has_tag(t, result) - for s in self.tags_for(result): - self.tag_usage_counts[s] += 1 - self.rescore(s) - return t, result diff -Nru python-hypothesis-3.44.1/src/hypothesis/internal/conjecture/floats.py python-hypothesis-3.71.11/src/hypothesis/internal/conjecture/floats.py --- python-hypothesis-3.44.1/src/hypothesis/internal/conjecture/floats.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/internal/conjecture/floats.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,246 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from array import array - -from hypothesis.internal.compat import hbytes, hrange, int_to_bytes -from hypothesis.internal.floats import float_to_int, int_to_float - -""" -This module implements support for arbitrary floating point numbers in -Conjecture. It doesn't make any attempt to get a good distribution, only to -get a format that will shrink well. - -It works by defining an encoding of non-negative floating point numbers -(including NaN values with a zero sign bit) that has good lexical shrinking -properties. - -This encoding is a tagged union of two separate encodings for floating point -numbers, with the tag being the first bit of 64 and the remaining 63-bits being -the payload. - -If the tag bit is 0, the next 7 bits are ignored, and the remaining 7 bytes are -interpreted as a 7 byte integer in big-endian order and then converted to a -float (there is some redundancy here, as 7 * 8 = 56, which is larger than the -largest integer that floating point numbers can represent exactly, so multiple -encodings may map to the same float). - -If the tag bit is 1, we instead use somemthing that is closer to the normal -representation of floats (and can represent every non-negative float exactly) -but has a better ordering: - -1. NaNs are ordered after everything else. -2. Infinity is ordered after every finite number. -3. The sign is ignored unless two floating point numbers are identical in - absolute magnitude. In that case, the positive is ordered before the - negative. -4. Positive floating point numbers are ordered first by int(x) where - encoding(x) < encoding(y) if int(x) < int(y). -5. If int(x) == int(y) then x and y are sorted towards lower denominators of - their fractional parts. - -The format of this encoding of floating point goes as follows: - - [exponent] [mantissa] - -Each of these is the same size their equivalent in IEEE floating point, but are -in a different format. - -We translate exponents as follows: - - 1. The maximum exponent (2 ** 11 - 1) is left unchanged. - 2. We reorder the remaining exponents so that all of the positive exponents - are first, in increasing order, followed by all of the negative - exponents in decreasing order (where positive/negative is done by the - unbiased exponent e - 1023). - -We translate the mantissa as follows: - - 1. If the unbiased exponent is <= 0 we reverse it bitwise. - 2. If the unbiased exponent is >= 52 we leave it alone. - 3. If the unbiased exponent is in the range [1, 51] then we reverse the - low k bits, where k is 52 - unbiased exponen. - -The low bits correspond to the fractional part of the floating point number. -Reversing it bitwise means that we try to minimize the low bits, which kills -off the higher powers of 2 in the fraction first. -""" - - -MAX_EXPONENT = 0x7ff - -SPECIAL_EXPONENTS = (0, MAX_EXPONENT) - -BIAS = 1023 -MAX_POSITIVE_EXPONENT = (MAX_EXPONENT - 1 - BIAS) - - -def exponent_key(e): - if e == MAX_EXPONENT: - return float('inf') - unbiased = e - BIAS - if unbiased < 0: - return 10000 - unbiased - else: - return unbiased - - -ENCODING_TABLE = array('H', sorted(hrange(MAX_EXPONENT + 1), key=exponent_key)) -DECODING_TABLE = array('H', [0]) * len(ENCODING_TABLE) - -for i, b in enumerate(ENCODING_TABLE): - DECODING_TABLE[b] = i - -del i, b - - -def decode_exponent(e): - """Take draw_bits(11) and turn it into a suitable floating point exponent - such that lexicographically simpler leads to simpler floats.""" - assert 0 <= e <= MAX_EXPONENT - return ENCODING_TABLE[e] - - -def encode_exponent(e): - """Take a floating point exponent and turn it back into the equivalent - result from conjecture.""" - assert 0 <= e <= MAX_EXPONENT - return DECODING_TABLE[e] - - -def reverse_byte(b): - result = 0 - for _ in range(8): - result <<= 1 - result |= (b & 1) - b >>= 1 - return result - - -# Table mapping individual bytes to the equivalent byte with the bits of the -# byte reversed. e.g. 1=0b1 is mapped to 0xb10000000=0x80=128. We use this -# precalculated table to simplify calculating the bitwise reversal of a longer -# integer. -REVERSE_BITS_TABLE = bytearray(map(reverse_byte, range(256))) - - -def reverse64(v): - """Reverse a 64-bit integer bitwise. - - We do this by breaking it up into 8 bytes. The 64-bit integer is then the - concatenation of each of these bytes. We reverse it by reversing each byte - on its own using the REVERSE_BITS_TABLE above, and then concatenating the - reversed bytes. - - In this case concatenating consists of shifting them into the right - position for the word and then oring the bits together. - - """ - assert v.bit_length() <= 64 - return ( - (REVERSE_BITS_TABLE[(v >> 0) & 0xff] << 56) | - (REVERSE_BITS_TABLE[(v >> 8) & 0xff] << 48) | - (REVERSE_BITS_TABLE[(v >> 16) & 0xff] << 40) | - (REVERSE_BITS_TABLE[(v >> 24) & 0xff] << 32) | - (REVERSE_BITS_TABLE[(v >> 32) & 0xff] << 24) | - (REVERSE_BITS_TABLE[(v >> 40) & 0xff] << 16) | - (REVERSE_BITS_TABLE[(v >> 48) & 0xff] << 8) | - (REVERSE_BITS_TABLE[(v >> 56) & 0xff] << 0) - ) - - -MANTISSA_MASK = ((1 << 52) - 1) - - -def reverse_bits(x, n): - assert x.bit_length() <= n <= 64 - x = reverse64(x) - x >>= (64 - n) - return x - - -def update_mantissa(unbiased_exponent, mantissa): - if unbiased_exponent <= 0: - mantissa = reverse_bits(mantissa, 52) - elif unbiased_exponent <= 51: - n_fractional_bits = (52 - unbiased_exponent) - fractional_part = mantissa & ((1 << n_fractional_bits) - 1) - mantissa ^= fractional_part - mantissa |= reverse_bits(fractional_part, n_fractional_bits) - return mantissa - - -def lex_to_float(i): - assert i.bit_length() <= 64 - has_fractional_part = i >> 63 - if has_fractional_part: - exponent = (i >> 52) & ((1 << 11) - 1) - exponent = decode_exponent(exponent) - mantissa = i & MANTISSA_MASK - mantissa = update_mantissa(exponent - BIAS, mantissa) - - assert mantissa.bit_length() <= 52 - - return int_to_float((exponent << 52) | mantissa) - else: - integral_part = i & ((1 << 56) - 1) - return float(integral_part) - - -def float_to_lex(f): - if is_simple(f): - assert f >= 0 - return int(f) - - i = float_to_int(f) - i &= ((1 << 63) - 1) - exponent = i >> 52 - mantissa = i & MANTISSA_MASK - mantissa = update_mantissa(exponent - BIAS, mantissa) - exponent = encode_exponent(exponent) - - assert mantissa.bit_length() <= 52 - return (1 << 63) | (exponent << 52) | mantissa - - -def is_simple(f): - try: - i = int(f) - except (ValueError, OverflowError): - return False - if i != f: - return False - return i.bit_length() <= 56 - - -def draw_float(data): - try: - data.start_example() - f = lex_to_float(data.draw_bits(64)) - if data.draw_bits(1): - f = -f - return f - finally: - data.stop_example() - - -def write_float(data, f): - data.write(int_to_bytes(float_to_lex(abs(f)), 8)) - sign = float_to_int(f) >> 63 - data.write(hbytes([sign])) diff -Nru python-hypothesis-3.44.1/src/hypothesis/internal/conjecture/__init__.py python-hypothesis-3.71.11/src/hypothesis/internal/conjecture/__init__.py --- python-hypothesis-3.44.1/src/hypothesis/internal/conjecture/__init__.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/internal/conjecture/__init__.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER diff -Nru python-hypothesis-3.44.1/src/hypothesis/internal/conjecture/minimizer.py python-hypothesis-3.71.11/src/hypothesis/internal/conjecture/minimizer.py --- python-hypothesis-3.44.1/src/hypothesis/internal/conjecture/minimizer.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/internal/conjecture/minimizer.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,330 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import sys -import math - -from hypothesis.internal.compat import ceil, floor, hbytes, hrange, \ - int_to_bytes, int_from_bytes -from hypothesis.internal.conjecture.floats import is_simple, \ - float_to_lex, lex_to_float - - -""" -This module implements a lexicographic minimizer for blocks of bytes. - -That is, given a block of bytes of a given size, and a predicate that accepts -such blocks, it tries to find a lexicographically minimal block of that size -that satisfies the predicate, by repeatedly making local changes to that -starting point. - -Assuming it is allowed to run to completion (which due to the way we use it it -actually often isn't) it makes the following guarantees, but it usually tries -to do better in practice: - -1. The lexicographic predecessor (i.e. the largest block smaller than it) of - the answer is not a solution. -2. No individual byte in the solution may be lowered while holding the others - fixed. -""" - - -class Minimizer(object): - - def __init__(self, initial, condition, random, full): - self.current = hbytes(initial) - self.size = len(self.current) - self.condition = condition - self.random = random - self.full = full - self.changes = 0 - self.seen = set() - - def incorporate(self, buffer): - """Consider this buffer as a possible replacement for the current best - buffer. - - Return True if it succeeds as such. - - """ - assert isinstance(buffer, hbytes) - assert len(buffer) == self.size - assert buffer <= self.current - if buffer in self.seen: - return False - self.seen.add(buffer) - if buffer != self.current and self.condition(buffer): - self.current = buffer - self.changes += 1 - return True - return False - - def shift(self): - """Attempt to shift individual byte values right as far as they can - go.""" - prev = -1 - while prev != self.changes: - prev = self.changes - for i in hrange(self.size): - block = bytearray(self.current) - c = block[i] - for k in hrange(c.bit_length(), 0, -1): - block[i] = c >> k - if self.incorporate(hbytes(block)): - break - - def rotate_suffixes(self): - for significant, c in enumerate(self.current): # pragma: no branch - if c: - break - assert self.current[significant] - - prefix = hbytes(significant) - - for i in hrange(1, self.size - significant): - left = self.current[significant:significant + i] - right = self.current[significant + i:] - rotated = prefix + right + left - if rotated < self.current: - self.incorporate(rotated) - - def shrink_indices(self): - # We take a bet that there is some monotonic lower bound such that - # whenever current >= lower_bound the result works. - for i in hrange(self.size): - if self.current[i] == 0: - continue - - if self.incorporate( - self.current[:i] + hbytes([0]) + self.current[i + 1:] - ): - continue - - prefix = self.current[:i] - original_suffix = self.current[i + 1:] - - for suffix in [ - original_suffix, - hbytes([255]) * len(original_suffix), - ]: - minimize_byte( - self.current[i], - lambda c: self.current[i] == c or self.incorporate( - prefix + hbytes([c]) + suffix) - ) - - def incorporate_int(self, i): - return self.incorporate(int_to_bytes(i, self.size)) - - def incorporate_float(self, f): - assert self.size == 8 - return self.incorporate_int(float_to_lex(f)) - - def float_hack(self): - """Our encoding of floating point numbers does the right thing when you - lexically shrink it, but there are some highly non-obvious lexical - shrinks corresponding to natural floating point operations. - - We can't actually tell when the floating point encoding is being used - (that would break the assumptions that Hypothesis doesn't inspect - the generated values), but we can cheat: We just guess when it might be - being used and perform shrinks that are valid regardless of our guess - is correct. - - So that's what this method does. It's a cheat to give us good shrinking - of floating at low cost in runtime and only moderate cost in elegance. - - """ - - # If the block is of the wrong size then we're certainly not using the - # float encoding. - if self.size != 8: - return - - # If the high bit is zero then we're in the integer representation of - # floats so we don't need these hacks because it will shrink normally. - if self.current[0] >> 7 == 0: - return - - i = int_from_bytes(self.current) - f = lex_to_float(i) - - # This floating point number can be represented in our simple format. - # So we try converting it to that (which will give the same float, but - # a different encoding of it). If that doesn't work then the float - # value of this doesn't unambiguously give the desired predicate, so - # this approach isn't useful. If it *does* work, then we're now in a - # situation where we don't need it, so either way we return here. - if is_simple(f): - self.incorporate_float(f) - return - - # We check for a bunch of standard "large" floats. If we're currently - # worse than them and the shrink downwards doesn't help, abort early - # because there's not much useful we can do here. - for g in [ - float('nan'), float('inf'), sys.float_info.max, - ]: - j = float_to_lex(g) - if j < i: - if self.incorporate_int(j): - f = g - i = j - - if math.isinf(f) or math.isnan(f): - return - - # Finally we get to the important bit: Each of these is a small change - # to the floating point number that corresponds to a large change in - # the lexical representation. Trying these ensures that our floating - # point shrink can always move past these obstacles. In particular it - # ensures we can always move to integer boundaries and shrink past a - # change that would require shifting the exponent while not changing - # the float value much. - for g in [floor(f), ceil(f)]: - if self.incorporate_float(g): - return - - if f > 2: - self.incorporate_float(f - 1) - - def run(self): - if not any(self.current): - return - if len(self.current) == 1: - minimize_byte( - self.current[0], - lambda c: c == self.current[0] or self.incorporate(hbytes([c])) - ) - return - - # Initial checks as to whether the two smallest possible buffers of - # this length can work. If so there's nothing to do here. - if self.incorporate(hbytes(self.size)): - return - - if self.incorporate(hbytes([0] * (self.size - 1) + [1])): - return - - # Perform a binary search to try to replace a long initial segment with - # zero bytes. - # Note that because this property isn't monotonic this will not always - # find the longest subsequence we can replace with zero, only some - # subsequence. - - # Replacing the first nonzero bytes with zero does *not* work - nonzero = len(self.current) - - # Replacing the first canzero bytes with zero *does* work. - canzero = 0 - while self.current[canzero] == 0: - canzero += 1 - - base = self.current - - @binsearch(canzero, nonzero) - def zero_prefix(mid): - return self.incorporate( - hbytes(mid) + - base[mid:] - ) - - base = self.current - - @binsearch(0, self.size) - def shift_right(mid): - if mid == 0: - return True - if mid == self.size: - return False - return self.incorporate(hbytes(mid) + base[:-mid]) - - change_counter = -1 - first = True - while ( - (first or self.full) and - change_counter < self.changes - ): - first = False - change_counter = self.changes - - self.float_hack() - self.shift() - self.shrink_indices() - self.rotate_suffixes() - - -def minimize(initial, condition, random, full=True): - """Perform a lexicographical minimization of the byte string 'initial' such - that the predicate 'condition' returns True, and return the minimized - string.""" - m = Minimizer(initial, condition, random, full) - m.run() - return m.current - - -def binsearch(_lo, _hi): - """Run a binary search to find the point at which a function changes value - between two bounds. - - This function is used purely for its side effects and returns - nothing. - - """ - def accept(f): - lo = _lo - hi = _hi - - loval = f(lo) - hival = f(hi) - - if loval == hival: - return - - while lo + 1 < hi: - mid = (lo + hi) // 2 - midval = f(mid) - if midval == loval: - lo = mid - else: - assert hival == midval - hi = mid - return accept - - -def minimize_byte(c, f): - """Return the smallest byte for which a function `f` returns True, starting - with the byte `c` as an unsigned integer.""" - if f(0): - return 0 - if c == 1 or f(1): - return 1 - elif c == 2: - return 2 - if f(c - 1): - lo = 1 - hi = c - 1 - while lo + 1 < hi: - mid = (lo + hi) // 2 - if f(mid): - hi = mid - else: - lo = mid - return hi - return c diff -Nru python-hypothesis-3.44.1/src/hypothesis/internal/conjecture/utils.py python-hypothesis-3.71.11/src/hypothesis/internal/conjecture/utils.py --- python-hypothesis-3.44.1/src/hypothesis/internal/conjecture/utils.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/internal/conjecture/utils.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,348 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import enum -import math -from collections import Sequence, OrderedDict - -from hypothesis._settings import note_deprecation -from hypothesis.internal.compat import floor, hbytes, bit_length, \ - int_from_bytes -from hypothesis.internal.floats import int_to_float - - -def integer_range(data, lower, upper, center=None): - assert lower <= upper - if lower == upper: - return int(lower) - - if center is None: - center = lower - center = min(max(center, lower), upper) - - if center == upper: - above = False - elif center == lower: - above = True - else: - above = boolean(data) - - if above: - gap = upper - center - else: - gap = center - lower - - assert gap > 0 - - bits = bit_length(gap) - probe = gap + 1 - - while probe > gap: - probe = data.draw_bits(bits) - - if above: - result = center + probe - else: - result = center - probe - - assert lower <= result <= upper - return int(result) - - -def centered_integer_range(data, lower, upper, center): - return integer_range( - data, lower, upper, center=center - ) - - -def check_sample(values): - try: - from numpy import ndarray - if isinstance(values, ndarray): - if values.ndim != 1: - note_deprecation(( - 'Only one-dimensional arrays are supported for sampling, ' - 'and the given value has {ndim} dimensions (shape ' - '{shape}). This array would give samples of array slices ' - 'instead of elements! Use np.ravel(values) to convert ' - 'to a one-dimensional array, or tuple(values) if you ' - 'want to sample slices. Sampling a multi-dimensional ' - 'array will be an error in a future version of Hypothesis.' - ).format(ndim=values.ndim, shape=values.shape)) - return tuple(values) - except ImportError: # pragma: no cover - pass - - if not isinstance(values, (OrderedDict, Sequence, enum.EnumMeta)): - note_deprecation( - ('Cannot sample from %r, not a sequence. ' % (values,)) + - 'Hypothesis goes to some length to ensure that sampling an ' - 'element from a collection (with `sampled_from` or `choices`) is ' - 'replayable and can be minimised. To replay a saved example, ' - 'the sampled values must have the same iteration order on every ' - 'run - ruling out sets, dicts, etc due to hash randomisation. ' - 'Most cases can simply use `sorted(values)`, but mixed types or ' - 'special values such as math.nan require careful handling - and ' - 'note that when simplifying an example, Hypothesis treats ' - 'earlier values as simpler.') - return tuple(values) - - -def choice(data, values): - return values[integer_range(data, 0, len(values) - 1)] - - -def getrandbits(data, n): - n_bytes = n // 8 - if n % 8 != 0: - n_bytes += 1 - return int_from_bytes(data.draw_bytes(n_bytes)) & ((1 << n) - 1) - - -FLOAT_PREFIX = 0b1111111111 << 52 -FULL_FLOAT = int_to_float(FLOAT_PREFIX | ((2 << 53) - 1)) - 1 - - -def fractional_float(data): - return ( - int_to_float(FLOAT_PREFIX | getrandbits(data, 52)) - 1 - ) / FULL_FLOAT - - -def geometric(data, p): - denom = math.log1p(-p) - - data.start_example() - while True: - probe = fractional_float(data) - if probe < 1.0: - result = int(math.log1p(-probe) / denom) - assert result >= 0, (probe, p, result) - data.stop_example() - return result - - -def boolean(data): - return bool(data.draw_bits(1)) - - -def biased_coin(data, p): - """Return False with probability p (assuming a uniform generator), - shrinking towards False.""" - data.start_example() - while True: - # The logic here is a bit complicated and special cased to make it - # play better with the shrinker. - - # We imagine partitioning the real interval [0, 1] into 256 equal parts - # and looking at each part and whether its interior is wholly <= p - # or wholly >= p. At most one part can be neither. - - # We then pick a random part. If it's wholly on one side or the other - # of p then we use that as the answer. If p is contained in the - # interval then we start again with a new probability that is given - # by the fraction of that interval that was <= our previous p. - - # We then take advantage of the fact that we have control of the - # labelling to make this shrink better, using the following tricks: - - # If p is <= 0 or >= 1 the result of this coin is certain. We make sure - # to write a byte to the data stream anyway so that these don't cause - # difficulties when shrinking. - if p <= 0: - data.write(hbytes([0])) - result = False - elif p >= 1: - data.write(hbytes([1])) - result = True - else: - falsey = floor(256 * (1 - p)) - truthy = floor(256 * p) - remainder = 256 * p - truthy - - if falsey + truthy == 256: - m, n = p.as_integer_ratio() - assert n & (n - 1) == 0, n # n is a power of 2 - assert n > m > 0 - truthy = m - falsey = n - m - bits = bit_length(n) - 1 - partial = False - else: - bits = 8 - partial = True - - i = data.draw_bits(bits) - - # We always label the region that causes us to repeat the loop as - # 255 so that shrinking this byte never causes us to need to draw - # more data. - if partial and i == 255: - p = remainder - continue - if falsey == 0: - # Every other partition is truthy, so the result is true - result = True - elif truthy == 0: - # Every other partition is falsey, so the result is false - result = False - elif i <= 1: - # We special case so that zero is always false and 1 is always - # true which makes shrinking easier because we can always - # replace a truthy block with 1. This has the slightly weird - # property that shrinking from 2 to 1 can cause the result to - # grow, but the shrinker always tries 0 and 1 first anyway, so - # this will usually be fine. - result = bool(i) - else: - # Originally everything in the region 0 <= i < falsey was false - # and everything above was true. We swapped one truthy element - # into this region, so the region becomes 0 <= i <= falsey - # except for i = 1. We know i > 1 here, so the test for truth - # becomes i > falsey. - result = i > falsey - break - data.stop_example() - return result - - -class Sampler(object): - """Sampler based on "Succinct Sampling from Discrete Distributions" by - Bringmann and Larsen. In general it has some advantages and disadvantages - compared to the more normal alias method, but its big advantage for us is - that it plays well with shrinking: The values are laid out in their natural - order, so shrink in that order. - - Its big disadvantage is that for heavily biased distributions it can - use a lot of memory. Solution is some mix of "don't do that then" - and not worrying about it because Hypothesis is something of a - memory hog anyway. - - """ - - def __init__(self, weights): - # We consider each weight expressed in terms of the average weight, - # say t. We write the weight of i as nt + f, where n is an integer and - # 0 <= f < 1. We then store n items for this weight which correspond - # to drawing i unconditionally, and if f > 0 we store an additional - # item that corresponds to drawing i with probability f. This ensures - # that (under a uniform model) we draw i with probability proportionate - # to its weight. - - # We then rearrange things to shrink better. The table with the whole - # weights is kept in sorted order so that shrinking still corresponds - # to shrinking leftwards. The fractional weights however are put in - # a second table that is logically "to the right" of the whole weights - # and are sorted in order of decreasing acceptance probaility. This - # ensures that shrinking lexicographically always results in drawing - # less data. - self.table = [] - self.extras = [] - self.acceptance = [] - total = sum(weights) - n = len(weights) - for i, x in enumerate(weights): - whole_occurrences = floor(x * n / total) - acceptance = x - whole_occurrences - self.acceptance.append(acceptance) - for _ in range(whole_occurrences): - self.table.append(i) - if acceptance > 0: - self.extras.append(i) - self.extras.sort(key=self.acceptance.__getitem__, reverse=True) - - def sample(self, data): - while True: - data.start_example() - # We always draw the acceptance data even if we don't need it, - # because that way we keep the amount of data we use stable. - i = integer_range(data, 0, len(self.table) + len(self.extras) - 1) - if i < len(self.table): - result = self.table[i] - data.stop_example() - return result - else: - result = self.extras[i - len(self.table)] - accept = not biased_coin(data, 1 - self.acceptance[result]) - data.stop_example() - if accept: - return result - - -class many(object): - """Utility class for collections. Bundles up the logic we use for "should I - keep drawing more values?" and handles starting and stopping examples in - the right place. - - Intended usage is something like: - - elements = many(data, ...) - while elements.more(): - add_stuff_to_result() - - """ - - def __init__(self, data, min_size, max_size, average_size): - self.min_size = min_size - self.max_size = max_size - self.data = data - self.stopping_value = 1 - 1.0 / (1 + average_size) - self.count = 0 - self.rejections = 0 - self.drawn = False - self.force_stop = False - - def more(self): - """Should I draw another element to add to the collection?""" - if self.drawn: - self.data.stop_example() - - self.drawn = True - - if self.min_size == self.max_size: - should_continue = self.count < self.min_size - elif self.force_stop: - should_continue = False - else: - if self.count < self.min_size: - p_continue = 1.0 - elif self.count >= self.max_size: - p_continue = 0.0 - else: - p_continue = self.stopping_value - should_continue = biased_coin(self.data, p_continue) - - if should_continue: - self.data.start_example() - self.count += 1 - return True - else: - return False - - def reject(self): - """Reject the last example (i.e. don't count it towards our budget of - elements because it's not going to go in the final collection)""" - assert self.count > 0 - self.count -= 1 - self.rejections += 1 - if self.rejections > 2 * self.count: - if self.count < self.min_size: - self.data.mark_invalid() - else: - self.force_stop = True diff -Nru python-hypothesis-3.44.1/src/hypothesis/internal/coverage.py python-hypothesis-3.71.11/src/hypothesis/internal/coverage.py --- python-hypothesis-3.44.1/src/hypothesis/internal/coverage.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/internal/coverage.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,125 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import os -import sys -import json -from contextlib import contextmanager - -from hypothesis.internal.reflection import proxies - -""" -This module implements a custom coverage system that records conditions and -then validates that every condition has been seen to be both True and False -during the execution of our tests. - -The only thing we use it for at present is our argument validation functions, -where we assert that every validation function has been seen to both pass and -fail in the course of testing. - -When not running with a magic environment variable set, this module disables -itself and has essentially no overhead. -""" - -pretty_file_name_cache = {} - - -def pretty_file_name(f): - try: - return pretty_file_name_cache[f] - except KeyError: - pass - - parts = f.split(os.path.sep) - parts = parts[parts.index('hypothesis'):] - result = os.path.sep.join(parts) - pretty_file_name_cache[f] = result - return result - - -IN_COVERAGE_TESTS = os.getenv('HYPOTHESIS_INTERNAL_COVERAGE') == 'true' - - -if IN_COVERAGE_TESTS: - log = open('branch-check', 'w') - written = set() - - def record_branch(name, value): - key = (name, value) - if key in written: - return - written.add(key) - log.write( - json.dumps({'name': name, 'value': value}) - ) - log.write('\n') - log.flush() - - description_stack = [] - - @contextmanager - def check_block(name, depth): - # We add an extra two callers to the stack: One for the contextmanager - # function, one for our actual caller, so we want to go two extra - # stack frames up. - caller = sys._getframe(depth + 2) - local_description = '%s at %s:%d' % ( - name, - pretty_file_name(caller.f_code.co_filename), - caller.f_lineno, - ) - try: - description_stack.append(local_description) - description = ' in '.join(reversed(description_stack)) + ' passed' - yield - record_branch(description, True) - except BaseException: - record_branch(description, False) - raise - finally: - description_stack.pop() - - @contextmanager - def check(name): - with check_block(name, 2): - yield - - def check_function(f): - @proxies(f) - def accept(*args, **kwargs): - # depth of 2 because of the proxy function calling us. - with check_block(f.__name__, 2): - return f(*args, **kwargs) - return accept -else: - def check_function(f): - return f - - @contextmanager - def check(name): - yield - - -class suppress_tracing(object): - def __enter__(self): - self.__original_trace = sys.gettrace() - sys.settrace(None) - - def __exit__(self, exc_type, exc_value, traceback): - sys.settrace(self.__original_trace) diff -Nru python-hypothesis-3.44.1/src/hypothesis/internal/detection.py python-hypothesis-3.71.11/src/hypothesis/internal/detection.py --- python-hypothesis-3.44.1/src/hypothesis/internal/detection.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/internal/detection.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,26 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from types import MethodType - - -def is_hypothesis_test(test): - if isinstance(test, MethodType): - return is_hypothesis_test(test.__func__) - return getattr(test, 'is_hypothesis_test', False) diff -Nru python-hypothesis-3.44.1/src/hypothesis/internal/escalation.py python-hypothesis-3.71.11/src/hypothesis/internal/escalation.py --- python-hypothesis-3.44.1/src/hypothesis/internal/escalation.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/internal/escalation.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,83 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import os -import sys - -import coverage - -import hypothesis -from hypothesis.errors import StopTest, DeadlineExceeded, \ - HypothesisException, UnsatisfiedAssumption -from hypothesis.internal.compat import text_type, binary_type, \ - encoded_filepath - - -def belongs_to(package): - root = os.path.dirname(package.__file__) - cache = {text_type: {}, binary_type: {}} - - def accept(filepath): - try: - return cache[type(filepath)][filepath] - except KeyError: - pass - filepath = encoded_filepath(filepath) - result = os.path.abspath(filepath).startswith(root) - cache[type(filepath)][filepath] = result - return result - accept.__name__ = 'is_%s_file' % (package.__name__,) - return accept - - -PREVENT_ESCALATION = os.getenv('HYPOTHESIS_DO_NOT_ESCALATE') == 'true' - -FILE_CACHE = {} - - -is_hypothesis_file = belongs_to(hypothesis) -is_coverage_file = belongs_to(coverage) - -HYPOTHESIS_CONTROL_EXCEPTIONS = ( - DeadlineExceeded, StopTest, UnsatisfiedAssumption -) - - -def mark_for_escalation(e): - if not isinstance(e, HYPOTHESIS_CONTROL_EXCEPTIONS): - e.hypothesis_internal_always_escalate = True - - -def escalate_hypothesis_internal_error(): - if PREVENT_ESCALATION: - return - error_type, e, tb = sys.exc_info() - if getattr(e, 'hypothesis_internal_always_escalate', False): - raise - import traceback - filepath = traceback.extract_tb(tb)[-1][0] - if is_hypothesis_file(filepath) and not isinstance( - e, (HypothesisException,) + HYPOTHESIS_CONTROL_EXCEPTIONS, - ): - raise - # This is so that if we do something wrong and trigger an internal Coverage - # error we don't try to catch it. It should be impossible to trigger, but - # you never know. - if is_coverage_file(filepath): # pragma: no cover - raise diff -Nru python-hypothesis-3.44.1/src/hypothesis/internal/floats.py python-hypothesis-3.71.11/src/hypothesis/internal/floats.py --- python-hypothesis-3.44.1/src/hypothesis/internal/floats.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/internal/floats.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,59 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import math - -from hypothesis.internal.compat import struct_pack, struct_unpack - - -def sign(x): - try: - return math.copysign(1.0, x) - except TypeError: - raise TypeError('Expected float but got %r of type %s' % ( - x, type(x).__name__ - )) - - -def is_negative(x): - return sign(x) < 0 - - -def count_between_floats(x, y): - assert x <= y - if is_negative(x): - if is_negative(y): - return float_to_int(x) - float_to_int(y) + 1 - else: - return count_between_floats(x, -0.0) + count_between_floats(0.0, y) - else: - assert not is_negative(y) - return float_to_int(y) - float_to_int(x) + 1 - - -def float_to_int(value): - return ( - struct_unpack(b'!Q', struct_pack(b'!d', value))[0] - ) - - -def int_to_float(value): - return ( - struct_unpack(b'!d', struct_pack(b'!Q', value))[0] - ) diff -Nru python-hypothesis-3.44.1/src/hypothesis/internal/healthcheck.py python-hypothesis-3.71.11/src/hypothesis/internal/healthcheck.py --- python-hypothesis-3.44.1/src/hypothesis/internal/healthcheck.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/internal/healthcheck.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,38 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from hypothesis.errors import FailedHealthCheck - - -def fail_health_check(settings, message, label): - # Tell pytest to omit the body of this function from tracebacks - # http://doc.pytest.org/en/latest/example/simple.html#writing-well-integrated-assertion-helpers - __tracebackhide__ = True - - if label in settings.suppress_health_check: - return - if not settings.perform_health_check: - return - message += ( - '\nSee https://hypothesis.readthedocs.io/en/latest/health' - 'checks.html for more information about this. ' - 'If you want to disable just this health check, add %s ' - 'to the suppress_health_check settings for this test.' - ) % (label,) - raise FailedHealthCheck(message, label) diff -Nru python-hypothesis-3.44.1/src/hypothesis/internal/__init__.py python-hypothesis-3.71.11/src/hypothesis/internal/__init__.py --- python-hypothesis-3.44.1/src/hypothesis/internal/__init__.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/internal/__init__.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER diff -Nru python-hypothesis-3.44.1/src/hypothesis/internal/intervalsets.py python-hypothesis-3.71.11/src/hypothesis/internal/intervalsets.py --- python-hypothesis-3.44.1/src/hypothesis/internal/intervalsets.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/internal/intervalsets.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,84 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - - -class IntervalSet(object): - - def __init__(self, intervals): - self.intervals = tuple(intervals) - self.offsets = [0] - for u, v in self.intervals: - self.offsets.append( - self.offsets[-1] + v - u + 1 - ) - self.size = self.offsets.pop() - - def __len__(self): - return self.size - - def __iter__(self): - for u, v in self.intervals: - for i in range(u, v + 1): - yield i - - def __getitem__(self, i): - if i < 0: - i = self.size + i - if i < 0 or i >= self.size: - raise IndexError('Invalid index %d for [0, %d)' % (i, self.size)) - # Want j = maximal such that offsets[j] <= i - - j = len(self.intervals) - 1 - if self.offsets[j] > i: - hi = j - lo = 0 - # Invariant: offsets[lo] <= i < offsets[hi] - while lo + 1 < hi: - mid = (lo + hi) // 2 - if self.offsets[mid] <= i: - lo = mid - else: - hi = mid - j = lo - t = i - self.offsets[j] - u, v = self.intervals[j] - r = u + t - assert r <= v - return r - - def __repr__(self): - return 'IntervalSet(%r)' % (self.intervals,) - - def index(self, value): - for offset, (u, v) in zip(self.offsets, self.intervals): - if u == value: - return offset - elif u > value: - raise ValueError('%d is not in list' % (value,)) - if value <= v: - return offset + (value - u) - raise ValueError('%d is not in list' % (value,)) - - def index_above(self, value): - for offset, (u, v) in zip(self.offsets, self.intervals): - if u >= value: - return offset - if value <= v: - return offset + (value - u) - return self.size diff -Nru python-hypothesis-3.44.1/src/hypothesis/internal/lazyformat.py python-hypothesis-3.71.11/src/hypothesis/internal/lazyformat.py --- python-hypothesis-3.44.1/src/hypothesis/internal/lazyformat.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/internal/lazyformat.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,42 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - - -class lazyformat(object): - """A format string that isn't evaluated until it's needed.""" - - def __init__(self, format_string, *args): - self.__format_string = format_string - self.__args = args - - def __str__(self): - return self.__format_string % self.__args - - def __eq__(self, other): - return ( - isinstance(other, lazyformat) and - self.__format_string == other.__format_string and - self.__args == other.__args - ) - - def __ne__(self, other): - return not self.__eq__(other) - - def __hash__(self): - return hash(self.__format_string) diff -Nru python-hypothesis-3.44.1/src/hypothesis/internal/reflection.py python-hypothesis-3.71.11/src/hypothesis/internal/reflection.py --- python-hypothesis-3.44.1/src/hypothesis/internal/reflection.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/internal/reflection.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,545 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -"""This file can approximately be considered the collection of hypothesis going -to really unreasonable lengths to produce pretty output.""" - - -from __future__ import division, print_function, absolute_import - -import re -import ast -import uuid -import types -import hashlib -import inspect -from types import ModuleType -from functools import wraps - -from hypothesis.configuration import storage_directory -from hypothesis.vendor.pretty import pretty -from hypothesis.internal.compat import ARG_NAME_ATTRIBUTE, hrange, \ - to_str, qualname, to_unicode, isidentifier, str_to_bytes, \ - getfullargspec, update_code_location - - -def fully_qualified_name(f): - """Returns a unique identifier for f pointing to the module it was define - on, and an containing functions.""" - if f.__module__ is not None: - return f.__module__ + '.' + qualname(f) - else: - return qualname(f) - - -def is_mock(obj): - """Determine if the given argument is a mock type. - - We want to be able to detect these when dealing with various test - args. As they are sneaky and can look like almost anything else, - we'll check this by looking for random attributes. This is more - robust than looking for types. - - """ - for _ in range(10): - if not hasattr(obj, str(uuid.uuid4())): - return False - return True - - -def function_digest(function): - """Returns a string that is stable across multiple invocations across - multiple processes and is prone to changing significantly in response to - minor changes to the function. - - No guarantee of uniqueness though it usually will be. - - """ - hasher = hashlib.md5() - try: - hasher.update(to_unicode(inspect.getsource(function)).encode('utf-8')) - # Different errors on different versions of python. What fun. - except (OSError, IOError, TypeError): - pass - try: - hasher.update(str_to_bytes(function.__name__)) - except AttributeError: - pass - try: - hasher.update(function.__module__.__name__.encode('utf-8')) - except AttributeError: - pass - try: - hasher.update(str_to_bytes(repr(getfullargspec(function)))) - except TypeError: - pass - return hasher.digest() - - -def required_args(target, args=(), kwargs=()): - """Return a set of names of required args to target that were not supplied - in args or kwargs. - - This is used in builds() to determine which arguments to attempt to - fill from type hints. target may be any callable (including classes - and bound methods). args and kwargs should be as they are passed to - builds() - that is, a tuple of values and a dict of names: values. - - """ - try: - spec = getfullargspec( - target.__init__ if inspect.isclass(target) else target) - except TypeError: # pragma: no cover - return None - # self appears in the argspec of __init__ and bound methods, but it's an - # error to explicitly supply it - so we might skip the first argument. - skip_self = int(inspect.isclass(target) or inspect.ismethod(target)) - # Start with the args that were not supplied and all kwonly arguments, - # then remove all positional arguments with default values, and finally - # remove kwonly defaults and any supplied keyword arguments - return set(spec.args[skip_self + len(args):] + spec.kwonlyargs) \ - - set(spec.args[len(spec.args) - len(spec.defaults or ()):]) \ - - set(spec.kwonlydefaults or ()) - set(kwargs) - - -def convert_keyword_arguments(function, args, kwargs): - """Returns a pair of a tuple and a dictionary which would be equivalent - passed as positional and keyword args to the function. Unless function has. - - **kwargs the dictionary will always be empty. - - """ - argspec = getfullargspec(function) - new_args = [] - kwargs = dict(kwargs) - - defaults = dict(argspec.kwonlydefaults or {}) - - if argspec.defaults: - for name, value in zip( - argspec.args[-len(argspec.defaults):], - argspec.defaults - ): - defaults[name] = value - - n = max(len(args), len(argspec.args)) - - for i in hrange(n): - if i < len(args): - new_args.append(args[i]) - else: - arg_name = argspec.args[i] - if arg_name in kwargs: - new_args.append(kwargs.pop(arg_name)) - elif arg_name in defaults: - new_args.append(defaults[arg_name]) - else: - raise TypeError('No value provided for argument %r' % ( - arg_name - )) - - if kwargs and not argspec.varkw: - if len(kwargs) > 1: - raise TypeError('%s() got unexpected keyword arguments %s' % ( - function.__name__, ', '.join(map(repr, kwargs)) - )) - else: - bad_kwarg = next(iter(kwargs)) - raise TypeError('%s() got an unexpected keyword argument %r' % ( - function.__name__, bad_kwarg - )) - return tuple(new_args), kwargs - - -def convert_positional_arguments(function, args, kwargs): - """Return a tuple (new_args, new_kwargs) where all possible arguments have - been moved to kwargs. - - new_args will only be non-empty if function has a variadic argument. - - """ - argspec = getfullargspec(function) - new_kwargs = dict(argspec.kwonlydefaults or {}) - new_kwargs.update(kwargs) - if not argspec.varkw: - for k in new_kwargs.keys(): - if k not in argspec.args and k not in argspec.kwonlyargs: - raise TypeError( - '%s() got an unexpected keyword argument %r' % ( - function.__name__, k - )) - if len(args) < len(argspec.args): - for i in hrange( - len(args), len(argspec.args) - len(argspec.defaults or ()) - ): - if argspec.args[i] not in kwargs: - raise TypeError('No value provided for argument %s' % ( - argspec.args[i], - )) - for kw in argspec.kwonlyargs: - if kw not in new_kwargs: - raise TypeError('No value provided for argument %s' % kw) - - if len(args) > len(argspec.args) and not argspec.varargs: - raise TypeError( - '%s() takes at most %d positional arguments (%d given)' % ( - function.__name__, len(argspec.args), len(args) - ) - ) - - for arg, name in zip(args, argspec.args): - if name in new_kwargs: - raise TypeError( - '%s() got multiple values for keyword argument %r' % ( - function.__name__, name - )) - else: - new_kwargs[name] = arg - return ( - tuple(args[len(argspec.args):]), - new_kwargs, - ) - - -def extract_all_lambdas(tree): - lambdas = [] - - class Visitor(ast.NodeVisitor): - - def visit_Lambda(self, node): - lambdas.append(node) - - Visitor().visit(tree) - - return lambdas - - -def args_for_lambda_ast(l): - return [getattr(n, ARG_NAME_ATTRIBUTE) for n in l.args.args] - - -LINE_CONTINUATION = re.compile(r"\\\n") -WHITESPACE = re.compile(r"\s+") -PROBABLY_A_COMMENT = re.compile("""#[^'"]*$""") -SPACE_FOLLOWS_OPEN_BRACKET = re.compile(r"\( ") -SPACE_PRECEDES_CLOSE_BRACKET = re.compile(r" \)") - - -def extract_lambda_source(f): - """Extracts a single lambda expression from the string source. Returns a - string indicating an unknown body if it gets confused in any way. - - This is not a good function and I am sorry for it. Forgive me my - sins, oh lord - - """ - argspec = getfullargspec(f) - arg_strings = [] - # In Python 2 you can have destructuring arguments to functions. This - # results in an argspec with non-string values. I'm not very interested in - # handling these properly, but it's important to not crash on them. - bad_lambda = False - for a in argspec.args: - if isinstance(a, (tuple, list)): # pragma: no cover - arg_strings.append('(%s)' % (', '.join(a),)) - bad_lambda = True - else: - assert isinstance(a, str) - arg_strings.append(a) - if argspec.varargs: - arg_strings.append('*' + argspec.varargs) - elif argspec.kwonlyargs: - arg_strings.append('*') - for a in (argspec.kwonlyargs or []): - default = (argspec.kwonlydefaults or {}).get(a) - if default: - arg_strings.append('{}={}'.format(a, default)) - else: - arg_strings.append(a) - - if_confused = 'lambda %s: ' % (', '.join(arg_strings),) - if bad_lambda: # pragma: no cover - return if_confused - try: - source = inspect.getsource(f) - except IOError: - return if_confused - - source = LINE_CONTINUATION.sub(' ', source) - source = WHITESPACE.sub(' ', source) - source = source.strip() - assert 'lambda' in source - - tree = None - - try: - tree = ast.parse(source) - except SyntaxError: - for i in hrange(len(source) - 1, len('lambda'), -1): - prefix = source[:i] - if 'lambda' not in prefix: - break - try: - tree = ast.parse(prefix) - source = prefix - break - except SyntaxError: - continue - if tree is None: - if source.startswith('@'): - # This will always eventually find a valid expression because - # the decorator must be a valid Python function call, so will - # eventually be syntactically valid and break out of the loop. Thus - # this loop can never terminate normally, so a no branch pragma is - # appropriate. - for i in hrange(len(source) + 1): # pragma: no branch - p = source[1:i] - if 'lambda' in p: - try: - tree = ast.parse(p) - source = p - break - except SyntaxError: - pass - - if tree is None: - return if_confused - - all_lambdas = extract_all_lambdas(tree) - aligned_lambdas = [ - l for l in all_lambdas - if args_for_lambda_ast(l) == argspec.args - ] - if len(aligned_lambdas) != 1: - return if_confused - lambda_ast = aligned_lambdas[0] - assert lambda_ast.lineno == 1 - source = source[lambda_ast.col_offset:].strip() - - source = source[source.index('lambda'):] - for i in hrange(len(source), len('lambda'), -1): # pragma: no branch - try: - parsed = ast.parse(source[:i]) - assert len(parsed.body) == 1 - assert parsed.body - if isinstance(parsed.body[0].value, ast.Lambda): - source = source[:i] - break - except SyntaxError: - pass - lines = source.split('\n') - lines = [PROBABLY_A_COMMENT.sub('', l) for l in lines] - source = '\n'.join(lines) - - source = WHITESPACE.sub(' ', source) - source = SPACE_FOLLOWS_OPEN_BRACKET.sub('(', source) - source = SPACE_PRECEDES_CLOSE_BRACKET.sub(')', source) - source = source.strip() - return source - - -def get_pretty_function_description(f): - if not hasattr(f, '__name__'): - return repr(f) - name = f.__name__ - if name == '': - result = extract_lambda_source(f) - return result - elif isinstance(f, types.MethodType): - self = f.__self__ - if not (self is None or inspect.isclass(self)): - return '%r.%s' % (self, name) - return name - - -def nicerepr(v): - if inspect.isfunction(v): - return get_pretty_function_description(v) - elif isinstance(v, type): - return v.__name__ - else: - return to_str(pretty(v)) - - -def arg_string(f, args, kwargs, reorder=True): - if reorder: - args, kwargs = convert_positional_arguments(f, args, kwargs) - - argspec = getfullargspec(f) - - bits = [] - - for a in argspec.args: - if a in kwargs: - bits.append('%s=%s' % (a, nicerepr(kwargs.pop(a)))) - if kwargs: - for a in sorted(kwargs): - bits.append('%s=%s' % (a, nicerepr(kwargs[a]))) - - return ', '.join([nicerepr(x) for x in args] + bits) - - -def unbind_method(f): - """Take something that might be a method or a function and return the - underlying function.""" - return getattr(f, 'im_func', getattr(f, '__func__', f)) - - -def check_valid_identifier(identifier): - if not isidentifier(identifier): - raise ValueError('%r is not a valid python identifier' % - (identifier,)) - - -def eval_directory(): - return storage_directory('eval_source') - - -eval_cache = {} - - -def source_exec_as_module(source): - try: - return eval_cache[source] - except KeyError: - pass - - result = ModuleType('hypothesis_temporary_module_%s' % ( - hashlib.sha1(str_to_bytes(source)).hexdigest(), - )) - assert isinstance(source, str) - exec(source, result.__dict__) - eval_cache[source] = result - return result - - -COPY_ARGSPEC_SCRIPT = """ -from hypothesis.utils.conventions import not_set - -def accept(%(funcname)s): - def %(name)s(%(argspec)s): - return %(funcname)s(%(invocation)s) - return %(name)s -""".strip() + '\n' - - -def define_function_signature(name, docstring, argspec): - """A decorator which sets the name, argspec and docstring of the function - passed into it.""" - check_valid_identifier(name) - for a in argspec.args: - check_valid_identifier(a) - if argspec.varargs is not None: - check_valid_identifier(argspec.varargs) - if argspec.varkw is not None: - check_valid_identifier(argspec.varkw) - n_defaults = len(argspec.defaults or ()) - if n_defaults: - parts = [] - for a in argspec.args[:-n_defaults]: - parts.append(a) - for a in argspec.args[-n_defaults:]: - parts.append('%s=not_set' % (a,)) - else: - parts = list(argspec.args) - used_names = list(argspec.args) + list(argspec.kwonlyargs) - used_names.append(name) - - for a in argspec.kwonlyargs: - check_valid_identifier(a) - - def accept(f): - fargspec = getfullargspec(f) - must_pass_as_kwargs = [] - invocation_parts = [] - for a in argspec.args: - if a not in fargspec.args and not fargspec.varargs: - must_pass_as_kwargs.append(a) - else: - invocation_parts.append(a) - if argspec.varargs: - used_names.append(argspec.varargs) - parts.append('*' + argspec.varargs) - invocation_parts.append('*' + argspec.varargs) - elif argspec.kwonlyargs: - parts.append('*') - for k in must_pass_as_kwargs: - invocation_parts.append('%(k)s=%(k)s' % {'k': k}) - - for k in argspec.kwonlyargs: - invocation_parts.append('%(k)s=%(k)s' % {'k': k}) - if k in (argspec.kwonlydefaults or []): - parts.append('%(k)s=not_set' % {'k': k}) - else: - parts.append(k) - if argspec.varkw: - used_names.append(argspec.varkw) - parts.append('**' + argspec.varkw) - invocation_parts.append('**' + argspec.varkw) - - candidate_names = ['f'] + [ - 'f_%d' % (i,) for i in hrange(1, len(used_names) + 2) - ] - - for funcname in candidate_names: # pragma: no branch - if funcname not in used_names: - break - - base_accept = source_exec_as_module( - COPY_ARGSPEC_SCRIPT % { - 'name': name, - 'funcname': funcname, - 'argspec': ', '.join(parts), - 'invocation': ', '.join(invocation_parts) - }).accept - - result = base_accept(f) - result.__doc__ = docstring - result.__defaults__ = argspec.defaults - if argspec.kwonlydefaults: - result.__kwdefaults__ = argspec.kwonlydefaults - if argspec.annotations: - result.__annotations__ = argspec.annotations - return result - return accept - - -def impersonate(target): - """Decorator to update the attributes of a function so that to external - introspectors it will appear to be the target function. - - Note that this updates the function in place, it doesn't return a - new one. - - """ - def accept(f): - f.__code__ = update_code_location( - f.__code__, - target.__code__.co_filename, target.__code__.co_firstlineno - ) - f.__name__ = target.__name__ - f.__module__ = target.__module__ - f.__doc__ = target.__doc__ - return f - return accept - - -def proxies(target): - def accept(proxy): - return impersonate(target)(wraps(target)(define_function_signature( - target.__name__, target.__doc__, getfullargspec(target))(proxy))) - return accept diff -Nru python-hypothesis-3.44.1/src/hypothesis/internal/renaming.py python-hypothesis-3.71.11/src/hypothesis/internal/renaming.py --- python-hypothesis-3.44.1/src/hypothesis/internal/renaming.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/internal/renaming.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,66 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from hypothesis._settings import note_deprecation -from hypothesis.internal.reflection import proxies - - -def renamed_arguments(**rename_mapping): - """Helper function for deprecating arguments that have been renamed to a - new form.""" - assert len(set(rename_mapping.values())) == len(rename_mapping) - - def accept(f): - @proxies(f) - def with_name_check(**kwargs): - for k, v in list(kwargs.items()): - if k in rename_mapping and v is not None: - t = rename_mapping[k] - note_deprecation(( - 'The argument %s has been renamed to %s. The old ' - 'name will go away in a future version of ' - 'Hypothesis.') % (k, t)) - kwargs[t] = kwargs.pop(k) - return f(**kwargs) - - # This decorates things in the public API, which all have docstrings. - # (If they're not in the public API, we don't need a deprecation path.) - # But docstrings are stripped when running with PYTHONOPTIMIZE=2. - # - # If somebody's running with that flag, they don't expect any - # docstrings to be present, so this message isn't useful. Absence of - # a docstring is a strong indicator that they're running in this mode, - # so skip adding this message if that's the case. - if with_name_check.__doc__ is not None: - with_name_check.__doc__ += '\n'.join(( - '', '', - 'The following arguments have been renamed:', - '', - ) + tuple( - ' * %s has been renamed to %s' % s - for s in rename_mapping.items() - ) + ( - '', - 'Use of the old names has been deprecated and will be removed', - 'in a future version of Hypothesis.' - ) - ) - - return with_name_check - return accept diff -Nru python-hypothesis-3.44.1/src/hypothesis/internal/validation.py python-hypothesis-3.71.11/src/hypothesis/internal/validation.py --- python-hypothesis-3.44.1/src/hypothesis/internal/validation.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/internal/validation.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,147 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import math -from numbers import Rational - -from hypothesis.errors import InvalidArgument -from hypothesis.internal.compat import integer_types -from hypothesis.internal.coverage import check_function - - -@check_function -def check_type(typ, arg, name=''): - if name: - name += '=' - if not isinstance(arg, typ): - if isinstance(typ, type): - typ_string = typ.__name__ - else: - typ_string = 'one of %s' % ( - ', '.join(t.__name__ for t in typ)) - raise InvalidArgument('Expected %s but got %s%r (type=%s)' - % (typ_string, name, arg, type(arg).__name__)) - - -@check_function -def check_strategy(arg, name=''): - from hypothesis.searchstrategy import SearchStrategy - check_type(SearchStrategy, arg, name) - - -@check_function -def check_valid_integer(value): - """Checks that value is either unspecified, or a valid integer. - - Otherwise raises InvalidArgument. - - """ - if value is None: - return - check_type(integer_types, value) - - -@check_function -def check_valid_bound(value, name): - """Checks that value is either unspecified, or a valid interval bound. - - Otherwise raises InvalidArgument. - - """ - if value is None or isinstance(value, integer_types + (Rational,)): - return - if math.isnan(value): - raise InvalidArgument(u'Invalid end point %s=%r' % (name, value)) - - -@check_function -def try_convert(typ, value, name): - if value is None: - return None - if isinstance(value, typ): - return value - try: - return typ(value) - except TypeError: - raise InvalidArgument( - 'Cannot convert %s=%r of type %s to type %s' % ( - name, value, type(value).__name__, typ.__name__ - ) - ) - except (OverflowError, ValueError): - raise InvalidArgument( - 'Cannot convert %s=%r to type %s' % ( - name, value, typ.__name__ - ) - ) - - -@check_function -def check_valid_size(value, name): - """Checks that value is either unspecified, or a valid non-negative size - expressed as an integer/float. - - Otherwise raises InvalidArgument. - - """ - if value is None: - return - check_type(integer_types + (float,), value) - if value < 0: - raise InvalidArgument(u'Invalid size %s=%r < 0' % (name, value)) - if isinstance(value, float) and math.isnan(value): - raise InvalidArgument(u'Invalid size %s=%r' % (name, value)) - - -@check_function -def check_valid_interval(lower_bound, upper_bound, lower_name, upper_name): - """Checks that lower_bound and upper_bound are either unspecified, or they - define a valid interval on the number line. - - Otherwise raises InvalidArgument. - - """ - if lower_bound is None or upper_bound is None: - return - if upper_bound < lower_bound: - raise InvalidArgument( - 'Cannot have %s=%r < %s=%r' % ( - upper_name, upper_bound, lower_name, lower_bound - )) - - -@check_function -def check_valid_sizes(min_size, average_size, max_size): - check_valid_size(min_size, 'min_size') - check_valid_size(max_size, 'max_size') - check_valid_size(average_size, 'average_size') - check_valid_interval(min_size, max_size, 'min_size', 'max_size') - check_valid_interval(average_size, max_size, 'average_size', 'max_size') - check_valid_interval(min_size, average_size, 'min_size', 'average_size') - - if ( - average_size == 0 and ( - max_size is None or - max_size > 0 - ) - ): - raise InvalidArgument( - 'Cannot have average_size=%r with non-zero max_size=%r' % ( - average_size, min_size - )) diff -Nru python-hypothesis-3.44.1/src/hypothesis/provisional.py python-hypothesis-3.71.11/src/hypothesis/provisional.py --- python-hypothesis-3.44.1/src/hypothesis/provisional.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/provisional.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,84 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -"""This module contains various provisional APIs and strategies. - -It is intended for internal use, to ease code reuse, and is not stable. -Point releases may move or break the contents at any time! - -Internet strategies should conform to https://tools.ietf.org/html/rfc3696 or -the authoritative definitions it links to. If not, report the bug! - -""" - -from __future__ import division, print_function, absolute_import - -import string - -import hypothesis.strategies as st - - -@st.defines_strategy_with_reusable_values -def domains(): - """A strategy for :rfc:`1035` fully qualified domain names.""" - atoms = st.text(string.ascii_letters + '0123456789-', - min_size=1, max_size=63 - ).filter(lambda s: '-' not in s[0] + s[-1]) - return st.builds( - lambda x, y: '.'.join(x + [y]), - st.lists(atoms, min_size=1), - # TODO: be more devious about top-level domains - st.sampled_from(['com', 'net', 'org', 'biz', 'info']) - ).filter(lambda url: len(url) <= 255) - - -@st.defines_strategy_with_reusable_values -def emails(): - """A strategy for email addresses. - - See https://github.com/HypothesisWorks/hypothesis-python/issues/162 - for work on a permanent replacement. - - """ - local_chars = string.ascii_letters + string.digits + "!#$%&'*+-/=^_`{|}~" - local_part = st.text(local_chars, min_size=1, max_size=64) - # TODO: include dot-atoms, quoted strings, escaped chars, etc in local part - return st.builds('{}@{}'.format, local_part, domains()).filter( - lambda addr: len(addr) <= 255) - - -@st.defines_strategy_with_reusable_values -def ip4_addr_strings(): - """A strategy for IPv4 address strings. - - This consists of four strings representing integers [0..255], - without zero-padding, joined by dots. - - """ - return st.builds('{}.{}.{}.{}'.format, *(4 * [st.integers(0, 255)])) - - -@st.defines_strategy_with_reusable_values -def ip6_addr_strings(): - """A strategy for IPv6 address strings. - - This consists of sixteen quads of hex digits (0000 .. FFFF), joined - by colons. Values do not currently have zero-segments collapsed. - - """ - part = st.integers(0, 2**16 - 1).map(u'{:04x}'.format) - return st.tuples(*[part] * 8).map(lambda a: u':'.join(a).upper()) diff -Nru python-hypothesis-3.44.1/src/hypothesis/reporting.py python-hypothesis-3.71.11/src/hypothesis/reporting.py --- python-hypothesis-3.44.1/src/hypothesis/reporting.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/reporting.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,74 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import inspect - -from hypothesis._settings import Verbosity, settings -from hypothesis.internal.compat import print_unicode, \ - escape_unicode_characters -from hypothesis.utils.dynamicvariables import DynamicVariable - - -def silent(value): - pass - - -def default(value): - try: - print_unicode(value) - except UnicodeEncodeError: - print_unicode(escape_unicode_characters(value)) - - -reporter = DynamicVariable(default) - - -def current_reporter(): - return reporter.value - - -def with_reporter(new_reporter): - return reporter.with_value(new_reporter) - - -def current_verbosity(): - return settings.default.verbosity - - -def to_text(textish): - if inspect.isfunction(textish): - textish = textish() - if isinstance(textish, bytes): - textish = textish.decode('utf-8') - return textish - - -def verbose_report(text): - if current_verbosity() >= Verbosity.verbose: - current_reporter()(to_text(text)) - - -def debug_report(text): - if current_verbosity() >= Verbosity.debug: - current_reporter()(to_text(text)) - - -def report(text): - if current_verbosity() >= Verbosity.normal: - current_reporter()(to_text(text)) diff -Nru python-hypothesis-3.44.1/src/hypothesis/searchstrategy/collections.py python-hypothesis-3.71.11/src/hypothesis/searchstrategy/collections.py --- python-hypothesis-3.44.1/src/hypothesis/searchstrategy/collections.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/searchstrategy/collections.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,225 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import hypothesis.internal.conjecture.utils as cu -from hypothesis.errors import InvalidArgument -from hypothesis.internal.compat import OrderedDict, hbytes -from hypothesis.searchstrategy.strategies import SearchStrategy, \ - MappedSearchStrategy, one_of_strategies - - -class TupleStrategy(SearchStrategy): - - """A strategy responsible for fixed length tuples based on heterogenous - strategies for each of their elements.""" - - def __init__(self, - strategies, tuple_type): - SearchStrategy.__init__(self) - strategies = tuple(strategies) - self.element_strategies = strategies - - def do_validate(self): - for s in self.element_strategies: - s.validate() - - def __repr__(self): - if len(self.element_strategies) == 1: - tuple_string = '%s,' % (repr(self.element_strategies[0]),) - else: - tuple_string = ', '.join(map(repr, self.element_strategies)) - return 'TupleStrategy((%s))' % ( - tuple_string, - ) - - def calc_has_reusable_values(self, recur): - return all(recur(e) for e in self.element_strategies) - - def newtuple(self, xs): - """Produce a new tuple of the correct type.""" - return tuple(xs) - - def do_draw(self, data): - return self.newtuple( - data.draw(e) for e in self.element_strategies - ) - - def calc_is_empty(self, recur): - return any(recur(e) for e in self.element_strategies) - - -TERMINATOR = hbytes(b'\0') - - -class ListStrategy(SearchStrategy): - - """A strategy for lists which takes an intended average length and a - strategy for each of its element types and generates lists containing any - of those element types. - - The conditional distribution of the length is geometric, and the - conditional distribution of each parameter is whatever their - strategies define. - - """ - - def __init__( - self, - strategies, average_length=50.0, min_size=0, max_size=float('inf') - ): - SearchStrategy.__init__(self) - - assert average_length > 0 - self.average_length = average_length - strategies = tuple(strategies) - self.min_size = min_size or 0 - self.max_size = max_size or float('inf') - self.element_strategy = one_of_strategies(strategies) - - def do_validate(self): - self.element_strategy.validate() - if self.is_empty: - raise InvalidArgument(( - 'Cannot create non-empty lists with elements drawn from ' - 'strategy %r because it has no values.') % ( - self.element_strategy,)) - - def calc_is_empty(self, recur): - if self.min_size == 0: - return False - else: - return recur(self.element_strategy) - - def do_draw(self, data): - if self.element_strategy.is_empty: - assert self.min_size == 0 - return [] - - elements = cu.many( - data, - min_size=self.min_size, max_size=self.max_size, - average_size=self.average_length - ) - result = [] - while elements.more(): - result.append(data.draw(self.element_strategy)) - return result - - def __repr__(self): - return ( - 'ListStrategy(%r, min_size=%r, average_size=%r, max_size=%r)' - ) % ( - self.element_strategy, self.min_size, self.average_length, - self.max_size - ) - - -class UniqueListStrategy(SearchStrategy): - - def __init__( - self, - elements, min_size, max_size, average_size, - key - ): - super(UniqueListStrategy, self).__init__() - assert min_size <= average_size <= max_size - self.min_size = min_size - self.max_size = max_size - self.average_size = average_size - self.element_strategy = elements - self.key = key - - def do_validate(self): - self.element_strategy.validate() - if self.is_empty: - raise InvalidArgument(( - 'Cannot create non-empty lists with elements drawn from ' - 'strategy %r because it has no values.') % ( - self.element_strategy,)) - - def calc_is_empty(self, recur): - if self.min_size == 0: - return False - else: - return recur(self.element_strategy) - - def do_draw(self, data): - if self.element_strategy.is_empty: - assert self.min_size == 0 - return [] - - elements = cu.many( - data, - min_size=self.min_size, max_size=self.max_size, - average_size=self.average_size - ) - seen = set() - result = [] - - while elements.more(): - value = data.draw(self.element_strategy) - k = self.key(value) - if k in seen: - elements.reject() - else: - seen.add(k) - result.append(value) - assert self.max_size >= len(result) >= self.min_size - return result - - -class FixedKeysDictStrategy(MappedSearchStrategy): - - """A strategy which produces dicts with a fixed set of keys, given a - strategy for each of their equivalent values. - - e.g. {'foo' : some_int_strategy} would - generate dicts with the single key 'foo' mapping to some integer. - - """ - - def __init__(self, strategy_dict): - self.dict_type = type(strategy_dict) - - if isinstance(strategy_dict, OrderedDict): - self.keys = tuple(strategy_dict.keys()) - else: - try: - self.keys = tuple(sorted( - strategy_dict.keys(), - )) - except TypeError: - self.keys = tuple(sorted( - strategy_dict.keys(), key=repr, - )) - super(FixedKeysDictStrategy, self).__init__( - strategy=TupleStrategy( - (strategy_dict[k] for k in self.keys), tuple - ) - ) - - def calc_is_empty(self, recur): - return recur(self.mapped_strategy) - - def __repr__(self): - return 'FixedKeysDictStrategy(%r, %r)' % ( - self.keys, self.mapped_strategy) - - def pack(self, value): - return self.dict_type(zip(self.keys, value)) diff -Nru python-hypothesis-3.44.1/src/hypothesis/searchstrategy/datetime.py python-hypothesis-3.71.11/src/hypothesis/searchstrategy/datetime.py --- python-hypothesis-3.44.1/src/hypothesis/searchstrategy/datetime.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/searchstrategy/datetime.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,120 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import datetime as dt - -from hypothesis.internal.conjecture import utils -from hypothesis.searchstrategy.strategies import SearchStrategy - -__all__ = ['DateStrategy', 'DatetimeStrategy', 'TimedeltaStrategy'] - - -def is_pytz_timezone(tz): - if not isinstance(tz, dt.tzinfo): - return False - module = type(tz).__module__ - return module == 'pytz' or module.startswith('pytz.') - - -class DatetimeStrategy(SearchStrategy): - - def __init__(self, min_value, max_value, timezones_strat): - assert isinstance(min_value, dt.datetime) - assert isinstance(max_value, dt.datetime) - assert min_value.tzinfo is None - assert max_value.tzinfo is None - assert min_value <= max_value - assert isinstance(timezones_strat, SearchStrategy) - self.min_dt = min_value - self.max_dt = max_value - self.tz_strat = timezones_strat - - def _attempt_one_draw(self, data): - result = dict() - cap_low, cap_high = True, True - for name in ('year', 'month', 'day', - 'hour', 'minute', 'second', 'microsecond'): - low = getattr(self.min_dt if cap_low else dt.datetime.min, name) - high = getattr(self.max_dt if cap_high else dt.datetime.max, name) - if name == 'year': - val = utils.centered_integer_range(data, low, high, 2000) - else: - val = utils.integer_range(data, low, high) - result[name] = val - cap_low = cap_low and val == low - cap_high = cap_high and val == high - tz = data.draw(self.tz_strat) - try: - result = dt.datetime(**result) - if is_pytz_timezone(tz): - # Can't just construct; see http://pytz.sourceforge.net - return tz.normalize(tz.localize(result)) - return result.replace(tzinfo=tz) - except (ValueError, OverflowError): - return None - - def do_draw(self, data): - for _ in range(3): - result = self._attempt_one_draw(data) - if result is not None: - return result - data.note_event('3 attempts to create a datetime between %r and %r ' - 'with timezone from %r failed.' % - (self.min_dt, self.max_dt, self.tz_strat)) - data.mark_invalid() - - -class DateStrategy(SearchStrategy): - - def __init__(self, min_value, max_value): - assert isinstance(min_value, dt.date) - assert isinstance(max_value, dt.date) - assert min_value < max_value - self.min_value = min_value - self.days_apart = (max_value - min_value).days - self.center = (dt.date(2000, 1, 1) - min_value).days - - def do_draw(self, data): - return self.min_value + dt.timedelta(days=utils.centered_integer_range( - data, 0, self.days_apart, center=self.center)) - - -class TimedeltaStrategy(SearchStrategy): - - def __init__(self, min_value, max_value): - assert isinstance(min_value, dt.timedelta) - assert isinstance(max_value, dt.timedelta) - assert min_value < max_value - self.min_value = min_value - self.max_value = max_value - - def do_draw(self, data): - result = dict() - low_bound = True - high_bound = True - for name in ('days', 'seconds', 'microseconds'): - low = getattr( - self.min_value if low_bound else dt.timedelta.min, name) - high = getattr( - self.max_value if high_bound else dt.timedelta.max, name) - val = utils.centered_integer_range(data, low, high, 0) - result[name] = val - low_bound = low_bound and val == low - high_bound = high_bound and val == high - return dt.timedelta(**result) diff -Nru python-hypothesis-3.44.1/src/hypothesis/searchstrategy/deferred.py python-hypothesis-3.71.11/src/hypothesis/searchstrategy/deferred.py --- python-hypothesis-3.44.1/src/hypothesis/searchstrategy/deferred.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/searchstrategy/deferred.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,89 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import inspect - -from hypothesis.errors import InvalidArgument -from hypothesis.internal.reflection import get_pretty_function_description -from hypothesis.searchstrategy.strategies import SearchStrategy - - -class DeferredStrategy(SearchStrategy): - - """A strategy which may be used before it is fully defined.""" - - def __init__(self, definition): - SearchStrategy.__init__(self) - self.__wrapped_strategy = None - self.__in_repr = False - self.__is_empty = None - self.__definition = definition - - @property - def wrapped_strategy(self): - if self.__wrapped_strategy is None: - if not inspect.isfunction(self.__definition): - raise InvalidArgument(( - 'Excepted a definition to be a function but got %r of type' - ' %s instead.') % ( - self.__definition, type(self.__definition).__name__)) - result = self.__definition() - if result is self: - raise InvalidArgument( - 'Cannot define a deferred strategy to be itself') - if not isinstance(result, SearchStrategy): - raise InvalidArgument(( - 'Expected definition to return a SearchStrategy but ' - 'returned %r of type %s') % ( - result, type(result).__name__ - )) - self.__wrapped_strategy = result - del self.__definition - return self.__wrapped_strategy - - @property - def branches(self): - return self.wrapped_strategy.branches - - @property - def supports_find(self): - return self.wrapped_strategy.supports_find - - def calc_is_empty(self, recur): - return recur(self.wrapped_strategy) - - def calc_has_reusable_values(self, recur): - return recur(self.wrapped_strategy) - - def __repr__(self): - if self.__wrapped_strategy is not None: - if self.__in_repr: - return '(deferred@%r)' % (id(self),) - try: - self.__in_repr = True - return repr(self.__wrapped_strategy) - finally: - self.__in_repr = False - else: - return 'deferred(%s)' % ( - get_pretty_function_description(self.__definition) - ) - - def do_draw(self, data): - return data.draw(self.wrapped_strategy) diff -Nru python-hypothesis-3.44.1/src/hypothesis/searchstrategy/flatmapped.py python-hypothesis-3.71.11/src/hypothesis/searchstrategy/flatmapped.py --- python-hypothesis-3.44.1/src/hypothesis/searchstrategy/flatmapped.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/searchstrategy/flatmapped.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,52 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from hypothesis.internal.reflection import get_pretty_function_description -from hypothesis.searchstrategy.strategies import SearchStrategy - - -class FlatMapStrategy(SearchStrategy): - - def __init__( - self, strategy, expand - ): - super(FlatMapStrategy, self).__init__() - self.flatmapped_strategy = strategy - self.expand = expand - - def calc_is_empty(self, recur): - return recur(self.flatmapped_strategy) - - def __repr__(self): - if not hasattr(self, u'_cached_repr'): - self._cached_repr = u'%r.flatmap(%s)' % ( - self.flatmapped_strategy, get_pretty_function_description( - self.expand)) - return self._cached_repr - - def do_draw(self, data): - source = data.draw(self.flatmapped_strategy) - return data.draw(self.expand(source)) - - @property - def branches(self): - return [ - FlatMapStrategy(strategy=strategy, expand=self.expand) - for strategy in self.flatmapped_strategy.branches - ] diff -Nru python-hypothesis-3.44.1/src/hypothesis/searchstrategy/__init__.py python-hypothesis-3.71.11/src/hypothesis/searchstrategy/__init__.py --- python-hypothesis-3.44.1/src/hypothesis/searchstrategy/__init__.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/searchstrategy/__init__.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,26 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -"""Package defining SearchStrategy, which is the core type that Hypothesis uses -to explore data.""" - - -from .strategies import SearchStrategy - -__all__ = [ - 'SearchStrategy', -] diff -Nru python-hypothesis-3.44.1/src/hypothesis/searchstrategy/lazy.py python-hypothesis-3.71.11/src/hypothesis/searchstrategy/lazy.py --- python-hypothesis-3.44.1/src/hypothesis/searchstrategy/lazy.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/searchstrategy/lazy.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,158 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from hypothesis.internal.compat import getfullargspec -from hypothesis.internal.reflection import arg_string, \ - convert_keyword_arguments, convert_positional_arguments -from hypothesis.searchstrategy.strategies import SearchStrategy - -unwrap_cache = {} -unwrap_depth = 0 - - -def unwrap_strategies(s): - global unwrap_depth - - if not isinstance(s, SearchStrategy): - return s - try: - return unwrap_cache[s] - except KeyError: - pass - - unwrap_cache[s] = s - - try: - unwrap_depth += 1 - try: - result = unwrap_strategies(s.wrapped_strategy) - unwrap_cache[s] = result - try: - assert result.force_has_reusable_values == \ - s.force_has_reusable_values - except AttributeError: - pass - - try: - result.force_has_reusable_values = s.force_has_reusable_values - except AttributeError: - pass - return result - except AttributeError: - return s - finally: - unwrap_depth -= 1 - if unwrap_depth <= 0: - unwrap_cache.clear() - assert unwrap_depth >= 0 - - -class LazyStrategy(SearchStrategy): - - """A strategy which is defined purely by conversion to and from another - strategy. - - Its parameter and distribution come from that other strategy. - - """ - - def __init__(self, function, args, kwargs): - SearchStrategy.__init__(self) - self.__wrapped_strategy = None - self.__representation = None - self.__function = function - self.__args = args - self.__kwargs = kwargs - - @property - def supports_find(self): - return self.wrapped_strategy.supports_find - - def calc_is_empty(self, recur): - return recur(self.wrapped_strategy) - - def calc_has_reusable_values(self, recur): - return recur(self.wrapped_strategy) - - def calc_is_cacheable(self, recur): - for source in (self.__args, self.__kwargs.values()): - for v in source: - if isinstance(v, SearchStrategy) and not v.is_cacheable: - return False - return True - - @property - def wrapped_strategy(self): - if self.__wrapped_strategy is None: - unwrapped_args = tuple( - unwrap_strategies(s) for s in self.__args) - unwrapped_kwargs = { - k: unwrap_strategies(v) - for k, v in self.__kwargs.items() - } - - base = self.__function( - *self.__args, **self.__kwargs - ) - if ( - unwrapped_args == self.__args and - unwrapped_kwargs == self.__kwargs - ): - self.__wrapped_strategy = base - else: - self.__wrapped_strategy = self.__function( - *unwrapped_args, - **unwrapped_kwargs) - return self.__wrapped_strategy - - def do_validate(self): - w = self.wrapped_strategy - assert isinstance(w, SearchStrategy), \ - '%r returned non-strategy %r' % (self, w) - w.validate() - - def __repr__(self): - if self.__representation is None: - _args = self.__args - _kwargs = self.__kwargs - argspec = getfullargspec(self.__function) - defaults = dict(argspec.kwonlydefaults or {}) - if argspec.defaults is not None: - for name, value in zip(reversed(argspec.args), - reversed(argspec.defaults)): - defaults[name] = value - if len(argspec.args) > 1 or argspec.defaults: - _args, _kwargs = convert_positional_arguments( - self.__function, _args, _kwargs) - else: - _args, _kwargs = convert_keyword_arguments( - self.__function, _args, _kwargs) - kwargs_for_repr = dict(_kwargs) - for k, v in defaults.items(): - if k in kwargs_for_repr and kwargs_for_repr[k] is defaults[k]: - del kwargs_for_repr[k] - self.__representation = '%s(%s)' % ( - self.__function.__name__, - arg_string( - self.__function, _args, kwargs_for_repr, reorder=False), - ) - return self.__representation - - def do_draw(self, data): - return data.draw(self.wrapped_strategy) diff -Nru python-hypothesis-3.44.1/src/hypothesis/searchstrategy/misc.py python-hypothesis-3.71.11/src/hypothesis/searchstrategy/misc.py --- python-hypothesis-3.44.1/src/hypothesis/searchstrategy/misc.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/searchstrategy/misc.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,107 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import hypothesis.internal.conjecture.utils as d -from hypothesis.types import RandomWithSeed -from hypothesis.searchstrategy.strategies import SearchStrategy, \ - MappedSearchStrategy - - -class BoolStrategy(SearchStrategy): - - """A strategy that produces Booleans with a Bernoulli conditional - distribution.""" - - def __repr__(self): - return u'BoolStrategy()' - - def calc_has_reusable_values(self, recur): - return True - - def do_draw(self, data): - return d.boolean(data) - - -def is_simple_data(value): - try: - hash(value) - return True - except TypeError: - return False - - -class JustStrategy(SearchStrategy): - - """A strategy which simply returns a single fixed value with probability - 1.""" - - def __init__(self, value): - SearchStrategy.__init__(self) - self.value = value - - def __repr__(self): - return 'just(%r)' % (self.value,) - - def calc_has_reusable_values(self, recur): - return True - - def calc_is_cacheable(self, recur): - return is_simple_data(self.value) - - def do_draw(self, data): - return self.value - - -class RandomStrategy(MappedSearchStrategy): - - """A strategy which produces Random objects. - - The conditional distribution is simply a RandomWithSeed seeded with - a 128 bits of data chosen uniformly at random. - - """ - - def pack(self, i): - return RandomWithSeed(i) - - -class SampledFromStrategy(SearchStrategy): - - """A strategy which samples from a set of elements. This is essentially - equivalent to using a OneOfStrategy over Just strategies but may be more - efficient and convenient. - - The conditional distribution chooses uniformly at random from some - non-empty subset of the elements. - - """ - - def __init__(self, elements): - SearchStrategy.__init__(self) - self.elements = d.check_sample(elements) - assert self.elements - - def calc_has_reusable_values(self, recur): - return True - - def calc_is_cacheable(self, recur): - return is_simple_data(self.elements) - - def do_draw(self, data): - return d.choice(data, self.elements) diff -Nru python-hypothesis-3.44.1/src/hypothesis/searchstrategy/numbers.py python-hypothesis-3.71.11/src/hypothesis/searchstrategy/numbers.py --- python-hypothesis-3.44.1/src/hypothesis/searchstrategy/numbers.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/searchstrategy/numbers.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,199 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import math - -import hypothesis.internal.conjecture.utils as d -import hypothesis.internal.conjecture.floats as flt -from hypothesis.control import assume -from hypothesis.internal.compat import int_from_bytes -from hypothesis.internal.floats import sign -from hypothesis.searchstrategy.strategies import SearchStrategy, \ - MappedSearchStrategy - - -class IntStrategy(SearchStrategy): - - """A generic strategy for integer types that provides the basic methods - other than produce. - - Subclasses should provide the produce method. - - """ - - -class IntegersFromStrategy(SearchStrategy): - - def __init__(self, lower_bound, average_size=100000.0): - super(IntegersFromStrategy, self).__init__() - self.lower_bound = lower_bound - self.average_size = average_size - - def __repr__(self): - return 'IntegersFromStrategy(%d)' % (self.lower_bound,) - - def do_draw(self, data): - return int( - self.lower_bound + d.geometric(data, 1.0 / self.average_size)) - - -class WideRangeIntStrategy(IntStrategy): - - def __repr__(self): - return 'WideRangeIntStrategy()' - - def do_draw(self, data): - size = 16 - sign_mask = 2 ** (size * 8 - 1) - - byt = data.draw_bytes(size) - r = int_from_bytes(byt) - negative = r & sign_mask - r &= (~sign_mask) - if negative: - r = -r - return int(r) - - -class BoundedIntStrategy(SearchStrategy): - - """A strategy for providing integers in some interval with inclusive - endpoints.""" - - def __init__(self, start, end): - SearchStrategy.__init__(self) - self.start = start - self.end = end - - def __repr__(self): - return 'BoundedIntStrategy(%d, %d)' % (self.start, self.end) - - def do_draw(self, data): - return d.integer_range(data, self.start, self.end) - - -NASTY_FLOATS = sorted([ - 0.0, 0.5, 1.1, 1.5, 1.9, 1.0 / 3, 10e6, 10e-6, 1.175494351e-38, - 2.2250738585072014e-308, - 1.7976931348623157e+308, 3.402823466e+38, 9007199254740992, 1 - 10e-6, - 2 + 10e-6, 1.192092896e-07, 2.2204460492503131e-016, - -] + [float('inf'), float('nan')] * 5, key=flt.float_to_lex) -NASTY_FLOATS = list(map(float, NASTY_FLOATS)) -NASTY_FLOATS.extend([-x for x in NASTY_FLOATS]) - - -class FloatStrategy(SearchStrategy): - - """Generic superclass for strategies which produce floats.""" - - def __init__(self, allow_infinity, allow_nan): - SearchStrategy.__init__(self) - assert isinstance(allow_infinity, bool) - assert isinstance(allow_nan, bool) - self.allow_infinity = allow_infinity - self.allow_nan = allow_nan - - self.nasty_floats = [f for f in NASTY_FLOATS if self.permitted(f)] - weights = [ - 0.6 * len(self.nasty_floats) - ] + [0.4] * len(self.nasty_floats) - self.sampler = d.Sampler(weights) - - def __repr__(self): - return '%s()' % (self.__class__.__name__,) - - def permitted(self, f): - assert isinstance(f, float) - if not self.allow_infinity and math.isinf(f): - return False - if not self.allow_nan and math.isnan(f): - return False - return True - - def do_draw(self, data): - while True: - data.start_example() - i = self.sampler.sample(data) - if i == 0: - result = flt.draw_float(data) - else: - result = self.nasty_floats[i - 1] - flt.write_float(data, result) - data.stop_example() - if self.permitted(result): - return result - - -def float_order_key(k): - return (sign(k), k) - - -class FixedBoundedFloatStrategy(SearchStrategy): - - """A strategy for floats distributed between two endpoints. - - The conditional distribution tries to produce values clustered - closer to one of the ends. - - """ - - def __init__(self, lower_bound, upper_bound): - SearchStrategy.__init__(self) - self.lower_bound = float(lower_bound) - self.upper_bound = float(upper_bound) - assert not math.isinf(self.upper_bound - self.lower_bound) - lb = float_order_key(self.lower_bound) - ub = float_order_key(self.upper_bound) - - self.critical = [ - z for z in (-0.0, 0.0) - if lb <= float_order_key(z) <= ub - ] - self.critical.append(self.lower_bound) - self.critical.append(self.upper_bound) - - def __repr__(self): - return 'FixedBoundedFloatStrategy(%s, %s)' % ( - self.lower_bound, self.upper_bound, - ) - - def do_draw(self, data): - f = self.lower_bound + ( - self.upper_bound - self.lower_bound) * d.fractional_float(data) - assume(self.lower_bound <= f <= self.upper_bound) - assume(sign(self.lower_bound) <= sign(f) <= sign(self.upper_bound)) - # Special handling for bounds of -0.0 - for g in [self.lower_bound, self.upper_bound]: - if f == g: - f = math.copysign(f, g) - return f - - -class ComplexStrategy(MappedSearchStrategy): - - """A strategy over complex numbers, with real and imaginary values - distributed according to some provided strategy for floating point - numbers.""" - - def __repr__(self): - return 'ComplexStrategy()' - - def pack(self, value): - return complex(*value) diff -Nru python-hypothesis-3.44.1/src/hypothesis/searchstrategy/recursive.py python-hypothesis-3.71.11/src/hypothesis/searchstrategy/recursive.py --- python-hypothesis-3.44.1/src/hypothesis/searchstrategy/recursive.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/searchstrategy/recursive.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,109 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from contextlib import contextmanager - -from hypothesis.errors import InvalidArgument -from hypothesis.internal.lazyformat import lazyformat -from hypothesis.internal.reflection import get_pretty_function_description -from hypothesis.searchstrategy.strategies import OneOfStrategy, \ - SearchStrategy - - -class LimitReached(BaseException): - pass - - -class LimitedStrategy(SearchStrategy): - - def __init__(self, strategy): - super(LimitedStrategy, self).__init__() - self.base_strategy = strategy - self.marker = 0 - self.currently_capped = False - - def do_validate(self): - self.base_strategy.validate() - - def do_draw(self, data): - assert self.currently_capped - if self.marker <= 0: - raise LimitReached() - self.marker -= 1 - return data.draw(self.base_strategy) - - @contextmanager - def capped(self, max_templates): - assert not self.currently_capped - try: - self.currently_capped = True - self.marker = max_templates - yield - finally: - self.currently_capped = False - - -class RecursiveStrategy(SearchStrategy): - - def __init__(self, base, extend, max_leaves): - self.max_leaves = max_leaves - self.base = base - self.limited_base = LimitedStrategy(base) - self.extend = extend - - strategies = [self.limited_base, self.extend(self.limited_base)] - while 2 ** len(strategies) <= max_leaves: - strategies.append( - extend(OneOfStrategy(tuple(strategies), bias=0.8))) - self.strategy = OneOfStrategy(strategies) - - def __repr__(self): - if not hasattr(self, '_cached_repr'): - self._cached_repr = 'recursive(%r, %s, max_leaves=%d)' % ( - self.base, get_pretty_function_description(self.extend), - self.max_leaves - ) - return self._cached_repr - - def do_validate(self): - if not isinstance(self.base, SearchStrategy): - raise InvalidArgument( - 'Expected base to be SearchStrategy but got %r' % (self.base,) - ) - extended = self.extend(self.limited_base) - if not isinstance(extended, SearchStrategy): - raise InvalidArgument( - 'Expected extend(%r) to be a SearchStrategy but got %r' % ( - self.limited_base, extended - )) - self.limited_base.validate() - self.extend(self.limited_base).validate() - - def do_draw(self, data): - count = 0 - while True: - try: - with self.limited_base.capped(self.max_leaves): - return data.draw(self.strategy) - except LimitReached: - if count == 0: - data.note_event(lazyformat( - 'Draw for %r exceeded max_leaves ' - 'and had to be retried', self,)) - count += 1 diff -Nru python-hypothesis-3.44.1/src/hypothesis/searchstrategy/regex.py python-hypothesis-3.71.11/src/hypothesis/searchstrategy/regex.py --- python-hypothesis-3.44.1/src/hypothesis/searchstrategy/regex.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/searchstrategy/regex.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,499 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import re -import sys -import operator -import sre_parse -import sre_constants as sre - -import hypothesis.strategies as st -from hypothesis import reject -from hypothesis.internal.compat import PY3, hrange, hunichr, text_type, \ - int_to_byte - -HAS_SUBPATTERN_FLAGS = sys.version_info[:2] >= (3, 6) - - -UNICODE_CATEGORIES = set([ - 'Cf', 'Cn', 'Co', 'LC', 'Ll', 'Lm', 'Lo', 'Lt', 'Lu', - 'Mc', 'Me', 'Mn', 'Nd', 'Nl', 'No', 'Pc', 'Pd', 'Pe', - 'Pf', 'Pi', 'Po', 'Ps', 'Sc', 'Sk', 'Sm', 'So', 'Zl', - 'Zp', 'Zs', -]) - - -SPACE_CHARS = set(u' \t\n\r\f\v') -UNICODE_SPACE_CHARS = SPACE_CHARS | set(u'\x1c\x1d\x1e\x1f\x85') -UNICODE_DIGIT_CATEGORIES = set(['Nd']) -UNICODE_SPACE_CATEGORIES = set(['Zs', 'Zl', 'Zp']) -UNICODE_LETTER_CATEGORIES = set(['LC', 'Ll', 'Lm', 'Lo', 'Lt', 'Lu']) -UNICODE_WORD_CATEGORIES = UNICODE_LETTER_CATEGORIES | set(['Nd', 'Nl', 'No']) - -# This is verbose, but correct on all versions of Python -BYTES_ALL = set(int_to_byte(i) for i in range(256)) -BYTES_DIGIT = set(b for b in BYTES_ALL if re.match(b'\\d', b)) -BYTES_SPACE = set(b for b in BYTES_ALL if re.match(b'\\s', b)) -BYTES_WORD = set(b for b in BYTES_ALL if re.match(b'\\w', b)) -BYTES_LOOKUP = { - sre.CATEGORY_DIGIT: BYTES_DIGIT, - sre.CATEGORY_SPACE: BYTES_SPACE, - sre.CATEGORY_WORD: BYTES_WORD, - sre.CATEGORY_NOT_DIGIT: BYTES_ALL - BYTES_DIGIT, - sre.CATEGORY_NOT_SPACE: BYTES_ALL - BYTES_SPACE, - sre.CATEGORY_NOT_WORD: BYTES_ALL - BYTES_WORD, -} - -# On Python < 3.4 (including 2.7), the following unicode chars are weird. -# They are matched by the \W, meaning 'not word', but unicodedata.category(c) -# returns one of the word categories above. There's special handling below. -HAS_WEIRD_WORD_CHARS = sys.version_info[:2] < (3, 4) -UNICODE_WEIRD_NONWORD_CHARS = set(u'\U00012432\U00012433\U00012456\U00012457') - - -GROUP_CACHE_STRATEGY = st.shared( - st.builds(dict), key='hypothesis.regex.group_cache' -) - - -@st.composite -def update_group(draw, group_name, strategy): - cache = draw(GROUP_CACHE_STRATEGY) - result = draw(strategy) - cache[group_name] = result - return result - - -@st.composite -def reuse_group(draw, group_name): - cache = draw(GROUP_CACHE_STRATEGY) - try: - return cache[group_name] - except KeyError: - reject() - - -@st.composite -def group_conditional(draw, group_name, if_yes, if_no): - cache = draw(GROUP_CACHE_STRATEGY) - if group_name in cache: - return draw(if_yes) - else: - return draw(if_no) - - -@st.composite -def clear_cache_after_draw(draw, base_strategy): - cache = draw(GROUP_CACHE_STRATEGY) - result = draw(base_strategy) - cache.clear() - return result - - -class Context(object): - __slots__ = ['flags'] - - def __init__(self, groups=None, flags=0): - self.flags = flags - - -class CharactersBuilder(object): - """Helper object that allows to configure `characters` strategy with - various unicode categories and characters. Also allows negation of - configured set. - - :param negate: If True, configure :func:`hypothesis.strategies.characters` - to match anything other than configured character set - :param flags: Regex flags. They affect how and which characters are matched - - """ - - def __init__(self, negate=False, flags=0): - self._categories = set() - self._whitelist_chars = set() - self._blacklist_chars = set() - self._negate = negate - self._ignorecase = flags & re.IGNORECASE - self._unicode = not bool(flags & re.ASCII) \ - if PY3 else bool(flags & re.UNICODE) - self.code_to_char = hunichr - - @property - def strategy(self): - """Returns resulting strategy that generates configured char set.""" - max_codepoint = None if self._unicode else 127 - if self._negate: - black_chars = self._blacklist_chars - self._whitelist_chars - return st.characters( - blacklist_categories=self._categories | {'Cc', 'Cs'}, - blacklist_characters=self._whitelist_chars, - whitelist_characters=black_chars, - max_codepoint=max_codepoint, - ) - white_chars = self._whitelist_chars - self._blacklist_chars - return st.characters( - whitelist_categories=self._categories, - blacklist_characters=self._blacklist_chars, - whitelist_characters=white_chars, - max_codepoint=max_codepoint, - ) - - def add_category(self, category): - """Update unicode state to match sre_parse object ``category``.""" - if category == sre.CATEGORY_DIGIT: - self._categories |= UNICODE_DIGIT_CATEGORIES - elif category == sre.CATEGORY_NOT_DIGIT: - self._categories |= UNICODE_CATEGORIES - UNICODE_DIGIT_CATEGORIES - elif category == sre.CATEGORY_SPACE: - self._categories |= UNICODE_SPACE_CATEGORIES - self._whitelist_chars |= UNICODE_SPACE_CHARS \ - if self._unicode else SPACE_CHARS - elif category == sre.CATEGORY_NOT_SPACE: - self._categories |= UNICODE_CATEGORIES - UNICODE_SPACE_CATEGORIES - self._blacklist_chars |= UNICODE_SPACE_CHARS \ - if self._unicode else SPACE_CHARS - elif category == sre.CATEGORY_WORD: - self._categories |= UNICODE_WORD_CATEGORIES - self._whitelist_chars.add(u'_') - if HAS_WEIRD_WORD_CHARS and self._unicode: # pragma: no cover - # This code is workaround of weird behavior in - # specific Python versions and run only on those versions - self._blacklist_chars |= UNICODE_WEIRD_NONWORD_CHARS - elif category == sre.CATEGORY_NOT_WORD: - self._categories |= UNICODE_CATEGORIES - UNICODE_WORD_CATEGORIES - self._blacklist_chars.add(u'_') - if HAS_WEIRD_WORD_CHARS and self._unicode: # pragma: no cover - # This code is workaround of weird behavior in - # specific Python versions and run only on those versions - self._whitelist_chars |= UNICODE_WEIRD_NONWORD_CHARS - else: # pragma: no cover - raise AssertionError('Unknown character category: %s' % category) - - def add_char(self, char): - """Add given char to the whitelist.""" - c = self.code_to_char(char) - self._whitelist_chars.add(c) - if self._ignorecase and \ - re.match(c, c.swapcase(), re.IGNORECASE) is not None: - self._whitelist_chars.add(c.swapcase()) - - -class BytesBuilder(CharactersBuilder): - - def __init__(self, negate=False, flags=0): - self._whitelist_chars = set() - self._blacklist_chars = set() - self._negate = negate - self._ignorecase = flags & re.IGNORECASE - self.code_to_char = int_to_byte - - @property - def strategy(self): - """Returns resulting strategy that generates configured char set.""" - allowed = self._whitelist_chars - if self._negate: - allowed = BYTES_ALL - allowed - return st.sampled_from(sorted(allowed)) - - def add_category(self, category): - """Update characters state to match sre_parse object ``category``.""" - self._whitelist_chars |= BYTES_LOOKUP[category] - - -@st.composite -def maybe_pad(draw, regex, strategy, left_pad_strategy, right_pad_strategy): - """Attempt to insert padding around the result of a regex draw while - preserving the match.""" - result = draw(strategy) - left_pad = draw(left_pad_strategy) - if left_pad and regex.search(left_pad + result): - result = left_pad + result - right_pad = draw(right_pad_strategy) - if right_pad and regex.search(result + right_pad): - result += right_pad - return result - - -def base_regex_strategy(regex, parsed=None): - if parsed is None: - parsed = sre_parse.parse(regex.pattern, flags=regex.flags) - return clear_cache_after_draw(_strategy( - parsed, - Context(flags=regex.flags), - isinstance(regex.pattern, text_type) - )) - - -def regex_strategy(regex): - if not hasattr(regex, 'pattern'): - regex = re.compile(regex) - - is_unicode = isinstance(regex.pattern, text_type) - - parsed = sre_parse.parse(regex.pattern, flags=regex.flags) - - if not parsed: - if is_unicode: - return st.text() - else: - return st.binary() - - if is_unicode: - base_padding_strategy = st.text(average_size=1) - empty = st.just(u'') - newline = st.just(u'\n') - else: - base_padding_strategy = st.binary(average_size=1) - empty = st.just(b'') - newline = st.just(b'\n') - - right_pad = base_padding_strategy - left_pad = base_padding_strategy - - if parsed[-1][0] == sre.AT: - if parsed[-1][1] == sre.AT_END_STRING: - right_pad = empty - elif parsed[-1][1] == sre.AT_END: - if regex.flags & re.MULTILINE: - right_pad = st.one_of( - empty, - st.builds(operator.add, newline, right_pad) - ) - else: - right_pad = st.one_of(empty, newline) - if parsed[0][0] == sre.AT: - if parsed[0][1] == sre.AT_BEGINNING_STRING: - left_pad = empty - elif parsed[0][1] == sre.AT_BEGINNING: - if regex.flags & re.MULTILINE: - left_pad = st.one_of( - empty, - st.builds(operator.add, left_pad, newline), - ) - else: - left_pad = empty - - base = base_regex_strategy(regex, parsed).filter(regex.search) - - return maybe_pad(regex, base, left_pad, right_pad) - - -def _strategy(codes, context, is_unicode): - """Convert SRE regex parse tree to strategy that generates strings matching - that regex represented by that parse tree. - - `codes` is either a list of SRE regex elements representations or a - particular element representation. Each element is a tuple of element code - (as string) and parameters. E.g. regex 'ab[0-9]+' compiles to following - elements: - - [ - (LITERAL, 97), - (LITERAL, 98), - (MAX_REPEAT, (1, 4294967295, [ - (IN, [ - (RANGE, (48, 57)) - ]) - ])) - ] - - The function recursively traverses regex element tree and converts each - element to strategy that generates strings that match that element. - - Context stores - 1. List of groups (for backreferences) - 2. Active regex flags (e.g. IGNORECASE, DOTALL, UNICODE, they affect - behavior of various inner strategies) - - """ - def recurse(codes): - return _strategy(codes, context, is_unicode) - - if is_unicode: - empty = u'' - to_char = hunichr - else: - empty = b'' - to_char = int_to_byte - binary_char = st.binary(min_size=1, max_size=1) - - if not isinstance(codes, tuple): - # List of codes - strategies = [] - - i = 0 - while i < len(codes): - if codes[i][0] == sre.LITERAL and \ - not context.flags & re.IGNORECASE: - # Merge subsequent "literals" into one `just()` strategy - # that generates corresponding text if no IGNORECASE - j = i + 1 - while j < len(codes) and codes[j][0] == sre.LITERAL: - j += 1 - - if i + 1 < j: - strategies.append(st.just( - empty.join([to_char(charcode) - for (_, charcode) in codes[i:j]]) - )) - - i = j - continue - - strategies.append(recurse(codes[i])) - i += 1 - - # We handle this separately at the top level, but some regex can - # contain empty lists internally, so we need to handle this here too. - if not strategies: - return st.just(empty) - - if len(strategies) == 1: - return strategies[0] - return st.tuples(*strategies).map(empty.join) - else: - # Single code - code, value = codes - if code == sre.LITERAL: - # Regex 'a' (single char) - c = to_char(value) - if context.flags & re.IGNORECASE and \ - re.match(c, c.swapcase(), re.IGNORECASE) is not None: - # We do the explicit check for swapped-case matching because - # eg 'ß'.upper() == 'SS' and ignorecase doesn't match it. - return st.sampled_from([c, c.swapcase()]) - return st.just(c) - - elif code == sre.NOT_LITERAL: - # Regex '[^a]' (negation of a single char) - c = to_char(value) - blacklist = set(c) - if context.flags & re.IGNORECASE and \ - re.match(c, c.swapcase(), re.IGNORECASE) is not None: - blacklist |= set(c.swapcase()) - if is_unicode: - return st.characters(blacklist_characters=blacklist) - else: - return binary_char.filter(lambda c: c not in blacklist) - - elif code == sre.IN: - # Regex '[abc0-9]' (set of characters) - negate = value[0][0] == sre.NEGATE - if is_unicode: - builder = CharactersBuilder(negate, context.flags) - else: - builder = BytesBuilder(negate, context.flags) - - for charset_code, charset_value in value: - if charset_code == sre.NEGATE: - # Regex '[^...]' (negation) - # handled by builder = CharactersBuilder(...) above - pass - elif charset_code == sre.LITERAL: - # Regex '[a]' (single char) - builder.add_char(charset_value) - elif charset_code == sre.RANGE: - # Regex '[a-z]' (char range) - low, high = charset_value - for char_code in hrange(low, high + 1): - builder.add_char(char_code) - elif charset_code == sre.CATEGORY: - # Regex '[\w]' (char category) - builder.add_category(charset_value) - else: # pragma: no cover - # Currently there are no known code points other than - # handled here. This code is just future proofing - raise AssertionError('Unknown charset code: %s' - % charset_code) - return builder.strategy - - elif code == sre.ANY: - # Regex '.' (any char) - if is_unicode: - if context.flags & re.DOTALL: - return st.characters() - return st.characters(blacklist_characters=u'\n') - else: - if context.flags & re.DOTALL: - return binary_char - return binary_char.filter(lambda c: c != b'\n') - - elif code == sre.AT: - # Regexes like '^...', '...$', '\bfoo', '\Bfoo' - # An empty string (or newline) will match the token itself, but - # we don't and can't check the position (eg '%' at the end) - return st.just(empty) - - elif code == sre.SUBPATTERN: - # Various groups: '(...)', '(:...)' or '(?P...)' - old_flags = context.flags - if HAS_SUBPATTERN_FLAGS: # pragma: no cover - # This feature is available only in specific Python versions - context.flags = (context.flags | value[1]) & ~value[2] - - strat = _strategy(value[-1], context, is_unicode) - - context.flags = old_flags - - if value[0]: - strat = update_group(value[0], strat) - - return strat - - elif code == sre.GROUPREF: - # Regex '\\1' or '(?P=name)' (group reference) - return reuse_group(value) - - elif code == sre.ASSERT: - # Regex '(?=...)' or '(?<=...)' (positive lookahead/lookbehind) - return recurse(value[1]) - - elif code == sre.ASSERT_NOT: - # Regex '(?!...)' or '(? 50: # pragma: no cover - key = frozenset(mapping.items()) - assert key not in seen, (key, name) - seen.add(key) - to_update = needs_update - needs_update = set() - for strat in to_update: - def recur(other): - try: - return forced_value(other) - except AttributeError: - pass - listeners[other].add(strat) - try: - return mapping[other] - except KeyError: - needs_update.add(other) - mapping[other] = default - return default - - new_value = getattr(strat, calculation)(recur) - if new_value != mapping[strat]: - needs_update.update(listeners[strat]) - mapping[strat] = new_value - - # We now have a complete and accurate calculation of the - # property values for everything we have seen in the course of - # running this calculation. We simultaneously update all of - # them (not just the strategy we started out with). - for k, v in mapping.items(): - setattr(k, cache_key, v) - return getattr(self, cache_key) - - accept.__name__ = name - return property(accept) - - # Returns True if this strategy can never draw a value and will always - # result in the data being marked invalid. - # The fact that this returns False does not guarantee that a valid value - # can be drawn - this is not intended to be perfect, and is primarily - # intended to be an optimisation for some cases. - is_empty = recursive_property('is_empty', True) - - # Returns True if values from this strategy can safely be reused without - # this causing unexpected behaviour. - has_reusable_values = recursive_property('has_reusable_values', True) - - # Whether this strategy is suitable for holding onto in a cache. - is_cacheable = recursive_property('is_cacheable', True) - - def calc_is_cacheable(self, recur): - return True - - def calc_is_empty(self, recur): - # Note: It is correct and significant that the default return value - # from calc_is_empty is False despite the default value for is_empty - # being true. The reason for this is that strategies should be treated - # as empty absent evidence to the contrary, but most basic strategies - # are trivially non-empty and it would be annoying to have to override - # this method to show that. - return False - - def calc_has_reusable_values(self, recur): - return False - - def example(self, random=None): - """Provide an example of the sort of value that this strategy - generates. This is biased to be slightly simpler than is typical for - values from this strategy, for clarity purposes. - - This method shouldn't be taken too seriously. It's here for interactive - exploration of the API, not for any sort of real testing. - - This method is part of the public API. - - """ - context = _current_build_context.value - if context is not None: - if context.data is not None and context.data.depth > 0: - note_deprecation( - 'Using example() inside a strategy definition is a bad ' - 'idea. It will become an error in a future version of ' - "Hypothesis, but it's unlikely that it's doing what you " - 'intend even now. Instead consider using ' - 'hypothesis.strategies.builds() or ' - '@hypothesis.strategies.composite to define your strategy.' - ' See ' - 'https://hypothesis.readthedocs.io/en/latest/data.html' - '#hypothesis.strategies.builds or ' - 'https://hypothesis.readthedocs.io/en/latest/data.html' - '#composite-strategies for more details.' - ) - else: - note_deprecation( - 'Using example() inside a test function is a bad ' - 'idea. It will become an error in a future version of ' - "Hypothesis, but it's unlikely that it's doing what you " - 'intend even now. Instead consider using ' - 'hypothesis.strategies.data() to draw ' - 'more examples during testing. See ' - 'https://hypothesis.readthedocs.io/en/latest/data.html' - '#drawing-interactively-in-tests for more details.' - ) - - from hypothesis import find, settings, Verbosity - - # Conjecture will always try the zero example first. This would result - # in us producing the same example each time, which is boring, so we - # deliberately skip the first example it feeds us. - first = [] - - def condition(x): - if first: - return True - else: - first.append(x) - return False - try: - return find( - self, - condition, - random=random, - settings=settings( - max_shrinks=0, - max_iterations=1000, - database=None, - verbosity=Verbosity.quiet, - ) - ) - except (NoSuchExample, Unsatisfiable): - # This can happen when a strategy has only one example. e.g. - # st.just(x). In that case we wanted the first example after all. - if first: - return first[0] - raise NoExamples( - u'Could not find any valid examples in 100 tries' - ) - - def map(self, pack): - """Returns a new strategy that generates values by generating a value - from this strategy and then calling pack() on the result, giving that. - - This method is part of the public API. - - """ - return MappedSearchStrategy( - pack=pack, strategy=self - ) - - def flatmap(self, expand): - """Returns a new strategy that generates values by generating a value - from this strategy, say x, then generating a value from - strategy(expand(x)) - - This method is part of the public API. - - """ - from hypothesis.searchstrategy.flatmapped import FlatMapStrategy - return FlatMapStrategy( - expand=expand, strategy=self - ) - - def filter(self, condition): - """Returns a new strategy that generates values from this strategy - which satisfy the provided condition. Note that if the condition is too - hard to satisfy this might result in your tests failing with - Unsatisfiable. - - This method is part of the public API. - - """ - return FilteredStrategy( - condition=condition, - strategy=self, - ) - - @property - def branches(self): - return [self] - - def __or__(self, other): - """Return a strategy which produces values by randomly drawing from one - of this strategy or the other strategy. - - This method is part of the public API. - - """ - if not isinstance(other, SearchStrategy): - raise ValueError('Cannot | a SearchStrategy with %r' % (other,)) - return one_of_strategies((self, other)) - - def validate(self): - """Throw an exception if the strategy is not valid. - - This can happen due to lazy construction - - """ - if self.validate_called: - return - try: - self.validate_called = True - self.do_validate() - self.is_empty - self.has_reusable_values - except Exception: - self.validate_called = False - raise - - def do_validate(self): - pass - - def do_draw(self, data): - raise NotImplementedError('%s.do_draw' % (type(self).__name__,)) - - def __init__(self): - pass - - -class OneOfStrategy(SearchStrategy): - - """Implements a union of strategies. Given a number of strategies this - generates values which could have come from any of them. - - The conditional distribution draws uniformly at random from some - non-empty subset of these strategies and then draws from the - conditional distribution of that strategy. - - """ - - def __init__(self, strategies, bias=None): - SearchStrategy.__init__(self) - strategies = tuple(strategies) - self.original_strategies = list(strategies) - self.__element_strategies = None - self.bias = bias - self.__in_branches = False - if bias is not None: - assert 0 < bias < 1 - self.sampler = cu.Sampler( - [bias ** i for i in range(len(strategies))]) - else: - self.sampler = None - - def calc_is_empty(self, recur): - return all(recur(e) for e in self.original_strategies) - - def calc_has_reusable_values(self, recur): - return all(recur(e) for e in self.original_strategies) - - def calc_is_cacheable(self, recur): - return all(recur(e) for e in self.original_strategies) - - @property - def element_strategies(self): - from hypothesis.strategies import check_strategy - if self.__element_strategies is None: - strategies = [] - for arg in self.original_strategies: - check_strategy(arg) - if not arg.is_empty: - strategies.extend( - [s for s in arg.branches if not s.is_empty]) - pruned = [] - seen = set() - for s in strategies: - if s is self: - continue - if s in seen: - continue - seen.add(s) - pruned.append(s) - self.__element_strategies = pruned - return self.__element_strategies - - def do_draw(self, data): - n = len(self.element_strategies) - assert n > 0 - if n == 1: - return data.draw(self.element_strategies[0]) - elif self.sampler is None: - i = cu.integer_range(data, 0, n - 1) - else: - i = self.sampler.sample(data) - - return data.draw(self.element_strategies[i]) - - def __repr__(self): - return ' | '.join(map(repr, self.original_strategies)) - - def do_validate(self): - for e in self.element_strategies: - e.validate() - - @property - def branches(self): - if self.bias is None and not self.__in_branches: - try: - self.__in_branches = True - return self.element_strategies - finally: - self.__in_branches = False - else: - return [self] - - -class MappedSearchStrategy(SearchStrategy): - - """A strategy which is defined purely by conversion to and from another - strategy. - - Its parameter and distribution come from that other strategy. - - """ - - def __init__(self, strategy, pack=None): - SearchStrategy.__init__(self) - self.mapped_strategy = strategy - if pack is not None: - self.pack = pack - - def calc_is_empty(self, recur): - return recur(self.mapped_strategy) - - def calc_is_cacheable(self, recur): - return recur(self.mapped_strategy) - - def __repr__(self): - if not hasattr(self, '_cached_repr'): - self._cached_repr = '%r.map(%s)' % ( - self.mapped_strategy, get_pretty_function_description( - self.pack) - ) - return self._cached_repr - - def do_validate(self): - self.mapped_strategy.validate() - - def pack(self, x): - """Take a value produced by the underlying mapped_strategy and turn it - into a value suitable for outputting from this strategy.""" - raise NotImplementedError( - '%s.pack()' % (self.__class__.__name__)) - - def do_draw(self, data): - for _ in range(3): - i = data.index - try: - return self.pack(data.draw(self.mapped_strategy)) - except UnsatisfiedAssumption: - if data.index == i: - raise - reject() - - @property - def branches(self): - return [ - MappedSearchStrategy(pack=self.pack, strategy=strategy) - for strategy in self.mapped_strategy.branches - ] - - -class FilteredStrategy(SearchStrategy): - - def __init__(self, strategy, condition): - super(FilteredStrategy, self).__init__() - self.condition = condition - self.filtered_strategy = strategy - - def calc_is_empty(self, recur): - return recur(self.filtered_strategy) - - def calc_is_cacheable(self, recur): - return recur(self.filtered_strategy) - - def __repr__(self): - if not hasattr(self, '_cached_repr'): - self._cached_repr = '%r.filter(%s)' % ( - self.filtered_strategy, get_pretty_function_description( - self.condition) - ) - return self._cached_repr - - def do_validate(self): - self.filtered_strategy.validate() - - def do_draw(self, data): - for i in hrange(3): - start_index = data.index - value = data.draw(self.filtered_strategy) - if self.condition(value): - return value - else: - if i == 0: - data.note_event(lazyformat( - 'Retried draw from %r to satisfy filter', self,)) - # This is to guard against the case where we consume no data. - # As long as we consume data, we'll eventually pass or raise. - # But if we don't this could be an infinite loop. - assume(data.index > start_index) - data.note_event('Aborted test because unable to satisfy %r' % ( - self, - )) - data.mark_invalid() - - @property - def branches(self): - branches = [ - FilteredStrategy(strategy=strategy, condition=self.condition) - for strategy in self.filtered_strategy.branches - ] - return branches diff -Nru python-hypothesis-3.44.1/src/hypothesis/searchstrategy/streams.py python-hypothesis-3.71.11/src/hypothesis/searchstrategy/streams.py --- python-hypothesis-3.44.1/src/hypothesis/searchstrategy/streams.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/searchstrategy/streams.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from hypothesis.types import Stream -from hypothesis.searchstrategy.strategies import SearchStrategy - - -class StreamStrategy(SearchStrategy): - - supports_find = False - - def __init__(self, source_strategy): - super(StreamStrategy, self).__init__() - self.source_strategy = source_strategy - - def __repr__(self): - return u'StreamStrategy(%r)' % (self.source_strategy,) - - def do_draw(self, data): - data.can_reproduce_example_from_repr = False - - def gen(): - while True: - yield data.draw(self.source_strategy) - return Stream(gen()) diff -Nru python-hypothesis-3.44.1/src/hypothesis/searchstrategy/strings.py python-hypothesis-3.71.11/src/hypothesis/searchstrategy/strings.py --- python-hypothesis-3.44.1/src/hypothesis/searchstrategy/strings.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/searchstrategy/strings.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,106 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from hypothesis.errors import InvalidArgument -from hypothesis.internal import charmap -from hypothesis.internal.compat import hunichr, text_type, binary_type -from hypothesis.internal.intervalsets import IntervalSet -from hypothesis.internal.conjecture.utils import integer_range -from hypothesis.searchstrategy.strategies import SearchStrategy, \ - MappedSearchStrategy - - -class OneCharStringStrategy(SearchStrategy): - - """A strategy which generates single character strings of text type.""" - specifier = text_type - zero_point = ord('0') - - def __init__(self, - whitelist_categories=None, - blacklist_categories=None, - blacklist_characters=None, - min_codepoint=None, - max_codepoint=None, - whitelist_characters=None): - intervals = charmap.query( - include_categories=whitelist_categories, - exclude_categories=blacklist_categories, - min_codepoint=min_codepoint, - max_codepoint=max_codepoint, - include_characters=whitelist_characters, - exclude_characters=blacklist_characters, - ) - if not intervals: - raise InvalidArgument( - 'No valid characters in set' - ) - self.intervals = IntervalSet(intervals) - if whitelist_characters: - self.whitelist_characters = set(whitelist_characters) - else: - self.whitelist_characters = set() - self.zero_point = self.intervals.index_above(ord('0')) - - def do_draw(self, data): - i = integer_range( - data, 0, len(self.intervals) - 1, - center=self.zero_point, - ) - return hunichr(self.intervals[i]) - - -class StringStrategy(MappedSearchStrategy): - - """A strategy for text strings, defined in terms of a strategy for lists of - single character text strings.""" - - def __init__(self, list_of_one_char_strings_strategy): - super(StringStrategy, self).__init__( - strategy=list_of_one_char_strings_strategy - ) - - def __repr__(self): - return 'StringStrategy()' - - def pack(self, ls): - return u''.join(ls) - - -class BinaryStringStrategy(MappedSearchStrategy): - - """A strategy for strings of bytes, defined in terms of a strategy for - lists of bytes.""" - - def __repr__(self): - return 'BinaryStringStrategy()' - - def pack(self, x): - assert isinstance(x, list), repr(x) - ba = bytearray(x) - return binary_type(ba) - - -class FixedSizeBytes(SearchStrategy): - - def __init__(self, size): - self.size = size - - def do_draw(self, data): - return binary_type(data.draw_bytes(self.size)) diff -Nru python-hypothesis-3.44.1/src/hypothesis/searchstrategy/types.py python-hypothesis-3.71.11/src/hypothesis/searchstrategy/types.py --- python-hypothesis-3.44.1/src/hypothesis/searchstrategy/types.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/searchstrategy/types.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,243 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import io -import uuid -import decimal -import datetime -import fractions -import functools -import collections - -import hypothesis.strategies as st -from hypothesis.errors import ResolutionFailed -from hypothesis.internal.compat import text_type, integer_types - - -def type_sorting_key(t): - """Minimise to None, then non-container types, then container types.""" - if t is None or t is type(None): # noqa: E721 - return -1 - return issubclass(t, collections.abc.Container) - - -def try_issubclass(thing, maybe_superclass): - try: - return issubclass(thing, maybe_superclass) - except (AttributeError, TypeError): # pragma: no cover - # Some types can't be the subject or object of an instance or - # subclass check under Python 3.5 - return False - - -def from_typing_type(thing): - # We start with special-case support for Union and Tuple - the latter - # isn't actually a generic type. Support for Callable may be added to - # this section later. - # We then explicitly error on non-Generic types, which don't carry enough - # information to sensibly resolve to strategies at runtime. - # Finally, we run a variation of the subclass lookup in st.from_type - # among generic types in the lookup. - import typing - # Under 3.6 Union is handled directly in st.from_type, as the argument is - # not an instance of `type`. However, under Python 3.5 Union *is* a type - # and we have to handle it here, including failing if it has no parameters. - if hasattr(thing, '__union_params__'): # pragma: no cover - args = sorted(thing.__union_params__ or (), key=type_sorting_key) - if not args: - raise ResolutionFailed('Cannot resolve Union of no types.') - return st.one_of([st.from_type(t) for t in args]) - if isinstance(thing, typing.TupleMeta): - elem_types = getattr(thing, '__tuple_params__', None) or () - elem_types += getattr(thing, '__args__', None) or () - if getattr(thing, '__tuple_use_ellipsis__', False) or \ - len(elem_types) == 2 and elem_types[-1] is Ellipsis: - return st.lists(st.from_type(elem_types[0])).map(tuple) - return st.tuples(*map(st.from_type, elem_types)) - # Now, confirm that we're dealing with a generic type as we expected - if not isinstance(thing, typing.GenericMeta): # pragma: no cover - raise ResolutionFailed('Cannot resolve %s to a strategy' % (thing,)) - # Parametrised generic types have their __origin__ attribute set to the - # un-parametrised version, which we need to use in the subclass checks. - # e.g.: typing.List[int].__origin__ == typing.List - mapping = {k: v for k, v in _global_type_lookup.items() - if isinstance(k, typing.GenericMeta) and - try_issubclass(k, getattr(thing, '__origin__', None) or thing)} - if typing.Dict in mapping: - # The subtype relationships between generic and concrete View types - # are sometimes inconsistent under Python 3.5, so we pop them out to - # preserve our invariant that all examples of from_type(T) are - # instances of type T - and simplify the strategy for abstract types - # such as Container - for t in (typing.KeysView, typing.ValuesView, typing.ItemsView): - mapping.pop(t, None) - strategies = [v if isinstance(v, st.SearchStrategy) else v(thing) - for k, v in mapping.items() - if sum(try_issubclass(k, T) for T in mapping) == 1] - empty = ', '.join(repr(s) for s in strategies if s.is_empty) - if empty or not strategies: # pragma: no cover - raise ResolutionFailed( - 'Could not resolve %s to a strategy; consider using ' - 'register_type_strategy' % (empty or thing,)) - return st.one_of(strategies) - - -_global_type_lookup = { - # Types with core Hypothesis strategies - type(None): st.none(), - bool: st.booleans(), - float: st.floats(), - complex: st.complex_numbers(), - fractions.Fraction: st.fractions(), - decimal.Decimal: st.decimals(), - text_type: st.text(), - bytes: st.binary(), - datetime.datetime: st.datetimes(), - datetime.date: st.dates(), - datetime.time: st.times(), - datetime.timedelta: st.timedeltas(), - uuid.UUID: st.uuids(), - tuple: st.builds(tuple), - list: st.builds(list), - set: st.builds(set), - frozenset: st.builds(frozenset), - dict: st.builds(dict), - # Built-in types - type: st.sampled_from([type(None), bool, int, str, list, set, dict]), - type(Ellipsis): st.just(Ellipsis), - type(NotImplemented): st.just(NotImplemented), - bytearray: st.binary().map(bytearray), - memoryview: st.binary().map(memoryview), - # Pull requests with more types welcome! -} -for t in integer_types: - _global_type_lookup[t] = st.integers() - -try: - from hypothesis.extra.pytz import timezones - _global_type_lookup[datetime.tzinfo] = timezones() -except ImportError: # pragma: no cover - pass -try: # pragma: no cover - import numpy as np - from hypothesis.extra.numpy import \ - arrays, array_shapes, scalar_dtypes, nested_dtypes - _global_type_lookup.update({ - np.dtype: nested_dtypes(), - np.ndarray: arrays(scalar_dtypes(), array_shapes(max_dims=2)), - }) -except ImportError: # pragma: no cover - pass - -try: - import typing -except ImportError: # pragma: no cover - pass -else: - _global_type_lookup.update({ - typing.ByteString: st.binary(), - typing.io.BinaryIO: st.builds(io.BytesIO, st.binary()), - typing.io.TextIO: st.builds(io.StringIO, st.text()), - typing.Reversible: st.lists(st.integers()), - typing.SupportsAbs: st.complex_numbers(), - typing.SupportsComplex: st.complex_numbers(), - typing.SupportsFloat: st.complex_numbers(), - typing.SupportsInt: st.complex_numbers(), - }) - - try: - # These aren't present in the typing module backport. - _global_type_lookup[typing.SupportsBytes] = st.binary() - _global_type_lookup[typing.SupportsRound] = st.complex_numbers() - except AttributeError: # pragma: no cover - pass - - def register(type_, fallback=None): - if isinstance(type_, str): - # Use the name of generic types which are not available on all - # versions, and the function just won't be added to the registry - type_ = getattr(typing, type_, None) - if type_ is None: # pragma: no cover - return lambda f: f - - def inner(func): - if fallback is None: - _global_type_lookup[type_] = func - return func - - @functools.wraps(func) - def really_inner(thing): - if getattr(thing, '__args__', None) is None: - return fallback - return func(thing) - _global_type_lookup[type_] = really_inner - return really_inner - return inner - - @register('Type') - def resolve_Type(thing): - if thing.__args__ is None: - return st.just(type) - inner = thing.__args__[0] - if getattr(inner, '__origin__', None) is typing.Union: - return st.sampled_from(inner.__args__) - elif hasattr(inner, '__union_params__'): # pragma: no cover - return st.sampled_from(inner.__union_params__) - return st.just(inner) - - @register(typing.List, st.builds(list)) - def resolve_List(thing): - return st.lists(st.from_type(thing.__args__[0])) - - @register(typing.Set, st.builds(set)) - def resolve_Set(thing): - return st.sets(st.from_type(thing.__args__[0])) - - @register(typing.FrozenSet, st.builds(frozenset)) - def resolve_FrozenSet(thing): - return st.frozensets(st.from_type(thing.__args__[0])) - - @register(typing.Dict, st.builds(dict)) - def resolve_Dict(thing): - # If thing is a Collection instance, we need to fill in the values - keys_vals = [st.from_type(t) for t in thing.__args__] * 2 - return st.dictionaries(keys_vals[0], keys_vals[1]) - - @register('DefaultDict', st.builds(collections.defaultdict)) - def resolve_DefaultDict(thing): - return resolve_Dict(thing).map( - lambda d: collections.defaultdict(None, d)) - - @register(typing.ItemsView, st.builds(dict).map(dict.items)) - def resolve_ItemsView(thing): - return resolve_Dict(thing).map(dict.items) - - @register(typing.KeysView, st.builds(dict).map(dict.keys)) - def resolve_KeysView(thing): - return st.dictionaries(st.from_type(thing.__args__[0]), st.none() - ).map(dict.keys) - - @register(typing.ValuesView, st.builds(dict).map(dict.values)) - def resolve_ValuesView(thing): - return st.dictionaries(st.integers(), st.from_type(thing.__args__[0]) - ).map(dict.values) - - @register(typing.Iterator, st.iterables(st.nothing())) - def resolve_Iterator(thing): - return st.iterables(st.from_type(thing.__args__[0])) diff -Nru python-hypothesis-3.44.1/src/hypothesis/_settings.py python-hypothesis-3.71.11/src/hypothesis/_settings.py --- python-hypothesis-3.44.1/src/hypothesis/_settings.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/_settings.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,740 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -"""A module controlling settings for Hypothesis to use in falsification. - -Either an explicit settings object can be used or the default object on -this module can be modified. - -""" - -from __future__ import division, print_function, absolute_import - -import os -import inspect -import warnings -import threading -from enum import Enum, IntEnum, unique - -import attr - -from hypothesis.errors import InvalidArgument, HypothesisDeprecationWarning -from hypothesis.configuration import hypothesis_home_dir -from hypothesis.utils.conventions import UniqueIdentifier, not_set -from hypothesis.internal.validation import try_convert -from hypothesis.utils.dynamicvariables import DynamicVariable - -__all__ = [ - 'settings', -] - - -unlimited = UniqueIdentifier('unlimited') - - -all_settings = {} - - -_db_cache = {} - - -class settingsProperty(object): - - def __init__(self, name, show_default): - self.name = name - self.show_default = show_default - - def __get__(self, obj, type=None): - if obj is None: - return self - else: - try: - return obj.__dict__[self.name] - except KeyError: - raise AttributeError(self.name) - - def __set__(self, obj, value): - obj.__dict__[self.name] = value - - def __delete__(self, obj): - raise AttributeError('Cannot delete attribute %s' % (self.name,)) - - @property - def __doc__(self): - description = all_settings[self.name].description - deprecation_message = all_settings[self.name].deprecation_message - default = repr(getattr(settings.default, self.name)) if \ - self.show_default else '(dynamically calculated)' - return '\n\n'.join([description, 'default value: %s' % (default,), - (deprecation_message or '').strip()]).strip() - - -default_variable = DynamicVariable(None) - - -class settingsMeta(type): - - def __init__(self, *args, **kwargs): - super(settingsMeta, self).__init__(*args, **kwargs) - - @property - def default(self): - v = default_variable.value - if v is not None: - return v - if hasattr(settings, '_current_profile'): - settings.load_profile(settings._current_profile) - assert default_variable.value is not None - return default_variable.value - - @default.setter - def default(self, value): - raise AttributeError('Cannot assign settings.default') - - def _assign_default_internal(self, value): - default_variable.value = value - - -class settings(settingsMeta('settings', (object,), {})): - - """A settings object controls a variety of parameters that are used in - falsification. These may control both the falsification strategy and the - details of the data that is generated. - - Default values are picked up from the settings.default object and - changes made there will be picked up in newly created settings. - - """ - - _WHITELISTED_REAL_PROPERTIES = [ - '_database', '_construction_complete', 'storage' - ] - __definitions_are_locked = False - _profiles = {} - - def __getattr__(self, name): - if name in all_settings: - d = all_settings[name].default - if inspect.isfunction(d): - d = d() - return d - else: - raise AttributeError('settings has no attribute %s' % (name,)) - - def __init__( - self, - parent=None, - **kwargs - ): - self._construction_complete = False - self._database = kwargs.pop('database', not_set) - database_file = kwargs.get('database_file', not_set) - deprecations = [] - defaults = parent or settings.default - if defaults is not None: - for setting in all_settings.values(): - if kwargs.get(setting.name, not_set) is not_set: - kwargs[setting.name] = getattr(defaults, setting.name) - else: - if kwargs[setting.name] != setting.future_default: - if setting.deprecation_message is not None: - deprecations.append(setting) - if setting.validator: - kwargs[setting.name] = setting.validator( - kwargs[setting.name]) - if self._database is not_set and database_file is not_set: - self._database = defaults.database - for name, value in kwargs.items(): - if name not in all_settings: - raise InvalidArgument( - 'Invalid argument %s' % (name,)) - setattr(self, name, value) - self.storage = threading.local() - self._construction_complete = True - - for d in deprecations: - note_deprecation(d.deprecation_message, self) - - def defaults_stack(self): - try: - return self.storage.defaults_stack - except AttributeError: - self.storage.defaults_stack = [] - return self.storage.defaults_stack - - def __call__(self, test): - test._hypothesis_internal_use_settings = self - return test - - @classmethod - def define_setting( - cls, name, description, default, options=None, deprecation=None, - validator=None, show_default=True, future_default=not_set, - deprecation_message=None, - ): - """Add a new setting. - - - name is the name of the property that will be used to access the - setting. This must be a valid python identifier. - - description will appear in the property's docstring - - default is the default value. This may be a zero argument - function in which case it is evaluated and its result is stored - the first time it is accessed on any given settings object. - - """ - if settings.__definitions_are_locked: - from hypothesis.errors import InvalidState - raise InvalidState( - 'settings have been locked and may no longer be defined.' - ) - if options is not None: - options = tuple(options) - assert default in options - - if future_default is not_set: - future_default = default - - all_settings[name] = Setting( - name, description.strip(), default, options, validator, - future_default, deprecation_message, - ) - setattr(settings, name, settingsProperty(name, show_default)) - - @classmethod - def lock_further_definitions(cls): - settings.__definitions_are_locked = True - - def __setattr__(self, name, value): - if name in settings._WHITELISTED_REAL_PROPERTIES: - return object.__setattr__(self, name, value) - elif name == 'database': - assert self._construction_complete - raise AttributeError( - 'settings objects are immutable and may not be assigned to' - ' after construction.' - ) - elif name in all_settings: - if self._construction_complete: - raise AttributeError( - 'settings objects are immutable and may not be assigned to' - ' after construction.' - ) - else: - setting = all_settings[name] - if ( - setting.options is not None and - value not in setting.options - ): - raise InvalidArgument( - 'Invalid %s, %r. Valid options: %r' % ( - name, value, setting.options - ) - ) - return object.__setattr__(self, name, value) - else: - raise AttributeError('No such setting %s' % (name,)) - - def __repr__(self): - bits = [] - for name in all_settings: - value = getattr(self, name) - bits.append('%s=%r' % (name, value)) - bits.sort() - return 'settings(%s)' % ', '.join(bits) - - @property - def database(self): - """An ExampleDatabase instance to use for storage of examples. May be - None. - - If this was explicitly set at settings instantiation then that - value will be used (even if it was None). If not and the - database_file setting is not None this will be lazily loaded as - an ExampleDatabase, using that file the first time that this - property is accessed on a particular thread. - - """ - if self._database is not_set and self.database_file is not None: - from hypothesis.database import ExampleDatabase - if self.database_file not in _db_cache: - _db_cache[self.database_file] = ( - ExampleDatabase(self.database_file)) - return _db_cache[self.database_file] - if self._database is not_set: - self._database = None - return self._database - - def __enter__(self): - default_context_manager = default_variable.with_value(self) - self.defaults_stack().append(default_context_manager) - default_context_manager.__enter__() - return self - - def __exit__(self, *args, **kwargs): - default_context_manager = self.defaults_stack().pop() - return default_context_manager.__exit__(*args, **kwargs) - - @staticmethod - def register_profile(name, settings): - """registers a collection of values to be used as a settings profile. - These settings can be loaded in by name. Enable different defaults for - different settings. - - - settings is a settings object - - """ - settings._profiles[name] = settings - - @staticmethod - def get_profile(name): - """Return the profile with the given name. - - - name is a string representing the name of the profile - to load - A InvalidArgument exception will be thrown if the - profile does not exist - - """ - try: - return settings._profiles[name] - except KeyError: - raise InvalidArgument( - "Profile '{0}' has not been registered".format( - name - ) - ) - - @staticmethod - def load_profile(name): - """Loads in the settings defined in the profile provided If the profile - does not exist an InvalidArgument will be thrown. - - Any setting not defined in the profile will be the library - defined default for that setting - - """ - settings._current_profile = name - settings._assign_default_internal(settings.get_profile(name)) - - -@attr.s() -class Setting(object): - name = attr.ib() - description = attr.ib() - default = attr.ib() - options = attr.ib() - validator = attr.ib() - future_default = attr.ib() - deprecation_message = attr.ib() - - -settings.define_setting( - 'min_satisfying_examples', - default=5, - description=""" -Raise Unsatisfiable for any tests which do not produce at least this many -values that pass all assume() calls and which have not exhaustively covered the -search space. -""" -) - -settings.define_setting( - 'max_examples', - default=100, - description=""" -Once this many satisfying examples have been considered without finding any -counter-example, falsification will terminate. -""" -) - -settings.define_setting( - 'max_iterations', - default=1000, - description=""" -Once this many iterations of the example loop have run, including ones which -failed to satisfy assumptions and ones which produced duplicates, falsification -will terminate. -""" -) - -settings.define_setting( - 'buffer_size', - default=8 * 1024, - description=""" -The size of the underlying data used to generate examples. If you need to -generate really large examples you may want to increase this, but it will make -your tests slower. -""" -) - - -settings.define_setting( - 'max_shrinks', - default=500, - description=""" -Once this many successful shrinks have been performed, Hypothesis will assume -something has gone a bit wrong and give up rather than continuing to try to -shrink the example. -""" -) - - -def _validate_timeout(n): - if n is unlimited: - return -1 - else: - return n - - -settings.define_setting( - 'timeout', - default=60, - description=""" -Once this many seconds have passed, falsify will terminate even -if it has not found many examples. This is a soft rather than a hard -limit - Hypothesis won't e.g. interrupt execution of the called -function to stop it. If this value is <= 0 then no timeout will be -applied. -""", - deprecation_message=""" -The timeout setting is deprecated and will be removed in a future version of -Hypothesis. To get the future behaviour set ``timeout=hypothesis.unlimited`` -instead (which will remain valid for a further deprecation period after this -setting has gone away). -""", - future_default=unlimited, - validator=_validate_timeout -) - -settings.define_setting( - 'derandomize', - default=False, - description=""" -If this is True then hypothesis will run in deterministic mode -where each falsification uses a random number generator that is seeded -based on the hypothesis to falsify, which will be consistent across -multiple runs. This has the advantage that it will eliminate any -randomness from your tests, which may be preferable for some situations. -It does have the disadvantage of making your tests less likely to -find novel breakages. -""" -) - -settings.define_setting( - 'strict', - default=os.getenv('HYPOTHESIS_STRICT_MODE') == 'true', - description=""" -If set to True, anything that would cause Hypothesis to issue a warning will -instead raise an error. Note that new warnings may be added at any time, so -running with strict set to True means that new Hypothesis releases may validly -break your code. Note also that, as strict mode is itself deprecated, -enabling it is now an error! - -You can enable this setting temporarily by setting the HYPOTHESIS_STRICT_MODE -environment variable to the string 'true'. -""", - deprecation_message=""" -Strict mode is deprecated and will go away in a future version of Hypothesis. -To get the same behaviour, use -warnings.simplefilter('error', HypothesisDeprecationWarning). -""", - future_default=False, -) - -settings.define_setting( - 'database_file', - default=lambda: ( - os.getenv('HYPOTHESIS_DATABASE_FILE') or - os.path.join(hypothesis_home_dir(), 'examples') - ), - show_default=False, - description=""" - An instance of hypothesis.database.ExampleDatabase that will be -used to save examples to and load previous examples from. May be None -in which case no storage will be used. -""" -) - - -@unique -class Phase(IntEnum): - explicit = 0 - reuse = 1 - generate = 2 - shrink = 3 - - -@unique -class HealthCheck(Enum): - """Arguments for :attr:`~hypothesis.settings.suppress_health_check`. - - Each member of this enum is a type of health check to suppress. - - """ - - exception_in_generation = 0 - """Deprecated and no longer does anything. It used to convert errors in - data generation into FailedHealthCheck error.""" - - data_too_large = 1 - """Check for when the typical size of the examples you are generating - exceeds the maximum allowed size too often.""" - - filter_too_much = 2 - """Check for when the test is filtering out too many examples, either - through use of :func:`~hypothesis.assume()` or :ref:`filter() `, - or occasionally for Hypothesis internal reasons.""" - - too_slow = 3 - """Check for when your data generation is extremely slow and likely to hurt - testing.""" - - random_module = 4 - """Deprecated and no longer does anything. It used to check for whether - your tests used the global random module. Now @given tests automatically - seed random so this is no longer an error.""" - - return_value = 5 - """Checks if your tests return a non-None value (which will be ignored and - is unlikely to do what you want).""" - - hung_test = 6 - """Checks if your tests have been running for a very long time.""" - - large_base_example = 7 - """Checks if the natural example to shrink towards is very large.""" - - -@unique -class Statistics(IntEnum): - never = 0 - interesting = 1 - always = 2 - - -class Verbosity(object): - - def __repr__(self): - return 'Verbosity.%s' % (self.name,) - - def __init__(self, name, level): - self.name = name - self.level = level - - def __eq__(self, other): - return isinstance(other, Verbosity) and ( - self.level == other.level - ) - - def __ne__(self, other): - return not self.__eq__(other) - - def __hash__(self): - return self.level - - def __lt__(self, other): - return self.level < other.level - - def __le__(self, other): - return self.level <= other.level - - def __gt__(self, other): - return self.level > other.level - - def __ge__(self, other): - return self.level >= other.level - - @classmethod - def by_name(cls, key): - result = getattr(cls, key, None) - if isinstance(result, Verbosity): - return result - raise InvalidArgument('No such verbosity level %r' % (key,)) - - -Verbosity.quiet = Verbosity('quiet', 0) -Verbosity.normal = Verbosity('normal', 1) -Verbosity.verbose = Verbosity('verbose', 2) -Verbosity.debug = Verbosity('debug', 3) -Verbosity.all = [ - Verbosity.quiet, Verbosity.normal, Verbosity.verbose, Verbosity.debug -] - - -ENVIRONMENT_VERBOSITY_OVERRIDE = os.getenv('HYPOTHESIS_VERBOSITY_LEVEL') - -if ENVIRONMENT_VERBOSITY_OVERRIDE: # pragma: no cover - DEFAULT_VERBOSITY = Verbosity.by_name(ENVIRONMENT_VERBOSITY_OVERRIDE) -else: - DEFAULT_VERBOSITY = Verbosity.normal - -settings.define_setting( - 'verbosity', - options=Verbosity.all, - default=DEFAULT_VERBOSITY, - description='Control the verbosity level of Hypothesis messages', -) - - -def _validate_phases(phases): - if phases is None: - return tuple(Phase) - phases = tuple(phases) - for a in phases: - if not isinstance(a, Phase): - raise InvalidArgument('%r is not a valid phase' % (a,)) - return phases - - -settings.define_setting( - 'phases', - default=tuple(Phase), - description=( - 'Control which phases should be run. ' + - 'See :ref:`the full documentation for more details `' - ), - validator=_validate_phases, -) - -settings.define_setting( - name='stateful_step_count', - default=50, - description=""" -Number of steps to run a stateful program for before giving up on it breaking. -""" -) - -settings.define_setting( - 'perform_health_check', - default=True, - description=u""" -If set to True, Hypothesis will run a preliminary health check before -attempting to actually execute your test. -""" -) - - -def validate_health_check_suppressions(suppressions): - suppressions = try_convert(list, suppressions, 'suppress_health_check') - for s in suppressions: - if not isinstance(s, HealthCheck): - note_deprecation(( - 'Non-HealthCheck value %r of type %s in suppress_health_check ' - 'will be ignored, and will become an error in a future ' - 'version of Hypothesis') % ( - s, type(s).__name__, - )) - elif s in ( - HealthCheck.exception_in_generation, HealthCheck.random_module - ): - note_deprecation(( - '%s is now ignored and suppressing it is a no-op. This will ' - 'become an error in a future version of Hypothesis. Simply ' - 'remove it from your list of suppressions to get the same ' - 'effect.') % (s,)) - return suppressions - - -settings.define_setting( - 'suppress_health_check', - default=(), - description="""A list of health checks to disable.""", - validator=validate_health_check_suppressions -) - -settings.define_setting( - 'deadline', - default=not_set, - description=u""" -If set, a time in milliseconds (which may be a float to express -smaller units of time) that each individual example (i.e. each time your test -function is called, not the whole decorated test) within a test is not -allowed to exceed. Tests which take longer than that may be converted into -errors (but will not necessarily be if close to the deadline, to allow some -variability in test run time). - -Set this to None to disable this behaviour entirely. - -In future this will default to 200. For now, a -HypothesisDeprecationWarning will be emitted if you exceed that default -deadline and have not explicitly set a deadline yourself. -""" -) - -settings.define_setting( - 'use_coverage', - default=True, - description=""" -Whether to use coverage information to improve Hypothesis's ability to find -bugs. - -You should generally leave this turned on unless your code performs -poorly when run under coverage. If you turn it off, please file a bug report -or add a comment to an existing one about the problem that prompted you to do -so. -""" -) - - -class PrintSettings(Enum): - """Flags to determine whether or not to print a detailed example blob to - use with :func:`~hypothesis.reproduce_failure` for failing test cases.""" - - NEVER = 0 - """Never print a blob.""" - - INFER = 1 - """Make an educated guess as to whether it would be appropriate to print - the blob. - - The current rules are that this will print if both: - - 1. The output from Hypothesis appears to be unsuitable for use with - :func:`~hypothesis.example`. - 2. The output is not too long.""" - - ALWAYS = 2 - """Always print a blob on failure.""" - - -settings.define_setting( - 'print_blob', - default=PrintSettings.INFER, - description=""" -Determines whether to print blobs after tests that can be used to reproduce -failures. - -See :ref:`the documentation on @reproduce_failure ` for -more details of this behaviour. -""" -) - -settings.lock_further_definitions() - -settings.register_profile('default', settings()) -settings.load_profile('default') -assert settings.default is not None - - -def note_deprecation(message, s=None): - if s is None: - s = settings.default - assert s is not None - verbosity = s.verbosity - warning = HypothesisDeprecationWarning(message) - if verbosity > Verbosity.quiet: - warnings.warn(warning, stacklevel=3) diff -Nru python-hypothesis-3.44.1/src/hypothesis/stateful.py python-hypothesis-3.71.11/src/hypothesis/stateful.py --- python-hypothesis-3.44.1/src/hypothesis/stateful.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/stateful.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,603 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -"""This module provides support for a stateful style of testing, where tests -attempt to find a sequence of operations that cause a breakage rather than just -a single value. - -Notably, the set of steps available at any point may depend on the -execution to date. - -""" - - -from __future__ import division, print_function, absolute_import - -import inspect -import traceback -from unittest import TestCase - -import attr - -import hypothesis.internal.conjecture.utils as cu -from hypothesis.core import find -from hypothesis.errors import Flaky, NoSuchExample, InvalidDefinition, \ - HypothesisException -from hypothesis.control import BuildContext -from hypothesis._settings import settings as Settings -from hypothesis._settings import Verbosity -from hypothesis.reporting import report, verbose_report, current_verbosity -from hypothesis.strategies import just, lists, builds, one_of, runner, \ - integers -from hypothesis.vendor.pretty import CUnicodeIO, RepresentationPrinter -from hypothesis.internal.reflection import proxies, nicerepr -from hypothesis.internal.conjecture.data import StopTest -from hypothesis.internal.conjecture.utils import integer_range -from hypothesis.searchstrategy.strategies import SearchStrategy -from hypothesis.searchstrategy.collections import TupleStrategy, \ - FixedKeysDictStrategy - - -class TestCaseProperty(object): # pragma: no cover - - def __get__(self, obj, typ=None): - if obj is not None: - typ = type(obj) - return typ._to_test_case() - - def __set__(self, obj, value): - raise AttributeError(u'Cannot set TestCase') - - def __delete__(self, obj): - raise AttributeError(u'Cannot delete TestCase') - - -def find_breaking_runner(state_machine_factory, settings=None): - def is_breaking_run(runner): - try: - runner.run(state_machine_factory()) - return False - except HypothesisException: - raise - except Exception: - verbose_report(traceback.format_exc) - return True - if settings is None: - try: - settings = state_machine_factory.TestCase.settings - except AttributeError: - settings = Settings.default - - search_strategy = StateMachineSearchStrategy(settings) - - return find( - search_strategy, - is_breaking_run, - settings=settings, - database_key=state_machine_factory.__name__.encode('utf-8') - ) - - -def run_state_machine_as_test(state_machine_factory, settings=None): - """Run a state machine definition as a test, either silently doing nothing - or printing a minimal breaking program and raising an exception. - - state_machine_factory is anything which returns an instance of - GenericStateMachine when called with no arguments - it can be a class or a - function. settings will be used to control the execution of the test. - - """ - try: - breaker = find_breaking_runner(state_machine_factory, settings) - except NoSuchExample: - return - try: - with BuildContext(None, is_final=True): - breaker.run(state_machine_factory(), print_steps=True) - except StopTest: - pass - raise Flaky( - u'Run failed initially but succeeded on a second try' - ) - - -class GenericStateMachine(object): - - """A GenericStateMachine is the basic entry point into Hypothesis's - approach to stateful testing. - - The intent is for it to be subclassed to provide state machine descriptions - - The way this is used is that Hypothesis will repeatedly execute something - that looks something like:: - - x = MyStatemachineSubclass() - x.check_invariants() - try: - for _ in range(n_steps): - x.execute_step(x.steps().example()) - x.check_invariants() - finally: - x.teardown() - - And if this ever produces an error it will shrink it down to a small - sequence of example choices demonstrating that. - - """ - - def steps(self): - """Return a SearchStrategy instance the defines the available next - steps.""" - raise NotImplementedError(u'%r.steps()' % (self,)) - - def execute_step(self, step): - """Execute a step that has been previously drawn from self.steps()""" - raise NotImplementedError(u'%r.execute_step()' % (self,)) - - def print_step(self, step): - """Print a step to the current reporter. - - This is called right before a step is executed. - - """ - self.step_count = getattr(self, u'step_count', 0) + 1 - report(u'Step #%d: %s' % (self.step_count, nicerepr(step))) - - def teardown(self): - """Called after a run has finished executing to clean up any necessary - state. - - Does nothing by default - - """ - pass - - def check_invariants(self): - """Called after initializing and after executing each step.""" - pass - - _test_case_cache = {} - - TestCase = TestCaseProperty() - - @classmethod - def _to_test_case(state_machine_class): - try: - return state_machine_class._test_case_cache[state_machine_class] - except KeyError: - pass - - class StateMachineTestCase(TestCase): - settings = Settings( - min_satisfying_examples=1 - ) - - # We define this outside of the class and assign it because you can't - # assign attributes to instance method values in Python 2 - def runTest(self): - run_state_machine_as_test(state_machine_class) - - runTest.is_hypothesis_test = True - StateMachineTestCase.runTest = runTest - base_name = state_machine_class.__name__ - StateMachineTestCase.__name__ = str( - base_name + u'.TestCase' - ) - StateMachineTestCase.__qualname__ = str( - getattr(state_machine_class, u'__qualname__', base_name) + - u'.TestCase' - ) - state_machine_class._test_case_cache[state_machine_class] = ( - StateMachineTestCase - ) - return StateMachineTestCase - - -GenericStateMachine.find_breaking_runner = classmethod(find_breaking_runner) - - -class StateMachineRunner(object): - - """A StateMachineRunner is a description of how to run a state machine. - - It contains values that it will use to shape the examples. - - """ - - def __init__(self, data, n_steps): - self.data = data - self.data.is_find = False - self.n_steps = n_steps - - def run(self, state_machine, print_steps=None): - if print_steps is None: - print_steps = current_verbosity() >= Verbosity.debug - self.data.hypothesis_runner = state_machine - - stopping_value = 1 - 1.0 / (1 + self.n_steps * 0.5) - try: - state_machine.check_invariants() - - steps = 0 - while True: - if steps >= self.n_steps: - stopping_value = 0 - self.data.start_example() - if not cu.biased_coin(self.data, stopping_value): - self.data.stop_example() - break - assert steps < self.n_steps - value = self.data.draw(state_machine.steps()) - steps += 1 - if print_steps: - state_machine.print_step(value) - state_machine.execute_step(value) - self.data.stop_example() - state_machine.check_invariants() - finally: - state_machine.teardown() - - -class StateMachineSearchStrategy(SearchStrategy): - - def __init__(self, settings=None): - self.program_size = (settings or Settings.default).stateful_step_count - - def do_draw(self, data): - return StateMachineRunner(data, self.program_size) - - -@attr.s() -class Rule(object): - targets = attr.ib() - function = attr.ib() - arguments = attr.ib() - precondition = attr.ib() - - -self_strategy = runner() - - -class Bundle(SearchStrategy): - - def __init__(self, name): - self.name = name - - def do_draw(self, data): - machine = data.draw(self_strategy) - bundle = machine.bundle(self.name) - if not bundle: - data.mark_invalid() - reference = bundle.pop() - bundle.insert(integer_range(data, 0, len(bundle)), reference) - return machine.names_to_values[reference.name] - - -RULE_MARKER = u'hypothesis_stateful_rule' -PRECONDITION_MARKER = u'hypothesis_stateful_precondition' -INVARIANT_MARKER = u'hypothesis_stateful_invariant' - - -def rule(targets=(), target=None, **kwargs): - """Decorator for RuleBasedStateMachine. Any name present in target or - targets will define where the end result of this function should go. If - both are empty then the end result will be discarded. - - targets may either be a Bundle or the name of a Bundle. - - kwargs then define the arguments that will be passed to the function - invocation. If their value is a Bundle then values that have previously - been produced for that bundle will be provided, if they are anything else - it will be turned into a strategy and values from that will be provided. - - """ - if target is not None: - targets += (target,) - - converted_targets = [] - for t in targets: - while isinstance(t, Bundle): - t = t.name - converted_targets.append(t) - - def accept(f): - existing_rule = getattr(f, RULE_MARKER, None) - if existing_rule is not None: - raise InvalidDefinition( - 'A function cannot be used for two distinct rules. ', - Settings.default, - ) - precondition = getattr(f, PRECONDITION_MARKER, None) - rule = Rule(targets=tuple(converted_targets), arguments=kwargs, - function=f, precondition=precondition) - - @proxies(f) - def rule_wrapper(*args, **kwargs): - return f(*args, **kwargs) - - setattr(rule_wrapper, RULE_MARKER, rule) - return rule_wrapper - return accept - - -@attr.s() -class VarReference(object): - name = attr.ib() - - -def precondition(precond): - """Decorator to apply a precondition for rules in a RuleBasedStateMachine. - Specifies a precondition for a rule to be considered as a valid step in the - state machine. The given function will be called with the instance of - RuleBasedStateMachine and should return True or False. Usually it will need - to look at attributes on that instance. - - For example:: - - class MyTestMachine(RuleBasedStateMachine): - state = 1 - - @precondition(lambda self: self.state != 0) - @rule(numerator=integers()) - def divide_with(self, numerator): - self.state = numerator / self.state - - This is better than using assume in your rule since more valid rules - should be able to be run. - - """ - def decorator(f): - @proxies(f) - def precondition_wrapper(*args, **kwargs): - return f(*args, **kwargs) - - rule = getattr(f, RULE_MARKER, None) - if rule is None: - setattr(precondition_wrapper, PRECONDITION_MARKER, precond) - else: - new_rule = Rule(targets=rule.targets, arguments=rule.arguments, - function=rule.function, precondition=precond) - setattr(precondition_wrapper, RULE_MARKER, new_rule) - - invariant = getattr(f, INVARIANT_MARKER, None) - if invariant is not None: - new_invariant = Invariant(function=invariant.function, - precondition=precond) - setattr(precondition_wrapper, INVARIANT_MARKER, new_invariant) - - return precondition_wrapper - return decorator - - -@attr.s() -class Invariant(object): - function = attr.ib() - precondition = attr.ib() - - -def invariant(): - """Decorator to apply an invariant for rules in a RuleBasedStateMachine. - The decorated function will be run after every rule and can raise an - exception to indicate failed invariants. - - For example:: - - class MyTestMachine(RuleBasedStateMachine): - state = 1 - - @invariant() - def is_nonzero(self): - assert self.state != 0 - - """ - def accept(f): - existing_invariant = getattr(f, INVARIANT_MARKER, None) - if existing_invariant is not None: - raise InvalidDefinition( - 'A function cannot be used for two distinct invariants.', - Settings.default, - ) - precondition = getattr(f, PRECONDITION_MARKER, None) - rule = Invariant(function=f, precondition=precondition) - - @proxies(f) - def invariant_wrapper(*args, **kwargs): - return f(*args, **kwargs) - - setattr(invariant_wrapper, INVARIANT_MARKER, rule) - return invariant_wrapper - return accept - - -@attr.s() -class ShuffleBundle(object): - bundle = attr.ib() - swaps = attr.ib() - - -class RuleBasedStateMachine(GenericStateMachine): - - """A RuleBasedStateMachine gives you a more structured way to define state - machines. - - The idea is that a state machine carries a bunch of types of data - divided into Bundles, and has a set of rules which may read data - from bundles (or just from normal strategies) and push data onto - bundles. At any given point a random applicable rule will be - executed. - - """ - _rules_per_class = {} - _invariants_per_class = {} - _base_rules_per_class = {} - - def __init__(self): - if not self.rules(): - raise InvalidDefinition(u'Type %s defines no rules' % ( - type(self).__name__, - )) - self.bundles = {} - self.name_counter = 1 - self.names_to_values = {} - self.__stream = CUnicodeIO() - self.__printer = RepresentationPrinter(self.__stream) - - def __pretty(self, value): - self.__stream.seek(0) - self.__stream.truncate(0) - self.__printer.output_width = 0 - self.__printer.buffer_width = 0 - self.__printer.buffer.clear() - self.__printer.pretty(value) - self.__printer.flush() - return self.__stream.getvalue() - - def __repr__(self): - return u'%s(%s)' % ( - type(self).__name__, - nicerepr(self.bundles), - ) - - def upcoming_name(self): - return u'v%d' % (self.name_counter,) - - def new_name(self): - result = self.upcoming_name() - self.name_counter += 1 - return result - - def bundle(self, name): - return self.bundles.setdefault(name, []) - - @classmethod - def rules(cls): - try: - return cls._rules_per_class[cls] - except KeyError: - pass - - for k, v in inspect.getmembers(cls): - r = getattr(v, RULE_MARKER, None) - if r is not None: - cls.define_rule( - r.targets, r.function, r.arguments, r.precondition, - ) - cls._rules_per_class[cls] = cls._base_rules_per_class.pop(cls, []) - return cls._rules_per_class[cls] - - @classmethod - def invariants(cls): - try: - return cls._invariants_per_class[cls] - except KeyError: - pass - - target = [] - for k, v in inspect.getmembers(cls): - i = getattr(v, INVARIANT_MARKER, None) - if i is not None: - target.append(i) - cls._invariants_per_class[cls] = target - return cls._invariants_per_class[cls] - - @classmethod - def define_rule(cls, targets, function, arguments, precondition=None): - converted_arguments = {} - for k, v in arguments.items(): - converted_arguments[k] = v - if cls in cls._rules_per_class: - target = cls._rules_per_class[cls] - else: - target = cls._base_rules_per_class.setdefault(cls, []) - - return target.append( - Rule( - targets, function, converted_arguments, precondition, - ) - ) - - def steps(self): - strategies = [] - for rule in self.rules(): - converted_arguments = {} - valid = True - if rule.precondition and not rule.precondition(self): - continue - for k, v in sorted(rule.arguments.items()): - if isinstance(v, Bundle): - bundle = self.bundle(v.name) - if not bundle: - valid = False - break - converted_arguments[k] = v - if valid: - strategies.append(TupleStrategy(( - just(rule), - FixedKeysDictStrategy(converted_arguments) - ), tuple)) - if not strategies: - raise InvalidDefinition( - u'No progress can be made from state %r' % (self,) - ) - - for name, bundle in self.bundles.items(): - if len(bundle) > 1: - strategies.append( - builds( - ShuffleBundle, just(name), - lists(integers(0, len(bundle) - 1)))) - - return one_of(strategies) - - def print_step(self, step): - if isinstance(step, ShuffleBundle): - return - rule, data = step - data_repr = {} - for k, v in data.items(): - data_repr[k] = self.__pretty(v) - self.step_count = getattr(self, u'step_count', 0) + 1 - report(u'Step #%d: %s%s(%s)' % ( - self.step_count, - u'%s = ' % (self.upcoming_name(),) if rule.targets else u'', - rule.function.__name__, - u', '.join(u'%s=%s' % kv for kv in data_repr.items()) - )) - - def execute_step(self, step): - if isinstance(step, ShuffleBundle): - bundle = self.bundle(step.bundle) - for i in step.swaps: - bundle.insert(i, bundle.pop()) - return - rule, data = step - data = dict(data) - result = rule.function(self, **data) - if rule.targets: - name = self.new_name() - self.names_to_values[name] = result - self.__printer.singleton_pprinters.setdefault( - id(result), lambda obj, p, cycle: p.text(name), - ) - for target in rule.targets: - self.bundle(target).append(VarReference(name)) - - def check_invariants(self): - for invar in self.invariants(): - if invar.precondition and not invar.precondition(self): - continue - invar.function(self) diff -Nru python-hypothesis-3.44.1/src/hypothesis/statistics.py python-hypothesis-3.71.11/src/hypothesis/statistics.py --- python-hypothesis-3.44.1/src/hypothesis/statistics.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/statistics.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,96 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import math - -from hypothesis.utils.dynamicvariables import DynamicVariable -from hypothesis.internal.conjecture.data import Status -from hypothesis.internal.conjecture.engine import ExitReason - -collector = DynamicVariable(None) - - -class Statistics(object): - - def __init__(self, engine): - self.passing_examples = len( - engine.status_runtimes.get(Status.VALID, ())) - self.invalid_examples = len( - engine.status_runtimes.get(Status.INVALID, []) + - engine.status_runtimes.get(Status.OVERRUN, []) - ) - self.failing_examples = len(engine.status_runtimes.get( - Status.INTERESTING, ())) - - runtimes = sorted( - engine.status_runtimes.get(Status.VALID, []) + - engine.status_runtimes.get(Status.INVALID, []) + - engine.status_runtimes.get(Status.INTERESTING, []) - ) - - self.has_runs = bool(runtimes) - if not self.has_runs: - return - - n = max(0, len(runtimes) - 1) - lower = int(runtimes[int(math.floor(n * 0.05))] * 1000) - upper = int(runtimes[int(math.ceil(n * 0.95))] * 1000) - if upper == 0: - self.runtimes = '< 1ms' - elif lower == upper: - self.runtimes = '~ %dms' % (lower,) - else: - self.runtimes = '%d-%d ms' % (lower, upper) - - if engine.exit_reason == ExitReason.finished: - self.exit_reason = 'nothing left to do' - elif engine.exit_reason == ExitReason.flaky: - self.exit_reason = 'test was flaky' - else: - self.exit_reason = ( - 'settings.%s=%r' % ( - engine.exit_reason.name, - getattr(engine.settings, engine.exit_reason.name) - ) - ) - - self.events = [ - '%.2f%%, %s' % ( - c / engine.call_count * 100, e - ) for e, c in sorted( - engine.event_call_counts.items(), key=lambda x: -x[1]) - ] - - total_runtime = math.fsum(engine.all_runtimes) - total_drawtime = math.fsum(engine.all_drawtimes) - - if total_drawtime == 0.0: - self.draw_time_percentage = '~ 0%' - else: - draw_time_percentage = 100.0 * min( - 1, total_drawtime / total_runtime) - - self.draw_time_percentage = '~ %d%%' % ( - round(draw_time_percentage),) - - -def note_engine_for_statistics(engine): - callback = collector.value - if callback is not None: - callback(Statistics(engine)) diff -Nru python-hypothesis-3.44.1/src/hypothesis/strategies.py python-hypothesis-3.71.11/src/hypothesis/strategies.py --- python-hypothesis-3.44.1/src/hypothesis/strategies.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/strategies.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,1822 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import enum -import math -import datetime as dt -import operator -from decimal import Context, Decimal -from inspect import isclass, isfunction -from fractions import Fraction -from functools import reduce - -from hypothesis.errors import InvalidArgument, ResolutionFailed -from hypothesis.control import assume -from hypothesis._settings import note_deprecation -from hypothesis.internal.cache import LRUReusedCache -from hypothesis.searchstrategy import SearchStrategy -from hypothesis.internal.compat import gcd, ceil, floor, hrange, \ - text_type, get_type_hints, getfullargspec, implements_iterator -from hypothesis.internal.floats import is_negative, float_to_int, \ - int_to_float, count_between_floats -from hypothesis.internal.renaming import renamed_arguments -from hypothesis.utils.conventions import infer, not_set -from hypothesis.internal.reflection import proxies, required_args -from hypothesis.internal.validation import check_type, try_convert, \ - check_strategy, check_valid_bound, check_valid_sizes, \ - check_valid_integer, check_valid_interval - -__all__ = [ - 'nothing', - 'just', 'one_of', - 'none', - 'choices', 'streaming', - 'booleans', 'integers', 'floats', 'complex_numbers', 'fractions', - 'decimals', - 'characters', 'text', 'from_regex', 'binary', 'uuids', - 'tuples', 'lists', 'sets', 'frozensets', 'iterables', - 'dictionaries', 'fixed_dictionaries', - 'sampled_from', 'permutations', - 'datetimes', 'dates', 'times', 'timedeltas', - 'builds', - 'randoms', 'random_module', - 'recursive', 'composite', - 'shared', 'runner', 'data', - 'deferred', - 'from_type', 'register_type_strategy', -] - -_strategies = set() - - -class FloatKey(object): - - def __init__(self, f): - self.value = float_to_int(f) - - def __eq__(self, other): - return isinstance(other, FloatKey) and ( - other.value == self.value - ) - - def __ne__(self, other): - return not self.__eq__(other) - - def __hash__(self): - return hash(self.value) - - -def convert_value(v): - if isinstance(v, float): - return FloatKey(v) - return (type(v), v) - - -STRATEGY_CACHE = LRUReusedCache(1024) - - -def cacheable(fn): - @proxies(fn) - def cached_strategy(*args, **kwargs): - kwargs_cache_key = set() - try: - for k, v in kwargs.items(): - kwargs_cache_key.add((k, convert_value(v))) - except TypeError: - return fn(*args, **kwargs) - cache_key = ( - fn, - tuple(map(convert_value, args)), frozenset(kwargs_cache_key)) - try: - return STRATEGY_CACHE[cache_key] - except TypeError: - return fn(*args, **kwargs) - except KeyError: - result = fn(*args, **kwargs) - if not isinstance(result, SearchStrategy) or result.is_cacheable: - STRATEGY_CACHE[cache_key] = result - return result - cached_strategy.__clear_cache = STRATEGY_CACHE.clear - return cached_strategy - - -def base_defines_strategy(force_reusable): - def decorator(strategy_definition): - from hypothesis.searchstrategy.lazy import LazyStrategy - _strategies.add(strategy_definition.__name__) - - @proxies(strategy_definition) - def accept(*args, **kwargs): - result = LazyStrategy(strategy_definition, args, kwargs) - if force_reusable: - result.force_has_reusable_values = True - assert result.has_reusable_values - return result - return accept - return decorator - - -defines_strategy = base_defines_strategy(False) -defines_strategy_with_reusable_values = base_defines_strategy(True) - - -class Nothing(SearchStrategy): - def calc_is_empty(self, recur): - return True - - def do_draw(self, data): - # This method should never be called because draw() will mark the - # data as invalid immediately because is_empty is True. - assert False # pragma: no cover - - def calc_has_reusable_values(self, recur): - return True - - def __repr__(self): - return 'nothing()' - - def map(self, f): - return self - - def filter(self, f): - return self - - def flatmap(self, f): - return self - - -NOTHING = Nothing() - - -@cacheable -def nothing(): - """This strategy never successfully draws a value and will always reject on - an attempt to draw. - - Examples from this strategy do not shrink (because there are none). - - """ - return NOTHING - - -def just(value): - """Return a strategy which only generates ``value``. - - Note: ``value`` is not copied. Be wary of using mutable values. - - If ``value`` is the result of a callable, you can use - :func:`builds(callable) ` instead - of ``just(callable())`` to get a fresh value each time. - - Examples from this strategy do not shrink (because there is only one). - - """ - from hypothesis.searchstrategy.misc import JustStrategy - - return JustStrategy(value) - - -@defines_strategy -def none(): - """Return a strategy which only generates None. - - Examples from this strategy do not shrink (because there is only - one). - - """ - return just(None) - - -def one_of(*args): - """Return a strategy which generates values from any of the argument - strategies. - - This may be called with one iterable argument instead of multiple - strategy arguments. In which case one_of(x) and one_of(\*x) are - equivalent. - - Examples from this strategy will generally shrink to ones that come from - strategies earlier in the list, then shrink according to behaviour of the - strategy that produced them. In order to get good shrinking behaviour, - try to put simpler strategies first. e.g. ``one_of(none(), text())`` is - better than ``one_of(text(), none())``. - - This is especially important when using recursive strategies. e.g. - ``x = st.deferred(lambda: st.none() | st.tuples(x, x))`` will shrink well, - but ``x = st.deferred(lambda: st.tuples(x, x) | st.none())`` will shrink - very badly indeed. - - """ - if len(args) == 1 and not isinstance(args[0], SearchStrategy): - try: - args = tuple(args[0]) - except TypeError: - pass - from hypothesis.searchstrategy.strategies import OneOfStrategy - return OneOfStrategy(args) - - -@cacheable -@defines_strategy_with_reusable_values -def integers(min_value=None, max_value=None): - """Returns a strategy which generates integers (in Python 2 these may be - ints or longs). - - If min_value is not None then all values will be >= min_value. If - max_value is not None then all values will be <= max_value - - Examples from this strategy will shrink towards being positive (e.g. 1000 - is considered simpler than -1) and then towards zero. - - """ - - check_valid_bound(min_value, 'min_value') - check_valid_bound(max_value, 'max_value') - check_valid_interval(min_value, max_value, 'min_value', 'max_value') - - from hypothesis.searchstrategy.numbers import IntegersFromStrategy, \ - BoundedIntStrategy, WideRangeIntStrategy - - min_int_value = None if min_value is None else ceil(min_value) - max_int_value = None if max_value is None else floor(max_value) - - if min_int_value is not None and max_int_value is not None and \ - min_int_value > max_int_value: - raise InvalidArgument('No integers between min_value=%r and ' - 'max_value=%r' % (min_value, max_value)) - - if min_int_value is None: - if max_int_value is None: - return ( - WideRangeIntStrategy() - ) - else: - return IntegersFromStrategy(0).map(lambda x: max_int_value - x) - else: - if max_int_value is None: - return IntegersFromStrategy(min_int_value) - else: - assert min_int_value <= max_int_value - if min_int_value == max_int_value: - return just(min_int_value) - elif min_int_value >= 0: - return BoundedIntStrategy(min_int_value, max_int_value) - elif max_int_value <= 0: - return BoundedIntStrategy( - -max_int_value, -min_int_value - ).map(lambda t: -t) - else: - return integers(min_value=0, max_value=max_int_value) | \ - integers(min_value=min_int_value, max_value=0) - - -@cacheable -@defines_strategy -def booleans(): - """Returns a strategy which generates instances of bool. - - Examples from this strategy will shrink towards False (i.e. - shrinking will try to replace True with False where possible). - - """ - from hypothesis.searchstrategy.misc import BoolStrategy - return BoolStrategy() - - -@cacheable -@defines_strategy_with_reusable_values -def floats( - min_value=None, max_value=None, allow_nan=None, allow_infinity=None -): - """Returns a strategy which generates floats. - - - If min_value is not None, all values will be >= min_value. - - If max_value is not None, all values will be <= max_value. - - If min_value or max_value is not None, it is an error to enable - allow_nan. - - If both min_value and max_value are not None, it is an error to enable - allow_infinity. - - Where not explicitly ruled out by the bounds, all of infinity, -infinity - and NaN are possible values generated by this strategy. - - Examples from this strategy have a complicated and hard to explain - shrinking behaviour, but it tries to improve "human readability". Finite - numbers will be preferred to infinity and infinity will be preferred to - NaN. - - """ - - if allow_nan is None: - allow_nan = bool(min_value is None and max_value is None) - elif allow_nan: - if min_value is not None or max_value is not None: - raise InvalidArgument( - 'Cannot have allow_nan=%r, with min_value or max_value' % ( - allow_nan - )) - - min_value = try_convert(float, min_value, 'min_value') - max_value = try_convert(float, max_value, 'max_value') - - check_valid_bound(min_value, 'min_value') - check_valid_bound(max_value, 'max_value') - check_valid_interval(min_value, max_value, 'min_value', 'max_value') - if min_value == float(u'-inf'): - min_value = None - if max_value == float(u'inf'): - max_value = None - - if allow_infinity is None: - allow_infinity = bool(min_value is None or max_value is None) - elif allow_infinity: - if min_value is not None and max_value is not None: - raise InvalidArgument( - 'Cannot have allow_infinity=%r, with both min_value and ' - 'max_value' % ( - allow_infinity - )) - - from hypothesis.searchstrategy.numbers import FloatStrategy, \ - FixedBoundedFloatStrategy - if min_value is None and max_value is None: - return FloatStrategy( - allow_infinity=allow_infinity, allow_nan=allow_nan, - ) - elif min_value is not None and max_value is not None: - if min_value == max_value: - return just(min_value) - elif is_negative(min_value): - if is_negative(max_value): - return floats(min_value=-max_value, max_value=-min_value).map( - operator.neg - ) - else: - return floats(min_value=0.0, max_value=max_value) | floats( - min_value=0.0, max_value=-min_value).map(operator.neg) - elif count_between_floats(min_value, max_value) > 1000: - return FixedBoundedFloatStrategy( - lower_bound=min_value, upper_bound=max_value - ) - else: - ub_int = float_to_int(max_value) - lb_int = float_to_int(min_value) - assert lb_int <= ub_int - return integers(min_value=lb_int, max_value=ub_int).map( - int_to_float - ) - elif min_value is not None: - if min_value < 0: - result = floats( - min_value=0.0 - ) | floats(min_value=min_value, max_value=-0.0) - else: - result = ( - floats(allow_infinity=allow_infinity, allow_nan=False).map( - lambda x: assume(not math.isnan(x)) and min_value + abs(x) - ) - ) - if min_value == 0 and not is_negative(min_value): - result = result.filter(lambda x: math.copysign(1.0, x) == 1) - return result - else: - assert max_value is not None - if max_value > 0: - result = floats( - min_value=0.0, - max_value=max_value, - ) | floats(max_value=-0.0) - else: - result = ( - floats(allow_infinity=allow_infinity, allow_nan=False).map( - lambda x: assume(not math.isnan(x)) and max_value - abs(x) - ) - ) - if max_value == 0 and is_negative(max_value): - result = result.filter(is_negative) - return result - - -@cacheable -@defines_strategy_with_reusable_values -def complex_numbers(): - """Returns a strategy that generates complex numbers. - - Examples from this strategy shrink by shrinking their component real - and imaginary parts. - - """ - from hypothesis.searchstrategy.numbers import ComplexStrategy - return ComplexStrategy( - tuples(floats(), floats()) - ) - - -@cacheable -@defines_strategy -def tuples(*args): - """Return a strategy which generates a tuple of the same length as args by - generating the value at index i from args[i]. - - e.g. tuples(integers(), integers()) would generate a tuple of length - two with both values an integer. - - Examples from this strategy shrink by shrinking their component parts. - - """ - for arg in args: - check_strategy(arg) - - from hypothesis.searchstrategy.collections import TupleStrategy - return TupleStrategy(args, tuple) - - -@defines_strategy -def sampled_from(elements): - """Returns a strategy which generates any value present in ``elements``. - - Note that as with :func:`~hypotheses.strategies.just`, values will not be - copied and thus you should be careful of using mutable data. - - ``sampled_from`` supports ordered collections, as well as - :class:`~python:enum.Enum` objects. :class:`~python:enum.Flag` objects - may also generate any combination of their members. - - Examples from this strategy shrink by replacing them with values earlier in - the list. So e.g. sampled_from((10, 1)) will shrink by trying to replace - 1 values with 10, and sampled_from((1, 10)) will shrink by trying to - replace 10 values with 1. - - """ - from hypothesis.searchstrategy.misc import SampledFromStrategy - from hypothesis.internal.conjecture.utils import check_sample - values = check_sample(elements) - if not values: - return nothing() - if len(values) == 1: - return just(values[0]) - if hasattr(enum, 'Flag') and isclass(elements) and \ - issubclass(elements, enum.Flag): - # Combinations of enum.Flag members are also members. We generate - # these dynamically, because static allocation takes O(2^n) memory. - return sets(sampled_from(values), min_size=1).map( - lambda s: reduce(operator.or_, s)) - return SampledFromStrategy(values) - - -_AVERAGE_LIST_LENGTH = 5.0 - - -@cacheable -@defines_strategy -def lists( - elements=None, min_size=None, average_size=None, max_size=None, - unique_by=None, unique=False, -): - """Returns a list containing values drawn from elements with length in the - interval [min_size, max_size] (no bounds in that direction if these are - None). If max_size is 0 then elements may be None and only the empty list - will be drawn. - - average_size may be used as a size hint to roughly control the size - of the list but it may not be the actual average of sizes you get, due - to a variety of factors. - - If unique is True (or something that evaluates to True), we compare direct - object equality, as if unique_by was `lambda x: x`. This comparison only - works for hashable types. - - if unique_by is not None it must be a function returning a hashable type - when given a value drawn from elements. The resulting list will satisfy the - condition that for i != j, unique_by(result[i]) != unique_by(result[j]). - - Examples from this strategy shrink by trying to remove elements from the - list, and by shrinking each individual element of the list. - - """ - check_valid_sizes(min_size, average_size, max_size) - if elements is None or (max_size is not None and max_size <= 0): - if max_size is None or max_size > 0: - raise InvalidArgument( - u'Cannot create non-empty lists without an element type' - ) - else: - return builds(list) - check_strategy(elements) - if unique: - if unique_by is not None: - raise InvalidArgument(( - 'cannot specify both unique and unique_by (you probably only ' - 'want to set unique_by)' - )) - else: - def unique_by(x): - return x - - if unique_by is not None: - from hypothesis.searchstrategy.collections import UniqueListStrategy - min_size = min_size or 0 - max_size = max_size or float(u'inf') - if average_size is None: - if max_size < float(u'inf'): - if max_size <= 5: - average_size = min_size + 0.75 * (max_size - min_size) - else: - average_size = (max_size + min_size) / 2 - else: - average_size = max( - _AVERAGE_LIST_LENGTH, - min_size * 2 - ) - result = UniqueListStrategy( - elements=elements, - average_size=average_size, - max_size=max_size, - min_size=min_size, - key=unique_by - ) - else: - from hypothesis.searchstrategy.collections import ListStrategy - if min_size is None: - min_size = 0 - if average_size is None: - if max_size is None: - average_size = _AVERAGE_LIST_LENGTH - else: - average_size = (min_size + max_size) * 0.5 - - result = ListStrategy( - (elements,), average_length=average_size, - min_size=min_size, max_size=max_size, - ) - return result - - -@cacheable -@defines_strategy -def sets(elements=None, min_size=None, average_size=None, max_size=None): - """This has the same behaviour as lists, but returns sets instead. - - Note that Hypothesis cannot tell if values are drawn from elements - are hashable until running the test, so you can define a strategy - for sets of an unhashable type but it will fail at test time. - - Examples from this strategy shrink by trying to remove elements from the - set, and by shrinking each individual element of the set. - - """ - return lists( - elements=elements, min_size=min_size, average_size=average_size, - max_size=max_size, unique=True - ).map(set) - - -@cacheable -@defines_strategy -def frozensets(elements=None, min_size=None, average_size=None, max_size=None): - """This is identical to the sets function but instead returns - frozensets.""" - return lists( - elements=elements, min_size=min_size, average_size=average_size, - max_size=max_size, unique=True - ).map(frozenset) - - -@defines_strategy -def iterables(elements=None, min_size=None, average_size=None, max_size=None, - unique_by=None, unique=False): - """This has the same behaviour as lists, but returns iterables instead. - - Some iterables cannot be indexed (e.g. sets) and some do not have a - fixed length (e.g. generators). This strategy produces iterators, - which cannot be indexed and do not have a fixed length. This ensures - that you do not accidentally depend on sequence behaviour. - - """ - @implements_iterator - class PrettyIter(object): - def __init__(self, values): - self._values = values - self._iter = iter(self._values) - - def __iter__(self): - return self._iter - - def __next__(self): - return next(self._iter) - - def __repr__(self): - return 'iter({!r})'.format(self._values) - - return lists( - elements=elements, min_size=min_size, average_size=average_size, - max_size=max_size, unique_by=unique_by, unique=unique - ).map(PrettyIter) - - -@defines_strategy -def fixed_dictionaries(mapping): - """Generates a dictionary of the same type as mapping with a fixed set of - keys mapping to strategies. mapping must be a dict subclass. - - Generated values have all keys present in mapping, with the - corresponding values drawn from mapping[key]. If mapping is an - instance of OrderedDict the keys will also be in the same order, - otherwise the order is arbitrary. - - Examples from this strategy shrink by shrinking each individual value in - the generated dictionary. - - """ - from hypothesis.searchstrategy.collections import FixedKeysDictStrategy - check_type(dict, mapping, 'mapping') - for v in mapping.values(): - check_strategy(v) - return FixedKeysDictStrategy(mapping) - - -@cacheable -@defines_strategy -def dictionaries( - keys, values, dict_class=dict, - min_size=None, average_size=None, max_size=None -): - """Generates dictionaries of type dict_class with keys drawn from the keys - argument and values drawn from the values argument. - - The size parameters have the same interpretation as for lists. - - Examples from this strategy shrink by trying to remove keys from the - generated dictionary, and by shrinking each generated key and value. - - """ - check_valid_sizes(min_size, average_size, max_size) - if max_size == 0: - return fixed_dictionaries(dict_class()) - check_strategy(keys) - check_strategy(values) - - return lists( - tuples(keys, values), - min_size=min_size, average_size=average_size, max_size=max_size, - unique_by=lambda x: x[0] - ).map(dict_class) - - -@defines_strategy -def streaming(elements): - """Generates an infinite stream of values where each value is drawn from - elements. - - The result is iterable (the iterator will never terminate) and - indexable. - - Examples from this strategy shrink by trying to shrink each value drawn. - - .. deprecated:: 3.15.0 - Use :func:`data() ` instead. - - """ - note_deprecation( - 'streaming() has been deprecated. Use the data() strategy instead and ' - 'replace stream iteration with data.draw() calls.' - ) - - check_strategy(elements) - - from hypothesis.searchstrategy.streams import StreamStrategy - return StreamStrategy(elements) - - -@cacheable -@defines_strategy_with_reusable_values -def characters(whitelist_categories=None, blacklist_categories=None, - blacklist_characters=None, min_codepoint=None, - max_codepoint=None, whitelist_characters=None): - """Generates unicode text type (unicode on python 2, str on python 3) - characters following specified filtering rules. - - When no filtering rules are specifed, any character can be produced. - - If ``min_codepoint`` or ``max_codepoint`` is specifed, then only - characters having a codepoint in that range will be produced. - - If ``whitelist_categories`` is specified, then only characters from those - Unicode categories will be produced. This is a further restriction, - characters must also satisfy ``min_codepoint`` and ``max_codepoint``. - - If ``blacklist_categories`` is specified, then any character from those - categories will not be produced. This is a further restriction, - characters that match both ``whitelist_categories`` and - ``blacklist_categories`` will not be produced. - - If ``whitelist_characters`` is specified, then any additional characters - in that list will also be produced. - - If ``blacklist_characters`` is specified, then any characters in that list - will be not be produced. Any overlap between ``whitelist_characters`` and - ``blacklist_characters`` will raise an exception. - - Examples from this strategy shrink towards smaller codepoints. - - """ - if ( - min_codepoint is not None and max_codepoint is not None and - min_codepoint > max_codepoint - ): - raise InvalidArgument( - 'Cannot have min_codepoint=%d > max_codepoint=%d ' % ( - min_codepoint, max_codepoint - ) - ) - if all((whitelist_characters is not None, - min_codepoint is None, - max_codepoint is None, - whitelist_categories is None, - blacklist_categories is None, - )): - raise InvalidArgument( - 'Cannot have just whitelist_characters=%r alone, ' - 'it would have no effect. Perhaps you want sampled_from()' % ( - whitelist_characters, - ) - ) - if ( - whitelist_characters is not None and - blacklist_characters is not None and - set(blacklist_characters).intersection(set(whitelist_characters)) - ): - raise InvalidArgument( - 'Characters %r are present in both whitelist_characters=%r, and ' - 'blacklist_characters=%r' % ( - set(blacklist_characters).intersection( - set(whitelist_characters) - ), - whitelist_characters, blacklist_characters, - ) - ) - - from hypothesis.searchstrategy.strings import OneCharStringStrategy - return OneCharStringStrategy(whitelist_categories=whitelist_categories, - blacklist_categories=blacklist_categories, - blacklist_characters=blacklist_characters, - min_codepoint=min_codepoint, - max_codepoint=max_codepoint, - whitelist_characters=whitelist_characters) - - -@cacheable -@defines_strategy_with_reusable_values -def text( - alphabet=None, - min_size=None, average_size=None, max_size=None -): - """Generates values of a unicode text type (unicode on python 2, str on - python 3) with values drawn from alphabet, which should be an iterable of - length one strings or a strategy generating such. If it is None it will - default to generating the full unicode range. If it is an empty collection - this will only generate empty strings. - - min_size, max_size and average_size have the usual interpretations. - - Examples from this strategy shrink towards shorter strings, and with the - characters in the text shrinking as per the alphabet strategy. - - """ - from hypothesis.searchstrategy.strings import StringStrategy - if alphabet is None: - char_strategy = characters(blacklist_categories=('Cs',)) - elif not alphabet: - if (min_size or 0) > 0: - raise InvalidArgument( - 'Invalid min_size %r > 0 for empty alphabet' % ( - min_size, - ) - ) - return just(u'') - elif isinstance(alphabet, SearchStrategy): - char_strategy = alphabet - else: - char_strategy = sampled_from(list(map(text_type, alphabet))) - return StringStrategy(lists( - char_strategy, average_size=average_size, min_size=min_size, - max_size=max_size - )) - - -@cacheable -@defines_strategy -def from_regex(regex): - """Generates strings that contain a match for the given regex (i.e. ones - for which :func:`re.search` will return a non-None result). - - ``regex`` may be a pattern or :func:`compiled regex `. - Both byte-strings and unicode strings are supported, and will generate - examples of the same type. - - You can use regex flags such as :const:`re.IGNORECASE`, :const:`re.DOTALL` - or :const:`re.UNICODE` to control generation. Flags can be passed either - in compiled regex or inside the pattern with a ``(?iLmsux)`` group. - - Some regular expressions are only partly supported - the underlying - strategy checks local matching and relies on filtering to resolve - context-dependent expressions. Using too many of these constructs may - cause health-check errors as too many examples are filtered out. This - mainly includes (positive or negative) lookahead and lookbehind groups. - - If you want the generated string to match the whole regex you should use - boundary markers. So e.g. ``r"\\A.\\Z"`` will return a single character - string, while ``"."`` will return any string, and ``r"\\A.$"`` will return - a single character optionally followed by a ``"\\n"``. - - Examples from this strategy shrink towards shorter strings and lower - character values. - - """ - from hypothesis.searchstrategy.regex import regex_strategy - return regex_strategy(regex) - - -@cacheable -@defines_strategy_with_reusable_values -def binary( - min_size=None, average_size=None, max_size=None -): - """Generates the appropriate binary type (str in python 2, bytes in python - 3). - - min_size, average_size and max_size have the usual interpretations. - - Examples from this strategy shrink towards smaller strings and lower byte - values. - - """ - from hypothesis.searchstrategy.strings import BinaryStringStrategy, \ - FixedSizeBytes - check_valid_sizes(min_size, average_size, max_size) - if min_size == max_size is not None: - return FixedSizeBytes(min_size) - return BinaryStringStrategy( - lists( - integers(min_value=0, max_value=255), - average_size=average_size, min_size=min_size, max_size=max_size - ) - ) - - -@cacheable -@defines_strategy -def randoms(): - """Generates instances of Random (actually a Hypothesis specific - RandomWithSeed class which displays what it was initially seeded with) - - Examples from this strategy shrink to seeds closer to zero. - - """ - from hypothesis.searchstrategy.misc import RandomStrategy - return RandomStrategy(integers()) - - -class RandomSeeder(object): - - def __init__(self, seed): - self.seed = seed - - def __repr__(self): - return 'random.seed(%r)' % (self.seed,) - - -@cacheable -@defines_strategy -def random_module(): - """If your code depends on the global random module then you need to use - this. - - It will explicitly seed the random module at the start of your test - so that tests are reproducible. The value it passes you is an opaque - object whose only useful feature is that its repr displays the - random seed. It is not itself a random number generator. If you want - a random number generator you should use the randoms() strategy - which will give you one. - - Examples from these strategy shrink to seeds closer to zero. - - """ - from hypothesis.control import cleanup - import random - - class RandomModule(SearchStrategy): - def do_draw(self, data): - data.can_reproduce_example_from_repr = False - seed = data.draw(integers()) - state = random.getstate() - random.seed(seed) - cleanup(lambda: random.setstate(state)) - return RandomSeeder(seed) - - return shared(RandomModule(), 'hypothesis.strategies.random_module()') - - -@cacheable -@defines_strategy -def builds(target, *args, **kwargs): - """Generates values by drawing from ``args`` and ``kwargs`` and passing - them to ``target`` in the appropriate argument position. - - e.g. ``builds(target, integers(), flag=booleans())`` would draw an - integer ``i`` and a boolean ``b`` and call ``target(i, flag=b)``. - - If ``target`` has type annotations, they will be used to infer a strategy - for required arguments that were not passed to builds. You can also tell - builds to infer a strategy for an optional argument by passing the special - value :const:`hypothesis.infer` as a keyword argument to - builds, instead of a strategy for that argument to ``target``. - - Examples from this strategy shrink by shrinking the argument values to - the target. - - """ - if infer in args: - # Avoid an implementation nightmare juggling tuples and worse things - raise InvalidArgument('infer was passed as a positional argument to ' - 'builds(), but is only allowed as a keyword arg') - hints = get_type_hints(target.__init__ if isclass(target) else target) - for kw in [k for k, v in kwargs.items() if v is infer]: - if kw not in hints: - raise InvalidArgument( - 'passed %s=infer for %s, but %s has no type annotation' - % (kw, target.__name__, kw)) - kwargs[kw] = from_type(hints[kw]) - required = required_args(target, args, kwargs) - for ms in set(hints) & (required or set()): - kwargs[ms] = from_type(hints[ms]) - return tuples(tuples(*args), fixed_dictionaries(kwargs)).map( - lambda value: target(*value[0], **value[1]) - ) - - -def delay_error(func): - """A decorator to make exceptions lazy but success immediate. - - We want from_type to resolve to a strategy immediately if possible, - for a useful repr and interactive use, but delay errors until a - value would be drawn to localise them to a particular test. - - """ - @proxies(func) - def inner(*args, **kwargs): - try: - return func(*args, **kwargs) - except Exception as e: - error = e - - def lazy_error(): - raise error - - return builds(lazy_error) - return inner - - -@cacheable -@delay_error -def from_type(thing): - """Looks up the appropriate search strategy for the given type. - - ``from_type`` is used internally to fill in missing arguments to - :func:`~hypothesis.strategies.builds` and can be used interactively - to explore what strategies are available or to debug type resolution. - - You can use :func:`~hypothesis.strategies.register_type_strategy` to - handle your custom types, or to globally redefine certain strategies - - for example excluding NaN from floats, or use timezone-aware instead of - naive time and datetime strategies. - - The resolution logic may be changed in a future version, but currently - tries these four options: - - 1. If ``thing`` is in the default lookup mapping or user-registered lookup, - return the corresponding strategy. The default lookup covers all types - with Hypothesis strategies, including extras where possible. - 2. If ``thing`` is from the :mod:`python:typing` module, return the - corresponding strategy (special logic). - 3. If ``thing`` has one or more subtypes in the merged lookup, return - the union of the strategies for those types that are not subtypes of - other elements in the lookup. - 4. Finally, if ``thing`` has type annotations for all required arguments, - it is resolved via :func:`~hypothesis.strategies.builds`. - - """ - from hypothesis.searchstrategy import types - if not isinstance(thing, type): - try: - # At runtime, `typing.NewType` returns an identity function rather - # than an actual type, but we can check that for a possible match - # and then read the magic attribute to unwrap it. - import typing - if all([ - hasattr(thing, '__supertype__'), hasattr(typing, 'NewType'), - isfunction(thing), getattr(thing, '__module__', 0) == 'typing' - ]): - return from_type(thing.__supertype__) - # Under Python 3.6, Unions are not instances of `type` - but we - # still want to resolve them! - if getattr(thing, '__origin__', None) is typing.Union: - args = sorted(thing.__args__, key=types.type_sorting_key) - return one_of([from_type(t) for t in args]) - except ImportError: # pragma: no cover - pass - raise InvalidArgument('thing=%s must be a type' % (thing,)) - # Now that we know `thing` is a type, the first step is to check for an - # explicitly registered strategy. This is the best (and hopefully most - # common) way to resolve a type to a strategy. Note that the value in the - # lookup may be a strategy or a function from type -> strategy; and we - # convert empty results into an explicit error. - if thing in types._global_type_lookup: - strategy = types._global_type_lookup[thing] - if not isinstance(strategy, SearchStrategy): - strategy = strategy(thing) - if strategy.is_empty: - raise ResolutionFailed( - 'Error: %r resolved to an empty strategy' % (thing,)) - return strategy - # If there's no explicitly registered strategy, maybe a subtype of thing - # is registered - if so, we can resolve it to the subclass strategy. - # We'll start by checking if thing is from from the typing module, - # because there are several special cases that don't play well with - # subclass and instance checks. - try: - import typing - if isinstance(thing, typing.TypingMeta): - return types.from_typing_type(thing) - except ImportError: # pragma: no cover - pass - # If it's not from the typing module, we get all registered types that are - # a subclass of `thing` and are not themselves a subtype of any other such - # type. For example, `Number -> integers() | floats()`, but bools() is - # not included because bool is a subclass of int as well as Number. - strategies = [ - v if isinstance(v, SearchStrategy) else v(thing) - for k, v in types._global_type_lookup.items() - if issubclass(k, thing) and - sum(types.try_issubclass(k, T) for T in types._global_type_lookup) == 1 - ] - empty = ', '.join(repr(s) for s in strategies if s.is_empty) - if empty: - raise ResolutionFailed( - 'Could not resolve %s to a strategy; consider using ' - 'register_type_strategy' % empty) - elif strategies: - return one_of(strategies) - # If we don't have a strategy registered for this type or any subtype, we - # may be able to fall back on type annotations. - # Types created via typing.NamedTuple use a custom attribute instead - - # but we can still use builds(), if we work out the right kwargs. - if issubclass(thing, tuple) and hasattr(thing, '_fields') \ - and hasattr(thing, '_field_types'): - kwargs = {k: from_type(thing._field_types[k]) for k in thing._fields} - return builds(thing, **kwargs) - if issubclass(thing, enum.Enum): - assert len(thing), repr(thing) + ' has no members to sample' - return sampled_from(thing) - # If the constructor has an annotation for every required argument, - # we can (and do) use builds() without supplying additional arguments. - required = required_args(thing) - if not required or required.issubset(get_type_hints(thing.__init__)): - return builds(thing) - # We have utterly failed, and might as well say so now. - raise ResolutionFailed('Could not resolve %r to a strategy; consider ' - 'using register_type_strategy' % (thing,)) - - -@cacheable -@defines_strategy_with_reusable_values -def fractions(min_value=None, max_value=None, max_denominator=None): - """Returns a strategy which generates Fractions. - - If min_value is not None then all generated values are no less than - min_value. If max_value is not None then all generated values are no - greater than max_value. min_value and max_value may be anything accepted - by the :class:`~fractions.Fraction` constructor. - - If max_denominator is not None then the denominator of any generated - values is no greater than max_denominator. Note that max_denominator must - be None or a positive integer. - - Examples from this strategy shrink towards smaller denominators, then - closer to zero. - - """ - min_value = try_convert(Fraction, min_value, 'min_value') - max_value = try_convert(Fraction, max_value, 'max_value') - - check_valid_interval(min_value, max_value, 'min_value', 'max_value') - check_valid_integer(max_denominator) - - if max_denominator is not None: - if max_denominator < 1: - raise InvalidArgument( - 'max_denominator=%r must be >= 1' % max_denominator) - - def fraction_bounds(value): - """Find the best lower and upper approximation for value.""" - # Adapted from CPython's Fraction.limit_denominator here: - # https://github.com/python/cpython/blob/3.6/Lib/fractions.py#L219 - if value is None or value.denominator <= max_denominator: - return value, value - p0, q0, p1, q1 = 0, 1, 1, 0 - n, d = value.numerator, value.denominator - while True: - a = n // d - q2 = q0 + a * q1 - if q2 > max_denominator: - break - p0, q0, p1, q1 = p1, q1, p0 + a * p1, q2 - n, d = d, n - a * d - k = (max_denominator - q0) // q1 - low, high = Fraction(p1, q1), Fraction(p0 + k * p1, q0 + k * q1) - assert low < value < high - return low, high - - # Take the high approximation for min_value and low for max_value - bounds = (max_denominator, min_value, max_value) - _, min_value = fraction_bounds(min_value) - max_value, _ = fraction_bounds(max_value) - - if None not in (min_value, max_value) and min_value > max_value: - raise InvalidArgument( - 'There are no fractions with a denominator <= %r between ' - 'min_value=%r and max_value=%r' % bounds) - - if min_value is not None and min_value == max_value: - return just(min_value) - - def dm_func(denom): - """Take denom, construct numerator strategy, and build fraction.""" - # Four cases of algebra to get integer bounds and scale factor. - min_num, max_num = None, None - if max_value is None and min_value is None: - pass - elif min_value is None: - max_num = denom * max_value.numerator - denom *= max_value.denominator - elif max_value is None: - min_num = denom * min_value.numerator - denom *= min_value.denominator - else: - low = min_value.numerator * max_value.denominator - high = max_value.numerator * min_value.denominator - scale = min_value.denominator * max_value.denominator - # After calculating our integer bounds and scale factor, we remove - # the gcd to avoid drawing more bytes for the example than needed. - # Note that `div` can be at most equal to `scale`. - div = gcd(scale, gcd(low, high)) - min_num = denom * low // div - max_num = denom * high // div - denom *= scale // div - - return builds( - Fraction, - integers(min_value=min_num, max_value=max_num), - just(denom) - ) - - if max_denominator is None: - return integers(min_value=1).flatmap(dm_func) - - return integers(1, max_denominator).flatmap(dm_func).map( - lambda f: f.limit_denominator(max_denominator)) - - -@cacheable -@defines_strategy_with_reusable_values -def decimals(min_value=None, max_value=None, - allow_nan=None, allow_infinity=None, places=None): - """Generates instances of :class:`decimals.Decimal`, which may be: - - - A finite rational number, between ``min_value`` and ``max_value``. - - Not a Number, if ``allow_nan`` is True. None means "allow NaN, unless - ``min_value`` and ``max_value`` are not None". - - Positive or negative infinity, if ``max_value`` and ``min_value`` - respectively are None, and ``allow_infinity`` is not False. None means - "allow infinity, unless excluded by the min and max values". - - Note that where floats have one ``NaN`` value, Decimals have four: signed, - and either *quiet* or *signalling*. See `the decimal module docs - `_ for - more information on special values. - - If ``places`` is not None, all finite values drawn from the strategy will - have that number of digits after the decimal place. - - Examples from this strategy do not have a well defined shrink order but - try to maximize human readability when shrinking. - - """ - # Convert min_value and max_value to Decimal values, and validate args - check_valid_integer(places) - if places is not None and places < 0: - raise InvalidArgument('places=%r may not be negative' % places) - - if min_value is not None: - min_value = try_convert(Decimal, min_value, 'min_value') - if min_value.is_infinite() and min_value < 0: - if not (allow_infinity or allow_infinity is None): - raise InvalidArgument('allow_infinity=%r, but min_value=%r' - % (allow_infinity, min_value)) - min_value = None - elif not min_value.is_finite(): - # This could be positive infinity, quiet NaN, or signalling NaN - raise InvalidArgument(u'Invalid min_value=%r' % min_value) - if max_value is not None: - max_value = try_convert(Decimal, max_value, 'max_value') - if max_value.is_infinite() and max_value > 0: - if not (allow_infinity or allow_infinity is None): - raise InvalidArgument('allow_infinity=%r, but max_value=%r' - % (allow_infinity, max_value)) - max_value = None - elif not max_value.is_finite(): - raise InvalidArgument(u'Invalid max_value=%r' % max_value) - check_valid_interval(min_value, max_value, 'min_value', 'max_value') - - if allow_infinity and (None not in (min_value, max_value)): - raise InvalidArgument('Cannot allow infinity between finite bounds') - # Set up a strategy for finite decimals. Note that both floating and - # fixed-point decimals require careful handling to remain isolated from - # any external precision context - in short, we always work out the - # required precision for lossless operation and use context methods. - if places is not None: - # Fixed-point decimals are basically integers with a scale factor - def ctx(val): - """Return a context in which this value is lossless.""" - precision = ceil(math.log10(abs(val) or 1)) + places + 1 - return Context(prec=max([precision, 1])) - - def int_to_decimal(val): - context = ctx(val) - return context.quantize(context.multiply(val, factor), factor) - - factor = Decimal(10) ** -places - min_num, max_num = None, None - if min_value is not None: - min_num = ceil(ctx(min_value).divide(min_value, factor)) - if max_value is not None: - max_num = floor(ctx(max_value).divide(max_value, factor)) - if None not in (min_num, max_num) and min_num > max_num: - raise InvalidArgument( - 'There are no decimals with %d places between min_value=%r ' - 'and max_value=%r ' % (places, min_value, max_value)) - strat = integers(min_num, max_num).map(int_to_decimal) - else: - # Otherwise, they're like fractions featuring a power of ten - def fraction_to_decimal(val): - precision = ceil(math.log10(abs(val.numerator) or 1) + - math.log10(val.denominator)) + 1 - return Context(prec=precision or 1).divide( - Decimal(val.numerator), val.denominator) - - strat = fractions(min_value, max_value).map(fraction_to_decimal) - # Compose with sampled_from for infinities and NaNs as appropriate - special = [] - if allow_nan or (allow_nan is None and (None in (min_value, max_value))): - special.extend(map(Decimal, ('NaN', '-NaN', 'sNaN', '-sNaN'))) - if allow_infinity or (allow_infinity is max_value is None): - special.append(Decimal('Infinity')) - if allow_infinity or (allow_infinity is min_value is None): - special.append(Decimal('-Infinity')) - return strat | sampled_from(special) - - -def recursive(base, extend, max_leaves=100): - """base: A strategy to start from. - - extend: A function which takes a strategy and returns a new strategy. - - max_leaves: The maximum number of elements to be drawn from base on a given - run. - - This returns a strategy ``S`` such that ``S = extend(base | S)``. That is, - values may be drawn from base, or from any strategy reachable by mixing - applications of | and extend. - - An example may clarify: ``recursive(booleans(), lists)`` would return a - strategy that may return arbitrarily nested and mixed lists of booleans. - So e.g. ``False``, ``[True]``, ``[False, []]``, and ``[[[[True]]]]`` are - all valid values to be drawn from that strategy. - - Examples from this strategy shrink by trying to reduce the amount of - recursion and by shrinking according to the shrinking behaviour of base - and the result of extend. - - """ - - from hypothesis.searchstrategy.recursive import RecursiveStrategy - return RecursiveStrategy(base, extend, max_leaves) - - -@defines_strategy -def permutations(values): - """Return a strategy which returns permutations of the collection - ``values``. - - Examples from this strategy shrink by trying to become closer to the - original order of values. - - """ - from hypothesis.internal.conjecture.utils import integer_range - - values = list(values) - if not values: - return builds(list) - - class PermutationStrategy(SearchStrategy): - - def do_draw(self, data): - # Reversed Fisher-Yates shuffle. Reverse order so that it shrinks - # propertly: This way we prefer things that are lexicographically - # closer to the identity. - result = list(values) - for i in hrange(len(result)): - j = integer_range(data, i, len(result) - 1) - result[i], result[j] = result[j], result[i] - return result - return PermutationStrategy() - - -@defines_strategy_with_reusable_values -@renamed_arguments( - min_datetime='min_value', - max_datetime='max_value', -) -def datetimes( - min_value=dt.datetime.min, max_value=dt.datetime.max, - timezones=none(), - min_datetime=None, max_datetime=None, -): - """A strategy for generating datetimes, which may be timezone-aware. - - This strategy works by drawing a naive datetime between ``min_datetime`` - and ``max_datetime``, which must both be naive (have no timezone). - - ``timezones`` must be a strategy that generates tzinfo objects (or None, - which is valid for naive datetimes). A value drawn from this strategy - will be added to a naive datetime, and the resulting tz-aware datetime - returned. - - .. note:: - tz-aware datetimes from this strategy may be ambiguous or non-existent - due to daylight savings, leap seconds, timezone and calendar - adjustments, etc. This is intentional, as malformed timestamps are a - common source of bugs. - - :py:func:`hypothesis.extra.timezones` requires the ``pytz`` package, but - provides all timezones in the Olsen database. If you also want to allow - naive datetimes, combine strategies like ``none() | timezones()``. - - Alternatively, you can create a list of the timezones you wish to allow - (e.g. from the standard library, ``datetutil``, or ``pytz``) and use - :py:func:`sampled_from`. Ensure that simple values such as None or UTC - are at the beginning of the list for proper minimisation. - - Examples from this strategy shrink towards midnight on January 1st 2000. - - """ - # Why must bounds be naive? In principle, we could also write a strategy - # that took aware bounds, but the API and validation is much harder. - # If you want to generate datetimes between two particular momements in - # time I suggest (a) just filtering out-of-bounds values; (b) if bounds - # are very close, draw a value and subtract it's UTC offset, handling - # overflows and nonexistent times; or (c) do something customised to - # handle datetimes in e.g. a four-microsecond span which is not - # representable in UTC. Handling (d), all of the above, leads to a much - # more complex API for all users and a useful feature for very few. - from hypothesis.searchstrategy.datetime import DatetimeStrategy - - check_type(dt.datetime, min_value, 'min_value') - check_type(dt.datetime, max_value, 'max_value') - if min_value.tzinfo is not None: - raise InvalidArgument('min_value=%r must not have tzinfo' - % (min_value,)) - if max_value.tzinfo is not None: - raise InvalidArgument('max_value=%r must not have tzinfo' - % (max_value,)) - check_valid_interval(min_value, max_value, - 'min_value', 'max_value') - if not isinstance(timezones, SearchStrategy): - raise InvalidArgument( - 'timezones=%r must be a SearchStrategy that can provide tzinfo ' - 'for datetimes (either None or dt.tzinfo objects)' % (timezones,)) - return DatetimeStrategy(min_value, max_value, timezones) - - -@defines_strategy_with_reusable_values -@renamed_arguments( - min_date='min_value', - max_date='max_value', -) -def dates( - min_value=dt.date.min, max_value=dt.date.max, - min_date=None, max_date=None, -): - """A strategy for dates between ``min_date`` and ``max_date``. - - Examples from this strategy shrink towards January 1st 2000. - - """ - from hypothesis.searchstrategy.datetime import DateStrategy - - check_type(dt.date, min_value, 'min_value') - check_type(dt.date, max_value, 'max_value') - check_valid_interval(min_value, max_value, 'min_value', 'max_value') - if min_value == max_value: - return just(min_value) - return DateStrategy(min_value, max_value) - - -@defines_strategy_with_reusable_values -@renamed_arguments( - min_time='min_value', - max_time='max_value', -) -def times( - min_value=dt.time.min, max_value=dt.time.max, timezones=none(), - min_time=None, max_time=None, -): - """A strategy for times between ``min_time`` and ``max_time``. - - The ``timezones`` argument is handled as for :py:func:`datetimes`. - - Examples from this strategy shrink towards midnight, with the timezone - component shrinking as for the strategy that provided it. - - """ - check_type(dt.time, min_value, 'min_value') - check_type(dt.time, max_value, 'max_value') - if min_value.tzinfo is not None: - raise InvalidArgument('min_value=%r must not have tzinfo' % min_value) - if max_value.tzinfo is not None: - raise InvalidArgument('max_value=%r must not have tzinfo' % max_value) - check_valid_interval(min_value, max_value, 'min_value', 'max_value') - day = dt.date(2000, 1, 1) - return datetimes(min_value=dt.datetime.combine(day, min_value), - max_value=dt.datetime.combine(day, max_value), - timezones=timezones).map(lambda t: t.timetz()) - - -@defines_strategy_with_reusable_values -@renamed_arguments( - min_delta='min_value', - max_delta='max_value', -) -def timedeltas( - min_value=dt.timedelta.min, max_value=dt.timedelta.max, - min_delta=None, max_delta=None -): - """A strategy for timedeltas between ``min_value`` and ``max_value``. - - Examples from this strategy shrink towards zero. - - """ - from hypothesis.searchstrategy.datetime import TimedeltaStrategy - - check_type(dt.timedelta, min_value, 'min_value') - check_type(dt.timedelta, max_value, 'max_value') - check_valid_interval(min_value, max_value, 'min_value', 'max_value') - if min_value == max_value: - return just(min_value) - return TimedeltaStrategy(min_value=min_value, max_value=max_value) - - -@cacheable -def composite(f): - """Defines a strategy that is built out of potentially arbitrarily many - other strategies. - - This is intended to be used as a decorator. See - :ref:`the full documentation for more details ` - about how to use this function. - - Examples from this strategy shrink by shrinking the output of each draw - call. - - """ - - from hypothesis.internal.reflection import define_function_signature - argspec = getfullargspec(f) - - if ( - argspec.defaults is not None and - len(argspec.defaults) == len(argspec.args) - ): - raise InvalidArgument( - 'A default value for initial argument will never be used') - if len(argspec.args) == 0 and not argspec.varargs: - raise InvalidArgument( - 'Functions wrapped with composite must take at least one ' - 'positional argument.' - ) - - annots = {k: v for k, v in argspec.annotations.items() - if k in (argspec.args + argspec.kwonlyargs + ['return'])} - new_argspec = argspec._replace(args=argspec.args[1:], annotations=annots) - - @defines_strategy - @define_function_signature(f.__name__, f.__doc__, new_argspec) - def accept(*args, **kwargs): - class CompositeStrategy(SearchStrategy): - - def do_draw(self, data): - first_draw = [True] - - def draw(strategy): - first_draw[0] = False - return data.draw(strategy) - - return f(draw, *args, **kwargs) - return CompositeStrategy() - accept.__module__ = f.__module__ - return accept - - -def shared(base, key=None): - """Returns a strategy that draws a single shared value per run, drawn from - base. Any two shared instances with the same key will share the same value, - otherwise the identity of this strategy will be used. That is: - - >>> s = integers() # or any other strategy - >>> x = shared(s) - >>> y = shared(s) - - In the above x and y may draw different (or potentially the same) values. - In the following they will always draw the same: - - >>> x = shared(s, key="hi") - >>> y = shared(s, key="hi") - - Examples from this strategy shrink as per their base strategy. - - """ - from hypothesis.searchstrategy.shared import SharedStrategy - return SharedStrategy(base, key) - - -@defines_strategy -def choices(): - """Strategy that generates a function that behaves like random.choice. - - Will note choices made for reproducibility. - - .. deprecated:: 3.15.0 - - Use :func:`data() ` with - :func:`sampled_from() ` instead. - - Examples from this strategy shrink by making each choice function return - an earlier value in the sequence passed to it. - - """ - from hypothesis.control import note, current_build_context - from hypothesis.internal.conjecture.utils import choice, check_sample - - note_deprecation( - 'choices() has been deprecated. Use the data() strategy instead and ' - 'replace its usage with data.draw(sampled_from(elements))) calls.' - ) - - class Chooser(object): - - def __init__(self, build_context, data): - self.build_context = build_context - self.data = data - self.choice_count = 0 - - def __call__(self, values): - if not values: - raise IndexError('Cannot choose from empty sequence') - result = choice(self.data, check_sample(values)) - with self.build_context.local(): - self.choice_count += 1 - note('Choice #%d: %r' % (self.choice_count, result)) - return result - - def __repr__(self): - return 'choice' - - class ChoiceStrategy(SearchStrategy): - supports_find = False - - def do_draw(self, data): - data.can_reproduce_example_from_repr = False - return Chooser(current_build_context(), data) - - return shared( - ChoiceStrategy(), - key='hypothesis.strategies.chooser.choice_function' - ) - - -@cacheable -@defines_strategy_with_reusable_values -def uuids(version=None): - """Returns a strategy that generates :class:`UUIDs `. - - If the optional version argument is given, value is passed through - to :class:`~python:uuid.UUID` and only UUIDs of that version will - be generated. - - All returned values from this will be unique, so e.g. if you do - ``lists(uuids())`` the resulting list will never contain duplicates. - - Examples from this strategy don't have any meaningful shrink order. - - """ - from uuid import UUID - if version not in (None, 1, 2, 3, 4, 5): - raise InvalidArgument(( - 'version=%r, but version must be in (None, 1, 2, 3, 4, 5) ' - 'to pass to the uuid.UUID constructor.') % (version, ) - ) - return shared(randoms(), key='hypothesis.strategies.uuids.generator').map( - lambda r: UUID(version=version, int=r.getrandbits(128)) - ) - - -@defines_strategy_with_reusable_values -def runner(default=not_set): - """A strategy for getting "the current test runner", whatever that may be. - The exact meaning depends on the entry point, but it will usually be the - associated 'self' value for it. - - If there is no current test runner and a default is provided, return - that default. If no default is provided, raises InvalidArgument. - - Examples from this strategy do not shrink (because there is only one). - - """ - class RunnerStrategy(SearchStrategy): - - def do_draw(self, data): - runner = getattr(data, 'hypothesis_runner', not_set) - if runner is not_set: - if default is not_set: - raise InvalidArgument( - 'Cannot use runner() strategy with no ' - 'associated runner or explicit default.' - ) - else: - return default - else: - return runner - return RunnerStrategy() - - -@cacheable -def data(): - """This isn't really a normal strategy, but instead gives you an object - which can be used to draw data interactively from other strategies. - - It can only be used within :func:`@given `, not - :func:`find() `. This is because the lifetime - of the object cannot outlast the test body. - - See :ref:`the rest of the documentation ` for more - complete information. - - Examples from this strategy do not shrink (because there is only one), - but the result of calls to each draw() call shrink as they normally would. - - """ - from hypothesis.control import note - - class DataObject(object): - - def __init__(self, data): - self.count = 0 - self.data = data - - def __repr__(self): - return 'data(...)' - - def draw(self, strategy, label=None): - result = self.data.draw(strategy) - self.count += 1 - if label is not None: - note('Draw %d (%s): %r' % (self.count, label, result)) - else: - note('Draw %d: %r' % (self.count, result)) - return result - - class DataStrategy(SearchStrategy): - supports_find = False - - def do_draw(self, data): - data.can_reproduce_example_from_repr = False - - if not hasattr(data, 'hypothesis_shared_data_strategy'): - data.hypothesis_shared_data_strategy = DataObject(data) - return data.hypothesis_shared_data_strategy - - def __repr__(self): - return 'data()' - - def map(self, f): - self.__not_a_first_class_strategy('map') - - def filter(self, f): - self.__not_a_first_class_strategy('filter') - - def flatmap(self, f): - self.__not_a_first_class_strategy('flatmap') - - def example(self): - self.__not_a_first_class_strategy('example') - - def __not_a_first_class_strategy(self, name): - raise InvalidArgument(( - 'Cannot call %s on a DataStrategy. You should probably be ' - "using @composite for whatever it is you're trying to do." - ) % (name,)) - return DataStrategy() - - -def register_type_strategy(custom_type, strategy): - """Add an entry to the global type-to-strategy lookup. - - This lookup is used in :func:`~hypothesis.strategies.builds` and - :func:`@given `. - - :func:`~hypothesis.strategies.builds` will be used automatically for - classes with type annotations on ``__init__`` , so you only need to - register a strategy if one or more arguments need to be more tightly - defined than their type-based default, or if you want to supply a strategy - for an argument with a default value. - - ``strategy`` may be a search strategy, or a function that takes a type and - returns a strategy (useful for generic types). - - """ - from hypothesis.searchstrategy import types - if not isinstance(custom_type, type): - raise InvalidArgument('custom_type=%r must be a type') - elif not (isinstance(strategy, SearchStrategy) or callable(strategy)): - raise InvalidArgument( - 'strategy=%r must be a SearchStrategy, or a function that takes ' - 'a generic type and returns a specific SearchStrategy') - elif isinstance(strategy, SearchStrategy) and strategy.is_empty: - raise InvalidArgument('strategy=%r must not be empty') - types._global_type_lookup[custom_type] = strategy - from_type.__clear_cache() - - -@cacheable -def deferred(definition): - """A deferred strategy allows you to write a strategy that references other - strategies that have not yet been defined. This allows for the easy - definition of recursive and mutually recursive strategies. - - The definition argument should be a zero-argument function that returns a - strategy. It will be evaluated the first time the strategy is used to - produce an example. - - Example usage: - - >>> import hypothesis.strategies as st - >>> x = st.deferred(lambda: st.booleans() | st.tuples(x, x)) - >>> x.example() - (((False, (True, True)), (False, True)), (True, True)) - >>> x.example() - (True, True) - - Mutual recursion also works fine: - - >>> a = st.deferred(lambda: st.booleans() | b) - >>> b = st.deferred(lambda: st.tuples(a, a)) - >>> a.example() - (True, (True, False)) - >>> b.example() - (False, True) - - Examples from this strategy shrink as they normally would from the strategy - returned by the definition. - - """ - from hypothesis.searchstrategy.deferred import DeferredStrategy - return DeferredStrategy(definition) - - -assert _strategies.issubset(set(__all__)), _strategies - set(__all__) diff -Nru python-hypothesis-3.44.1/src/hypothesis/types.py python-hypothesis-3.71.11/src/hypothesis/types.py --- python-hypothesis-3.44.1/src/hypothesis/types.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/types.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,128 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import inspect -from random import Random -from itertools import islice - -from hypothesis.errors import InvalidArgument - - -class RandomWithSeed(Random): - - """A subclass of Random designed to expose the seed it was initially - provided with. - - We consistently use this instead of Random objects because it makes - examples much easier to recreate. - - """ - - def __init__(self, seed): - super(RandomWithSeed, self).__init__(seed) - self.seed = seed - - def __copy__(self): - result = RandomWithSeed(self.seed) - result.setstate(self.getstate()) - return result - - def __deepcopy__(self, table): - return self.__copy__() - - def __repr__(self): - return u'RandomWithSeed(%s)' % (self.seed,) - - -class Stream(object): - - """A stream is a possibly infinite list. You can index into it, and you can - iterate over it, but you can't ask its length and iterating over it will - not necessarily terminate. - - Behind the scenes streams are backed by a generator, but they "remember" - the values as they evaluate them so you can replay them later. - - Internally Hypothesis uses the fact that you can tell how much of a stream - has been evaluated, but you shouldn't use that. The only public APIs of - a Stream are that you can index, slice, and iterate it. - - """ - - def __init__(self, generator=None): - if generator is None: - generator = iter(()) - elif not inspect.isgenerator(generator): - generator = iter(generator) - self.generator = generator - self.fetched = [] - - def map(self, f): - return Stream(f(v) for v in self) - - def __iter__(self): - i = 0 - while i < len(self.fetched): - yield self.fetched[i] - i += 1 - for v in self.generator: - self.fetched.append(v) - yield v - - def __getitem__(self, key): - if isinstance(key, slice): - return Stream(islice( - iter(self), - key.start, key.stop, key.step - )) - - if not isinstance(key, int): - raise InvalidArgument(u'Cannot index stream with %s' % ( - type(key).__name__,)) - self._thunk_to(key + 1) - return self.fetched[key] - - def _thunk_to(self, i): - it = iter(self) - try: - while len(self.fetched) < i: - next(it) - except StopIteration: - raise IndexError( - u'Index %d out of bounds for finite stream of length %d' % ( - i, len(self.fetched) - ) - ) - - def _thunked(self): - return len(self.fetched) - - def __repr__(self): - if not self.fetched: - return u'Stream(...)' - - return u'Stream(%s, ...)' % ( - u', '.join(map(repr, self.fetched)) - ) - - def __deepcopy__(self, table): - return self - - def __copy__(self): - return self diff -Nru python-hypothesis-3.44.1/src/hypothesis/utils/conventions.py python-hypothesis-3.71.11/src/hypothesis/utils/conventions.py --- python-hypothesis-3.44.1/src/hypothesis/utils/conventions.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/utils/conventions.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - - -class UniqueIdentifier(object): - - def __init__(self, identifier): - self.identifier = identifier - - def __repr__(self): - return self.identifier - - -infer = UniqueIdentifier(u'infer') -not_set = UniqueIdentifier(u'not_set') diff -Nru python-hypothesis-3.44.1/src/hypothesis/utils/dynamicvariables.py python-hypothesis-3.71.11/src/hypothesis/utils/dynamicvariables.py --- python-hypothesis-3.44.1/src/hypothesis/utils/dynamicvariables.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/utils/dynamicvariables.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import threading -from contextlib import contextmanager - - -class DynamicVariable(object): - - def __init__(self, default): - self.default = default - self.data = threading.local() - - @property - def value(self): - return getattr(self.data, 'value', self.default) - - @value.setter - def value(self, value): - setattr(self.data, 'value', value) - - @contextmanager - def with_value(self, value): - old_value = self.value - try: - self.data.value = value - yield - finally: - self.data.value = old_value diff -Nru python-hypothesis-3.44.1/src/hypothesis/utils/__init__.py python-hypothesis-3.71.11/src/hypothesis/utils/__init__.py --- python-hypothesis-3.44.1/src/hypothesis/utils/__init__.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/utils/__init__.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,19 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -"""hypothesis.utils is a package for things that you can consider part of the -semi-public Hypothesis API but aren't really the core point.""" diff -Nru python-hypothesis-3.44.1/src/hypothesis/vendor/__init__.py python-hypothesis-3.71.11/src/hypothesis/vendor/__init__.py --- python-hypothesis-3.44.1/src/hypothesis/vendor/__init__.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/vendor/__init__.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2016 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER diff -Nru python-hypothesis-3.44.1/src/hypothesis/vendor/pretty.py python-hypothesis-3.71.11/src/hypothesis/vendor/pretty.py --- python-hypothesis-3.44.1/src/hypothesis/vendor/pretty.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/vendor/pretty.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,875 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2016 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -# -*- coding: utf-8 -*- -""" -Python advanced pretty printer. This pretty printer is intended to -replace the old `pprint` python module which does not allow developers -to provide their own pretty print callbacks. -This module is based on ruby's `prettyprint.rb` library by `Tanaka Akira`. -Example Usage -------------- -To directly print the representation of an object use `pprint`:: - from pretty import pprint - pprint(complex_object) -To get a string of the output use `pretty`:: - from pretty import pretty - string = pretty(complex_object) -Extending ---------- -The pretty library allows developers to add pretty printing rules for their -own objects. This process is straightforward. All you have to do is to -add a `_repr_pretty_` method to your object and call the methods on the -pretty printer passed:: - class MyObject(object): - def _repr_pretty_(self, p, cycle): - ... -Here is an example implementation of a `_repr_pretty_` method for a list -subclass:: - class MyList(list): - def _repr_pretty_(self, p, cycle): - if cycle: - p.text('MyList(...)') - else: - with p.group(8, 'MyList([', '])'): - for idx, item in enumerate(self): - if idx: - p.text(',') - p.breakable() - p.pretty(item) -The `cycle` parameter is `True` if pretty detected a cycle. You *have* to -react to that or the result is an infinite loop. `p.text()` just adds -non breaking text to the output, `p.breakable()` either adds a whitespace -or breaks here. If you pass it an argument it's used instead of the -default space. `p.pretty` prettyprints another object using the pretty print -method. -The first parameter to the `group` function specifies the extra indentation -of the next line. In this example the next item will either be on the same -line (if the items are short enough) or aligned with the right edge of the -opening bracket of `MyList`. -If you just want to indent something you can use the group function -without open / close parameters. You can also use this code:: - with p.indent(2): - ... -Inheritance diagram: -.. inheritance-diagram:: IPython.lib.pretty - :parts: 3 -:copyright: 2007 by Armin Ronacher. - Portions (c) 2009 by Robert Kern. -:license: BSD License. -""" -from __future__ import division, print_function, absolute_import - -import re -import sys -import types -import datetime -import platform -from io import StringIO -from contextlib import contextmanager -from collections import deque - -from hypothesis.internal.compat import PY3, cast_unicode, string_types, \ - get_stream_enc - -__all__ = ['pretty', 'pprint', 'PrettyPrinter', 'RepresentationPrinter', - 'for_type_by_name'] - - -MAX_SEQ_LENGTH = 1000 -_re_pattern_type = type(re.compile('')) - -PYPY = platform.python_implementation() == 'PyPy' - - -def _safe_getattr(obj, attr, default=None): - """Safe version of getattr. - - Same as getattr, but will return ``default`` on any Exception, - rather than raising. - - """ - try: - return getattr(obj, attr, default) - except Exception: - return default - - -if PY3: - CUnicodeIO = StringIO -else: # pragma: no cover - class CUnicodeIO(StringIO): - """StringIO that casts str to unicode on Python 2.""" - - def write(self, text): - return super(CUnicodeIO, self).write( - cast_unicode(text, encoding=get_stream_enc(sys.stdout))) - - -def pretty( - obj, verbose=False, max_width=79, newline='\n', - max_seq_length=MAX_SEQ_LENGTH -): - """Pretty print the object's representation.""" - stream = CUnicodeIO() - printer = RepresentationPrinter( - stream, verbose, max_width, newline, max_seq_length=max_seq_length) - printer.pretty(obj) - printer.flush() - return stream.getvalue() - - -def pprint( - obj, verbose=False, max_width=79, newline='\n', - max_seq_length=MAX_SEQ_LENGTH -): - """Like `pretty` but print to stdout.""" - printer = RepresentationPrinter( - sys.stdout, verbose, max_width, newline, max_seq_length=max_seq_length) - printer.pretty(obj) - printer.flush() - sys.stdout.write(newline) - sys.stdout.flush() - - -class _PrettyPrinterBase(object): - - @contextmanager - def indent(self, indent): - """with statement support for indenting/dedenting.""" - self.indentation += indent - try: - yield - finally: - self.indentation -= indent - - @contextmanager - def group(self, indent=0, open='', close=''): - """like begin_group / end_group but for the with statement.""" - self.begin_group(indent, open) - try: - yield - finally: - self.end_group(indent, close) - - -class PrettyPrinter(_PrettyPrinterBase): - """Baseclass for the `RepresentationPrinter` prettyprinter that is used to - generate pretty reprs of objects. - - Contrary to the `RepresentationPrinter` this printer knows nothing - about the default pprinters or the `_repr_pretty_` callback method. - - """ - - def __init__( - self, output, max_width=79, newline='\n', max_seq_length=MAX_SEQ_LENGTH - ): - self.broken = False - self.output = output - self.max_width = max_width - self.newline = newline - self.max_seq_length = max_seq_length - self.output_width = 0 - self.buffer_width = 0 - self.buffer = deque() - - root_group = Group(0) - self.group_stack = [root_group] - self.group_queue = GroupQueue(root_group) - self.indentation = 0 - - def _break_outer_groups(self): - while self.max_width < self.output_width + self.buffer_width: - group = self.group_queue.deq() - if not group: - return - while group.breakables: - x = self.buffer.popleft() - self.output_width = x.output(self.output, self.output_width) - self.buffer_width -= x.width - while self.buffer and isinstance(self.buffer[0], Text): - x = self.buffer.popleft() - self.output_width = x.output(self.output, self.output_width) - self.buffer_width -= x.width - - def text(self, obj): - """Add literal text to the output.""" - width = len(obj) - if self.buffer: - text = self.buffer[-1] - if not isinstance(text, Text): - text = Text() - self.buffer.append(text) - text.add(obj, width) - self.buffer_width += width - self._break_outer_groups() - else: - self.output.write(obj) - self.output_width += width - - def breakable(self, sep=' '): - """Add a breakable separator to the output. - - This does not mean that it will automatically break here. If no - breaking on this position takes place the `sep` is inserted - which default to one space. - - """ - width = len(sep) - group = self.group_stack[-1] - if group.want_break: - self.flush() - self.output.write(self.newline) - self.output.write(' ' * self.indentation) - self.output_width = self.indentation - self.buffer_width = 0 - else: - self.buffer.append(Breakable(sep, width, self)) - self.buffer_width += width - self._break_outer_groups() - - def break_(self): - """Explicitly insert a newline into the output, maintaining correct - indentation.""" - self.flush() - self.output.write(self.newline) - self.output.write(' ' * self.indentation) - self.output_width = self.indentation - self.buffer_width = 0 - - def begin_group(self, indent=0, open=''): - """ - Begin a group. If you want support for python < 2.5 which doesn't has - the with statement this is the preferred way: - p.begin_group(1, '{') - ... - p.end_group(1, '}') - The python 2.5 expression would be this: - with p.group(1, '{', '}'): - ... - The first parameter specifies the indentation for the next line ( - usually the width of the opening text), the second the opening text. - All parameters are optional. - """ - if open: - self.text(open) - group = Group(self.group_stack[-1].depth + 1) - self.group_stack.append(group) - self.group_queue.enq(group) - self.indentation += indent - - def _enumerate(self, seq): - """like enumerate, but with an upper limit on the number of items.""" - for idx, x in enumerate(seq): - if self.max_seq_length and idx >= self.max_seq_length: - self.text(',') - self.breakable() - self.text('...') - return - yield idx, x - - def end_group(self, dedent=0, close=''): - """End a group. - - See `begin_group` for more details. - - """ - self.indentation -= dedent - group = self.group_stack.pop() - if not group.breakables: - self.group_queue.remove(group) - if close: - self.text(close) - - def flush(self): - """Flush data that is left in the buffer.""" - for data in self.buffer: - self.output_width += data.output(self.output, self.output_width) - self.buffer.clear() - self.buffer_width = 0 - - -def _get_mro(obj_class): - """Get a reasonable method resolution order of a class and its superclasses - for both old-style and new-style classes.""" - if not hasattr(obj_class, '__mro__'): # pragma: no cover - # Old-style class. Mix in object to make a fake new-style class. - try: - obj_class = type(obj_class.__name__, (obj_class, object), {}) - except TypeError: - # Old-style extension type that does not descend from object. - # FIXME: try to construct a more thorough MRO. - mro = [obj_class] - else: - mro = obj_class.__mro__[1:-1] - else: - mro = obj_class.__mro__ - return mro - - -class RepresentationPrinter(PrettyPrinter): - """Special pretty printer that has a `pretty` method that calls the pretty - printer for a python object. - - This class stores processing data on `self` so you must *never* use - this class in a threaded environment. Always lock it or - reinstanciate it. Instances also have a verbose flag callbacks can - access to control their output. For example the default instance - repr prints all attributes and methods that are not prefixed by an - underscore if the printer is in verbose mode. - - """ - - def __init__(self, output, verbose=False, max_width=79, newline='\n', - singleton_pprinters=None, type_pprinters=None, - deferred_pprinters=None, - max_seq_length=MAX_SEQ_LENGTH): - - PrettyPrinter.__init__(self, output, max_width, - newline, max_seq_length=max_seq_length) - self.verbose = verbose - self.stack = [] - if singleton_pprinters is None: - singleton_pprinters = _singleton_pprinters.copy() - self.singleton_pprinters = singleton_pprinters - if type_pprinters is None: - type_pprinters = _type_pprinters.copy() - self.type_pprinters = type_pprinters - if deferred_pprinters is None: - deferred_pprinters = _deferred_type_pprinters.copy() - self.deferred_pprinters = deferred_pprinters - - def pretty(self, obj): - """Pretty print the given object.""" - obj_id = id(obj) - cycle = obj_id in self.stack - self.stack.append(obj_id) - self.begin_group() - try: - obj_class = _safe_getattr(obj, '__class__', None) or type(obj) - # First try to find registered singleton printers for the type. - try: - printer = self.singleton_pprinters[obj_id] - except (TypeError, KeyError): - pass - else: - return printer(obj, self, cycle) - # Next walk the mro and check for either: - # 1) a registered printer - # 2) a _repr_pretty_ method - for cls in _get_mro(obj_class): - if cls in self.type_pprinters: - # printer registered in self.type_pprinters - return self.type_pprinters[cls](obj, self, cycle) - else: - # deferred printer - printer = self._in_deferred_types(cls) - if printer is not None: - return printer(obj, self, cycle) - else: - # Finally look for special method names. - # Some objects automatically create any requested - # attribute. Try to ignore most of them by checking for - # callability. - if '_repr_pretty_' in cls.__dict__: - meth = cls._repr_pretty_ - if callable(meth): - return meth(obj, self, cycle) - return _default_pprint(obj, self, cycle) - finally: - self.end_group() - self.stack.pop() - - def _in_deferred_types(self, cls): - """Check if the given class is specified in the deferred type registry. - - Returns the printer from the registry if it exists, and None if - the class is not in the registry. Successful matches will be - moved to the regular type registry for future use. - - """ - mod = _safe_getattr(cls, '__module__', None) - name = _safe_getattr(cls, '__name__', None) - key = (mod, name) - printer = None - if key in self.deferred_pprinters: - # Move the printer over to the regular registry. - printer = self.deferred_pprinters.pop(key) - self.type_pprinters[cls] = printer - return printer - - -class Printable(object): - - def output(self, stream, output_width): # pragma: no cover - raise NotImplementedError() - - -class Text(Printable): - - def __init__(self): - self.objs = [] - self.width = 0 - - def output(self, stream, output_width): - for obj in self.objs: - stream.write(obj) - return output_width + self.width - - def add(self, obj, width): - self.objs.append(obj) - self.width += width - - -class Breakable(Printable): - - def __init__(self, seq, width, pretty): - self.obj = seq - self.width = width - self.pretty = pretty - self.indentation = pretty.indentation - self.group = pretty.group_stack[-1] - self.group.breakables.append(self) - - def output(self, stream, output_width): - self.group.breakables.popleft() - if self.group.want_break: - stream.write(self.pretty.newline) - stream.write(' ' * self.indentation) - return self.indentation - if not self.group.breakables: - self.pretty.group_queue.remove(self.group) - stream.write(self.obj) - return output_width + self.width - - -class Group(Printable): - - def __init__(self, depth): - self.depth = depth - self.breakables = deque() - self.want_break = False - - -class GroupQueue(object): - - def __init__(self, *groups): - self.queue = [] - for group in groups: - self.enq(group) - - def enq(self, group): - depth = group.depth - while depth > len(self.queue) - 1: - self.queue.append([]) - self.queue[depth].append(group) - - def deq(self): - for stack in self.queue: - for idx, group in enumerate(reversed(stack)): - if group.breakables: - del stack[idx] - group.want_break = True - return group - for group in stack: - group.want_break = True - del stack[:] - - def remove(self, group): - try: - self.queue[group.depth].remove(group) - except ValueError: - pass - - -try: - _baseclass_reprs = (object.__repr__, types.InstanceType.__repr__) -except AttributeError: # Python 3 - _baseclass_reprs = (object.__repr__,) - - -def _default_pprint(obj, p, cycle): - """The default print function. - - Used if an object does not provide one and it's none of the builtin - objects. - - """ - klass = _safe_getattr(obj, '__class__', None) or type(obj) - if _safe_getattr(klass, '__repr__', None) not in _baseclass_reprs: - # A user-provided repr. Find newlines and replace them with p.break_() - _repr_pprint(obj, p, cycle) - return - p.begin_group(1, '<') - p.pretty(klass) - p.text(' at 0x%x' % id(obj)) - if cycle: - p.text(' ...') - elif p.verbose: - first = True - for key in dir(obj): - if not key.startswith('_'): - try: - value = getattr(obj, key) - except AttributeError: - continue - if isinstance(value, types.MethodType): - continue - if not first: - p.text(',') - p.breakable() - p.text(key) - p.text('=') - step = len(key) + 1 - p.indentation += step - p.pretty(value) - p.indentation -= step - first = False - p.end_group(1, '>') - - -def _seq_pprinter_factory(start, end, basetype): - """Factory that returns a pprint function useful for sequences. - - Used by the default pprint for tuples, dicts, and lists. - - """ - def inner(obj, p, cycle): - typ = type(obj) - if ( - basetype is not None and typ is not basetype and - typ.__repr__ != basetype.__repr__ - ): - # If the subclass provides its own repr, use it instead. - return p.text(typ.__repr__(obj)) - - if cycle: - return p.text(start + '...' + end) - step = len(start) - p.begin_group(step, start) - for idx, x in p._enumerate(obj): - if idx: - p.text(',') - p.breakable() - p.pretty(x) - if len(obj) == 1 and type(obj) is tuple: - # Special case for 1-item tuples. - p.text(',') - p.end_group(step, end) - return inner - - -def _set_pprinter_factory(start, end, basetype): - """Factory that returns a pprint function useful for sets and - frozensets.""" - def inner(obj, p, cycle): - typ = type(obj) - if ( - basetype is not None and typ is not basetype and - typ.__repr__ != basetype.__repr__ - ): - # If the subclass provides its own repr, use it instead. - return p.text(typ.__repr__(obj)) - - if cycle: - return p.text(start + '...' + end) - if len(obj) == 0: - # Special case. - p.text(basetype.__name__ + '()') - else: - step = len(start) - p.begin_group(step, start) - # Like dictionary keys, we will try to sort the items if there - # aren't too many - items = obj - if not (p.max_seq_length and len(obj) >= p.max_seq_length): - try: - items = sorted(obj) - except Exception: - # Sometimes the items don't sort. - pass - for idx, x in p._enumerate(items): - if idx: - p.text(',') - p.breakable() - p.pretty(x) - p.end_group(step, end) - return inner - - -def _dict_pprinter_factory(start, end, basetype=None): - """Factory that returns a pprint function used by the default pprint of - dicts and dict proxies.""" - def inner(obj, p, cycle): - typ = type(obj) - if ( - basetype is not None and typ is not basetype and - typ.__repr__ != basetype.__repr__ - ): - # If the subclass provides its own repr, use it instead. - return p.text(typ.__repr__(obj)) - - if cycle: - return p.text('{...}') - p.begin_group(1, start) - keys = obj.keys() - # if dict isn't large enough to be truncated, sort keys before - # displaying - if not (p.max_seq_length and len(obj) >= p.max_seq_length): - try: - keys = sorted(keys) - except Exception: - # Sometimes the keys don't sort. - pass - for idx, key in p._enumerate(keys): - if idx: - p.text(',') - p.breakable() - p.pretty(key) - p.text(': ') - p.pretty(obj[key]) - p.end_group(1, end) - inner.__name__ = '_dict_pprinter_factory(%r, %r, %r)' % ( - start, end, basetype - ) - return inner - - -def _super_pprint(obj, p, cycle): - """The pprint for the super type.""" - try: - # This section works around various pypy versions that don't do - # have the same attributes on super objects - obj.__thisclass__ - obj.__self__ - except AttributeError: # pragma: no cover - assert PYPY - _repr_pprint(obj, p, cycle) - return - p.begin_group(8, '') - - -def _re_pattern_pprint(obj, p, cycle): - """The pprint function for regular expression patterns.""" - p.text('re.compile(') - pattern = repr(obj.pattern) - if pattern[:1] in 'uU': # pragma: no cover - pattern = pattern[1:] - prefix = 'ur' - else: - prefix = 'r' - pattern = prefix + pattern.replace('\\\\', '\\') - p.text(pattern) - if obj.flags: - p.text(',') - p.breakable() - done_one = False - for flag in ('TEMPLATE', 'IGNORECASE', 'LOCALE', 'MULTILINE', 'DOTALL', - 'UNICODE', 'VERBOSE', 'DEBUG'): - if obj.flags & getattr(re, flag): - if done_one: - p.text('|') - p.text('re.' + flag) - done_one = True - p.text(')') - - -def _type_pprint(obj, p, cycle): - """The pprint for classes and types.""" - # Heap allocated types might not have the module attribute, - # and others may set it to None. - - # Checks for a __repr__ override in the metaclass - # != rather than is not because pypy compatibility - if type(obj).__repr__ != type.__repr__: - _repr_pprint(obj, p, cycle) - return - - mod = _safe_getattr(obj, '__module__', None) - try: - name = obj.__qualname__ - if not isinstance(name, string_types): # pragma: no cover - # This can happen if the type implements __qualname__ as a property - # or other descriptor in Python 2. - raise Exception('Try __name__') - except Exception: # pragma: no cover - name = obj.__name__ - if not isinstance(name, string_types): - name = '' - - if mod in (None, '__builtin__', 'builtins', 'exceptions'): - p.text(name) - else: - p.text(mod + '.' + name) - - -def _repr_pprint(obj, p, cycle): - """A pprint that just redirects to the normal repr function.""" - # Find newlines and replace them with p.break_() - output = repr(obj) - for idx, output_line in enumerate(output.splitlines()): - if idx: - p.break_() - p.text(output_line) - - -def _function_pprint(obj, p, cycle): - """Base pprint for all functions and builtin functions.""" - name = _safe_getattr(obj, '__qualname__', obj.__name__) - mod = obj.__module__ - if mod and mod not in ('__builtin__', 'builtins', 'exceptions'): - name = mod + '.' + name - p.text('' % name) - - -def _exception_pprint(obj, p, cycle): - """Base pprint for all exceptions.""" - name = getattr(obj.__class__, '__qualname__', obj.__class__.__name__) - if obj.__class__.__module__ not in ('exceptions', 'builtins'): - name = '%s.%s' % (obj.__class__.__module__, name) - step = len(name) + 1 - p.begin_group(step, name + '(') - for idx, arg in enumerate(getattr(obj, 'args', ())): - if idx: - p.text(',') - p.breakable() - p.pretty(arg) - p.end_group(step, ')') - - -#: the exception base -try: - _exception_base = BaseException -except NameError: # pragma: no cover - _exception_base = Exception - - -#: printers for builtin types -_type_pprinters = { - int: _repr_pprint, - float: _repr_pprint, - str: _repr_pprint, - tuple: _seq_pprinter_factory('(', ')', tuple), - list: _seq_pprinter_factory('[', ']', list), - dict: _dict_pprinter_factory('{', '}', dict), - - set: _set_pprinter_factory('{', '}', set), - frozenset: _set_pprinter_factory('frozenset({', '})', frozenset), - super: _super_pprint, - _re_pattern_type: _re_pattern_pprint, - type: _type_pprint, - types.FunctionType: _function_pprint, - types.BuiltinFunctionType: _function_pprint, - types.MethodType: _repr_pprint, - - datetime.datetime: _repr_pprint, - datetime.timedelta: _repr_pprint, - _exception_base: _exception_pprint -} - -try: # pragma: no cover - if types.DictProxyType != dict: - _type_pprinters[types.DictProxyType] = _dict_pprinter_factory( - '') - _type_pprinters[types.ClassType] = _type_pprint - _type_pprinters[types.SliceType] = _repr_pprint -except AttributeError: # Python 3 - _type_pprinters[slice] = _repr_pprint - -try: # pragma: no cover - _type_pprinters[xrange] = _repr_pprint - _type_pprinters[long] = _repr_pprint - _type_pprinters[unicode] = _repr_pprint -except NameError: - _type_pprinters[range] = _repr_pprint - _type_pprinters[bytes] = _repr_pprint - -#: printers for types specified by name -_deferred_type_pprinters = { -} - - -def for_type_by_name(type_module, type_name, func): - """Add a pretty printer for a type specified by the module and name of a - type rather than the type object itself.""" - key = (type_module, type_name) - oldfunc = _deferred_type_pprinters.get(key, None) - _deferred_type_pprinters[key] = func - return oldfunc - - -#: printers for the default singletons -_singleton_pprinters = dict.fromkeys(map(id, [None, True, False, Ellipsis, - NotImplemented]), _repr_pprint) - - -def _defaultdict_pprint(obj, p, cycle): - name = obj.__class__.__name__ - with p.group(len(name) + 1, name + '(', ')'): - if cycle: - p.text('...') - else: - p.pretty(obj.default_factory) - p.text(',') - p.breakable() - p.pretty(dict(obj)) - - -def _ordereddict_pprint(obj, p, cycle): - name = obj.__class__.__name__ - with p.group(len(name) + 1, name + '(', ')'): - if cycle: - p.text('...') - elif len(obj): - p.pretty(list(obj.items())) - - -def _deque_pprint(obj, p, cycle): - name = obj.__class__.__name__ - with p.group(len(name) + 1, name + '(', ')'): - if cycle: - p.text('...') - else: - p.pretty(list(obj)) - - -def _counter_pprint(obj, p, cycle): - name = obj.__class__.__name__ - with p.group(len(name) + 1, name + '(', ')'): - if cycle: - p.text('...') - elif len(obj): - p.pretty(dict(obj)) - - -for_type_by_name('collections', 'defaultdict', _defaultdict_pprint) -for_type_by_name('collections', 'OrderedDict', _ordereddict_pprint) -for_type_by_name('ordereddict', 'OrderedDict', _ordereddict_pprint) -for_type_by_name('collections', 'deque', _deque_pprint) -for_type_by_name('collections', 'Counter', _counter_pprint) -for_type_by_name('counter', 'Counter', _counter_pprint) - -for_type_by_name('_collections', 'defaultdict', _defaultdict_pprint) -for_type_by_name('_collections', 'OrderedDict', _ordereddict_pprint) -for_type_by_name('_collections', 'deque', _deque_pprint) -for_type_by_name('_collections', 'Counter', _counter_pprint) diff -Nru python-hypothesis-3.44.1/src/hypothesis/version.py python-hypothesis-3.71.11/src/hypothesis/version.py --- python-hypothesis-3.44.1/src/hypothesis/version.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/src/hypothesis/version.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -__version_info__ = (3, 44, 1) -__version__ = '.'.join(map(str, __version_info__)) diff -Nru python-hypothesis-3.44.1/tests/common/arguments.py python-hypothesis-3.71.11/tests/common/arguments.py --- python-hypothesis-3.44.1/tests/common/arguments.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/common/arguments.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,50 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import pytest - -from hypothesis import given -from hypothesis.errors import InvalidArgument - - -def e(a, *args, **kwargs): - return (a, args, kwargs) - - -def e_to_str(elt): - f, args, kwargs = elt - bits = list(map(repr, args)) - bits.extend(sorted('%s=%r' % (k, v) for k, v in kwargs.items())) - return '%s(%s)' % (f.__name__, ', '.join(bits)) - - -def argument_validation_test(bad_args): - @pytest.mark.parametrize( - ('function', 'args', 'kwargs'), bad_args, - ids=list(map(e_to_str, bad_args)) - ) - def test_raise_invalid_argument(function, args, kwargs): - @given(function(*args, **kwargs)) - def test(x): - pass - - with pytest.raises(InvalidArgument): - test() - - return test_raise_invalid_argument diff -Nru python-hypothesis-3.44.1/tests/common/debug.py python-hypothesis-3.71.11/tests/common/debug.py --- python-hypothesis-3.44.1/tests/common/debug.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/common/debug.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,127 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import sys - -from hypothesis import settings as Settings -from hypothesis import find, given, assume, reject -from hypothesis.errors import NoSuchExample, Unsatisfiable - -TIME_INCREMENT = 0.01 - - -class Timeout(BaseException): - pass - - -def minimal( - definition, condition=None, - settings=None, timeout_after=10, random=None -): - settings = Settings( - settings, - max_examples=50000, - max_iterations=100000, - max_shrinks=5000, - database=None, - ) - - runtime = [] - - if condition is None: - def condition(x): - return True - - def wrapped_condition(x): - if runtime: - runtime[0] += TIME_INCREMENT - if runtime[0] >= timeout_after: - raise Timeout() - result = condition(x) - if result and not runtime: - runtime.append(0.0) - return result - - try: - orig = sys.gettrace() - return find( - definition, - wrapped_condition, - settings=settings, - random=random, - ) - finally: - sys.settrace(orig) - - -def find_any( - definition, condition=None, - settings=None, random=None -): - settings = Settings( - settings, - max_examples=10000, - max_iterations=10000, - max_shrinks=0000, - database=None, - ) - - if condition is None: - def condition(x): - return True - - return find( - definition, - condition, - settings=settings, - random=random, - ) - - -def assert_no_examples(strategy, condition=None): - if condition is None: - def predicate(x): - reject() - else: - def predicate(x): - assume(condition(x)) - - try: - result = find( - strategy, predicate, - settings=Settings(max_iterations=100, max_shrinks=1) - ) - assert False, 'Expected no results but found %r' % (result,) - except (Unsatisfiable, NoSuchExample): - pass - - -def assert_all_examples(strategy, predicate): - """Asserts that all examples of the given strategy match the predicate. - - :param strategy: Hypothesis strategy to check - :param predicate: (callable) Predicate that takes example and returns bool - - """ - @given(strategy) - def assert_examples(s): - assert predicate(s), \ - 'Found %r using strategy %s which does not match' % (s, strategy) - - assert_examples() diff -Nru python-hypothesis-3.44.1/tests/common/__init__.py python-hypothesis-3.71.11/tests/common/__init__.py --- python-hypothesis-3.44.1/tests/common/__init__.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/common/__init__.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,102 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -import sys -from collections import namedtuple - -try: - import pytest -except ImportError: - pytest = None - -from tests.common.debug import TIME_INCREMENT -from hypothesis.strategies import integers, floats, just, one_of, \ - sampled_from, lists, booleans, dictionaries, tuples, \ - frozensets, complex_numbers, sets, text, binary, decimals, fractions, \ - none, randoms, builds, fixed_dictionaries, recursive - - -__all__ = ['small_verifier', 'standard_types', 'OrderedPair', 'TIME_INCREMENT'] - -OrderedPair = namedtuple('OrderedPair', ('left', 'right')) - - -ordered_pair = integers().flatmap( - lambda right: integers(min_value=0).map( - lambda length: OrderedPair(right - length, right))) - - -def constant_list(strat): - return strat.flatmap( - lambda v: lists(just(v), average_size=10), - ) - - -ABC = namedtuple('ABC', ('a', 'b', 'c')) - - -def abc(x, y, z): - return builds(ABC, x, y, z) - - -standard_types = [ - lists(max_size=0), tuples(), sets(max_size=0), frozensets(max_size=0), - fixed_dictionaries({}), - abc(booleans(), booleans(), booleans()), - abc(booleans(), booleans(), integers()), - fixed_dictionaries({'a': integers(), 'b': booleans()}), - dictionaries(booleans(), integers()), - dictionaries(text(), booleans()), - one_of(integers(), tuples(booleans())), - sampled_from(range(10)), - one_of(just('a'), just('b'), just('c')), - sampled_from(('a', 'b', 'c')), - integers(), - integers(min_value=3), - integers(min_value=(-2 ** 32), max_value=(2 ** 64)), - floats(), floats(min_value=-2.0, max_value=3.0), - floats(), floats(min_value=-2.0), - floats(), floats(max_value=-0.0), - floats(), floats(min_value=0.0), - floats(min_value=3.14, max_value=3.14), - text(), binary(), - booleans(), - tuples(booleans(), booleans()), - frozensets(integers()), - sets(frozensets(booleans())), - complex_numbers(), - fractions(), - decimals(), - lists(lists(booleans(), average_size=10), average_size=10), - lists(lists(booleans(), average_size=100)), - lists(floats(0.0, 0.0), average_size=1.0), - ordered_pair, constant_list(integers()), - integers().filter(lambda x: abs(x) > 100), - floats(min_value=-sys.float_info.max, max_value=sys.float_info.max), - none(), randoms(), - booleans().flatmap(lambda x: booleans() if x else complex_numbers()), - recursive( - base=booleans(), extend=lambda x: lists(x, max_size=3), - max_leaves=10, - ) -] - - -if pytest is not None: - def parametrize(args, values): - return pytest.mark.parametrize( - args, values, ids=list(map(repr, values))) diff -Nru python-hypothesis-3.44.1/tests/common/setup.py python-hypothesis-3.71.11/tests/common/setup.py --- python-hypothesis-3.44.1/tests/common/setup.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/common/setup.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,67 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import os -import warnings -from tempfile import mkdtemp - -from hypothesis import settings, unlimited -from hypothesis.errors import HypothesisDeprecationWarning -from hypothesis.configuration import set_hypothesis_home_dir -from hypothesis.internal.charmap import charmap, charmap_file -from hypothesis.internal.coverage import IN_COVERAGE_TESTS - - -def run(): - warnings.filterwarnings('error', category=UnicodeWarning) - warnings.filterwarnings('error', category=HypothesisDeprecationWarning) - - set_hypothesis_home_dir(mkdtemp()) - - charmap() - assert os.path.exists(charmap_file()), charmap_file() - assert isinstance(settings, type) - - # We do a smoke test here before we mess around with settings. - x = settings() - - import hypothesis._settings as settings_module - - for s in settings_module.all_settings.values(): - v = getattr(x, s.name) - # Check if it has a dynamically defined default and if so skip - # comparison. - if getattr(settings, s.name).show_default: - assert v == s.default, '%r == x.%s != s.%s == %r' % ( - v, s.name, s.name, s.default, - ) - - settings.register_profile('default', settings( - timeout=unlimited, use_coverage=not IN_COVERAGE_TESTS)) - - settings.register_profile('with_coverage', settings( - timeout=unlimited, use_coverage=True, - )) - - settings.register_profile( - 'speedy', settings( - max_examples=5, - )) - - settings.load_profile(os.getenv('HYPOTHESIS_PROFILE', 'default')) diff -Nru python-hypothesis-3.44.1/tests/common/strategies.py python-hypothesis-3.71.11/tests/common/strategies.py --- python-hypothesis-3.44.1/tests/common/strategies.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/common/strategies.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,60 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import time - -from hypothesis.searchstrategy import SearchStrategy -from hypothesis.internal.compat import hrange - - -class _Slow(SearchStrategy): - def do_draw(self, data): - time.sleep(1.0) - data.draw_bytes(2) - return None - - -SLOW = _Slow() - - -class HardToShrink(SearchStrategy): - def __init__(self): - self.__last = None - self.accepted = set() - - def do_draw(self, data): - x = data.draw_bytes(100) - if x in self.accepted: - return True - ls = self.__last - if ls is None: - if all(x): - self.__last = x - self.accepted.add(x) - return True - else: - return False - diffs = [i for i in hrange(len(x)) if x[i] != ls[i]] - if len(diffs) == 1: - i = diffs[0] - if x[i] + 1 == ls[i]: - self.__last = x - self.accepted.add(x) - return True - return False diff -Nru python-hypothesis-3.44.1/tests/common/utils.py python-hypothesis-3.71.11/tests/common/utils.py --- python-hypothesis-3.44.1/tests/common/utils.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/common/utils.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,107 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import sys -import traceback -import contextlib -from io import BytesIO, StringIO - -from hypothesis.errors import HypothesisDeprecationWarning -from hypothesis.reporting import default, with_reporter -from hypothesis.internal.compat import PY2 -from hypothesis.internal.reflection import proxies - - -@contextlib.contextmanager -def capture_out(): - old_out = sys.stdout - try: - new_out = BytesIO() if PY2 else StringIO() - sys.stdout = new_out - with with_reporter(default): - yield new_out - finally: - sys.stdout = old_out - - -class ExcInfo(object): - pass - - -@contextlib.contextmanager -def raises(exctype): - e = ExcInfo() - try: - yield e - assert False, "Expected to raise an exception but didn't" - except exctype as err: - traceback.print_exc() - e.value = err - return - - -def fails_with(e): - def accepts(f): - @proxies(f) - def inverted_test(*arguments, **kwargs): - with raises(e): - f(*arguments, **kwargs) - return inverted_test - return accepts - - -fails = fails_with(AssertionError) - - -@contextlib.contextmanager -def validate_deprecation(): - import warnings - - try: - warnings.simplefilter('always', HypothesisDeprecationWarning) - with warnings.catch_warnings(record=True) as w: - yield - assert any( - e.category == HypothesisDeprecationWarning for e in w - ), 'Expected to get a deprecation warning but got %r' % ( - [e.category for e in w],) - finally: - warnings.simplefilter('error', HypothesisDeprecationWarning) - - -def checks_deprecated_behaviour(func): - """A decorator for testing deprecated behaviour.""" - @proxies(func) - def _inner(*args, **kwargs): - with validate_deprecation(): - return func(*args, **kwargs) - return _inner - - -def all_values(db): - return set(v for vs in db.data.values() for v in vs) - - -def non_covering_examples(database): - return { - v - for k, vs in database.data.items() - if not k.endswith(b'.coverage') - for v in vs - } diff -Nru python-hypothesis-3.44.1/tests/conftest.py python-hypothesis-3.71.11/tests/conftest.py --- python-hypothesis-3.44.1/tests/conftest.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/conftest.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,84 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import gc -import sys -import time as time_module - -import pytest - -from tests.common import TIME_INCREMENT -from tests.common.setup import run -from hypothesis.internal.coverage import IN_COVERAGE_TESTS - -run() - - -def pytest_configure(config): - config.addinivalue_line( - 'markers', - 'slow: pandas expects this marker to exist.') - - -@pytest.fixture(scope=u'function', autouse=True) -def gc_before_each_test(): - gc.collect() - - -@pytest.fixture(scope=u'function', autouse=True) -def consistently_increment_time(monkeypatch): - """Rather than rely on real system time we monkey patch time.time so that - it passes at a consistent rate between calls. - - The reason for this is that when these tests run on travis, performance is - extremely variable and the VM the tests are on might go to sleep for a bit, - introducing arbitrary delays. This can cause a number of tests to fail - flakily. - - Replacing time with a fake version under our control avoids this problem. - - """ - frozen = [False] - - current_time = [time_module.time()] - - def time(): - if not frozen[0]: - current_time[0] += TIME_INCREMENT - return current_time[0] - - def sleep(naptime): - current_time[0] += naptime - - def freeze(): - frozen[0] = True - - monkeypatch.setattr(time_module, 'time', time) - try: - monkeypatch.setattr(time_module, 'monotonic', time) - except AttributeError: - assert sys.version_info[0] == 2 - monkeypatch.setattr(time_module, 'sleep', sleep) - monkeypatch.setattr(time_module, 'freeze', freeze, raising=False) - - -if not IN_COVERAGE_TESTS: - @pytest.fixture(scope=u'function', autouse=True) - def validate_lack_of_trace_function(): - assert sys.gettrace() is None diff -Nru python-hypothesis-3.44.1/tests/cover/__init__.py python-hypothesis-3.71.11/tests/cover/__init__.py --- python-hypothesis-3.44.1/tests/cover/__init__.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/__init__.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER diff -Nru python-hypothesis-3.44.1/tests/cover/test_arbitrary_data.py python-hypothesis-3.71.11/tests/cover/test_arbitrary_data.py --- python-hypothesis-3.44.1/tests/cover/test_arbitrary_data.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_arbitrary_data.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,106 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import pytest - -from hypothesis import strategies as st -from hypothesis import find, given, reporting -from hypothesis.errors import InvalidArgument -from tests.common.utils import raises, capture_out - - -@given(st.integers(), st.data()) -def test_conditional_draw(x, data): - y = data.draw(st.integers(min_value=x)) - assert y >= x - - -def test_prints_on_failure(): - @given(st.data()) - def test(data): - x = data.draw(st.lists(st.integers(), min_size=1)) - y = data.draw(st.sampled_from(x)) - x.remove(y) - if y in x: - raise ValueError() - - with raises(ValueError): - with capture_out() as out: - with reporting.with_reporter(reporting.default): - test() - result = out.getvalue() - assert 'Draw 1: [0, 0]' in result - assert 'Draw 2: 0' in result - - -def test_prints_labels_if_given_on_failure(): - @given(st.data()) - def test(data): - x = data.draw(st.lists(st.integers(), min_size=1), - label='Some numbers') - y = data.draw(st.sampled_from(x), label='A number') - assert y in x - x.remove(y) - assert y not in x - - with raises(AssertionError): - with capture_out() as out: - with reporting.with_reporter(reporting.default): - test() - result = out.getvalue() - assert 'Draw 1 (Some numbers): [0, 0]' in result - assert 'Draw 2 (A number): 0' in result - - -def test_given_twice_is_same(): - @given(st.data(), st.data()) - def test(data1, data2): - data1.draw(st.integers()) - data2.draw(st.integers()) - raise ValueError() - - with raises(ValueError): - with capture_out() as out: - with reporting.with_reporter(reporting.default): - test() - result = out.getvalue() - assert 'Draw 1: 0' in result - assert 'Draw 2: 0' in result - - -def test_errors_when_used_in_find(): - with raises(InvalidArgument): - find(st.data(), lambda x: x.draw(st.booleans())) - - -@pytest.mark.parametrize('f', [ - 'filter', 'map', 'flatmap', -]) -def test_errors_when_normal_strategy_functions_are_used(f): - with raises(InvalidArgument): - getattr(st.data(), f)(lambda x: 1) - - -def test_errors_when_asked_for_example(): - with raises(InvalidArgument): - st.data().example() - - -def test_nice_repr(): - assert repr(st.data()) == 'data()' diff -Nru python-hypothesis-3.44.1/tests/cover/test_argument_validation.py python-hypothesis-3.71.11/tests/cover/test_argument_validation.py --- python-hypothesis-3.44.1/tests/cover/test_argument_validation.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_argument_validation.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,56 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import hypothesis.strategies as st -from tests.common.arguments import e, argument_validation_test - -BAD_ARGS = [] - - -def adjust(ex, **kwargs): - f, a, b = ex - b = dict(b) - b.update(kwargs) - BAD_ARGS.append((f, a, b)) - - -for ex in [ - e(st.lists, st.integers()), - e(st.sets, st.integers()), - e(st.frozensets, st.integers()), - e(st.dictionaries, st.integers(), st.integers()), - e(st.text), - e(st.binary) -]: - adjust(ex, average_size=10, max_size=9), - adjust(ex, average_size=10, min_size=11), - - adjust(ex, min_size=-1) - adjust(ex, average_size=-1) - adjust(ex, max_size=-1) - adjust(ex, min_size='no') - adjust(ex, average_size='no') - adjust(ex, max_size='no') - - -BAD_ARGS.extend([ - e(st.lists, st.nothing(), unique=True, min_size=1), -]) - -test_raise_invalid_argument = argument_validation_test(BAD_ARGS) diff -Nru python-hypothesis-3.44.1/tests/cover/test_bad_repr.py python-hypothesis-3.71.11/tests/cover/test_bad_repr.py --- python-hypothesis-3.44.1/tests/cover/test_bad_repr.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_bad_repr.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,67 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import pytest - -import hypothesis.strategies as st -from hypothesis import given -from hypothesis.internal.compat import PY3 -from hypothesis.internal.reflection import arg_string - - -class BadRepr(object): - - def __init__(self, value): - self.value = value - - def __repr__(self): - return self.value - - -Frosty = BadRepr('☃') - - -def test_just_frosty(): - assert repr(st.just(Frosty)) == 'just(☃)' - - -def test_sampling_snowmen(): - assert repr(st.sampled_from(( - Frosty, 'hi'))) == 'sampled_from((☃, %s))' % (repr('hi'),) - - -def varargs(*args, **kwargs): - pass - - -@pytest.mark.skipif(PY3, reason='Unicode repr is kosher on python 3') -def test_arg_strings_are_bad_repr_safe(): - assert arg_string(varargs, (Frosty,), {}) == '☃' - - -@pytest.mark.skipif(PY3, reason='Unicode repr is kosher on python 3') -def test_arg_string_kwargs_are_bad_repr_safe(): - assert arg_string(varargs, (), {'x': Frosty}) == 'x=☃' - - -@given(st.sampled_from([ - '✐', '✑', '✒', '✓', '✔', '✕', '✖', '✗', '✘', - '✙', '✚', '✛', '✜', '✝', '✞', '✟', '✠', '✡', '✢', '✣'])) -def test_sampled_from_bad_repr(c): - pass diff -Nru python-hypothesis-3.44.1/tests/cover/test_cacheable.py python-hypothesis-3.71.11/tests/cover/test_cacheable.py --- python-hypothesis-3.44.1/tests/cover/test_cacheable.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_cacheable.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import pytest - -import hypothesis.strategies as st - - -@pytest.mark.parametrize('s', [ - st.floats(), - st.tuples(st.integers()), - st.tuples(), - st.one_of(st.integers(), st.text()), -]) -def test_is_cacheable(s): - assert s.is_cacheable - - -@pytest.mark.parametrize('s', [ - st.just([]), - st.tuples(st.integers(), st.just([])), - st.one_of(st.integers(), st.text(), st.just([])), -]) -def test_is_not_cacheable(s): - assert not s.is_cacheable - - -def test_non_cacheable_things_are_not_cached(): - x = st.just([]) - assert st.tuples(x) != st.tuples(x) - - -def test_cacheable_things_are_cached(): - x = st.just(()) - assert st.tuples(x) == st.tuples(x) diff -Nru python-hypothesis-3.44.1/tests/cover/test_cache_implementation.py python-hypothesis-3.71.11/tests/cover/test_cache_implementation.py --- python-hypothesis-3.44.1/tests/cover/test_cache_implementation.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_cache_implementation.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,195 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from random import Random - -import pytest - -import hypothesis.strategies as st -from hypothesis import HealthCheck, note, given, assume, example, settings -from hypothesis.internal.cache import GenericCache, LRUReusedCache - - -class LRUCache(GenericCache): - __slots__ = ('__tick',) - - def __init__(self, max_size): - super(LRUCache, self).__init__(max_size) - self.__tick = 0 - - def new_entry(self, key, value): - return self.tick() - - def on_access(self, key, value, score): - return self.tick() - - def tick(self): - self.__tick += 1 - return self.__tick - - -class LFUCache(GenericCache): - def new_entry(self, key, value): - return 1 - - def on_access(self, key, value, score): - return score + 1 - - -@st.composite -def write_pattern(draw, min_size=0): - keys = draw(st.lists(st.integers(0, 1000), unique=True, min_size=1)) - values = draw(st.lists(st.integers(), unique=True, min_size=1)) - return draw( - st.lists(st.tuples(st.sampled_from(keys), st.sampled_from(values)), - min_size=min_size)) - - -class ValueScored(GenericCache): - def new_entry(self, key, value): - return value - - -class RandomCache(GenericCache): - def __init__(self, max_size): - super(RandomCache, self).__init__(max_size) - self.random = Random(0) - - def new_entry(self, key, value): - return self.random.random() - - def on_access(self, key, value, score): - return self.random.random() - - -@pytest.mark.parametrize( - 'implementation', [ - LRUCache, LFUCache, LRUReusedCache, ValueScored, RandomCache - ] -) -@example(writes=[(0, 0), (3, 0), (1, 0), (2, 0), (2, 0), (1, 0)], size=4) -@example(writes=[(0, 0)], size=1) -@example(writes=[(1, 0), (2, 0), (0, -1), (1, 0)], size=3) -@given(write_pattern(), st.integers(1, 10)) -def test_behaves_like_a_dict_with_losses(implementation, writes, size): - model = {} - target = implementation(max_size=size) - - for k, v in writes: - try: - assert model[k] == target[k] - except KeyError: - pass - model[k] = v - target[k] = v - target.check_valid() - assert target[k] == v - for r, s in model.items(): - try: - assert s == target[r] - except KeyError: - pass - assert len(target) <= min(len(model), size) - - -@settings(suppress_health_check=[HealthCheck.too_slow], deadline=None) -@given(write_pattern(min_size=2), st.data()) -def test_always_evicts_the_lowest_scoring_value(writes, data): - scores = {} - - n_keys = len({k for k, _ in writes}) - - assume(n_keys > 1) - - size = data.draw(st.integers(1, n_keys - 1)) - - evicted = set() - - def new_score(key): - scores[key] = data.draw( - st.integers(0, 1000), label='scores[%r]' % (key,)) - return scores[key] - - last_entry = [None] - - class Cache(GenericCache): - def new_entry(self, key, value): - last_entry[0] = key - evicted.discard(key) - assert key not in scores - return new_score(key) - - def on_access(self, key, value, score): - assert key in scores - return new_score(key) - - def on_evict(self, key, value, score): - note('Evicted %r' % (key,)) - assert score == scores[key] - del scores[key] - if len(scores) > 1: - assert score <= min( - v for k, v in scores.items() - if k != last_entry[0] - ) - evicted.add(key) - - target = Cache(max_size=size) - model = {} - - for k, v in writes: - target[k] = v - model[k] = v - - assert evicted - assert len(evicted) + len(target) == len(model) - assert len(scores) == len(target) - - for k, v in model.items(): - try: - assert target[k] == v - assert k not in evicted - except KeyError: - assert k in evicted - - -def test_basic_access(): - cache = ValueScored(max_size=2) - cache[1] = 0 - cache[1] = 0 - cache[0] = 1 - cache[2] = 0 - assert cache[2] == 0 - assert cache[0] == 1 - assert len(cache) == 2 - - -def test_can_clear_a_cache(): - x = ValueScored(1) - x[0] = 1 - assert len(x) == 1 - x.clear() - assert len(x) == 0 - - -def test_max_size_cache_ignores(): - x = ValueScored(0) - x[0] = 1 - with pytest.raises(KeyError): - x[0] diff -Nru python-hypothesis-3.44.1/tests/cover/test_caching.py python-hypothesis-3.71.11/tests/cover/test_caching.py --- python-hypothesis-3.44.1/tests/cover/test_caching.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_caching.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,56 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import pytest - -import hypothesis.strategies as st -from hypothesis.errors import InvalidArgument - - -def test_no_args(): - assert st.text() is st.text() - - -def test_tuple_lengths(): - assert st.tuples(st.integers()) is st.tuples(st.integers()) - assert st.tuples(st.integers()) is not st.tuples( - st.integers(), st.integers()) - - -def test_values(): - assert st.integers() is not st.integers(min_value=1) - - -def test_alphabet_key(): - assert st.text(alphabet='abcs') is st.text(alphabet='abcs') - - -def test_does_not_error_on_unhashable_posarg(): - st.text(['a', 'b', 'c']) - - -def test_does_not_error_on_unhashable_kwarg(): - with pytest.raises(InvalidArgument): - st.builds(lambda alphabet: 1, alphabet=['a', 'b', 'c']).validate() - - -def test_caches_floats_sensitively(): - assert st.floats(min_value=0.0) is st.floats(min_value=0.0) - assert st.floats(min_value=0.0) is not st.floats(min_value=0) - assert st.floats(min_value=0.0) is not st.floats(min_value=-0.0) diff -Nru python-hypothesis-3.44.1/tests/cover/test_charmap.py python-hypothesis-3.71.11/tests/cover/test_charmap.py --- python-hypothesis-3.44.1/tests/cover/test_charmap.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_charmap.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,171 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import os -import sys -import unicodedata - -import hypothesis.strategies as st -import hypothesis.internal.charmap as cm -from hypothesis import given, assume -from hypothesis.internal.compat import hunichr - - -def test_charmap_contains_all_unicode(): - n = 0 - for vs in cm.charmap().values(): - for u, v in vs: - n += (v - u + 1) - assert n == sys.maxunicode + 1 - - -def test_charmap_has_right_categories(): - for cat, intervals in cm.charmap().items(): - for u, v in intervals: - for i in range(u, v + 1): - real = unicodedata.category(hunichr(i)) - assert real == cat, \ - '%d is %s but reported in %s' % (i, real, cat) - - -def assert_valid_range_list(ls): - for u, v in ls: - assert u <= v - for i in range(len(ls) - 1): - assert ls[i] <= ls[i + 1] - assert ls[i][-1] < ls[i + 1][0] - - -@given( - st.sets(st.sampled_from(cm.categories())), - st.sets(st.sampled_from(cm.categories())) | st.none(), -) -def test_query_matches_categories(exclude, include): - values = cm.query(exclude, include) - assert_valid_range_list(values) - for u, v in values: - for i in (u, v, (u + v) // 2): - cat = unicodedata.category(hunichr(i)) - if include is not None: - assert cat in include - assert cat not in exclude - - -@given( - st.sets(st.sampled_from(cm.categories())), - st.sets(st.sampled_from(cm.categories())) | st.none(), - st.integers(0, sys.maxunicode), st.integers(0, sys.maxunicode), -) -def test_query_matches_categories_codepoints(exclude, include, m1, m2): - m1, m2 = sorted((m1, m2)) - values = cm.query(exclude, include, min_codepoint=m1, max_codepoint=m2) - assert_valid_range_list(values) - for u, v in values: - assert m1 <= u - assert v <= m2 - - -@given(st.sampled_from(cm.categories()), st.integers(0, sys.maxunicode)) -def test_exclude_only_excludes_from_that_category(cat, i): - c = hunichr(i) - assume(unicodedata.category(c) != cat) - intervals = cm.query(exclude_categories=(cat,)) - assert any(a <= i <= b for a, b in intervals) - - -def test_reload_charmap(): - x = cm.charmap() - assert x is cm.charmap() - cm._charmap = None - y = cm.charmap() - assert x is not y - assert x == y - - -def test_recreate_charmap(): - x = cm.charmap() - assert x is cm.charmap() - cm._charmap = None - os.unlink(cm.charmap_file()) - y = cm.charmap() - assert x is not y - assert x == y - - -def test_union_empty(): - assert cm._union_intervals([], []) == () - assert cm._union_intervals([], [[1, 2]]) == ((1, 2),) - assert cm._union_intervals([[1, 2]], []) == ((1, 2),) - - -def test_union_handles_totally_overlapped_gap(): - # < xx > Imagine the intervals x and y as bit strings. - # | The bit at position n is set if n falls inside that interval. - # = In this model _union_intervals() performs bit-wise or. - assert cm._union_intervals([[2, 3]], [[1, 2], [4, 5]]) == ((1, 5),) - - -def test_union_handles_partially_overlapped_gap(): - # < x > Imagine the intervals x and y as bit strings. - # | The bit at position n is set if n falls inside that interval. - # = In this model _union_intervals() performs bit-wise or. - assert cm._union_intervals([[3, 3]], [[1, 2], [5, 5]]) == ((1, 3), (5, 5)) - - -def test_successive_union(): - x = [] - for v in cm.charmap().values(): - x = cm._union_intervals(x, v) - assert x == ((0, sys.maxunicode),) - - -def test_can_handle_race_between_exist_and_create(monkeypatch): - x = cm.charmap() - cm._charmap = None - monkeypatch.setattr(os.path, 'exists', lambda p: False) - y = cm.charmap() - assert x is not y - assert x == y - - -def test_exception_in_write_does_not_lead_to_broken_charmap(monkeypatch): - def broken(*args, **kwargs): - raise ValueError() - - cm._charmap = None - monkeypatch.setattr(os.path, 'exists', lambda p: False) - monkeypatch.setattr(os, 'rename', broken) - - cm.charmap() - cm.charmap() - - -def test_regenerate_broken_charmap_file(): - cm.charmap() - file_loc = cm.charmap_file() - - with open(file_loc, 'wb'): - pass - - cm._charmap = None - cm.charmap() - - -def test_exclude_characters_are_included_in_key(): - assert cm.query() != cm.query(exclude_characters='0') diff -Nru python-hypothesis-3.44.1/tests/cover/test_choices.py python-hypothesis-3.71.11/tests/cover/test_choices.py --- python-hypothesis-3.44.1/tests/cover/test_choices.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_choices.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,60 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import pytest - -import hypothesis.strategies as st -from hypothesis import find, given -from hypothesis.errors import InvalidArgument -from tests.common.utils import checks_deprecated_behaviour - - -@checks_deprecated_behaviour -def test_exhaustion(): - @given(st.lists(st.text(), min_size=10), st.choices()) - def test(ls, choice): - while ls: - s = choice(ls) - assert s in ls - ls.remove(s) - test() - - -@checks_deprecated_behaviour -def test_choice_is_shared(): - @given(st.choices(), st.choices()) - def test(choice1, choice2): - assert choice1 is choice2 - test() - - -@checks_deprecated_behaviour -def test_cannot_use_choices_within_find(): - with pytest.raises(InvalidArgument): - find(st.choices(), lambda c: True) - - -@checks_deprecated_behaviour -def test_fails_to_draw_from_empty_sequence(): - @given(st.choices()) - def test(choice): - choice([]) - - with pytest.raises(IndexError): - test() diff -Nru python-hypothesis-3.44.1/tests/cover/test_completion.py python-hypothesis-3.71.11/tests/cover/test_completion.py --- python-hypothesis-3.44.1/tests/cover/test_completion.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_completion.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from hypothesis import strategies as st -from hypothesis import given, settings - - -@given(st.data()) -def test_never_draw_anything(data): - pass - - -@settings(min_satisfying_examples=1000) -@given(st.booleans()) -def test_want_more_than_exist(b): - pass diff -Nru python-hypothesis-3.44.1/tests/cover/test_composite.py python-hypothesis-3.71.11/tests/cover/test_composite.py --- python-hypothesis-3.44.1/tests/cover/test_composite.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_composite.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,146 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import pytest -from flaky import flaky - -import hypothesis.strategies as st -from hypothesis import find, given, assume -from hypothesis.errors import InvalidArgument -from tests.common.debug import minimal -from hypothesis.internal.compat import hrange - - -@st.composite -def badly_draw_lists(draw, m=0): - length = draw(st.integers(m, m + 10)) - return [ - draw(st.integers()) for _ in hrange(length) - ] - - -def test_simplify_draws(): - assert find(badly_draw_lists(), lambda x: len(x) >= 3) == [0] * 3 - - -def test_can_pass_through_arguments(): - assert find(badly_draw_lists(5), lambda x: True) == [0] * 5 - assert find(badly_draw_lists(m=6), lambda x: True) == [0] * 6 - - -@st.composite -def draw_ordered_with_assume(draw): - x = draw(st.floats()) - y = draw(st.floats()) - assume(x < y) - return (x, y) - - -@given(draw_ordered_with_assume()) -def test_can_assume_in_draw(xy): - assert xy[0] < xy[1] - - -def test_uses_definitions_for_reprs(): - assert repr(badly_draw_lists()) == 'badly_draw_lists()' - assert repr(badly_draw_lists(1)) == 'badly_draw_lists(m=1)' - assert repr(badly_draw_lists(m=1)) == 'badly_draw_lists(m=1)' - - -def test_errors_given_default_for_draw(): - with pytest.raises(InvalidArgument): - @st.composite - def foo(x=None): - pass - - -def test_errors_given_function_of_no_arguments(): - with pytest.raises(InvalidArgument): - @st.composite - def foo(): - pass - - -def test_errors_given_kwargs_only(): - with pytest.raises(InvalidArgument): - @st.composite - def foo(**kwargs): - pass - - -def test_can_use_pure_args(): - @st.composite - def stuff(*args): - return args[0](st.sampled_from(args[1:])) - assert find(stuff(1, 2, 3, 4, 5), lambda x: True) == 1 - - -def test_composite_of_lists(): - @st.composite - def f(draw): - return draw(st.integers()) + draw(st.integers()) - - assert find(st.lists(f()), lambda x: len(x) >= 10) == [0] * 10 - - -@flaky(min_passes=5, max_runs=5) -def test_can_shrink_matrices_with_length_param(): - @st.composite - def matrix(draw): - rows = draw(st.integers(1, 10)) - columns = draw(st.integers(1, 10)) - return [ - [draw(st.integers(0, 10000)) for _ in range(columns)] - for _ in range(rows) - ] - - def transpose(m): - rows = len(m) - columns = len(m[0]) - result = [ - [None] * rows - for _ in range(columns) - ] - for i in range(rows): - for j in range(columns): - result[j][i] = m[i][j] - return result - - def is_square(m): - return len(m) == len(m[0]) - - value = minimal(matrix(), lambda m: is_square(m) and transpose(m) != m) - assert len(value) == 2 - assert len(value[0]) == 2 - assert sorted(value[0] + value[1]) == [0, 0, 0, 1] - - -class MyList(list): - pass - - -@given(st.data(), st.lists(st.integers()).map(MyList)) -def test_does_not_change_arguments(data, ls): - # regression test for issue #1017 or other argument mutation - @st.composite - def strat(draw, arg): - return arg - - ex = data.draw(strat(ls)) - assert ex is ls diff -Nru python-hypothesis-3.44.1/tests/cover/test_conjecture_engine.py python-hypothesis-3.71.11/tests/cover/test_conjecture_engine.py --- python-hypothesis-3.44.1/tests/cover/test_conjecture_engine.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_conjecture_engine.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,778 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import time -from random import seed as seed_random -from random import Random - -import pytest - -from hypothesis import Phase, HealthCheck, settings, unlimited -from hypothesis.errors import FailedHealthCheck -from tests.common.utils import all_values, checks_deprecated_behaviour -from hypothesis.database import ExampleDatabase, InMemoryExampleDatabase -from tests.common.strategies import SLOW, HardToShrink -from hypothesis.internal.compat import hbytes, hrange, int_from_bytes -from hypothesis.internal.conjecture.data import Status, ConjectureData -from hypothesis.internal.conjecture.engine import ConjectureRunner - -MAX_SHRINKS = 1000 - - -def run_to_buffer(f): - runner = ConjectureRunner(f, settings=settings( - max_examples=5000, max_iterations=10000, max_shrinks=MAX_SHRINKS, - buffer_size=1024, - database=None, perform_health_check=False, - )) - runner.run() - assert runner.last_data.status == Status.INTERESTING - return hbytes(runner.last_data.buffer) - - -def test_can_index_results(): - @run_to_buffer - def f(data): - data.draw_bytes(5) - data.mark_interesting() - assert f.index(0) == 0 - assert f.count(0) == 5 - - -def test_non_cloneable_intervals(): - @run_to_buffer - def x(data): - data.draw_bytes(10) - data.draw_bytes(9) - data.mark_interesting() - assert x == hbytes(19) - - -def test_duplicate_buffers(): - @run_to_buffer - def x(data): - t = data.draw_bytes(10) - if not any(t): - data.mark_invalid() - s = data.draw_bytes(10) - if s == t: - data.mark_interesting() - assert x == hbytes([0] * 9 + [1]) * 2 - - -def test_deletable_draws(): - @run_to_buffer - def x(data): - while True: - x = data.draw_bytes(2) - if x[0] == 255: - data.mark_interesting() - assert x == hbytes([255, 0]) - - -def zero_dist(random, n): - return hbytes(n) - - -def test_can_load_data_from_a_corpus(): - key = b'hi there' - db = ExampleDatabase() - value = b'=\xc3\xe4l\x81\xe1\xc2H\xc9\xfb\x1a\xb6bM\xa8\x7f' - db.save(key, value) - - def f(data): - if data.draw_bytes(len(value)) == value: - data.mark_interesting() - runner = ConjectureRunner( - f, settings=settings(database=db), database_key=key) - runner.run() - assert runner.last_data.status == Status.INTERESTING - assert runner.last_data.buffer == value - assert len(list(db.fetch(key))) == 1 - - -def slow_shrinker(): - strat = HardToShrink() - - def accept(data): - if data.draw(strat): - data.mark_interesting() - return accept - - -@pytest.mark.parametrize('n', [1, 5]) -def test_terminates_shrinks(n, monkeypatch): - db = InMemoryExampleDatabase() - - def generate_new_examples(self): - def draw_bytes(data, n): - return hbytes([255] * n) - - self.test_function(ConjectureData( - draw_bytes=draw_bytes, max_length=self.settings.buffer_size)) - - monkeypatch.setattr( - ConjectureRunner, 'generate_new_examples', generate_new_examples) - - runner = ConjectureRunner(slow_shrinker(), settings=settings( - max_examples=5000, max_iterations=10000, max_shrinks=n, - database=db, timeout=unlimited, - ), random=Random(0), database_key=b'key') - runner.run() - assert runner.last_data.status == Status.INTERESTING - assert runner.shrinks == n - in_db = set( - v - for vs in db.data.values() - for v in vs - ) - assert len(in_db) == n + 1 - - -def test_detects_flakiness(): - failed_once = [False] - count = [0] - - def tf(data): - data.draw_bytes(1) - count[0] += 1 - if not failed_once[0]: - failed_once[0] = True - data.mark_interesting() - runner = ConjectureRunner(tf) - runner.run() - assert count == [2] - - -def test_variadic_draw(): - def draw_list(data): - result = [] - while True: - data.start_example() - d = data.draw_bytes(1)[0] & 7 - if d: - result.append(data.draw_bytes(d)) - data.stop_example() - if not d: - break - return result - - @run_to_buffer - def b(data): - if any(all(d) for d in draw_list(data)): - data.mark_interesting() - ls = draw_list(ConjectureData.for_buffer(b)) - assert len(ls) == 1 - assert len(ls[0]) == 1 - - -def test_draw_to_overrun(): - @run_to_buffer - def x(data): - d = (data.draw_bytes(1)[0] - 8) & 0xff - data.draw_bytes(128 * d) - if d >= 2: - data.mark_interesting() - assert x == hbytes([10]) + hbytes(128 * 2) - - -def test_can_navigate_to_a_valid_example(): - def f(data): - i = int_from_bytes(data.draw_bytes(2)) - data.draw_bytes(i) - data.mark_interesting() - runner = ConjectureRunner(f, settings=settings( - max_examples=5000, max_iterations=10000, - buffer_size=2, - database=None, - )) - runner.run() - assert runner.last_data.status == Status.INTERESTING - return hbytes(runner.last_data.buffer) - - -def test_stops_after_max_iterations_when_generating(): - key = b'key' - value = b'rubber baby buggy bumpers' - max_iterations = 100 - - db = ExampleDatabase(':memory:') - db.save(key, value) - - seen = [] - - def f(data): - seen.append(data.draw_bytes(len(value))) - data.mark_invalid() - - runner = ConjectureRunner(f, settings=settings( - max_examples=1, max_iterations=max_iterations, - database=db, perform_health_check=False, - ), database_key=key) - runner.run() - assert len(seen) == max_iterations - assert value in seen - - -def test_stops_after_max_iterations_when_reading(): - key = b'key' - max_iterations = 1 - - db = ExampleDatabase(':memory:') - for i in range(10): - db.save(key, hbytes([i])) - - seen = [] - - def f(data): - seen.append(data.draw_bytes(1)) - data.mark_invalid() - - runner = ConjectureRunner(f, settings=settings( - max_examples=1, max_iterations=max_iterations, - database=db, - ), database_key=key) - runner.run() - assert len(seen) == max_iterations - - -def test_stops_after_max_examples_when_reading(): - key = b'key' - - db = ExampleDatabase(':memory:') - for i in range(10): - db.save(key, hbytes([i])) - - seen = [] - - def f(data): - seen.append(data.draw_bytes(1)) - - runner = ConjectureRunner(f, settings=settings( - max_examples=1, - database=db, - ), database_key=key) - runner.run() - assert len(seen) == 1 - - -def test_stops_after_max_examples_when_generating(): - seen = [] - - def f(data): - seen.append(data.draw_bytes(1)) - - runner = ConjectureRunner(f, settings=settings( - max_examples=1, - database=None, - )) - runner.run() - assert len(seen) == 1 - - -def test_interleaving_engines(): - children = [] - - @run_to_buffer - def x(data): - rnd = Random(data.draw_bytes(1)) - - def g(d2): - d2.draw_bytes(1) - data.mark_interesting() - runner = ConjectureRunner(g, random=rnd) - children.append(runner) - runner.run() - assert x == b'\0' - for c in children: - assert not c.interesting_examples - - -@checks_deprecated_behaviour -def test_run_with_timeout_while_shrinking(): - def f(data): - time.sleep(0.1) - x = data.draw_bytes(32) - if any(x): - data.mark_interesting() - - runner = ConjectureRunner( - f, settings=settings(database=None, timeout=0.2)) - start = time.time() - runner.run() - assert time.time() <= start + 1 - assert runner.last_data.status == Status.INTERESTING - - -@checks_deprecated_behaviour -def test_run_with_timeout_while_boring(): - def f(data): - time.sleep(0.1) - - runner = ConjectureRunner( - f, settings=settings(database=None, timeout=0.2)) - start = time.time() - runner.run() - assert time.time() <= start + 1 - assert runner.last_data.status == Status.VALID - - -def test_max_shrinks_can_disable_shrinking(): - seen = set() - - def f(data): - seen.add(hbytes(data.draw_bytes(32))) - data.mark_interesting() - - runner = ConjectureRunner( - f, settings=settings(database=None, max_shrinks=0,)) - runner.run() - assert len(seen) == 1 - - -def test_phases_can_disable_shrinking(): - seen = set() - - def f(data): - seen.add(hbytes(data.draw_bytes(32))) - data.mark_interesting() - - runner = ConjectureRunner(f, settings=settings( - database=None, phases=(Phase.reuse, Phase.generate), - )) - runner.run() - assert len(seen) == 1 - - -def test_erratic_draws(): - n = [0] - - @run_to_buffer - def x(data): - data.draw_bytes(n[0]) - data.draw_bytes(255 - n[0]) - if n[0] == 255: - data.mark_interesting() - else: - n[0] += 1 - - -def test_no_read_no_shrink(): - count = [0] - - @run_to_buffer - def x(data): - count[0] += 1 - data.mark_interesting() - assert x == b'' - assert count == [1] - - -def test_one_dead_branch(): - seed_random(0) - seen = set() - - @run_to_buffer - def x(data): - i = data.draw_bytes(1)[0] - if i > 0: - data.mark_invalid() - i = data.draw_bytes(1)[0] - if len(seen) < 255: - seen.add(i) - elif i not in seen: - data.mark_interesting() - - -def test_fully_exhaust_base(monkeypatch): - """In this test we generate all possible values for the first byte but - never get to the point where we exhaust the root of the tree.""" - seed_random(0) - - seen = set() - - def f(data): - key = data.draw_bytes(2) - assert key not in seen - seen.add(key) - - runner = ConjectureRunner(f, settings=settings( - max_examples=10000, max_iterations=10000, max_shrinks=0, - buffer_size=1024, - database=None, - )) - - def call_with(buf): - buf = hbytes(buf) - - def draw_bytes(data, n): - return runner._ConjectureRunner__rewrite_for_novelty( - data, buf[data.index:data.index + n]) - d = ConjectureData( - draw_bytes=draw_bytes, max_length=2 - ) - runner.test_function(d) - return d - - # First we ensure that all children of 0 are dead. - for c in hrange(256): - call_with([0, c]) - - assert 1 in runner.dead - - # This must rewrite the first byte in order to get to a non-dead node. - assert call_with([0, 0]).buffer == hbytes([1, 0]) - - # This must rewrite the first byte in order to get to a non-dead node, but - # the result of doing that is *still* dead, so it must rewrite the second - # byte too. - assert call_with([0, 0]).buffer == hbytes([1, 1]) - - -def test_will_save_covering_examples(): - tags = {} - - def tagged(data): - b = hbytes(data.draw_bytes(4)) - try: - tag = tags[b] - except KeyError: - if len(tags) < 10: - tag = len(tags) - tags[b] = tag - else: - tag = None - if tag is not None: - data.add_tag(tag) - - db = InMemoryExampleDatabase() - runner = ConjectureRunner(tagged, settings=settings( - max_examples=100, max_iterations=10000, max_shrinks=0, - buffer_size=1024, - database=db, - ), database_key=b'stuff') - runner.run() - assert len(all_values(db)) == len(tags) - - -def test_will_shrink_covering_examples(): - best = [None] - replaced = [] - - def tagged(data): - b = hbytes(data.draw_bytes(4)) - if any(b): - data.add_tag('nonzero') - if best[0] is None: - best[0] = b - elif b < best[0]: - replaced.append(best[0]) - best[0] = b - - db = InMemoryExampleDatabase() - runner = ConjectureRunner(tagged, settings=settings( - max_examples=100, max_iterations=10000, max_shrinks=0, - buffer_size=1024, - database=db, - ), database_key=b'stuff') - runner.run() - saved = set(all_values(db)) - assert best[0] in saved - for r in replaced: - assert r not in saved - - -def test_can_cover_without_a_database_key(): - def tagged(data): - data.add_tag(0) - - runner = ConjectureRunner(tagged, settings=settings(), database_key=None) - runner.run() - assert len(runner.covering_examples) == 1 - - -def test_saves_on_interrupt(): - def interrupts(data): - raise KeyboardInterrupt() - - db = InMemoryExampleDatabase() - - runner = ConjectureRunner( - interrupts, settings=settings(database=db), database_key=b'key') - - with pytest.raises(KeyboardInterrupt): - runner.run() - assert db.data - - -def test_returns_written(): - value = hbytes(b'\0\1\2\3') - - @run_to_buffer - def written(data): - data.write(value) - data.mark_interesting() - - assert value == written - - -def fails_health_check(label): - def accept(f): - runner = ConjectureRunner(f, settings=settings( - max_examples=100, max_iterations=100, max_shrinks=0, - buffer_size=1024, database=None, perform_health_check=True, - )) - - with pytest.raises(FailedHealthCheck) as e: - runner.run() - assert e.value.health_check == label - assert not runner.interesting_examples - return accept - - -def test_fails_health_check_for_all_invalid(): - @fails_health_check(HealthCheck.filter_too_much) - def _(data): - data.draw_bytes(2) - data.mark_invalid() - - -def test_fails_health_check_for_large_base(): - @fails_health_check(HealthCheck.large_base_example) - def _(data): - data.draw_bytes(10 ** 6) - - -def test_fails_health_check_for_large_non_base(): - @fails_health_check(HealthCheck.data_too_large) - def _(data): - if data.draw_bits(8): - data.draw_bytes(10 ** 6) - - -def test_fails_health_check_for_slow_draws(): - @fails_health_check(HealthCheck.too_slow) - def _(data): - data.draw(SLOW) - - -def test_fails_healthcheck_for_hung_test(): - @fails_health_check(HealthCheck.hung_test) - def _(data): - data.draw_bytes(1) - time.sleep(3600) - - -@pytest.mark.parametrize('n_large', [1, 5, 8, 15]) -def test_can_shrink_variable_draws(n_large): - target = 128 * n_large - - @run_to_buffer - def x(data): - n = data.draw_bits(4) - b = [data.draw_bits(8) for _ in hrange(n)] - if sum(b) >= target: - data.mark_interesting() - assert x.count(0) == 0 - assert sum(x[1:]) == target - - -def test_run_nothing(): - def f(data): - assert False - - runner = ConjectureRunner(f, settings=settings(phases=())) - runner.run() - assert runner.call_count == 0 - - -class Foo(object): - def __repr__(self): - return 'stuff' - - -@pytest.mark.parametrize('event', ['hi', Foo()]) -def test_note_events(event): - def f(data): - data.note_event(event) - data.draw_bytes(1) - - runner = ConjectureRunner(f) - runner.run() - assert runner.event_call_counts[str(event)] == runner.call_count > 0 - - -def test_zeroes_bytes_above_bound(): - def f(data): - if data.draw_bits(1): - x = data.draw_bytes(9) - assert not any(x[4:8]) - - ConjectureRunner(f, settings=settings(buffer_size=10)).run() - - -def test_can_write_bytes_towards_the_end(): - buf = b'\1\2\3' - - def f(data): - if data.draw_bits(1): - data.draw_bytes(5) - data.write(hbytes(buf)) - assert hbytes(data.buffer[-len(buf):]) == buf - - ConjectureRunner(f, settings=settings(buffer_size=10)).run() - - -def test_can_increase_number_of_bytes_drawn_in_tail(): - # This is designed to trigger a case where the zero bound queue will end up - # increasing the size of data drawn because moving zeroes into the initial - # prefix will increase the amount drawn. - def f(data): - x = data.draw_bytes(5) - n = x.count(0) - b = data.draw_bytes(n + 1) - assert not any(b[:-1]) - - runner = ConjectureRunner( - f, settings=settings(buffer_size=11, perform_health_check=False)) - - runner.run() - - -@pytest.mark.xfail( - strict=True, - reason="""This is currently demonstrating that __rewrite_for_novelty is -broken. It should start passing once we have a more sensible deduplication -mechanism.""") -def test_uniqueness_is_preserved_when_writing_at_beginning(): - seen = set() - - def f(data): - data.write(hbytes(1)) - n = data.draw_bits(3) - assert n not in seen - seen.add(n) - - runner = ConjectureRunner( - f, settings=settings(max_examples=50)) - runner.run() - assert runner.valid_examples == len(seen) - - -@pytest.mark.parametrize('skip_target', [False, True]) -@pytest.mark.parametrize('initial_attempt', [127, 128]) -def test_clears_out_its_database_on_shrinking( - initial_attempt, skip_target, monkeypatch -): - def generate_new_examples(self): - self.test_function( - ConjectureData.for_buffer(hbytes([initial_attempt]))) - - monkeypatch.setattr( - ConjectureRunner, 'generate_new_examples', generate_new_examples) - - key = b'key' - db = InMemoryExampleDatabase() - - def f(data): - if data.draw_bits(8) >= 127: - data.mark_interesting() - - runner = ConjectureRunner( - f, settings=settings(database=db, max_examples=256), database_key=key, - random=Random(0), - ) - - for n in hrange(256): - if n != 127 or not skip_target: - db.save(runner.secondary_key, hbytes([n])) - runner.run() - assert len(runner.interesting_examples) == 1 - for b in db.fetch(runner.secondary_key): - assert b[0] >= 127 - assert len(list(db.fetch(runner.database_key))) == 1 - - -def test_saves_negated_examples_in_covering(): - def f(data): - if data.draw_bits(8) & 1: - data.add_tag('hi') - - runner = ConjectureRunner(f) - runner.run() - assert len(runner.target_selector.examples_by_tags) == 3 - - -def test_can_delete_intervals(monkeypatch): - def generate_new_examples(self): - self.test_function( - ConjectureData.for_buffer(hbytes([255] * 10 + [0]))) - - monkeypatch.setattr( - ConjectureRunner, 'generate_new_examples', generate_new_examples) - monkeypatch.setattr( - ConjectureRunner, 'shrink', ConjectureRunner.greedy_interval_deletion - ) - - def f(data): - if data.draw_bits(1): - while data.draw_bits(8): - pass - data.mark_interesting() - runner = ConjectureRunner(f, settings=settings(database=None)) - runner.run() - x, = runner.interesting_examples.values() - assert x.buffer == hbytes([1, 0]) - - -def test_shrinks_both_interesting_examples(monkeypatch): - def generate_new_examples(self): - self.test_function(ConjectureData.for_buffer(hbytes([1]))) - - monkeypatch.setattr( - ConjectureRunner, 'generate_new_examples', generate_new_examples) - - def f(data): - n = data.draw_bits(8) - data.mark_interesting(n & 1) - runner = ConjectureRunner(f, database_key=b'key') - runner.run() - assert runner.interesting_examples[0].buffer == hbytes([0]) - assert runner.interesting_examples[1].buffer == hbytes([1]) - - -def test_reorder_blocks(monkeypatch): - target = hbytes([1, 2, 3]) - - def generate_new_examples(self): - self.test_function(ConjectureData.for_buffer(hbytes(reversed(target)))) - - monkeypatch.setattr( - ConjectureRunner, 'generate_new_examples', generate_new_examples) - monkeypatch.setattr( - ConjectureRunner, 'shrink', ConjectureRunner.reorder_blocks) - - @run_to_buffer - def x(data): - if sorted( - data.draw_bits(8) for _ in hrange(len(target)) - ) == sorted(target): - data.mark_interesting() - - assert x == target diff -Nru python-hypothesis-3.44.1/tests/cover/test_conjecture_float_encoding.py python-hypothesis-3.71.11/tests/cover/test_conjecture_float_encoding.py --- python-hypothesis-3.44.1/tests/cover/test_conjecture_float_encoding.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_conjecture_float_encoding.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,227 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import sys -from random import Random - -import pytest - -import hypothesis.internal.conjecture.floats as flt -from hypothesis import strategies as st -from hypothesis import given, assume, example -from hypothesis.internal.compat import ceil, floor, hbytes, int_to_bytes, \ - int_from_bytes -from hypothesis.internal.floats import float_to_int -from hypothesis.internal.conjecture.data import ConjectureData -from hypothesis.internal.conjecture.minimizer import minimize - -EXPONENTS = list(range(0, flt.MAX_EXPONENT + 1)) -assert len(EXPONENTS) == 2 ** 11 - - -def assert_reordered_exponents(res): - res = list(res) - assert len(res) == len(EXPONENTS) - for x in res: - assert res.count(x) == 1 - assert 0 <= x <= flt.MAX_EXPONENT - - -def test_encode_permutes_elements(): - assert_reordered_exponents(map(flt.encode_exponent, EXPONENTS)) - - -def test_decode_permutes_elements(): - assert_reordered_exponents(map(flt.decode_exponent, EXPONENTS)) - - -def test_decode_encode(): - for e in EXPONENTS: - assert flt.decode_exponent(flt.encode_exponent(e)) == e - - -def test_encode_decode(): - for e in EXPONENTS: - assert flt.decode_exponent(flt.encode_exponent(e)) == e - - -@given(st.data()) -def test_double_reverse_bounded(data): - n = data.draw(st.integers(1, 64)) - i = data.draw(st.integers(0, 2 ** n - 1)) - j = flt.reverse_bits(i, n) - assert flt.reverse_bits(j, n) == i - - -@given(st.integers(0, 2 ** 64 - 1)) -def test_double_reverse(i): - j = flt.reverse64(i) - assert flt.reverse64(j) == i - - -@example(1.25) -@example(1.0) -@given(st.floats()) -def test_draw_write_round_trip(f): - d = ConjectureData.for_buffer(hbytes(10)) - flt.write_float(d, f) - d2 = ConjectureData.for_buffer(d.buffer) - g = flt.draw_float(d2) - - if f == f: - assert f == g - - assert float_to_int(f) == float_to_int(g) - - d3 = ConjectureData.for_buffer(d2.buffer) - flt.draw_float(d3) - assert d3.buffer == d2.buffer - - -@example(0.0) -@example(2.5) -@example(8.000000000000007) -@example(3.0) -@example(2.0) -@example(1.9999999999999998) -@example(1.0) -@given(st.floats(min_value=0.0)) -def test_floats_round_trip(f): - i = flt.float_to_lex(f) - g = flt.lex_to_float(i) - - assert float_to_int(f) == float_to_int(g) - - -@example(1, 0.5) -@given( - st.integers(1, 2 ** 53), st.floats(0, 1).filter(lambda x: x not in (0, 1)) -) -def test_floats_order_worse_than_their_integral_part(n, g): - f = n + g - assume(int(f) != f) - assume(int(f) != 0) - i = flt.float_to_lex(f) - if f < 0: - g = ceil(f) - else: - g = floor(f) - - assert flt.float_to_lex(float(g)) < i - - -integral_floats = st.floats( - allow_infinity=False, allow_nan=False, min_value=0.0 -).map(lambda x: float(int(x))) - - -@given(integral_floats, integral_floats) -def test_integral_floats_order_as_integers(x, y): - assume(x != y) - x, y = sorted((x, y)) - assume(y < 0 or x > 0) - if y < 0: - assert flt.float_to_lex(y) < flt.float_to_lex(x) - else: - assert flt.float_to_lex(x) < flt.float_to_lex(y) - - -@given(st.floats(0, 1)) -def test_fractional_floats_are_worse_than_one(f): - assume(0 < f < 1) - assert flt.float_to_lex(f) > flt.float_to_lex(1) - - -def test_reverse_bits_table_reverses_bits(): - def bits(x): - result = [] - for _ in range(8): - result.append(x & 1) - x >>= 1 - result.reverse() - return result - - for i, b in enumerate(flt.REVERSE_BITS_TABLE): - assert bits(i) == list(reversed(bits(b))) - - -def test_reverse_bits_table_has_right_elements(): - assert sorted(flt.REVERSE_BITS_TABLE) == list(range(256)) - - -def minimal_from(start, condition): - buf = int_to_bytes(flt.float_to_lex(start), 8) - - def parse_buf(b): - return flt.lex_to_float(int_from_bytes(b)) - - shrunk = minimize( - buf, lambda b: condition(parse_buf(b)), - full=True, random=Random(0) - ) - return parse_buf(shrunk) - - -INTERESTING_FLOATS = [ - 0.0, 1.0, 2.0, sys.float_info.max, float('inf'), float('nan') -] - - -@pytest.mark.parametrize(('start', 'end'), [ - (a, b) - for a in INTERESTING_FLOATS - for b in INTERESTING_FLOATS - if flt.float_to_lex(a) > flt.float_to_lex(b) -]) -def test_can_shrink_downwards(start, end): - assert minimal_from(start, lambda x: not (x < end)) == end - - -@pytest.mark.parametrize( - 'f', [1, 2, 4, 8, 10, 16, 32, 64, 100, 128, 256, 500, 512, 1000, 1024] -) -@pytest.mark.parametrize( - 'mul', [1.1, 1.5, 9.99, 10] -) -def test_shrinks_downwards_to_integers(f, mul): - g = minimal_from(f * mul, lambda x: x >= f) - assert g == f - - -def test_shrink_to_integer_upper_bound(): - assert minimal_from(1.1, lambda x: 1 < x <= 2) == 2 - - -def test_shrink_up_to_one(): - assert minimal_from(0.5, lambda x: 0.5 <= x <= 1.5) == 1 - - -def test_shrink_down_to_half(): - assert minimal_from(0.75, lambda x: 0 < x < 1) == 0.5 - - -def test_does_not_shrink_across_one(): - # This is something of an odd special case. Because of our encoding we - # prefer all numbers >= 1 to all numbers in 0 < x < 1. For the most part - # this is the correct thing to do, but there are some low negative exponent - # cases where we get odd behaviour like this. - - # This test primarily exists to validate that we don't try to subtract one - # from the starting point and trigger an internal exception. - assert minimal_from(1.1, lambda x: x == 1.1 or 0 < x < 1) == 1.1 diff -Nru python-hypothesis-3.44.1/tests/cover/test_conjecture_minimizer.py python-hypothesis-3.71.11/tests/cover/test_conjecture_minimizer.py --- python-hypothesis-3.44.1/tests/cover/test_conjecture_minimizer.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_conjecture_minimizer.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from random import Random - -from hypothesis.internal.compat import hbytes -from hypothesis.internal.conjecture.minimizer import minimize - - -def test_shrink_to_zero(): - assert minimize( - hbytes([255] * 8), lambda x: True, random=Random(0)) == hbytes(8) - - -def test_shrink_to_smallest(): - assert minimize( - hbytes([255] * 8), lambda x: sum(x) > 10, random=Random(0), - ) == hbytes([0] * 7 + [11]) - - -def test_float_hack_fails(): - assert minimize( - hbytes([255] * 8), lambda x: x[0] >> 7, random=Random(0), - ) == hbytes([128] + [0] * 7) diff -Nru python-hypothesis-3.44.1/tests/cover/test_conjecture_test_data.py python-hypothesis-3.71.11/tests/cover/test_conjecture_test_data.py --- python-hypothesis-3.44.1/tests/cover/test_conjecture_test_data.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_conjecture_test_data.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,120 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import pytest - -from hypothesis import strategies as st -from hypothesis import given -from hypothesis.errors import Frozen -from hypothesis.internal.conjecture.data import Status, StopTest, \ - ConjectureData -from hypothesis.searchstrategy.strategies import SearchStrategy - - -@given(st.binary()) -def test_buffer_draws_as_self(buf): - x = ConjectureData.for_buffer(buf) - assert x.draw_bytes(len(buf)) == buf - - -def test_cannot_draw_after_freeze(): - x = ConjectureData.for_buffer(b'hi') - x.draw_bytes(1) - x.freeze() - with pytest.raises(Frozen): - x.draw_bytes(1) - - -def test_can_double_freeze(): - x = ConjectureData.for_buffer(b'hi') - x.freeze() - assert x.frozen - x.freeze() - assert x.frozen - - -def test_can_draw_zero_bytes(): - x = ConjectureData.for_buffer(b'') - for _ in range(10): - assert x.draw_bytes(0) == b'' - - -def test_draw_past_end_sets_overflow(): - x = ConjectureData.for_buffer(bytes(5)) - with pytest.raises(StopTest) as e: - x.draw_bytes(6) - assert e.value.testcounter == x.testcounter - assert x.frozen - assert x.status == Status.OVERRUN - - -def test_notes_repr(): - x = ConjectureData.for_buffer(b'') - x.note(b'hi') - assert repr(b'hi') in x.output - - -def test_can_mark_interesting(): - x = ConjectureData.for_buffer(bytes()) - with pytest.raises(StopTest): - x.mark_interesting() - assert x.frozen - assert x.status == Status.INTERESTING - - -def test_drawing_zero_bits_is_free(): - x = ConjectureData.for_buffer(bytes()) - assert x.draw_bits(0) == 0 - - -def test_can_mark_invalid(): - x = ConjectureData.for_buffer(bytes()) - with pytest.raises(StopTest): - x.mark_invalid() - assert x.frozen - assert x.status == Status.INVALID - - -class BoomStrategy(SearchStrategy): - - def do_draw(self, data): - data.draw_bytes(1) - raise ValueError() - - -def test_closes_interval_on_error_in_strategy(): - x = ConjectureData.for_buffer(b'hi') - with pytest.raises(ValueError): - x.draw(BoomStrategy()) - x.freeze() - assert len(x.intervals) == 1 - - -class BigStrategy(SearchStrategy): - - def do_draw(self, data): - data.draw_bytes(10 ** 6) - - -def test_does_not_double_freeze_in_interval_close(): - x = ConjectureData.for_buffer(b'hi') - with pytest.raises(StopTest): - x.draw(BigStrategy()) - assert x.frozen - assert len(x.intervals) == 0 diff -Nru python-hypothesis-3.44.1/tests/cover/test_conjecture_utils.py python-hypothesis-3.71.11/tests/cover/test_conjecture_utils.py --- python-hypothesis-3.44.1/tests/cover/test_conjecture_utils.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_conjecture_utils.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,120 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from collections import Counter - -import hypothesis.internal.conjecture.utils as cu -from hypothesis.internal.compat import hbytes -from hypothesis.internal.conjecture.data import ConjectureData - - -def test_does_not_draw_data_for_empty_range(): - assert cu.integer_range(ConjectureData.for_buffer(b''), 1, 1) == 1 - - -def test_uniform_float_shrinks_to_zero(): - d = ConjectureData.for_buffer(hbytes([0] * 7)) - assert cu.fractional_float(d) == 0.0 - assert len(d.buffer) == 7 - - -def test_uniform_float_can_draw_1(): - d = ConjectureData.for_buffer(hbytes([255] * 7)) - assert cu.fractional_float(d) == 1.0 - assert len(d.buffer) == 7 - - -def test_geometric_can_handle_bad_first_draw(): - assert cu.geometric(ConjectureData.for_buffer(hbytes( - [255] * 7 + [0] * 7)), 0.5) == 0 - - -def test_coin_biased_towards_truth(): - p = 1 - 1.0 / 500 - - for i in range(255): - assert cu.biased_coin( - ConjectureData.for_buffer([i]), p - ) - - second_order = [ - cu.biased_coin(ConjectureData.for_buffer([255, i]), p) - for i in range(255) - ] - - assert False in second_order - assert True in second_order - - -def test_coin_biased_towards_falsehood(): - p = 1.0 / 500 - - for i in range(255): - assert not cu.biased_coin( - ConjectureData.for_buffer([i]), p - ) - - second_order = [ - cu.biased_coin(ConjectureData.for_buffer([255, i]), p) - for i in range(255) - ] - - assert False in second_order - assert True in second_order - - -def test_unbiased_coin_has_no_second_order(): - counts = Counter() - - for i in range(256): - buf = hbytes([i]) - data = ConjectureData.for_buffer(buf) - result = cu.biased_coin(data, 0.5) - if data.buffer == buf: - counts[result] += 1 - - assert counts[False] == counts[True] > 0 - - -def test_can_get_odd_number_of_bits(): - counts = Counter() - for i in range(256): - x = cu.getrandbits(ConjectureData.for_buffer([i]), 3) - assert 0 <= x <= 7 - counts[x] += 1 - assert len(set(counts.values())) == 1 - - -def test_8_bits_just_reads_stream(): - for i in range(256): - assert cu.getrandbits(ConjectureData.for_buffer([i]), 8) == i - - -def test_drawing_certain_coin_still_writes(): - data = ConjectureData.for_buffer([0, 1]) - assert not data.buffer - assert cu.biased_coin(data, 1) - assert data.buffer - - -def test_drawing_impossible_coin_still_writes(): - data = ConjectureData.for_buffer([1, 0]) - assert not data.buffer - assert not cu.biased_coin(data, 0) - assert data.buffer diff -Nru python-hypothesis-3.44.1/tests/cover/test_control.py python-hypothesis-3.71.11/tests/cover/test_control.py --- python-hypothesis-3.44.1/tests/cover/test_control.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_control.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,126 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import pytest - -from hypothesis.errors import CleanupFailed, InvalidArgument -from hypothesis.control import BuildContext, note, event, cleanup, \ - current_build_context, _current_build_context -from tests.common.utils import capture_out -from hypothesis.internal.conjecture.data import ConjectureData as TD - - -def bc(): - return BuildContext(TD.for_buffer(b'')) - - -def test_cannot_cleanup_with_no_context(): - with pytest.raises(InvalidArgument): - cleanup(lambda: None) - assert _current_build_context.value is None - - -def test_cannot_event_with_no_context(): - with pytest.raises(InvalidArgument): - event('hi') - assert _current_build_context.value is None - - -def test_cleanup_executes_on_leaving_build_context(): - data = [] - with bc(): - cleanup(lambda: data.append(1)) - assert not data - assert data == [1] - assert _current_build_context.value is None - - -def test_can_nest_build_context(): - data = [] - with bc(): - cleanup(lambda: data.append(1)) - with bc(): - cleanup(lambda: data.append(2)) - assert not data - assert data == [2] - assert data == [2, 1] - assert _current_build_context.value is None - - -def test_does_not_suppress_exceptions(): - with pytest.raises(AssertionError): - with bc(): - assert False - assert _current_build_context.value is None - - -def test_suppresses_exceptions_in_teardown(): - with capture_out() as o: - with pytest.raises(AssertionError): - with bc(): - def foo(): - raise ValueError() - cleanup(foo) - assert False - - assert u'ValueError' in o.getvalue() - assert _current_build_context.value is None - - -def test_runs_multiple_cleanup_with_teardown(): - with capture_out() as o: - with pytest.raises(AssertionError): - with bc(): - def foo(): - raise ValueError() - cleanup(foo) - - def bar(): - raise TypeError() - cleanup(foo) - cleanup(bar) - assert False - - assert u'ValueError' in o.getvalue() - assert u'TypeError' in o.getvalue() - assert _current_build_context.value is None - - -def test_raises_error_if_cleanup_fails_but_block_does_not(): - with pytest.raises(CleanupFailed): - with bc(): - def foo(): - raise ValueError() - cleanup(foo) - assert _current_build_context.value is None - - -def test_raises_if_note_out_of_context(): - with pytest.raises(InvalidArgument): - note('Hi') - - -def test_raises_if_current_build_context_out_of_context(): - with pytest.raises(InvalidArgument): - current_build_context() - - -def test_current_build_context_is_current(): - with bc() as a: - assert current_build_context() is a diff -Nru python-hypothesis-3.44.1/tests/cover/test_conventions.py python-hypothesis-3.71.11/tests/cover/test_conventions.py --- python-hypothesis-3.44.1/tests/cover/test_conventions.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_conventions.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,24 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from hypothesis.utils.conventions import UniqueIdentifier - - -def test_unique_identifier_repr(): - assert repr(UniqueIdentifier(u'hello_world')) == u'hello_world' diff -Nru python-hypothesis-3.44.1/tests/cover/test_core.py python-hypothesis-3.71.11/tests/cover/test_core.py --- python-hypothesis-3.44.1/tests/cover/test_core.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_core.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,99 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import time - -import pytest -from flaky import flaky - -import hypothesis.strategies as s -from hypothesis import find, given, reject, settings -from hypothesis.core import arc -from hypothesis.errors import NoSuchExample, Unsatisfiable -from tests.common.utils import checks_deprecated_behaviour - - -def test_stops_after_max_examples_if_satisfying(): - tracker = [] - - def track(x): - tracker.append(x) - return False - - max_examples = 100 - - with pytest.raises(NoSuchExample): - find( - s.integers(0, 10000), - track, settings=settings(max_examples=max_examples)) - - assert len(tracker) == max_examples - - -def test_stops_after_max_iterations_if_not_satisfying(): - tracker = set() - - def track(x): - tracker.add(x) - reject() - - max_examples = 100 - max_iterations = 200 - - with pytest.raises(Unsatisfiable): - find( - s.integers(0, 10000), - track, settings=settings( - max_examples=max_examples, max_iterations=max_iterations)) - - # May be less because of duplication - assert len(tracker) <= max_iterations - - -@checks_deprecated_behaviour -@flaky(min_passes=1, max_runs=2) -def test_can_time_out_in_simplify(): - def slow_always_true(x): - time.sleep(0.1) - return True - start = time.time() - find( - s.lists(s.booleans()), slow_always_true, - settings=settings(timeout=0.1, database=None) - ) - finish = time.time() - run_time = finish - start - assert run_time <= 0.3 - - -some_normal_settings = settings() - - -def test_is_not_normally_default(): - assert settings.default is not some_normal_settings - - -@given(s.booleans()) -@some_normal_settings -def test_settings_are_default_in_given(x): - assert settings.default is some_normal_settings - - -def test_arc_is_memoized(): - assert arc('foo', 1, 2) is arc('foo', 1, 2) diff -Nru python-hypothesis-3.44.1/tests/cover/test_custom_reprs.py python-hypothesis-3.71.11/tests/cover/test_custom_reprs.py --- python-hypothesis-3.44.1/tests/cover/test_custom_reprs.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_custom_reprs.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,66 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import pytest - -import hypothesis.strategies as st -from hypothesis import given - - -def test_includes_non_default_args_in_repr(): - assert repr(st.integers()) == 'integers()' - assert repr(st.integers(min_value=1)) == 'integers(min_value=1)' - - -def hi(there, stuff): - return there - - -def test_supports_positional_and_keyword_args_in_builds(): - assert repr(st.builds(hi, st.integers(), there=st.booleans())) == \ - 'builds(hi, integers(), there=booleans())' - - -def test_preserves_sequence_type_of_argument(): - assert repr(st.sampled_from([0])) == 'sampled_from([0])' - - -class IHaveABadRepr(object): - - def __repr__(self): - raise ValueError('Oh no!') - - -def test_errors_are_deferred_until_repr_is_calculated(): - s = st.builds( - lambda x, y: 1, - st.just(IHaveABadRepr()), - y=st.one_of( - st.sampled_from((IHaveABadRepr(),)), st.just(IHaveABadRepr())) - ).map(lambda t: t).filter(lambda t: True).flatmap( - lambda t: st.just(IHaveABadRepr())) - - with pytest.raises(ValueError): - repr(s) - - -@given(st.iterables(st.integers())) -def test_iterables_repr_is_useful(it): - # fairly hard-coded but useful; also ensures _values are inexhaustible - assert repr(it) == 'iter({!r})'.format(it._values) diff -Nru python-hypothesis-3.44.1/tests/cover/test_database_backend.py python-hypothesis-3.71.11/tests/cover/test_database_backend.py --- python-hypothesis-3.44.1/tests/cover/test_database_backend.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_database_backend.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,199 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import os -import base64 - -import pytest - -from hypothesis import given, settings -from tests.common.utils import validate_deprecation, \ - checks_deprecated_behaviour -from hypothesis.database import ExampleDatabase, SQLiteExampleDatabase, \ - InMemoryExampleDatabase, DirectoryBasedExampleDatabase -from hypothesis.strategies import lists, binary, tuples - -small_settings = settings(max_examples=50) - - -@given(lists(tuples(binary(), binary()))) -@small_settings -def test_backend_returns_what_you_put_in(xs): - backend = InMemoryExampleDatabase() - mapping = {} - for key, value in xs: - mapping.setdefault(key, set()).add(value) - backend.save(key, value) - for key, values in mapping.items(): - backend_contents = list(backend.fetch(key)) - distinct_backend_contents = set(backend_contents) - assert len(backend_contents) == len(distinct_backend_contents) - assert distinct_backend_contents == set(values) - - -@checks_deprecated_behaviour -def test_does_not_commit_in_error_state(): - backend = SQLiteExampleDatabase(':memory:') - backend.create_db_if_needed() - try: - with backend.cursor() as cursor: - cursor.execute(""" - insert into hypothesis_data_mapping(key, value) - values("a", "b") - """) - raise ValueError() - except ValueError: - pass - - assert list(backend.fetch(b'a')) == [] - - -@checks_deprecated_behaviour -def test_can_double_close(): - backend = SQLiteExampleDatabase(':memory:') - backend.create_db_if_needed() - backend.close() - backend.close() - - -def test_can_delete_keys(): - backend = InMemoryExampleDatabase() - backend.save(b'foo', b'bar') - backend.save(b'foo', b'baz') - backend.delete(b'foo', b'bar') - assert list(backend.fetch(b'foo')) == [b'baz'] - - -@checks_deprecated_behaviour -def test_ignores_badly_stored_values(): - backend = SQLiteExampleDatabase(':memory:') - backend.create_db_if_needed() - with backend.cursor() as cursor: - cursor.execute(""" - insert into hypothesis_data_mapping(key, value) - values(?, ?) - """, (base64.b64encode(b'foo'), u'kittens')) - assert list(backend.fetch(b'foo')) == [] - - -def test_default_database_is_in_memory(): - assert isinstance(ExampleDatabase(), InMemoryExampleDatabase) - - -def test_default_on_disk_database_is_dir(tmpdir): - assert isinstance( - ExampleDatabase(tmpdir.join('foo')), DirectoryBasedExampleDatabase) - - -@checks_deprecated_behaviour -def test_selects_sqlite_database_if_name_matches(tmpdir): - assert isinstance( - ExampleDatabase(tmpdir.join('foo.db')), SQLiteExampleDatabase) - assert isinstance( - ExampleDatabase(tmpdir.join('foo.sqlite')), SQLiteExampleDatabase) - assert isinstance( - ExampleDatabase(tmpdir.join('foo.sqlite3')), SQLiteExampleDatabase) - - -def test_selects_directory_based_if_already_directory(tmpdir): - path = str(tmpdir.join('hi.sqlite3')) - DirectoryBasedExampleDatabase(path).save(b'foo', b'bar') - assert isinstance(ExampleDatabase(path), DirectoryBasedExampleDatabase) - - -@checks_deprecated_behaviour -def test_selects_sqlite_if_already_sqlite(tmpdir): - path = str(tmpdir.join('hi')) - SQLiteExampleDatabase(path).save(b'foo', b'bar') - assert isinstance(ExampleDatabase(path), SQLiteExampleDatabase) - - -def test_does_not_error_when_fetching_when_not_exist(tmpdir): - db = DirectoryBasedExampleDatabase(tmpdir.join('examples')) - db.fetch(b'foo') - - -@pytest.fixture(scope='function', params=['memory', 'sql', 'directory']) -def exampledatabase(request, tmpdir): - if request.param == 'memory': - return ExampleDatabase() - if request.param == 'sql': - with validate_deprecation(): - return SQLiteExampleDatabase(str(tmpdir.join('example.db'))) - if request.param == 'directory': - return DirectoryBasedExampleDatabase(str(tmpdir.join('examples'))) - assert False - - -def test_can_delete_a_key_that_is_not_present(exampledatabase): - exampledatabase.delete(b'foo', b'bar') - - -def test_can_fetch_a_key_that_is_not_present(exampledatabase): - assert list(exampledatabase.fetch(b'foo')) == [] - - -def test_saving_a_key_twice_fetches_it_once(exampledatabase): - exampledatabase.save(b'foo', b'bar') - exampledatabase.save(b'foo', b'bar') - assert list(exampledatabase.fetch(b'foo')) == [b'bar'] - - -def test_can_close_a_database_without_touching_it(exampledatabase): - exampledatabase.close() - - -def test_can_close_a_database_after_saving(exampledatabase): - exampledatabase.save(b'foo', b'bar') - - -def test_class_name_is_in_repr(exampledatabase): - assert type(exampledatabase).__name__ in repr(exampledatabase) - exampledatabase.close() - - -def test_an_absent_value_is_present_after_it_moves(exampledatabase): - exampledatabase.move(b'a', b'b', b'c') - assert next(exampledatabase.fetch(b'b')) == b'c' - - -def test_an_absent_value_is_present_after_it_moves_to_self(exampledatabase): - exampledatabase.move(b'a', b'a', b'b') - assert next(exampledatabase.fetch(b'a')) == b'b' - - -def test_two_directory_databases_can_interact(tmpdir): - path = str(tmpdir) - db1 = DirectoryBasedExampleDatabase(path) - db2 = DirectoryBasedExampleDatabase(path) - db1.save(b'foo', b'bar') - assert list(db2.fetch(b'foo')) == [b'bar'] - db2.save(b'foo', b'bar') - db2.save(b'foo', b'baz') - assert sorted(db1.fetch(b'foo')) == [b'bar', b'baz'] - - -def test_can_handle_disappearing_files(tmpdir, monkeypatch): - path = str(tmpdir) - db = DirectoryBasedExampleDatabase(path) - db.save(b'foo', b'bar') - base_listdir = os.listdir - monkeypatch.setattr(os, 'listdir', - lambda d: base_listdir(d) + ['this-does-not-exist']) - assert list(db.fetch(b'foo')) == [b'bar'] diff -Nru python-hypothesis-3.44.1/tests/cover/test_database_seed_deprecation.py python-hypothesis-3.71.11/tests/cover/test_database_seed_deprecation.py --- python-hypothesis-3.44.1/tests/cover/test_database_seed_deprecation.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_database_seed_deprecation.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,42 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import pytest - -from hypothesis import strategies as st -from hypothesis import seed, given, settings -from tests.common.utils import validate_deprecation -from hypothesis.database import InMemoryExampleDatabase - - -@pytest.mark.parametrize('dec', [ - settings(database=InMemoryExampleDatabase(), derandomize=True), seed(1) -]) -def test_deprecated_determinism_with_database(dec): - @dec - @given(st.booleans()) - def test(i): - raise ValueError() - - with pytest.raises(ValueError): - test() - - with validate_deprecation(): - with pytest.raises(ValueError): - test() diff -Nru python-hypothesis-3.44.1/tests/cover/test_database_usage.py python-hypothesis-3.71.11/tests/cover/test_database_usage.py --- python-hypothesis-3.44.1/tests/cover/test_database_usage.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_database_usage.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,189 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import pytest - -import hypothesis.strategies as st -from hypothesis import Verbosity, core, find, given, assume, settings, \ - unlimited -from hypothesis.errors import NoSuchExample, Unsatisfiable -from tests.common.utils import all_values, non_covering_examples -from hypothesis.database import InMemoryExampleDatabase -from hypothesis.internal.compat import hbytes - - -def has_a_non_zero_byte(x): - return any(hbytes(x)) - - -def test_saves_incremental_steps_in_database(): - key = b'a database key' - database = InMemoryExampleDatabase() - find( - st.binary(min_size=10), lambda x: has_a_non_zero_byte(x), - settings=settings(database=database), database_key=key - ) - assert len(all_values(database)) > 1 - - -def test_clears_out_database_as_things_get_boring(): - key = b'a database key' - database = InMemoryExampleDatabase() - do_we_care = True - - def stuff(): - try: - find( - st.binary(min_size=50), - lambda x: do_we_care and has_a_non_zero_byte(x), - settings=settings(database=database, max_examples=10), - database_key=key - ) - except NoSuchExample: - pass - stuff() - assert len(all_values(database)) > 1 - do_we_care = False - stuff() - initial = len(all_values(database)) - assert initial > 0 - - for _ in range(initial): - stuff() - keys = len(all_values(database)) - if not keys: - break - else: - assert False - - -def test_trashes_invalid_examples(): - key = b'a database key' - database = InMemoryExampleDatabase() - finicky = False - - def stuff(): - try: - find( - st.binary(min_size=100), - lambda x: assume(not finicky) and has_a_non_zero_byte(x), - settings=settings(database=database, max_shrinks=10), - database_key=key - ) - except Unsatisfiable: - pass - stuff() - original = len(all_values(database)) - assert original > 1 - finicky = True - stuff() - assert len(all_values(database)) < original - - -def test_respects_max_examples_in_database_usage(): - key = b'a database key' - database = InMemoryExampleDatabase() - do_we_care = True - counter = [0] - - def check(x): - counter[0] += 1 - return do_we_care and has_a_non_zero_byte(x) - - def stuff(): - try: - find( - st.binary(min_size=100), check, - settings=settings(database=database, max_examples=10), - database_key=key - ) - except NoSuchExample: - pass - stuff() - assert len(all_values(database)) > 10 - do_we_care = False - counter[0] = 0 - stuff() - assert counter == [10] - - -def test_clears_out_everything_smaller_than_the_interesting_example(): - target = None - - # We retry the test run a few times to get a large enough initial - # set of examples that we're not going to explore them all in the - # initial run. - last_sum = [None] - - database = InMemoryExampleDatabase() - - seen = set() - - @settings( - database=database, verbosity=Verbosity.quiet, max_examples=100, - timeout=unlimited, max_shrinks=100 - ) - @given(st.binary(min_size=10, max_size=10)) - def test(b): - if target is not None: - if len(seen) < 30: - seen.add(b) - if b in seen: - return - if b >= target: - raise ValueError() - return - b = hbytes(b) - s = sum(b) - if ( - (last_sum[0] is None and s > 1000) or - (last_sum[0] is not None and s >= last_sum[0] - 1) - ): - last_sum[0] = s - raise ValueError() - - with pytest.raises(ValueError): - test() - - saved = non_covering_examples(database) - assert len(saved) > 30 - - target = sorted(saved)[len(saved) // 2] - - with pytest.raises(ValueError): - test() - - saved = non_covering_examples(database) - assert target in saved or target in seen - - for s in saved: - assert s >= target - - -def test_does_not_use_database_when_seed_is_forced(monkeypatch): - monkeypatch.setattr(core, 'global_force_seed', 42) - database = InMemoryExampleDatabase() - database.fetch = None - - @settings(database=database) - @given(st.integers()) - def test(i): - pass - - test() diff -Nru python-hypothesis-3.44.1/tests/cover/test_datetimes.py python-hypothesis-3.71.11/tests/cover/test_datetimes.py --- python-hypothesis-3.44.1/tests/cover/test_datetimes.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_datetimes.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,167 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import datetime as dt - -import pytest -from flaky import flaky - -from hypothesis import find, given, settings, unlimited -from tests.common.debug import minimal, find_any -from tests.common.utils import checks_deprecated_behaviour -from hypothesis.strategies import none, dates, times, binary, datetimes, \ - timedeltas -from hypothesis.internal.compat import hrange -from hypothesis.searchstrategy.datetime import DatetimeStrategy -from hypothesis.internal.conjecture.data import Status, StopTest, \ - ConjectureData - - -def test_can_find_positive_delta(): - assert minimal(timedeltas(), lambda x: x.days > 0) == dt.timedelta(1) - - -def test_can_find_negative_delta(): - assert minimal(timedeltas(max_value=dt.timedelta(10**6)), - lambda x: x.days < 0) == dt.timedelta(-1) - - -def test_can_find_on_the_second(): - find_any(timedeltas(), lambda x: x.seconds == 0) - - -def test_can_find_off_the_second(): - find_any(timedeltas(), lambda x: x.seconds != 0) - - -def test_simplifies_towards_zero_delta(): - d = minimal(timedeltas()) - assert d.days == d.seconds == d.microseconds == 0 - - -def test_min_value_is_respected(): - assert minimal(timedeltas(min_value=dt.timedelta(days=10))).days == 10 - - -def test_max_value_is_respected(): - assert minimal(timedeltas(max_value=dt.timedelta(days=-10))).days == -10 - - -@given(timedeltas()) -def test_single_timedelta(val): - assert find_any(timedeltas(val, val)) is val - - -def test_simplifies_towards_millenium(): - d = minimal(datetimes()) - assert d.year == 2000 - assert d.month == d.day == 1 - assert d.hour == d.minute == d.second == d.microsecond == 0 - - -@given(datetimes()) -def test_default_datetimes_are_naive(dt): - assert dt.tzinfo is None - - -@flaky(max_runs=3, min_passes=1) -def test_bordering_on_a_leap_year(): - with settings(database=None, max_examples=10 ** 7, timeout=unlimited): - x = minimal(datetimes(dt.datetime.min.replace(year=2003), - dt.datetime.max.replace(year=2005)), - lambda x: x.month == 2 and x.day == 29, - timeout_after=60) - assert x.year == 2004 - - -def test_DatetimeStrategy_draw_may_fail(): - def is_failure_inducing(b): - try: - return strat._attempt_one_draw( - ConjectureData.for_buffer(b)) is None - except StopTest: - return False - - strat = DatetimeStrategy(dt.datetime.min, dt.datetime.max, none()) - failure_inducing = find(binary(), is_failure_inducing) - data = ConjectureData.for_buffer(failure_inducing * 100) - with pytest.raises(StopTest): - data.draw(strat) - assert data.status == Status.INVALID - - -def test_can_find_after_the_year_2000(): - assert minimal(dates(), lambda x: x.year > 2000).year == 2001 - - -def test_can_find_before_the_year_2000(): - assert minimal(dates(), lambda x: x.year < 2000).year == 1999 - - -def test_can_find_each_month(): - for month in hrange(1, 13): - find_any(dates(), lambda x: x.month == month) - - -def test_min_year_is_respected(): - assert minimal(dates(min_value=dt.date.min.replace(2003))).year == 2003 - - -def test_max_year_is_respected(): - assert minimal(dates(max_value=dt.date.min.replace(1998))).year == 1998 - - -@given(dates()) -def test_single_date(val): - assert find_any(dates(val, val)) is val - - -def test_can_find_midnight(): - find_any(times(), lambda x: x.hour == x.minute == x.second == 0) - - -def test_can_find_non_midnight(): - assert minimal(times(), lambda x: x.hour != 0).hour == 1 - - -def test_can_find_on_the_minute(): - find_any(times(), lambda x: x.second == 0) - - -def test_can_find_off_the_minute(): - find_any(times(), lambda x: x.second != 0) - - -def test_simplifies_towards_midnight(): - d = minimal(times()) - assert d.hour == d.minute == d.second == d.microsecond == 0 - - -def test_can_generate_naive_time(): - find_any(times(), lambda d: not d.tzinfo) - - -@given(times()) -def test_naive_times_are_naive(dt): - assert dt.tzinfo is None - - -@checks_deprecated_behaviour -def test_deprecated_min_date_is_respected(): - assert minimal(dates(min_date=dt.date.min.replace(2003))).year == 2003 diff -Nru python-hypothesis-3.44.1/tests/cover/test_deadline.py python-hypothesis-3.71.11/tests/cover/test_deadline.py --- python-hypothesis-3.44.1/tests/cover/test_deadline.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_deadline.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,158 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import time -import warnings - -import pytest - -import hypothesis.strategies as st -from hypothesis import HealthCheck, given, settings, unlimited -from hypothesis.errors import Flaky, DeadlineExceeded, \ - HypothesisDeprecationWarning -from tests.common.utils import capture_out, checks_deprecated_behaviour - - -def test_raises_deadline_on_slow_test(): - @settings(deadline=500) - @given(st.integers()) - def slow(i): - time.sleep(1) - - with pytest.raises(DeadlineExceeded): - slow() - - -def test_only_warns_once(): - @given(st.integers()) - def slow(i): - time.sleep(1) - try: - warnings.simplefilter('always', HypothesisDeprecationWarning) - with warnings.catch_warnings(record=True) as w: - slow() - finally: - warnings.simplefilter('error', HypothesisDeprecationWarning) - assert len(w) == 1 - - -@checks_deprecated_behaviour -@given(st.integers()) -def test_slow_tests_are_deprecated_by_default(i): - time.sleep(1) - - -@given(st.integers()) -@settings(deadline=None) -def test_slow_with_none_deadline(i): - time.sleep(1) - - -def test_raises_flaky_if_a_test_becomes_fast_on_rerun(): - once = [True] - - @settings(deadline=500) - @given(st.integers()) - def test_flaky_slow(i): - if once[0]: - once[0] = False - time.sleep(1) - with pytest.raises(Flaky): - test_flaky_slow() - - -def test_deadlines_participate_in_shrinking(): - @settings(deadline=500) - @given(st.integers()) - def slow_if_large(i): - if i >= 10000: - time.sleep(1) - - with capture_out() as o: - with pytest.raises(DeadlineExceeded): - slow_if_large() - assert 'slow_if_large(i=10000)' in o.getvalue() - - -def test_keeps_you_well_above_the_deadline(): - seen = set() - failed_once = [False] - - @settings(deadline=100, timeout=unlimited, suppress_health_check=[ - HealthCheck.hung_test - ]) - @given(st.integers(0, 2000)) - def slow(i): - # Make sure our initial failure isn't something that immediately goes - # flaky. - if not failed_once[0]: - if i * 0.9 <= 100: - return - else: - failed_once[0] = True - - t = i / 1000 - if i in seen: - time.sleep(0.9 * t) - else: - seen.add(i) - time.sleep(t) - - with pytest.raises(DeadlineExceeded): - slow() - - -def test_gives_a_deadline_specific_flaky_error_message(): - once = [True] - - @settings(deadline=100) - @given(st.integers()) - def slow_once(i): - if once[0]: - once[0] = False - time.sleep(0.2) - - with capture_out() as o: - with pytest.raises(Flaky): - slow_once() - assert 'Unreliable test timing' in o.getvalue() - assert 'took 2' in o.getvalue() - - -@pytest.mark.parametrize('slow_strategy', [False, True]) -@pytest.mark.parametrize('slow_test', [False, True]) -def test_should_only_fail_a_deadline_if_the_test_is_slow( - slow_strategy, slow_test -): - s = st.integers() - if slow_strategy: - s = s.map(lambda x: time.sleep(0.08)) - - @settings(deadline=50) - @given(st.data()) - def test(data): - data.draw(s) - if slow_test: - time.sleep(0.1) - - if slow_test: - with pytest.raises(DeadlineExceeded): - test() - else: - test() diff -Nru python-hypothesis-3.44.1/tests/cover/test_deferred_errors.py python-hypothesis-3.71.11/tests/cover/test_deferred_errors.py --- python-hypothesis-3.44.1/tests/cover/test_deferred_errors.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_deferred_errors.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,74 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import pytest - -import hypothesis.strategies as st -from hypothesis import find, given -from hypothesis.errors import InvalidArgument - - -def test_does_not_error_on_initial_calculation(): - st.floats(max_value=float('nan')) - st.sampled_from([]) - st.lists(st.integers(), min_size=5, max_size=2) - st.floats(min_value=2.0, max_value=1.0) - - -def test_errors_each_time(): - s = st.integers(max_value=1, min_value=3) - with pytest.raises(InvalidArgument): - s.example() - with pytest.raises(InvalidArgument): - s.example() - - -def test_errors_on_test_invocation(): - @given(st.integers(max_value=1, min_value=3)) - def test(x): - pass - with pytest.raises(InvalidArgument): - test() - - -def test_errors_on_find(): - s = st.lists(st.integers(), min_size=5, max_size=2) - with pytest.raises(InvalidArgument): - find(s, lambda x: True) - - -def test_errors_on_example(): - s = st.floats(min_value=2.0, max_value=1.0) - with pytest.raises(InvalidArgument): - s.example() - - -def test_does_not_recalculate_the_strategy(): - calls = [0] - - @st.defines_strategy - def foo(): - calls[0] += 1 - return st.just(1) - f = foo() - assert calls == [0] - f.example() - assert calls == [1] - f.example() - assert calls == [1] diff -Nru python-hypothesis-3.44.1/tests/cover/test_deferred_strategies.py python-hypothesis-3.71.11/tests/cover/test_deferred_strategies.py --- python-hypothesis-3.44.1/tests/cover/test_deferred_strategies.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_deferred_strategies.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,202 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import pytest - -from hypothesis import strategies as st -from hypothesis import given -from hypothesis.errors import InvalidArgument -from tests.common.debug import minimal, assert_no_examples -from hypothesis.internal.compat import hrange - - -def test_binary_tree(): - tree = st.deferred(lambda: st.integers() | st.tuples(tree, tree)) - - assert minimal(tree) == 0 - assert minimal(tree, lambda x: isinstance(x, tuple)) == (0, 0) - - -def test_bad_binary_tree(): - tree = st.deferred(lambda: st.tuples(tree, tree) | st.integers()) - - assert minimal(tree) == 0 - assert minimal(tree, lambda x: isinstance(x, tuple)) == (0, 0) - - -def test_large_branching_tree(): - tree = st.deferred( - lambda: st.integers() | st.tuples(tree, tree, tree, tree, tree)) - assert minimal(tree) == 0 - assert minimal(tree, lambda x: isinstance(x, tuple)) == (0,) * 5 - - -def test_bad_branching_tree(): - tree = st.deferred( - lambda: st.tuples(tree, tree, tree, tree, tree) | st.integers()) - assert minimal(tree) == 0 - assert minimal(tree, lambda x: isinstance(x, tuple)) == (0,) * 5 - - -def test_mutual_recursion(): - t = st.deferred(lambda: a | b) - a = st.deferred(lambda: st.none() | st.tuples(st.just('a'), b)) - b = st.deferred(lambda: st.none() | st.tuples(st.just('b'), a)) - - for c in ('a', 'b'): - assert minimal( - t, lambda x: x is not None and x[0] == c) == (c, None) - - -def test_non_trivial_json(): - json = st.deferred( - lambda: st.none() | st.floats() | st.text() | lists | objects - ) - - lists = st.lists(json) - objects = st.dictionaries(st.text(), json) - - assert minimal(json) is None - - small_list = minimal(json, lambda x: isinstance(x, list) and x) - assert small_list == [None] - - x = minimal( - json, lambda x: isinstance(x, dict) and isinstance(x.get(''), list)) - - assert x == {'': []} - - -def test_errors_on_non_function_define(): - x = st.deferred(1) - with pytest.raises(InvalidArgument): - x.example() - - -def test_errors_if_define_does_not_return_search_strategy(): - x = st.deferred(lambda: 1) - with pytest.raises(InvalidArgument): - x.example() - - -def test_errors_on_definition_as_self(): - x = st.deferred(lambda: x) - with pytest.raises(InvalidArgument): - x.example() - - -def test_branches_pass_through_deferred(): - x = st.one_of(st.booleans(), st.integers()) - y = st.deferred(lambda: x) - assert x.branches == y.branches - - -def test_can_draw_one_of_self(): - x = st.deferred(lambda: st.one_of(st.booleans(), x)) - assert minimal(x) is False - assert len(x.branches) == 1 - - -def test_hidden_self_references_just_result_in_no_example(): - bad = st.deferred(lambda: st.none().flatmap(lambda _: bad)) - assert_no_examples(bad) - - -def test_self_recursive_flatmap(): - bad = st.deferred(lambda: bad.flatmap(lambda x: st.none())) - assert_no_examples(bad) - - -def test_self_reference_through_one_of_can_detect_emptiness(): - bad = st.deferred(lambda: st.one_of(bad, bad)) - assert bad.is_empty - - -def test_self_tuple_draws_nothing(): - x = st.deferred(lambda: st.tuples(x)) - assert_no_examples(x) - - -def test_mutually_recursive_tuples_draw_nothing(): - x = st.deferred(lambda: st.tuples(y)) - y = st.tuples(x) - - assert_no_examples(x) - assert_no_examples(y) - - -def test_self_recursive_lists(): - x = st.deferred(lambda: st.lists(x)) - assert minimal(x) == [] - assert minimal(x, bool) == [[]] - assert minimal(x, lambda x: len(x) > 1) == [[], []] - - -def test_literals_strategy_is_valid(): - literals = st.deferred(lambda: st.one_of( - st.booleans(), - st.tuples(literals, literals), - literals.map(lambda x: [x]), - )) - - @given(literals) - def test(e): - pass - test() - - assert not literals.has_reusable_values - - -def test_impossible_self_recursion(): - x = st.deferred(lambda: st.tuples(st.none(), x)) - assert x.is_empty - assert x.has_reusable_values - - -def test_very_deep_deferral(): - # This test is designed so that the recursive properties take a very long - # time to converge: Although we can rapidly determine them for the original - # value, each round in the fixed point calculation only manages to update - # a single value in the related strategies, so it takes 100 rounds to - # update everything. Most importantly this triggers our infinite loop - # detection heuristic and we start tracking duplicates, but we shouldn't - # see any because this loop isn't infinite, just long. - def strat(i): - if i == 0: - return st.deferred(lambda: st.one_of(strategies + [st.none()])) - else: - return st.deferred( - lambda: st.tuples(strategies[(i + 1) % len(strategies)])) - - strategies = list(map(strat, hrange(100))) - - assert strategies[0].has_reusable_values - assert not strategies[0].is_empty - - -def test_recursion_in_middle(): - # This test is significant because the integers().map(abs) is not checked - # in the initial pass - when we recurse into x initially we decide that - # x is empty, so the tuple is empty, and don't need to check the third - # argument. Then when we do the more refined test we've discovered that x - # is non-empty, so we need to check the non-emptiness of the last component - # to determine the non-emptiness of the tuples. - x = st.deferred( - lambda: st.tuples(st.none(), x, st.integers().map(abs)) | st.none()) - assert not x.is_empty diff -Nru python-hypothesis-3.44.1/tests/cover/test_detection.py python-hypothesis-3.71.11/tests/cover/test_detection.py --- python-hypothesis-3.44.1/tests/cover/test_detection.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_detection.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,67 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from hypothesis import given -from hypothesis.stateful import GenericStateMachine -from hypothesis.strategies import integers -from hypothesis.internal.detection import is_hypothesis_test - - -def test_functions_default_to_not_tests(): - def foo(): - pass - assert not is_hypothesis_test(foo) - - -def test_methods_default_to_not_tests(): - class Foo(object): - - def foo(): - pass - assert not is_hypothesis_test(Foo().foo) - - -def test_detection_of_functions(): - @given(integers()) - def test(i): - pass - - assert is_hypothesis_test(test) - - -def test_detection_of_methods(): - class Foo(object): - - @given(integers()) - def test(self, i): - pass - - assert is_hypothesis_test(Foo().test) - - -def test_detection_of_stateful_tests(): - class Stuff(GenericStateMachine): - - def steps(self): - return integers() - - def execute_step(self, step): - pass - - assert is_hypothesis_test(Stuff.TestCase().runTest) diff -Nru python-hypothesis-3.44.1/tests/cover/test_direct_strategies.py python-hypothesis-3.71.11/tests/cover/test_direct_strategies.py --- python-hypothesis-3.44.1/tests/cover/test_direct_strategies.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_direct_strategies.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,350 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import math -import decimal -import fractions -from datetime import date, time, datetime, timedelta - -import pytest - -import hypothesis.strategies as ds -from hypothesis import find, given, settings -from hypothesis.errors import InvalidArgument -from hypothesis.internal.reflection import nicerepr - - -def fn_test(*fnkwargs): - fnkwargs = list(fnkwargs) - return pytest.mark.parametrize( - ('fn', 'args'), fnkwargs, - ids=[ - '%s(%s)' % (fn.__name__, ', '.join(map(nicerepr, args))) - for fn, args in fnkwargs - ] - ) - - -def fn_ktest(*fnkwargs): - fnkwargs = list(fnkwargs) - return pytest.mark.parametrize( - ('fn', 'kwargs'), fnkwargs, - ids=[ - '%s(%s)' % (fn.__name__, ', '.join(sorted( - '%s=%r' % (k, v) - for k, v in kwargs.items() - )),) - for fn, kwargs in fnkwargs - ] - ) - - -@fn_ktest( - (ds.integers, {'min_value': float('nan')}), - (ds.integers, {'min_value': 2, 'max_value': 1}), - (ds.integers, {'min_value': 0.1, 'max_value': 0.2}), - (ds.integers, {'min_value': float('nan')}), - (ds.integers, {'max_value': float('nan')}), - (ds.dates, {'min_value': 'fish'}), - (ds.dates, {'max_value': 'fish'}), - (ds.dates, { - 'min_value': date(2017, 8, 22), - 'max_value': date(2017, 8, 21)}), - (ds.datetimes, {'min_value': 'fish'}), - (ds.datetimes, {'max_value': 'fish'}), - (ds.datetimes, { - 'min_value': datetime(2017, 8, 22), - 'max_value': datetime(2017, 8, 21)}), - (ds.decimals, {'min_value': float('nan')}), - (ds.decimals, {'max_value': float('nan')}), - (ds.decimals, {'min_value': 2, 'max_value': 1}), - (ds.decimals, {'max_value': '-snan'}), - (ds.decimals, {'max_value': complex(1, 2)}), - (ds.decimals, {'places': -1}), - (ds.decimals, {'places': 0.5}), - (ds.decimals, {'max_value': 0.0, 'min_value': 1.0}), - (ds.decimals, {'min_value': 1.0, 'max_value': 0.0}), - (ds.decimals, { - 'min_value': 0.0, 'max_value': 1.0, 'allow_infinity': True}), - (ds.decimals, {'min_value': 'inf'}), - (ds.decimals, {'max_value': '-inf'}), - (ds.decimals, {'min_value': '-inf', 'allow_infinity': False}), - (ds.decimals, {'max_value': 'inf', 'allow_infinity': False}), - (ds.decimals, {'min_value': complex(1, 2)}), - (ds.decimals, {'min_value': '0.1', 'max_value': '0.9', 'places': 0}), - (ds.dictionaries, { - 'keys': ds.booleans(), 'values': ds.booleans(), - 'min_size': 10, 'max_size': 1}), - (ds.floats, {'min_value': float('nan')}), - (ds.floats, {'max_value': float('nan')}), - (ds.floats, {'min_value': complex(1, 2)}), - (ds.floats, {'max_value': complex(1, 2)}), - (ds.fractions, {'min_value': 2, 'max_value': 1}), - (ds.fractions, {'min_value': '1/3', 'max_value': '1/3', - 'max_denominator': 2}), - (ds.fractions, {'min_value': float('nan')}), - (ds.fractions, {'max_value': float('nan')}), - (ds.fractions, {'max_denominator': 0}), - (ds.fractions, {'max_denominator': 1.5}), - (ds.fractions, {'min_value': complex(1, 2)}), - (ds.lists, {}), - (ds.lists, {'average_size': '5'}), - (ds.lists, {'average_size': float('nan')}), - (ds.lists, {'min_size': 10, 'max_size': 9}), - (ds.lists, {'min_size': -10, 'max_size': -9}), - (ds.lists, {'max_size': -9}), - (ds.lists, {'max_size': 10}), - (ds.lists, {'min_size': -10}), - (ds.lists, {'max_size': 10, 'average_size': 20}), - (ds.lists, {'min_size': 1.0, 'average_size': 0.5}), - (ds.lists, {'elements': 'hi'}), - (ds.text, {'min_size': 10, 'max_size': 9}), - (ds.text, {'max_size': 10, 'average_size': 20}), - (ds.binary, {'min_size': 10, 'max_size': 9}), - (ds.binary, {'max_size': 10, 'average_size': 20}), - (ds.floats, {'min_value': float('nan')}), - (ds.floats, {'max_value': 0.0, 'min_value': 1.0}), - (ds.floats, {'min_value': 0.0, 'allow_nan': True}), - (ds.floats, {'max_value': 0.0, 'allow_nan': True}), - (ds.floats, {'min_value': 0.0, 'max_value': 1.0, 'allow_infinity': True}), - (ds.fixed_dictionaries, {'mapping': 'fish'}), - (ds.fixed_dictionaries, {'mapping': {1: 'fish'}}), - (ds.dictionaries, {'keys': ds.integers(), 'values': 1}), - (ds.dictionaries, {'keys': 1, 'values': ds.integers()}), - (ds.text, {'alphabet': '', 'min_size': 1}), - (ds.timedeltas, {'min_value': 'fish'}), - (ds.timedeltas, {'max_value': 'fish'}), - (ds.timedeltas, { - 'min_value': timedelta(hours=1), - 'max_value': timedelta(minutes=1)}), - (ds.times, {'min_value': 'fish'}), - (ds.times, {'max_value': 'fish'}), - (ds.times, { - 'min_value': time(2, 0), - 'max_value': time(1, 0)}), - (ds.uuids, {'version': 6}), -) -def test_validates_keyword_arguments(fn, kwargs): - with pytest.raises(InvalidArgument): - fn(**kwargs).example() - - -@fn_ktest( - (ds.integers, {'min_value': 0}), - (ds.integers, {'min_value': 11}), - (ds.integers, {'min_value': 11, 'max_value': 100}), - (ds.integers, {'max_value': 0}), - (ds.integers, {'min_value': decimal.Decimal('1.5')}), - (ds.integers, {'min_value': -1.5, 'max_value': -0.5}), - (ds.decimals, {'min_value': 1.0, 'max_value': 1.5}), - (ds.decimals, {'min_value': '1.0', 'max_value': '1.5'}), - (ds.decimals, {'min_value': decimal.Decimal('1.5')}), - (ds.decimals, { - 'max_value': 1.0, 'min_value': -1.0, 'allow_infinity': False}), - (ds.decimals, {'min_value': 1.0, 'allow_nan': False}), - (ds.decimals, {'max_value': 1.0, 'allow_nan': False}), - (ds.decimals, {'max_value': 1.0, 'min_value': -1.0, 'allow_nan': False}), - (ds.decimals, {'min_value': '-inf'}), - (ds.decimals, {'max_value': 'inf'}), - (ds.fractions, { - 'min_value': -1, 'max_value': 1, 'max_denominator': 1000}), - (ds.fractions, {'min_value': 1, 'max_value': 1}), - (ds.fractions, {'min_value': 1, 'max_value': 1, 'max_denominator': 2}), - (ds.fractions, {'min_value': 1.0}), - (ds.fractions, {'min_value': decimal.Decimal('1.0')}), - (ds.fractions, {'min_value': fractions.Fraction(1, 2)}), - (ds.fractions, {'min_value': '1/2', 'max_denominator': 1}), - (ds.fractions, {'max_value': '1/2', 'max_denominator': 1}), - (ds.lists, {'max_size': 0}), - (ds.lists, {'elements': ds.integers()}), - (ds.lists, {'elements': ds.integers(), 'max_size': 5}), - (ds.lists, {'elements': ds.booleans(), 'min_size': 5}), - (ds.lists, {'elements': ds.booleans(), 'min_size': 5, 'max_size': 10}), - (ds.lists, { - 'average_size': 20, 'elements': ds.booleans(), 'max_size': 25}), - (ds.sets, { - 'min_size': 10, 'max_size': 10, 'elements': ds.integers(), - }), - (ds.booleans, {}), - (ds.just, {'value': 'hi'}), - (ds.integers, {'min_value': 12, 'max_value': 12}), - (ds.floats, {}), - (ds.floats, {'min_value': 1.0}), - (ds.floats, {'max_value': 1.0}), - (ds.floats, {'max_value': 1.0, 'min_value': -1.0}), - (ds.floats, { - 'max_value': 1.0, 'min_value': -1.0, 'allow_infinity': False}), - (ds.floats, {'min_value': 1.0, 'allow_nan': False}), - (ds.floats, {'max_value': 1.0, 'allow_nan': False}), - (ds.floats, {'max_value': 1.0, 'min_value': -1.0, 'allow_nan': False}), - (ds.sampled_from, {'elements': [1]}), - (ds.sampled_from, {'elements': [1, 2, 3]}), - (ds.fixed_dictionaries, {'mapping': {1: ds.integers()}}), - (ds.dictionaries, {'keys': ds.booleans(), 'values': ds.integers()}), - (ds.text, {'alphabet': 'abc'}), - (ds.text, {'alphabet': ''}), - (ds.text, {'alphabet': ds.sampled_from('abc')}), -) -def test_produces_valid_examples_from_keyword(fn, kwargs): - fn(**kwargs).example() - - -@fn_test( - (ds.one_of, (1,)), - (ds.tuples, (1,)), -) -def test_validates_args(fn, args): - with pytest.raises(InvalidArgument): - fn(*args).example() - - -@fn_test( - (ds.one_of, (ds.booleans(), ds.tuples(ds.booleans()))), - (ds.one_of, (ds.booleans(),)), - (ds.text, ()), - (ds.binary, ()), - (ds.builds, (lambda x, y: x + y, ds.integers(), ds.integers())), -) -def test_produces_valid_examples_from_args(fn, args): - fn(*args).example() - - -def test_tuples_raise_error_on_bad_kwargs(): - with pytest.raises(TypeError): - ds.tuples(stuff='things') - - -@given(ds.lists(ds.booleans(), min_size=10, max_size=10)) -def test_has_specified_length(xs): - assert len(xs) == 10 - - -@given(ds.integers(max_value=100)) -@settings(max_examples=100) -def test_has_upper_bound(x): - assert x <= 100 - - -@given(ds.integers(min_value=100)) -def test_has_lower_bound(x): - assert x >= 100 - - -@given(ds.integers(min_value=1, max_value=2)) -def test_is_in_bounds(x): - assert 1 <= x <= 2 - - -@given(ds.fractions(min_value=-1, max_value=1, max_denominator=1000)) -def test_fraction_is_in_bounds(x): - assert -1 <= x <= 1 and abs(x.denominator) <= 1000 - - -@given(ds.fractions(min_value=fractions.Fraction(1, 2))) -def test_fraction_gt_positive(x): - assert fractions.Fraction(1, 2) <= x - - -@given(ds.fractions(max_value=fractions.Fraction(-1, 2))) -def test_fraction_lt_negative(x): - assert x <= fractions.Fraction(-1, 2) - - -@given(ds.decimals(min_value=-1.5, max_value=1.5, allow_nan=False)) -def test_decimal_is_in_bounds(x): - # decimal.Decimal("-1.5") == -1.5 (not explicitly testable in py2.6) - assert decimal.Decimal('-1.5') <= x <= decimal.Decimal('1.5') - - -def test_float_can_find_max_value_inf(): - assert find( - ds.floats(max_value=float('inf')), lambda x: math.isinf(x) - ) == float('inf') - assert find( - ds.floats(min_value=0.0), lambda x: math.isinf(x)) == float('inf') - - -def test_float_can_find_min_value_inf(): - find(ds.floats(), lambda x: x < 0 and math.isinf(x)) - find( - ds.floats(min_value=float('-inf'), max_value=0.0), - lambda x: math.isinf(x)) - - -def test_can_find_none_list(): - assert find(ds.lists(ds.none()), lambda x: len(x) >= 3) == [None] * 3 - - -def test_fractions(): - assert find(ds.fractions(), lambda f: f >= 1) == 1 - - -def test_decimals(): - assert find(ds.decimals(), lambda f: f.is_finite() and f >= 1) == 1 - - -def test_non_float_decimal(): - find( - ds.decimals(), - lambda d: d.is_finite() and decimal.Decimal(float(d)) != d) - - -def test_produces_dictionaries_of_at_least_minimum_size(): - t = find( - ds.dictionaries(ds.booleans(), ds.integers(), min_size=2), - lambda x: True) - assert t == {False: 0, True: 0} - - -@given(ds.dictionaries(ds.integers(), ds.integers(), max_size=5)) -@settings(max_examples=50) -def test_dictionaries_respect_size(d): - assert len(d) <= 5 - - -@given(ds.dictionaries(ds.integers(), ds.integers(), max_size=0)) -@settings(max_examples=50) -def test_dictionaries_respect_zero_size(d): - assert len(d) <= 5 - - -@given( - ds.lists(ds.none(), max_size=5) -) -def test_none_lists_respect_max_size(ls): - assert len(ls) <= 5 - - -@given( - ds.lists(ds.none(), max_size=5, min_size=1) -) -def test_none_lists_respect_max_and_min_size(ls): - assert 1 <= len(ls) <= 5 - - -@given(ds.iterables(ds.integers(), max_size=5, min_size=1)) -def test_iterables_are_exhaustible(it): - for _ in it: - pass - with pytest.raises(StopIteration): - next(it) - - -def test_minimal_iterable(): - assert list(find(ds.iterables(ds.integers()), lambda x: True)) == [] diff -Nru python-hypothesis-3.44.1/tests/cover/test_draw_example.py python-hypothesis-3.71.11/tests/cover/test_draw_example.py --- python-hypothesis-3.44.1/tests/cover/test_draw_example.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_draw_example.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import pytest - -from tests.common import standard_types -from hypothesis.strategies import lists - - -@pytest.mark.parametrize( - u'spec', standard_types, ids=list(map(repr, standard_types))) -def test_single_example(spec): - spec.example() - - -@pytest.mark.parametrize( - u'spec', standard_types, ids=list(map(repr, standard_types))) -def test_list_example(spec): - lists(spec, average_size=2).example() diff -Nru python-hypothesis-3.44.1/tests/cover/test_duplication.py python-hypothesis-3.71.11/tests/cover/test_duplication.py --- python-hypothesis-3.44.1/tests/cover/test_duplication.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_duplication.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,69 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from collections import Counter - -import pytest - -from hypothesis import given, settings -from hypothesis.searchstrategy import SearchStrategy - - -class Blocks(SearchStrategy): - def __init__(self, n): - self.n = n - - def do_draw(self, data): - return data.draw_bytes(self.n) - - -@pytest.mark.parametrize('n', range(1, 5)) -def test_does_not_duplicate_blocks(n): - counts = Counter() - - @given(Blocks(n)) - def test(b): - counts[b] += 1 - test() - assert set(counts.values()) == {1} - - -@pytest.mark.parametrize('n', range(1, 5)) -def test_mostly_does_not_duplicate_blocks_even_when_failing(n): - counts = Counter() - - @settings(database=None) - @given(Blocks(n)) - def test(b): - counts[b] += 1 - if len(counts) > 3: - raise ValueError() - try: - test() - except ValueError: - pass - # There are two circumstances in which a duplicate is allowed: We replay - # the failing test once to check for flakiness, and then we replay the - # fully minimized failing test at the end to display the error. The - # complication comes from the fact that these may or may not be the same - # test case, so we can see either two test cases each run twice or one - # test case which has been run three times. - seen_counts = set(counts.values()) - assert seen_counts in ({1, 2}, {1, 3}) - assert len([k for k, v in counts.items() if v > 1]) <= 2 diff -Nru python-hypothesis-3.44.1/tests/cover/test_dynamic_variable.py python-hypothesis-3.71.11/tests/cover/test_dynamic_variable.py --- python-hypothesis-3.44.1/tests/cover/test_dynamic_variable.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_dynamic_variable.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,38 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from hypothesis.utils.dynamicvariables import DynamicVariable - - -def test_can_assign(): - d = DynamicVariable(1) - assert d.value == 1 - with d.with_value(2): - assert d.value == 2 - assert d.value == 1 - - -def test_can_nest(): - d = DynamicVariable(1) - with d.with_value(2): - assert d.value == 2 - with d.with_value(3): - assert d.value == 3 - assert d.value == 2 - assert d.value == 1 diff -Nru python-hypothesis-3.44.1/tests/cover/test_escalation.py python-hypothesis-3.71.11/tests/cover/test_escalation.py --- python-hypothesis-3.44.1/tests/cover/test_escalation.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_escalation.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,68 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import pytest - -import hypothesis.strategies as st -import hypothesis.internal.escalation as esc -from hypothesis import given - - -def test_does_not_escalate_errors_in_non_hypothesis_file(): - try: - assert False - except AssertionError: - esc.escalate_hypothesis_internal_error() - - -def test_does_escalate_errors_in_hypothesis_file(monkeypatch): - monkeypatch.setattr(esc, 'is_hypothesis_file', lambda x: True) - - with pytest.raises(AssertionError): - try: - assert False - except AssertionError: - esc.escalate_hypothesis_internal_error() - - -def test_does_not_escalate_errors_in_hypothesis_file_if_disabled(monkeypatch): - monkeypatch.setattr(esc, 'is_hypothesis_file', lambda x: True) - monkeypatch.setattr(esc, 'PREVENT_ESCALATION', True) - - try: - assert False - except AssertionError: - esc.escalate_hypothesis_internal_error() - - -def test_immediately_escalates_errors_in_generation(): - count = [0] - - def explode(s): - count[0] += 1 - raise ValueError() - - @given(st.integers().map(explode)) - def test(i): - pass - - with pytest.raises(ValueError): - test() - - assert count == [1] diff -Nru python-hypothesis-3.44.1/tests/cover/test_eval_as_source.py python-hypothesis-3.71.11/tests/cover/test_eval_as_source.py --- python-hypothesis-3.44.1/tests/cover/test_eval_as_source.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_eval_as_source.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,43 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from hypothesis.internal.reflection import source_exec_as_module - - -def test_can_eval_as_source(): - assert source_exec_as_module('foo=1').foo == 1 - - -def test_caches(): - x = source_exec_as_module('foo=2') - y = source_exec_as_module('foo=2') - assert x is y - - -RECURSIVE = """ -from hypothesis.internal.reflection import source_exec_as_module - -def test_recurse(): - assert not ( - source_exec_as_module("too_much_recursion = False").too_much_recursion) -""" - - -def test_can_call_self_recursively(): - source_exec_as_module(RECURSIVE).test_recurse() diff -Nru python-hypothesis-3.44.1/tests/cover/test_example.py python-hypothesis-3.71.11/tests/cover/test_example.py --- python-hypothesis-3.44.1/tests/cover/test_example.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_example.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,76 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from random import Random -from decimal import Decimal - -import pytest - -import hypothesis.strategies as st -from hypothesis import find, given, example, settings -from hypothesis.errors import NoExamples -from hypothesis.control import _current_build_context -from tests.common.utils import checks_deprecated_behaviour - - -@settings(deadline=None) -@given(st.integers()) -def test_deterministic_examples_are_deterministic(seed): - with _current_build_context.with_value(None): - assert st.lists(st.integers()).example(Random(seed)) == \ - st.lists(st.integers()).example(Random(seed)) - - -def test_example_of_none_is_none(): - assert st.none().example() is None - - -def test_exception_in_compare_can_still_have_example(): - st.one_of( - st.none().map(lambda n: Decimal('snan')), - st.just(Decimal(0))).example() - - -def test_does_not_always_give_the_same_example(): - s = st.integers() - assert len(set( - s.example() for _ in range(100) - )) >= 10 - - -def test_raises_on_no_examples(): - with pytest.raises(NoExamples): - st.nothing().example() - - -@checks_deprecated_behaviour -@example(False) -@given(st.booleans()) -def test_example_inside_given(b): - st.integers().example() - - -@checks_deprecated_behaviour -def test_example_inside_find(): - find(st.integers(0, 100), lambda x: st.integers().example()) - - -@checks_deprecated_behaviour -def test_example_inside_strategy(): - st.booleans().map(lambda x: st.integers().example()).example() diff -Nru python-hypothesis-3.44.1/tests/cover/test_executors.py python-hypothesis-3.71.11/tests/cover/test_executors.py --- python-hypothesis-3.44.1/tests/cover/test_executors.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_executors.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,98 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import inspect -from unittest import TestCase - -import pytest - -from hypothesis import given, example -from hypothesis.executors import ConjectureRunner -from hypothesis.strategies import booleans, integers - - -def test_must_use_result_of_test(): - class DoubleRun(object): - - def execute_example(self, function): - x = function() - if inspect.isfunction(x): - return x() - - @given(booleans()) - def boom(self, b): - def f(): - raise ValueError() - return f - - with pytest.raises(ValueError): - DoubleRun().boom() - - -class TestTryReallyHard(TestCase): - - @given(integers()) - def test_something(self, i): - pass - - def execute_example(self, f): - f() - return f() - - -class Valueless(object): - - def execute_example(self, f): - try: - return f() - except ValueError: - return None - - @given(integers()) - @example(1) - def test_no_boom_on_example(self, x): - raise ValueError() - - @given(integers()) - def test_no_boom(self, x): - raise ValueError() - - @given(integers()) - def test_boom(self, x): - assert False - - -def test_boom(): - with pytest.raises(AssertionError): - Valueless().test_boom() - - -def test_no_boom(): - Valueless().test_no_boom() - - -def test_no_boom_on_example(): - Valueless().test_no_boom_on_example() - - -class TestNormal(ConjectureRunner, TestCase): - - @given(booleans()) - def test_stuff(self, b): - pass diff -Nru python-hypothesis-3.44.1/tests/cover/test_explicit_examples.py python-hypothesis-3.71.11/tests/cover/test_explicit_examples.py --- python-hypothesis-3.44.1/tests/cover/test_explicit_examples.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_explicit_examples.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,234 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from unittest import TestCase - -import pytest - -from hypothesis import Verbosity, note, given, example, settings, reporting -from hypothesis.errors import InvalidArgument -from tests.common.utils import capture_out -from hypothesis.strategies import text, integers -from hypothesis.internal.compat import integer_types, print_unicode - - -class TestInstanceMethods(TestCase): - - @given(integers()) - @example(1) - def test_hi_1(self, x): - assert isinstance(x, integer_types) - - @given(integers()) - @example(x=1) - def test_hi_2(self, x): - assert isinstance(x, integer_types) - - @given(x=integers()) - @example(x=1) - def test_hi_3(self, x): - assert isinstance(x, integer_types) - - -def test_kwarg_example_on_testcase(): - class Stuff(TestCase): - - @given(integers()) - @example(x=1) - def test_hi(self, x): - assert isinstance(x, integer_types) - - Stuff(u'test_hi').test_hi() - - -def test_errors_when_run_with_not_enough_args(): - @given(integers(), int) - @example(1) - def foo(x, y): - pass - - with pytest.raises(TypeError): - foo() - - -def test_errors_when_run_with_not_enough_kwargs(): - @given(integers(), int) - @example(x=1) - def foo(x, y): - pass - - with pytest.raises(TypeError): - foo() - - -def test_can_use_examples_after_given(): - long_str = u"This is a very long string that you've no chance of hitting" - - @example(long_str) - @given(text()) - def test_not_long_str(x): - assert x != long_str - - with pytest.raises(AssertionError): - test_not_long_str() - - -def test_can_use_examples_before_given(): - long_str = u"This is a very long string that you've no chance of hitting" - - @given(text()) - @example(long_str) - def test_not_long_str(x): - assert x != long_str - - with pytest.raises(AssertionError): - test_not_long_str() - - -def test_can_use_examples_around_given(): - long_str = u"This is a very long string that you've no chance of hitting" - short_str = u'Still no chance' - - seen = [] - - @example(short_str) - @given(text()) - @example(long_str) - def test_not_long_str(x): - seen.append(x) - - test_not_long_str() - assert set(seen[:2]) == set((long_str, short_str)) - - -@pytest.mark.parametrize((u'x', u'y'), [(1, False), (2, True)]) -@example(z=10) -@given(z=integers()) -def test_is_a_thing(x, y, z): - pass - - -def test_no_args_and_kwargs(): - with pytest.raises(InvalidArgument): - example(1, y=2) - - -def test_no_empty_examples(): - with pytest.raises(InvalidArgument): - example() - - -def test_does_not_print_on_explicit_examples_if_no_failure(): - @example(1) - @given(integers()) - def test_positive(x): - assert x > 0 - - with reporting.with_reporter(reporting.default): - with pytest.raises(AssertionError): - with capture_out() as out: - test_positive() - out = out.getvalue() - assert u'Falsifying example: test_positive(1)' not in out - - -def test_prints_output_for_explicit_examples(): - @example(-1) - @given(integers()) - def test_positive(x): - assert x > 0 - - with reporting.with_reporter(reporting.default): - with pytest.raises(AssertionError): - with capture_out() as out: - test_positive() - out = out.getvalue() - assert u'Falsifying example: test_positive(x=-1)' in out - - -def test_prints_verbose_output_for_explicit_examples(): - @settings(verbosity=Verbosity.verbose) - @example('NOT AN INTEGER') - @given(integers()) - def test_always_passes(x): - pass - - with reporting.with_reporter(reporting.default): - with capture_out() as out: - test_always_passes() - out = out.getvalue() - assert u"Trying example: test_always_passes(x='NOT AN INTEGER')" in out - - -def test_captures_original_repr_of_example(): - @example(x=[]) - @given(integers()) - def test_mutation(x): - x.append(1) - assert not x - - with reporting.with_reporter(reporting.default): - with pytest.raises(AssertionError): - with capture_out() as out: - test_mutation() - out = out.getvalue() - assert u'Falsifying example: test_mutation(x=[])' in out - - -def test_examples_are_tried_in_order(): - @example(x=1) - @example(x=2) - @given(integers()) - @settings(max_examples=0) - @example(x=3) - def test(x): - print_unicode(u"x -> %d" % (x,)) - with capture_out() as out: - with reporting.with_reporter(reporting.default): - test() - ls = out.getvalue().splitlines() - assert ls == [u"x -> 1", 'x -> 2', 'x -> 3'] - - -def test_prints_note_in_failing_example(): - @example(x=42) - @example(x=43) - @given(integers()) - def test(x): - note('x -> %d' % (x,)) - assert x == 42 - - with capture_out() as out: - with reporting.with_reporter(reporting.default): - with pytest.raises(AssertionError): - test() - v = out.getvalue() - print_unicode(v) - assert 'x -> 43' in v - assert 'x -> 42' not in v - - -def test_must_agree_with_number_of_arguments(): - @example(1, 2) - @given(integers()) - def test(a): - pass - - with pytest.raises(InvalidArgument): - test() diff -Nru python-hypothesis-3.44.1/tests/cover/test_fancy_repr.py python-hypothesis-3.71.11/tests/cover/test_fancy_repr.py --- python-hypothesis-3.44.1/tests/cover/test_fancy_repr.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_fancy_repr.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,53 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import hypothesis.strategies as st - - -def test_floats_is_floats(): - assert repr(st.floats()) == u'floats()' - - -def test_includes_non_default_values(): - assert repr(st.floats(max_value=1.0)) == u'floats(max_value=1.0)' - - -def foo(*args, **kwargs): - pass - - -def test_builds_repr(): - assert repr(st.builds(foo, st.just(1), x=st.just(10))) == \ - u'builds(foo, just(1), x=just(10))' - - -def test_map_repr(): - assert repr(st.integers().map(abs)) == u'integers().map(abs)' - assert repr(st.integers().map(lambda x: x * 2)) == \ - u'integers().map(lambda x: x * 2)' - - -def test_filter_repr(): - assert repr(st.integers().filter(lambda x: x != 3)) == \ - u'integers().filter(lambda x: x != 3)' - - -def test_flatmap_repr(): - assert repr(st.integers().flatmap(lambda x: st.booleans())) == \ - u'integers().flatmap(lambda x: st.booleans())' diff -Nru python-hypothesis-3.44.1/tests/cover/test_filestorage.py python-hypothesis-3.71.11/tests/cover/test_filestorage.py --- python-hypothesis-3.44.1/tests/cover/test_filestorage.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_filestorage.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,57 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import os - -import hypothesis.configuration as fs - -previous_home_dir = None - - -def setup_function(function): - global previous_home_dir - previous_home_dir = fs.hypothesis_home_dir() - fs.set_hypothesis_home_dir(None) - - -def teardown_function(function): - global previous_home_dir - fs.set_hypothesis_home_dir(previous_home_dir) - previous_home_dir = None - - -def test_homedir_exists_automatically(): - assert os.path.exists(fs.hypothesis_home_dir()) - - -def test_can_set_homedir_and_it_will_exist(tmpdir): - fs.set_hypothesis_home_dir(str(tmpdir.mkdir(u'kittens'))) - d = fs.hypothesis_home_dir() - assert u'kittens' in d - assert os.path.exists(d) - - -def test_will_pick_up_location_from_env(tmpdir): - os.environ[u'HYPOTHESIS_STORAGE_DIRECTORY'] = str(tmpdir) - assert fs.hypothesis_home_dir() == str(tmpdir) - - -def test_storage_directories_are_created_automatically(tmpdir): - fs.set_hypothesis_home_dir(str(tmpdir)) - assert os.path.exists(fs.storage_directory(u'badgers')) diff -Nru python-hypothesis-3.44.1/tests/cover/test_filtering.py python-hypothesis-3.71.11/tests/cover/test_filtering.py --- python-hypothesis-3.44.1/tests/cover/test_filtering.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_filtering.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import pytest - -from hypothesis import given -from hypothesis.strategies import lists, integers - - -@pytest.mark.parametrize((u'specifier', u'condition'), [ - (integers(), lambda x: x > 1), - (lists(integers()), bool), -]) -def test_filter_correctly(specifier, condition): - @given(specifier.filter(condition)) - def test_is_filtered(x): - assert condition(x) - - test_is_filtered() diff -Nru python-hypothesis-3.44.1/tests/cover/test_find.py python-hypothesis-3.71.11/tests/cover/test_find.py --- python-hypothesis-3.44.1/tests/cover/test_find.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_find.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,99 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import math -import time - -import pytest - -from hypothesis import settings as Settings -from hypothesis import find -from hypothesis.errors import Timeout, NoSuchExample -from tests.common.utils import checks_deprecated_behaviour -from hypothesis.strategies import lists, floats, booleans, integers, \ - dictionaries - - -def test_can_find_an_int(): - assert find(integers(), lambda x: True) == 0 - assert find(integers(), lambda x: x >= 13) == 13 - - -def test_can_find_list(): - x = find(lists(integers()), lambda x: sum(x) >= 10) - assert sum(x) == 10 - - -def test_can_find_nan(): - find(floats(), math.isnan) - - -def test_can_find_nans(): - x = find(lists(floats()), lambda x: math.isnan(sum(x))) - if len(x) == 1: - assert math.isnan(x[0]) - else: - assert 2 <= len(x) <= 3 - - -def test_raises_when_no_example(): - settings = Settings( - max_examples=20, - min_satisfying_examples=0, - ) - with pytest.raises(NoSuchExample): - find(integers(), lambda x: False, settings=settings) - - -def test_condition_is_name(): - settings = Settings( - max_examples=20, - min_satisfying_examples=0, - ) - with pytest.raises(NoSuchExample) as e: - find(booleans(), lambda x: False, settings=settings) - assert 'lambda x:' in e.value.args[0] - - with pytest.raises(NoSuchExample) as e: - find(integers(), lambda x: '☃' in str(x), settings=settings) - assert 'lambda x:' in e.value.args[0] - - def bad(x): - return False - - with pytest.raises(NoSuchExample) as e: - find(integers(), bad, settings=settings) - assert 'bad' in e.value.args[0] - - -def test_find_dictionary(): - assert len(find( - dictionaries(keys=integers(), values=integers()), - lambda xs: any(kv[0] > kv[1] for kv in xs.items()))) == 1 - - -@checks_deprecated_behaviour -def test_times_out(): - with pytest.raises(Timeout) as e: - find( - integers(), - lambda x: time.sleep(0.05) or False, - settings=Settings(timeout=0.01)) - - e.value.args[0] diff -Nru python-hypothesis-3.44.1/tests/cover/test_flakiness.py python-hypothesis-3.71.11/tests/cover/test_flakiness.py --- python-hypothesis-3.44.1/tests/cover/test_flakiness.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_flakiness.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,124 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import pytest - -from hypothesis import Verbosity, given, assume, reject, example, settings -from hypothesis.errors import Flaky, Unsatisfiable, UnsatisfiedAssumption -from hypothesis.strategies import lists, booleans, integers, composite, \ - random_module - - -class Nope(Exception): - pass - - -def test_fails_only_once_is_flaky(): - first_call = [True] - - @given(integers()) - def rude(x): - if first_call[0]: - first_call[0] = False - raise Nope() - - with pytest.raises(Flaky): - rude() - - -def test_gives_flaky_error_if_assumption_is_flaky(): - seen = set() - - @given(integers()) - @settings(verbosity=Verbosity.quiet) - def oops(s): - assume(s not in seen) - seen.add(s) - assert False - - with pytest.raises(Flaky): - oops() - - -def test_does_not_attempt_to_shrink_flaky_errors(): - values = [] - - @given(integers()) - def test(x): - values.append(x) - assert len(values) != 1 - with pytest.raises(Flaky): - test() - assert len(set(values)) == 1 - - -class SatisfyMe(Exception): - pass - - -@composite -def single_bool_lists(draw): - n = draw(integers(0, 20)) - result = [False] * (n + 1) - result[n] = True - return result - - -@example([True, False, False, False], [3], None,) -@example([False, True, False, False], [3], None,) -@example([False, False, True, False], [3], None,) -@example([False, False, False, True], [3], None,) -@settings(max_examples=0) -@given( - lists(booleans(), average_size=20) | single_bool_lists(), - lists(integers(1, 3), average_size=20), random_module()) -def test_failure_sequence_inducing(building, testing, rnd): - buildit = iter(building) - testit = iter(testing) - - def build(x): - try: - assume(not next(buildit)) - except StopIteration: - pass - return x - - @given(integers().map(build)) - @settings( - verbosity=Verbosity.quiet, database=None, - perform_health_check=False, max_shrinks=0 - ) - def test(x): - try: - i = next(testit) - except StopIteration: - return - if i == 1: - return - elif i == 2: - reject() - else: - raise Nope() - - try: - test() - except (Nope, Unsatisfiable, Flaky): - pass - except UnsatisfiedAssumption: - raise SatisfyMe() diff -Nru python-hypothesis-3.44.1/tests/cover/test_flatmap.py python-hypothesis-3.71.11/tests/cover/test_flatmap.py --- python-hypothesis-3.44.1/tests/cover/test_flatmap.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_flatmap.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,116 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import pytest - -from hypothesis import find, given, assume, settings -from hypothesis.database import ExampleDatabase -from hypothesis.strategies import just, text, lists, floats, tuples, \ - booleans, integers -from hypothesis.internal.compat import Counter - -ConstantLists = integers().flatmap(lambda i: lists(just(i))) - -OrderedPairs = integers(1, 200).flatmap( - lambda e: tuples(integers(0, e - 1), just(e)) -) - -with settings(max_examples=100): - @given(ConstantLists) - def test_constant_lists_are_constant(x): - assume(len(x) >= 3) - assert len(set(x)) == 1 - - @given(OrderedPairs) - def test_in_order(x): - assert x[0] < x[1] - - -def test_flatmap_retrieve_from_db(): - constant_float_lists = floats(0, 1).flatmap( - lambda x: lists(just(x)) - ) - - track = [] - - db = ExampleDatabase() - - @given(constant_float_lists) - @settings(database=db) - def record_and_test_size(xs): - if sum(xs) >= 1: - track.append(xs) - assert False - - with pytest.raises(AssertionError): - record_and_test_size() - - assert track - example = track[-1] - track = [] - - with pytest.raises(AssertionError): - record_and_test_size() - - assert track[0] == example - - -def test_flatmap_does_not_reuse_strategies(): - s = lists(max_size=0).flatmap(just) - assert s.example() is not s.example() - - -def test_flatmap_has_original_strategy_repr(): - ints = integers() - ints_up = ints.flatmap(lambda n: integers(min_value=n)) - assert repr(ints) in repr(ints_up) - - -def test_mixed_list_flatmap(): - s = lists( - booleans().flatmap(lambda b: booleans() if b else text()) - ) - - def criterion(ls): - c = Counter(type(l) for l in ls) - return len(c) >= 2 and min(c.values()) >= 3 - - result = find(s, criterion) - assert len(result) == 6 - assert set(result) == set([False, u'']) - - -@pytest.mark.parametrize('n', range(1, 10)) -def test_can_shrink_through_a_binding(n): - bool_lists = integers(0, 100).flatmap( - lambda k: lists(booleans(), min_size=k, max_size=k)) - - assert find( - bool_lists, lambda x: len(list(filter(bool, x))) >= n - ) == [True] * n - - -@pytest.mark.parametrize('n', range(1, 10)) -def test_can_delete_in_middle_of_a_binding(n): - bool_lists = integers(1, 100).flatmap( - lambda k: lists(booleans(), min_size=k, max_size=k)) - - assert find( - bool_lists, lambda x: x[0] and x[-1] and x.count(False) >= n - ) == [True] + [False] * n + [True] diff -Nru python-hypothesis-3.44.1/tests/cover/test_float_nastiness.py python-hypothesis-3.71.11/tests/cover/test_float_nastiness.py --- python-hypothesis-3.44.1/tests/cover/test_float_nastiness.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_float_nastiness.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,155 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import sys -import math - -import pytest - -import hypothesis.strategies as st -from hypothesis import find, given, assume, settings -from hypothesis.internal.compat import WINDOWS -from hypothesis.internal.floats import float_to_int, int_to_float - - -@pytest.mark.parametrize(('lower', 'upper'), [ - # Exact values don't matter, but they're large enough so that x + y = inf. - (9.9792015476736e+291, 1.7976931348623157e+308), - (-sys.float_info.max, sys.float_info.max) -]) -def test_floats_are_in_range(lower, upper): - @given(st.floats(lower, upper)) - def test_is_in_range(t): - assert lower <= t <= upper - test_is_in_range() - - -def test_can_generate_both_zeros(): - find( - st.floats(), - lambda x: assume(x >= 0) and math.copysign(1, x) < 0, - settings=settings(max_examples=10000) - ) - - -@pytest.mark.parametrize((u'l', u'r'), [ - (-1.0, 1.0), - (-0.0, 1.0), - (-1.0, 0.0), - (-sys.float_info.min, sys.float_info.min), -]) -def test_can_generate_both_zeros_when_in_interval(l, r): - interval = st.floats(l, r) - find( - interval, - lambda x: assume(x == 0) and math.copysign(1, x) == 1, - settings=settings(max_iterations=20000)) - find( - interval, lambda x: assume(x == 0) and math.copysign(1, x) == -1, - settings=settings(max_iterations=20000)) - - -@given(st.floats(0.0, 1.0)) -def test_does_not_generate_negative_if_right_boundary_is_positive(x): - assert math.copysign(1, x) == 1 - - -@given(st.floats(-1.0, -0.0)) -def test_does_not_generate_positive_if_right_boundary_is_negative(x): - assert math.copysign(1, x) == -1 - - -@pytest.mark.parametrize((u'l', u'r'), [ - (0.0, 1.0), - (-1.0, 0.0), - (-sys.float_info.min, sys.float_info.min), -]) -def test_can_generate_interval_endpoints(l, r): - interval = st.floats(l, r) - find(interval, lambda x: x == l, settings=settings(max_examples=10000)) - find(interval, lambda x: x == r, settings=settings(max_examples=10000)) - - -def test_half_bounded_generates_endpoint(): - find(st.floats(min_value=-1.0), lambda x: x == -1.0, - settings=settings(max_examples=10000)) - find(st.floats(max_value=-1.0), lambda x: x == -1.0, - settings=settings(max_examples=10000)) - - -def test_half_bounded_generates_zero(): - find(st.floats(min_value=-1.0), lambda x: x == 0.0) - find(st.floats(max_value=1.0), lambda x: x == 0.0) - - -@pytest.mark.xfail( - WINDOWS, - reason=( - 'Seems to be triggering a floating point bug on 2.7 + windows + x64')) -@given(st.floats(max_value=-0.0)) -def test_half_bounded_respects_sign_of_upper_bound(x): - assert math.copysign(1, x) == -1 - - -@given(st.floats(min_value=0.0)) -def test_half_bounded_respects_sign_of_lower_bound(x): - assert math.copysign(1, x) == 1 - - -@given(st.floats(allow_nan=False)) -def test_filter_nan(x): - assert not math.isnan(x) - - -@given(st.floats(allow_infinity=False)) -def test_filter_infinity(x): - assert not math.isinf(x) - - -def test_can_guard_against_draws_of_nan(): - """In this test we create a NaN value that naturally "tries" to shrink into - the first strategy, where it is not permitted. This tests a case that is - very unlikely to happen in random generation: When the unconstrained first - branch of generating a float just happens to produce a NaN value. - - Here what happens is that we get a NaN from the *second* strategy, - but this then shrinks into its unconstrained branch. The natural - thing to happen is then to try to zero the branch parameter of the - one_of, but that will put an illegal value there, so it's not - allowed to happen. - - """ - tagged_floats = st.one_of( - st.tuples(st.just(0), st.floats(allow_nan=False)), - st.tuples(st.just(1), st.floats(allow_nan=True)), - ) - - tag, f = find(tagged_floats, lambda x: math.isnan(x[1])) - assert tag == 1 - - -def test_very_narrow_interval(): - upper_bound = -1.0 - lower_bound = int_to_float(float_to_int(upper_bound) + 10) - assert lower_bound < upper_bound - - @given(st.floats(lower_bound, upper_bound)) - def test(f): - assert lower_bound <= f <= upper_bound - test() diff -Nru python-hypothesis-3.44.1/tests/cover/test_float_utils.py python-hypothesis-3.71.11/tests/cover/test_float_utils.py --- python-hypothesis-3.44.1/tests/cover/test_float_utils.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_float_utils.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,24 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from hypothesis.internal.floats import count_between_floats - - -def test_can_handle_straddling_zero(): - assert count_between_floats(-0.0, 0.0) == 2 diff -Nru python-hypothesis-3.44.1/tests/cover/test_given_error_conditions.py python-hypothesis-3.71.11/tests/cover/test_given_error_conditions.py --- python-hypothesis-3.44.1/tests/cover/test_given_error_conditions.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_given_error_conditions.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,91 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import time - -import pytest - -from hypothesis import given, infer, assume, reject, settings -from hypothesis.errors import Timeout, Unsatisfiable, InvalidArgument -from tests.common.utils import validate_deprecation -from hypothesis.strategies import booleans, integers - - -def test_raises_timeout_on_slow_test(): - with validate_deprecation(): - @given(integers()) - @settings(timeout=0.01) - def test_is_slow(x): - time.sleep(0.02) - - with validate_deprecation(): - with pytest.raises(Timeout): - test_is_slow() - - -def test_raises_unsatisfiable_if_all_false(): - @given(integers()) - @settings(max_examples=50, perform_health_check=False) - def test_assume_false(x): - reject() - - with pytest.raises(Unsatisfiable): - test_assume_false() - - -def test_raises_unsatisfiable_if_all_false_in_finite_set(): - @given(booleans()) - def test_assume_false(x): - reject() - - with pytest.raises(Unsatisfiable): - test_assume_false() - - -def test_does_not_raise_unsatisfiable_if_some_false_in_finite_set(): - @given(booleans()) - def test_assume_x(x): - assume(x) - - test_assume_x() - - -def test_error_if_has_no_hints(): - @given(a=infer) - def inner(a): - pass - with pytest.raises(InvalidArgument): - inner() - - -def test_error_if_infer_is_posarg(): - @given(infer) - def inner(ex): - pass - with pytest.raises(InvalidArgument): - inner() - - -def test_given_twice_deprecated(): - @given(booleans()) - @given(integers()) - def inner(a, b): - pass - with validate_deprecation(): - inner() diff -Nru python-hypothesis-3.44.1/tests/cover/test_given_reuse.py python-hypothesis-3.71.11/tests/cover/test_given_reuse.py --- python-hypothesis-3.44.1/tests/cover/test_given_reuse.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_given_reuse.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,53 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import pytest - -from hypothesis import strategies as st -from hypothesis import given - -given_booleans = given(st.booleans()) - - -@given_booleans -def test_has_an_arg_named_x(x): - pass - - -@given_booleans -def test_has_an_arg_named_y(y): - pass - - -given_named_booleans = given(z=st.text()) - - -def test_fail_independently(): - @given_named_booleans - def test_z1(z): - assert False - - @given_named_booleans - def test_z2(z): - pass - - with pytest.raises(AssertionError): - test_z1() - - test_z2() diff -Nru python-hypothesis-3.44.1/tests/cover/test_health_checks.py python-hypothesis-3.71.11/tests/cover/test_health_checks.py --- python-hypothesis-3.44.1/tests/cover/test_health_checks.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_health_checks.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,213 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import time - -import pytest -from pytest import raises - -import hypothesis.strategies as st -from hypothesis import HealthCheck, given, settings -from hypothesis.errors import InvalidArgument, FailedHealthCheck -from hypothesis.control import assume -from tests.common.utils import checks_deprecated_behaviour -from hypothesis.internal.compat import int_from_bytes -from hypothesis.searchstrategy.strategies import SearchStrategy - - -def test_slow_generation_fails_a_health_check(): - @given(st.integers().map(lambda x: time.sleep(0.2))) - def test(x): - pass - - with raises(FailedHealthCheck): - test() - - -def test_slow_generation_inline_fails_a_health_check(): - @settings(deadline=None) - @given(st.data()) - def test(data): - data.draw(st.integers().map(lambda x: time.sleep(0.2))) - - with raises(FailedHealthCheck): - test() - - -def test_default_health_check_can_weaken_specific(): - import random - - @given(st.lists(st.integers(), min_size=1)) - def test(x): - random.choice(x) - - with settings(perform_health_check=False): - test() - - -def test_suppressing_filtering_health_check(): - count = [0] - - def too_soon(x): - count[0] += 1 - return count[0] >= 200 - - @given(st.integers().filter(too_soon)) - def test1(x): - raise ValueError() - - with raises(FailedHealthCheck): - test1() - - count[0] = 0 - - @settings(suppress_health_check=[ - HealthCheck.filter_too_much, HealthCheck.too_slow]) - @given(st.integers().filter(too_soon)) - def test2(x): - raise ValueError() - - with raises(ValueError): - test2() - - -def test_filtering_everything_fails_a_health_check(): - @given(st.integers().filter(lambda x: False)) - @settings(database=None) - def test(x): - pass - - with raises(FailedHealthCheck) as e: - test() - assert 'filter' in e.value.args[0] - - -class fails_regularly(SearchStrategy): - - def do_draw(self, data): - b = int_from_bytes(data.draw_bytes(2)) - assume(b == 3) - print('ohai') - - -@settings(max_shrinks=0) -def test_filtering_most_things_fails_a_health_check(): - @given(fails_regularly()) - @settings(database=None) - def test(x): - pass - - with raises(FailedHealthCheck) as e: - test() - assert 'filter' in e.value.args[0] - - -def test_large_data_will_fail_a_health_check(): - @given(st.lists(st.binary(min_size=1024, max_size=1024), average_size=100)) - @settings(database=None, buffer_size=1000) - def test(x): - pass - - with raises(FailedHealthCheck) as e: - test() - assert 'allowable size' in e.value.args[0] - - -def test_returning_non_none_is_forbidden(): - @given(st.integers()) - def a(x): - return 1 - - with raises(FailedHealthCheck): - a() - - -def test_a_very_slow_test_will_fail_a_health_check(): - @given(st.integers()) - @settings(deadline=None) - def a(x): - time.sleep(1000) - with raises(FailedHealthCheck): - a() - - -def test_the_slow_test_health_check_can_be_disabled(): - @given(st.integers()) - @settings(suppress_health_check=[ - HealthCheck.hung_test, - ], deadline=None) - def a(x): - time.sleep(1000) - a() - - -def test_the_slow_test_health_only_runs_if_health_checks_are_on(): - @given(st.integers()) - @settings(perform_health_check=False, deadline=None) - def a(x): - time.sleep(1000) - a() - - -def test_returning_non_none_does_not_fail_if_health_check_disabled(): - @given(st.integers()) - @settings(perform_health_check=False) - def a(x): - return 1 - - a() - - -def test_large_base_example_fails_health_check(): - @given(st.binary(min_size=7000, max_size=7000)) - def test(b): - pass - - with pytest.raises(FailedHealthCheck) as exc: - test() - - assert exc.value.health_check == HealthCheck.large_base_example - - -def test_example_that_shrinks_to_overrun_fails_health_check(): - @given(st.binary(min_size=9000, max_size=9000) | st.none()) - def test(b): - pass - - with pytest.raises(FailedHealthCheck) as exc: - test() - - assert exc.value.health_check == HealthCheck.large_base_example - - -@pytest.mark.parametrize( - 'check', [HealthCheck.random_module, HealthCheck.exception_in_generation]) -@checks_deprecated_behaviour -def test_noop_health_checks(check): - settings(suppress_health_check=[check]) - - -def test_it_is_an_error_to_suppress_non_iterables(): - with raises(InvalidArgument): - settings(suppress_health_check=1) - - -@checks_deprecated_behaviour -def test_is_is_deprecated_to_suppress_non_healthchecks(): - settings(suppress_health_check=[1]) diff -Nru python-hypothesis-3.44.1/tests/cover/test_imports.py python-hypothesis-3.71.11/tests/cover/test_imports.py --- python-hypothesis-3.44.1/tests/cover/test_imports.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_imports.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from hypothesis import * -from hypothesis.strategies import * - - -def test_can_star_import_from_hypothesis(): - find(lists(integers()), lambda x: sum(x) > 1, settings=settings( - max_examples=10000, verbosity=Verbosity.quiet - )) diff -Nru python-hypothesis-3.44.1/tests/cover/test_integer_ranges.py python-hypothesis-3.71.11/tests/cover/test_integer_ranges.py --- python-hypothesis-3.44.1/tests/cover/test_integer_ranges.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_integer_ranges.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,52 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import hypothesis.strategies as st -from hypothesis import find, given, settings, unlimited -from hypothesis.internal.conjecture.utils import integer_range -from hypothesis.searchstrategy.strategies import SearchStrategy - - -class interval(SearchStrategy): - - def __init__(self, lower, upper, center=None): - self.lower = lower - self.upper = upper - self.center = center - - def do_draw(self, data): - return integer_range( - data, self.lower, self.upper, center=self.center, - ) - - -@given( - st.tuples(st.integers(), st.integers(), st.integers()).map(sorted), - st.random_module(), -) -@settings(max_examples=100, max_shrinks=0, deadline=None) -def test_intervals_shrink_to_center(inter, rnd): - lower, center, upper = inter - s = interval(lower, upper, center) - with settings(database=None, max_shrinks=2000, timeout=unlimited): - assert find(s, lambda x: True) == center - if lower < center: - assert find(s, lambda x: x < center) == center - 1 - if center < upper: - assert find(s, lambda x: x > center) == center + 1 diff -Nru python-hypothesis-3.44.1/tests/cover/test_interleaving.py python-hypothesis-3.71.11/tests/cover/test_interleaving.py --- python-hypothesis-3.44.1/tests/cover/test_interleaving.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_interleaving.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,42 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from hypothesis import strategies as st -from hypothesis import find, note, given, settings -from tests.common.utils import checks_deprecated_behaviour - - -@checks_deprecated_behaviour -def test_can_eval_stream_inside_find(): - @given(st.streaming(st.integers(min_value=0)), st.random_module()) - @settings( - buffer_size=200, max_shrinks=5, max_examples=10, - perform_health_check=False) - def test(stream, rnd): - x = find( - st.lists(st.integers(min_value=0), min_size=10), - lambda t: any(t > s for (t, s) in zip(t, stream)), - settings=settings( - database=None, max_shrinks=2000, max_examples=2000) - ) - note('x: %r' % (x,)) - note('Evalled: %r' % (stream,)) - assert len([1 for i, v in enumerate(x) if stream[i] < v]) == 1 - - test() diff -Nru python-hypothesis-3.44.1/tests/cover/test_internal_helpers.py python-hypothesis-3.71.11/tests/cover/test_internal_helpers.py --- python-hypothesis-3.44.1/tests/cover/test_internal_helpers.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_internal_helpers.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import pytest - -from hypothesis.internal.floats import sign - - -def test_sign_gives_good_type_error(): - x = 'foo' - with pytest.raises(TypeError) as e: - sign(x) - assert repr(x) in e.value.args[0] diff -Nru python-hypothesis-3.44.1/tests/cover/test_intervalset.py python-hypothesis-3.71.11/tests/cover/test_intervalset.py --- python-hypothesis-3.44.1/tests/cover/test_intervalset.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_intervalset.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,110 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import pytest - -import hypothesis.strategies as st -from hypothesis import given, assume, example -from hypothesis.internal.charmap import _subtract_intervals -from hypothesis.internal.intervalsets import IntervalSet - - -def build_intervals(ls): - ls.sort() - result = [] - for u, l in ls: - v = u + l - if result: - a, b = result[-1] - if u <= b + 1: - result[-1] = (a, v) - continue - result.append((u, v)) - return result - - -IntervalLists = st.builds( - build_intervals, - st.lists(st.tuples(st.integers(0, 200), st.integers(0, 20))) -) - -Intervals = st.builds(IntervalSet, IntervalLists) - - -@given(Intervals) -def test_intervals_are_equivalent_to_their_lists(intervals): - ls = list(intervals) - assert len(ls) == len(intervals) - for i in range(len(ls)): - assert ls[i] == intervals[i] - for i in range(1, len(ls) - 1): - assert ls[-i] == intervals[-i] - - -@given(Intervals) -def test_intervals_match_indexes(intervals): - ls = list(intervals) - for v in ls: - assert ls.index(v) == intervals.index(v) - - -@given(Intervals, st.integers()) -def test_error_for_index_of_not_present_value(intervals, v): - assume(v not in intervals) - with pytest.raises(ValueError): - intervals.index(v) - - -def test_validates_index(): - with pytest.raises(IndexError): - IntervalSet([])[1] - - with pytest.raises(IndexError): - IntervalSet([[1, 10]])[11] - - with pytest.raises(IndexError): - IntervalSet([[1, 10]])[-11] - - -def test_index_above_is_index_if_present(): - assert IntervalSet([[1, 10]]).index_above(1) == 0 - assert IntervalSet([[1, 10]]).index_above(2) == 1 - - -def test_index_above_is_length_if_higher(): - assert IntervalSet([[1, 10]]).index_above(100) == 10 - - -def intervals_to_set(ints): - return set(IntervalSet(ints)) - - -@example(x=[(0, 1), (3, 3)], y=[(1, 3)]) -@example(x=[(0, 1)], y=[(0, 0), (1, 1)]) -@example(x=[(0, 1)], y=[(1, 1)]) -@given(IntervalLists, IntervalLists) -def test_subtraction_of_intervals(x, y): - xs = intervals_to_set(x) - ys = intervals_to_set(x) - assume(not xs.isdisjoint(ys)) - z = _subtract_intervals(x, y) - assert z == tuple(sorted(z)) - for a, b in z: - assert a <= b - assert intervals_to_set(z) == intervals_to_set(x) - intervals_to_set(y) diff -Nru python-hypothesis-3.44.1/tests/cover/test_lambda_formatting.py python-hypothesis-3.71.11/tests/cover/test_lambda_formatting.py --- python-hypothesis-3.44.1/tests/cover/test_lambda_formatting.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_lambda_formatting.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,180 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2016 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from hypothesis.internal.reflection import get_pretty_function_description - - -def test_bracket_whitespace_is_striped(): - assert get_pretty_function_description( - lambda x: (x + 1) - ) == 'lambda x: (x + 1)' - - -def test_can_have_unicode_in_lambda_sources(): - t = lambda x: 'é' not in x - assert get_pretty_function_description(t) == ( - "lambda x: 'é' not in x" - ) - - -ordered_pair = ( - lambda right: [].map( - lambda length: ())) - - -def test_can_get_descriptions_of_nested_lambdas_with_different_names(): - assert get_pretty_function_description(ordered_pair) == \ - 'lambda right: [].map(lambda length: ())' - - -def test_does_not_error_on_unparsable_source(): - t = [ - lambda x: \ - # This will break ast.parse, but the brackets are needed for the real - # parser to accept this lambda - x][0] - assert get_pretty_function_description(t) == 'lambda x: ' - - -def test_source_of_lambda_is_pretty(): - assert get_pretty_function_description( - lambda x: True - ) == 'lambda x: True' - - -def test_variable_names_are_not_pretty(): - t = lambda x: True - assert get_pretty_function_description(t) == 'lambda x: True' - - -def test_does_not_error_on_dynamically_defined_functions(): - x = eval('lambda t: 1') - get_pretty_function_description(x) - - -def test_collapses_whitespace_nicely(): - t = ( - lambda x, y: 1 - ) - assert get_pretty_function_description(t) == 'lambda x, y: 1' - - -def test_is_not_confused_by_tuples(): - p = (lambda x: x > 1, 2)[0] - - assert get_pretty_function_description(p) == 'lambda x: x > 1' - - -def test_strips_comments_from_the_end(): - t = lambda x: 1 # A lambda comment - assert get_pretty_function_description(t) == 'lambda x: 1' - - -def test_does_not_strip_hashes_within_a_string(): - t = lambda x: '#' - assert get_pretty_function_description(t) == "lambda x: '#'" - - -def test_can_distinguish_between_two_lambdas_with_different_args(): - a, b = (lambda x: 1, lambda y: 2) - assert get_pretty_function_description(a) == 'lambda x: 1' - assert get_pretty_function_description(b) == 'lambda y: 2' - - -def test_does_not_error_if_it_cannot_distinguish_between_two_lambdas(): - a, b = (lambda x: 1, lambda x: 2) - assert 'lambda x:' in get_pretty_function_description(a) - assert 'lambda x:' in get_pretty_function_description(b) - - -def test_lambda_source_break_after_def_with_brackets(): - f = (lambda n: - 'aaa') - - source = get_pretty_function_description(f) - assert source == "lambda n: 'aaa'" - - -def test_lambda_source_break_after_def_with_line_continuation(): - f = lambda n:\ - 'aaa' - - source = get_pretty_function_description(f) - assert source == "lambda n: 'aaa'" - - -def arg_decorator(*s): - def accept(f): - return s - return accept - - -@arg_decorator(lambda x: x + 1) -def plus_one(): - pass - - -@arg_decorator(lambda x: x + 1, lambda y: y * 2) -def two_decorators(): - pass - - -def test_can_extract_lambda_repr_in_a_decorator(): - assert get_pretty_function_description(plus_one[0]) == 'lambda x: x + 1' - - -def test_can_extract_two_lambdas_from_a_decorator_if_args_differ(): - a, b = two_decorators - assert get_pretty_function_description(a) == 'lambda x: x + 1' - assert get_pretty_function_description(b) == 'lambda y: y * 2' - - -@arg_decorator( - lambda x: x + 1 -) -def decorator_with_space(): - pass - - -def test_can_extract_lambda_repr_in_a_decorator_with_spaces(): - assert get_pretty_function_description( - decorator_with_space[0]) == 'lambda x: x + 1' - - -@arg_decorator(lambda: ()) -def to_brackets(): - pass - - -def test_can_handle_brackets_in_decorator_argument(): - assert get_pretty_function_description(to_brackets[0]) == "lambda: ()" - - -def identity(x): - return x - - -@arg_decorator(identity(lambda x: x + 1)) -def decorator_with_wrapper(): - pass - - -def test_can_handle_nested_lambda_in_decorator_argument(): - assert get_pretty_function_description( - decorator_with_wrapper[0]) == "lambda x: x + 1" diff -Nru python-hypothesis-3.44.1/tests/cover/test_limits.py python-hypothesis-3.71.11/tests/cover/test_limits.py --- python-hypothesis-3.44.1/tests/cover/test_limits.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_limits.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from hypothesis import strategies as st -from hypothesis import given, settings - - -def test_max_examples_are_respected(): - counter = [0] - - @given(st.random_module(), st.integers()) - @settings(max_examples=100) - def test(rnd, i): - counter[0] += 1 - test() - assert counter == [100] diff -Nru python-hypothesis-3.44.1/tests/cover/test_map.py python-hypothesis-3.71.11/tests/cover/test_map.py --- python-hypothesis-3.44.1/tests/cover/test_map.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_map.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from hypothesis import strategies as st -from hypothesis import given, assume -from tests.common.debug import assert_no_examples - - -@given(st.integers().map(lambda x: assume(x % 3 != 0) and x)) -def test_can_assume_in_map(x): - assert x % 3 != 0 - - -def test_assume_in_just_raises_immediately(): - assert_no_examples(st.just(1).map(lambda x: assume(x == 2))) diff -Nru python-hypothesis-3.44.1/tests/cover/test_nesting.py python-hypothesis-3.71.11/tests/cover/test_nesting.py --- python-hypothesis-3.44.1/tests/cover/test_nesting.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_nesting.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,39 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from pytest import raises - -import hypothesis.strategies as st -from hypothesis import Verbosity, given, settings - - -def test_nesting_1(): - @given(st.integers(0, 100)) - @settings(max_examples=5, database=None, deadline=None) - def test_blah(x): - @given(st.integers()) - @settings( - max_examples=100, max_shrinks=0, database=None, - verbosity=Verbosity.quiet) - def test_nest(y): - if y >= x: - raise ValueError() - with raises(ValueError): - test_nest() - test_blah() diff -Nru python-hypothesis-3.44.1/tests/cover/test_nothing.py python-hypothesis-3.71.11/tests/cover/test_nothing.py --- python-hypothesis-3.44.1/tests/cover/test_nothing.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_nothing.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,75 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import pytest - -from hypothesis import strategies as st -from hypothesis import find, given -from hypothesis.errors import InvalidArgument -from tests.common.debug import assert_no_examples - - -def test_resampling(): - x = find( - st.lists(st.integers()).flatmap( - lambda x: st.lists(st.sampled_from(x))), - lambda x: len(x) >= 10 and len(set(x)) == 1) - assert x == [0] * 10 - - -@given(st.lists(st.nothing())) -def test_list_of_nothing(xs): - assert xs == [] - - -@given(st.sets(st.nothing())) -def test_set_of_nothing(xs): - assert xs == set() - - -def test_validates_min_size(): - with pytest.raises(InvalidArgument): - st.lists(st.nothing(), min_size=1).validate() - - -def test_function_composition(): - assert st.nothing().map(lambda x: 'hi').is_empty - assert st.nothing().filter(lambda x: True).is_empty - assert st.nothing().flatmap(lambda x: st.integers()).is_empty - - -def test_tuples_detect_empty_elements(): - assert st.tuples(st.nothing()).is_empty - - -def test_fixed_dictionaries_detect_empty_values(): - assert st.fixed_dictionaries({'a': st.nothing()}).is_empty - - -def test_no_examples(): - assert_no_examples(st.nothing()) - - -@pytest.mark.parametrize('s', [ - st.nothing(), st.nothing().map(lambda x: x), - st.nothing().filter(lambda x: True), - st.nothing().flatmap(lambda x: st.integers()) -]) -def test_empty(s): - assert s.is_empty diff -Nru python-hypothesis-3.44.1/tests/cover/test_numerics.py python-hypothesis-3.71.11/tests/cover/test_numerics.py --- python-hypothesis-3.44.1/tests/cover/test_numerics.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_numerics.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,131 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import math -import decimal - -import pytest - -from hypothesis import given, assume, reject -from hypothesis.errors import InvalidArgument -from tests.common.utils import fails -from hypothesis.strategies import data, none, tuples, decimals, integers, \ - fractions - - -@given(data()) -def test_fuzz_fractions_bounds(data): - denom = data.draw(none() | integers(1, 100), label='denominator') - fracs = none() | fractions(max_denominator=denom) - low, high = data.draw(tuples(fracs, fracs), label='low, high') - if low is not None and high is not None and low > high: - low, high = high, low - try: - val = data.draw(fractions(low, high, denom), label='value') - except InvalidArgument: - reject() # fractions too close for given max_denominator - if low is not None: - assert low <= val - if high is not None: - assert val <= high - if denom is not None: - assert 1 <= val.denominator <= denom - - -@given(data()) -def test_fuzz_decimals_bounds(data): - places = data.draw(none() | integers(0, 20), label='places') - finite_decs = decimals(allow_nan=False, allow_infinity=False, - places=places) | none() - low, high = data.draw(tuples(finite_decs, finite_decs), label='low, high') - if low is not None and high is not None and low > high: - low, high = high, low - ctx = decimal.Context(prec=data.draw(integers(1, 100), label='precision')) - try: - with decimal.localcontext(ctx): - strat = decimals(low, high, allow_nan=False, - allow_infinity=False, places=places) - val = data.draw(strat, label='value') - except InvalidArgument: - reject() # decimals too close for given places - if low is not None: - assert low <= val - if high is not None: - assert val <= high - if places is not None: - assert val.as_tuple().exponent == -places - - -@fails -@given(decimals()) -def test_all_decimals_can_be_exact_floats(x): - assume(x.is_finite()) - assert decimal.Decimal(float(x)) == x - - -@given(fractions(), fractions(), fractions()) -def test_fraction_addition_is_well_behaved(x, y, z): - assert x + y + z == y + x + z - - -@fails -@given(decimals()) -def test_decimals_include_nan(x): - assert not math.isnan(x) - - -@fails -@given(decimals()) -def test_decimals_include_inf(x): - assume(not x.is_snan()) - assert not math.isinf(x) - - -@given(decimals(allow_nan=False)) -def test_decimals_can_disallow_nan(x): - assert not math.isnan(x) - - -@given(decimals(allow_infinity=False)) -def test_decimals_can_disallow_inf(x): - assume(not x.is_snan()) - assert not math.isinf(x) - - -@pytest.mark.parametrize('places', range(10)) -def test_decimals_have_correct_places(places): - @given(decimals(0, 10, allow_nan=False, places=places)) - def inner_tst(n): - assert n.as_tuple().exponent == -places - inner_tst() - - -@given(decimals(min_value='0.1', max_value='0.2', allow_nan=False, places=1)) -def test_works_with_few_values(dec): - assert dec in (decimal.Decimal('0.1'), decimal.Decimal('0.2')) - - -@given(decimals(places=3, allow_nan=False, allow_infinity=False)) -def test_issue_725_regression(x): - pass - - -@given(decimals(min_value='0.1', max_value='0.3')) -def test_issue_739_regression(x): - pass diff -Nru python-hypothesis-3.44.1/tests/cover/test_one_of.py python-hypothesis-3.71.11/tests/cover/test_one_of.py --- python-hypothesis-3.44.1/tests/cover/test_one_of.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_one_of.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import hypothesis.strategies as st -from tests.common.debug import assert_no_examples - - -def test_one_of_empty(): - e = st.one_of() - assert e.is_empty - assert_no_examples(e) diff -Nru python-hypothesis-3.44.1/tests/cover/test_permutations.py python-hypothesis-3.71.11/tests/cover/test_permutations.py --- python-hypothesis-3.44.1/tests/cover/test_permutations.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_permutations.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from hypothesis import find, given -from hypothesis.strategies import permutations - - -def test_can_find_non_trivial_permutation(): - x = find( - permutations(list(range(5))), lambda x: x[0] != 0 - ) - - assert x == [1, 0, 2, 3, 4] - - -@given(permutations(list(u'abcd'))) -def test_permutation_values_are_permutations(perm): - assert len(perm) == 4 - assert set(perm) == set(u'abcd') - - -@given(permutations([])) -def test_empty_permutations_are_empty(xs): - assert xs == [] diff -Nru python-hypothesis-3.44.1/tests/cover/test_phases.py python-hypothesis-3.71.11/tests/cover/test_phases.py --- python-hypothesis-3.44.1/tests/cover/test_phases.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_phases.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,93 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import pytest - -import hypothesis.strategies as st -from hypothesis import Phase, given, example, settings -from hypothesis.errors import InvalidArgument -from hypothesis.database import ExampleDatabase, InMemoryExampleDatabase - - -@example(11) -@settings(phases=(Phase.explicit,)) -@given(st.integers()) -def test_only_runs_explicit_examples(i): - assert i == 11 - - -@example(u"hello world") -@settings(phases=(Phase.reuse, Phase.generate, Phase.shrink)) -@given(st.booleans()) -def test_does_not_use_explicit_examples(i): - assert isinstance(i, bool) - - -@settings(phases=(Phase.reuse, Phase.shrink)) -@given(st.booleans()) -def test_this_would_fail_if_you_ran_it(b): - assert False - - -def test_phases_default_to_all(): - assert settings(phases=None).phases == tuple(Phase) - - -def test_does_not_reuse_saved_examples_if_reuse_not_in_phases(): - class BadDatabase(ExampleDatabase): - def save(self, key, value): - pass - - def delete(self, key, value): - pass - - def fetch(self, key): - raise ValueError() - - def close(self): - pass - - @settings(database=BadDatabase(), phases=(Phase.generate,)) - @given(st.integers()) - def test_usage(i): - pass - - test_usage() - - -def test_will_save_when_reuse_not_in_phases(): - database = InMemoryExampleDatabase() - - assert not database.data - - @settings(database=database, phases=(Phase.generate,)) - @given(st.integers()) - def test_usage(i): - raise ValueError() - - with pytest.raises(ValueError): - test_usage() - - saved, = [v for k, v in database.data.items() if b'coverage' not in k] - assert len(saved) == 1 - - -def test_rejects_non_phases(): - with pytest.raises(InvalidArgument): - settings(phases=['cabbage']) diff -Nru python-hypothesis-3.44.1/tests/cover/test_pretty.py python-hypothesis-3.71.11/tests/cover/test_pretty.py --- python-hypothesis-3.44.1/tests/cover/test_pretty.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_pretty.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,754 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -# coding: utf-8 - -"""This file originates in the IPython project and is made use of under the -following licensing terms: - -The IPython licensing terms -IPython is licensed under the terms of the Modified BSD License (also known as -New or Revised or 3-Clause BSD), as follows: - -Copyright (c) 2008-2014, IPython Development Team -Copyright (c) 2001-2007, Fernando Perez -Copyright (c) 2001, Janko Hauser -Copyright (c) 2001, Nathaniel Gray -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this -list of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -Neither the name of the IPython Development Team nor the names of its -contributors may be used to endorse or promote products derived from this -software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -""" - -from __future__ import division, print_function, absolute_import - -import re -from collections import deque, defaultdict - -import pytest - -from hypothesis.vendor import pretty -from tests.common.utils import capture_out -from hypothesis.internal.compat import PY3, Counter, OrderedDict, \ - a_good_encoding - -py2_only = pytest.mark.skipif(PY3, reason='This test only runs on python 2') - -if PY3: - from io import StringIO - - def unicode_to_str(x, encoding=None): - return x -else: - from StringIO import StringIO - - def unicode_to_str(x, encoding=None): - return x.encode(encoding or a_good_encoding()) - - -def assert_equal(x, y): - assert x == y - - -def assert_true(x): - assert x - - -def assert_in(x, xs): - assert x in xs - - -def skip_without(mod): - try: - __import__(mod) - return lambda f: f - except ImportError: - return pytest.mark.skipif(True, reason='Missing %s' % (mod,)) - - -assert_raises = pytest.raises - - -class MyList(object): - - def __init__(self, content): - self.content = content - - def _repr_pretty_(self, p, cycle): - if cycle: - p.text('MyList(...)') - else: - with p.group(3, 'MyList(', ')'): - for (i, child) in enumerate(self.content): - if i: - p.text(',') - p.breakable() - else: - p.breakable('') - p.pretty(child) - - -class MyDict(dict): - - def _repr_pretty_(self, p, cycle): - p.text('MyDict(...)') - - -class MyObj(object): - - def somemethod(self): - pass - - -class Dummy1(object): - - def _repr_pretty_(self, p, cycle): - p.text('Dummy1(...)') - - -class Dummy2(Dummy1): - _repr_pretty_ = None - - -class NoModule(object): - pass - - -NoModule.__module__ = None - - -class Breaking(object): - - def _repr_pretty_(self, p, cycle): - with p.group(4, 'TG: ', ':'): - p.text('Breaking(') - p.break_() - p.text(')') - - -class BreakingRepr(object): - - def __repr__(self): - return 'Breaking(\n)' - - -class BreakingReprParent(object): - - def _repr_pretty_(self, p, cycle): - with p.group(4, 'TG: ', ':'): - p.pretty(BreakingRepr()) - - -class BadRepr(object): - - def __repr__(self): - return 1 / 0 - - -def test_list(): - assert pretty.pretty([]) == '[]' - assert pretty.pretty([1]) == '[1]' - - -def test_dict(): - assert pretty.pretty({}) == '{}' - assert pretty.pretty({1: 1}) == '{1: 1}' - - -def test_tuple(): - assert pretty.pretty(()) == '()' - assert pretty.pretty((1,)) == '(1,)' - assert pretty.pretty((1, 2)) == '(1, 2)' - - -class ReprDict(dict): - - def __repr__(self): - return 'hi' - - -def test_dict_with_custom_repr(): - assert pretty.pretty(ReprDict()) == 'hi' - - -class ReprList(list): - - def __repr__(self): - return 'bye' - - -class ReprSet(set): - - def __repr__(self): - return 'cat' - - -def test_set_with_custom_repr(): - assert pretty.pretty(ReprSet()) == 'cat' - - -def test_list_with_custom_repr(): - assert pretty.pretty(ReprList()) == 'bye' - - -def test_indentation(): - """Test correct indentation in groups.""" - count = 40 - gotoutput = pretty.pretty(MyList(range(count))) - expectedoutput = 'MyList(\n' + ',\n'.join(' %d' % - i for i in range(count)) + ')' - - assert_equal(gotoutput, expectedoutput) - - -def test_dispatch(): - """Test correct dispatching: The _repr_pretty_ method for MyDict must be - found before the registered printer for dict.""" - gotoutput = pretty.pretty(MyDict()) - expectedoutput = 'MyDict(...)' - - assert_equal(gotoutput, expectedoutput) - - -def test_callability_checking(): - """Test that the _repr_pretty_ method is tested for callability and skipped - if not.""" - gotoutput = pretty.pretty(Dummy2()) - expectedoutput = 'Dummy1(...)' - - assert_equal(gotoutput, expectedoutput) - - -def test_sets(): - """Test that set and frozenset use Python 3 formatting.""" - objects = [set(), frozenset(), set([1]), frozenset([1]), set([1, 2]), - frozenset([1, 2]), set([-1, -2, -3])] - expected = ['set()', 'frozenset()', '{1}', 'frozenset({1})', '{1, 2}', - 'frozenset({1, 2})', '{-3, -2, -1}'] - for obj, expected_output in zip(objects, expected): - got_output = pretty.pretty(obj) - assert_equal(got_output, expected_output) - - -def test_unsortable_set(): - xs = set([1, 2, 3, 'foo', 'bar', 'baz', object()]) - p = pretty.pretty(xs) - for x in xs: - assert pretty.pretty(x) in p - - -def test_unsortable_dict(): - xs = dict((k, 1) for k in [1, 2, 3, 'foo', 'bar', 'baz', object()]) - p = pretty.pretty(xs) - for x in xs: - assert pretty.pretty(x) in p - - -@skip_without('xxlimited') -def test_pprint_heap_allocated_type(): - """Test that pprint works for heap allocated types.""" - import xxlimited - output = pretty.pretty(xxlimited.Null) - assert_equal(output, 'xxlimited.Null') - - -def test_pprint_nomod(): - """Test that pprint works for classes with no __module__.""" - output = pretty.pretty(NoModule) - assert_equal(output, 'NoModule') - - -def test_pprint_break(): - """Test that p.break_ produces expected output.""" - output = pretty.pretty(Breaking()) - expected = 'TG: Breaking(\n ):' - assert_equal(output, expected) - - -def test_pprint_break_repr(): - """Test that p.break_ is used in repr.""" - output = pretty.pretty(BreakingReprParent()) - expected = 'TG: Breaking(\n ):' - assert_equal(output, expected) - - -def test_bad_repr(): - """Don't catch bad repr errors.""" - with assert_raises(ZeroDivisionError): - pretty.pretty(BadRepr()) - - -class BadException(Exception): - - def __str__(self): - return -1 - - -class ReallyBadRepr(object): - __module__ = 1 - - @property - def __class__(self): - raise ValueError('I am horrible') - - def __repr__(self): - raise BadException() - - -def test_really_bad_repr(): - with assert_raises(BadException): - pretty.pretty(ReallyBadRepr()) - - -class SA(object): - pass - - -class SB(SA): - pass - - -try: - super(SA).__self__ - - def test_super_repr(): - output = pretty.pretty(super(SA)) - assert_in('SA', output) - - sb = SB() - output = pretty.pretty(super(SA, sb)) - assert_in('SA', output) -except AttributeError: - def test_super_repr(): - pretty.pretty(super(SA)) - sb = SB() - pretty.pretty(super(SA, sb)) - - -def test_long_list(): - lis = list(range(10000)) - p = pretty.pretty(lis) - last2 = p.rsplit('\n', 2)[-2:] - assert_equal(last2, [' 999,', ' ...]']) - - -def test_long_set(): - s = set(range(10000)) - p = pretty.pretty(s) - last2 = p.rsplit('\n', 2)[-2:] - assert_equal(last2, [' 999,', ' ...}']) - - -def test_long_tuple(): - tup = tuple(range(10000)) - p = pretty.pretty(tup) - last2 = p.rsplit('\n', 2)[-2:] - assert_equal(last2, [' 999,', ' ...)']) - - -def test_long_dict(): - d = dict((n, n) for n in range(10000)) - p = pretty.pretty(d) - last2 = p.rsplit('\n', 2)[-2:] - assert_equal(last2, [' 999: 999,', ' ...}']) - - -def test_unbound_method(): - output = pretty.pretty(MyObj.somemethod) - assert_in('MyObj.somemethod', output) - - -class MetaClass(type): - - def __new__(cls, name): - return type.__new__(cls, name, (object,), {'name': name}) - - def __repr__(self): - return '[CUSTOM REPR FOR CLASS %s]' % self.name - - -ClassWithMeta = MetaClass('ClassWithMeta') - - -def test_metaclass_repr(): - output = pretty.pretty(ClassWithMeta) - assert_equal(output, '[CUSTOM REPR FOR CLASS ClassWithMeta]') - - -def test_unicode_repr(): - u = u"üniçodé" - ustr = unicode_to_str(u) - - class C(object): - - def __repr__(self): - return ustr - - c = C() - p = pretty.pretty(c) - assert_equal(p, u) - p = pretty.pretty([c]) - assert_equal(p, u'[%s]' % u) - - -def test_basic_class(): - def type_pprint_wrapper(obj, p, cycle): - if obj is MyObj: - type_pprint_wrapper.called = True - return pretty._type_pprint(obj, p, cycle) - type_pprint_wrapper.called = False - - stream = StringIO() - printer = pretty.RepresentationPrinter(stream) - printer.type_pprinters[type] = type_pprint_wrapper - printer.pretty(MyObj) - printer.flush() - output = stream.getvalue() - - assert_equal(output, '%s.MyObj' % __name__) - assert_true(type_pprint_wrapper.called) - - -# This is only run on Python 2 because in Python 3 the language prevents you -# from setting a non-unicode value for __qualname__ on a metaclass, and it -# doesn't respect the descriptor protocol if you subclass unicode and implement -# __get__. -@py2_only -def test_fallback_to__name__on_type(): - # Test that we correctly repr types that have non-string values for - # __qualname__ by falling back to __name__ - - class Type(object): - __qualname__ = 5 - - # Test repring of the type. - stream = StringIO() - printer = pretty.RepresentationPrinter(stream) - - printer.pretty(Type) - printer.flush() - output = stream.getvalue() - - # If __qualname__ is malformed, we should fall back to __name__. - expected = '.'.join([__name__, Type.__name__]) - assert_equal(output, expected) - - # Clear stream buffer. - stream.buf = '' - - # Test repring of an instance of the type. - instance = Type() - printer.pretty(instance) - printer.flush() - output = stream.getvalue() - - # Should look like: - # - prefix = '<' + '.'.join([__name__, Type.__name__]) + ' at 0x' - assert_true(output.startswith(prefix)) - - -@py2_only -def test_fail_gracefully_on_bogus__qualname__and__name__(): - # Test that we correctly repr types that have non-string values for both - # __qualname__ and __name__ - - class Meta(type): - __name__ = 5 - - class Type(object): - __metaclass__ = Meta - __qualname__ = 5 - - stream = StringIO() - printer = pretty.RepresentationPrinter(stream) - - printer.pretty(Type) - printer.flush() - output = stream.getvalue() - - # If we can't find __name__ or __qualname__ just use a sentinel string. - expected = '.'.join([__name__, '']) - assert_equal(output, expected) - - # Clear stream buffer. - stream.buf = '' - - # Test repring of an instance of the type. - instance = Type() - printer.pretty(instance) - printer.flush() - output = stream.getvalue() - - # Should look like: - # at 0x7f7658ae07d0> - prefix = '<' + '.'.join([__name__, '']) + ' at 0x' - assert_true(output.startswith(prefix)) - - -def test_collections_defaultdict(): - # Create defaultdicts with cycles - a = defaultdict() - a.default_factory = a - b = defaultdict(list) - b['key'] = b - - # Dictionary order cannot be relied on, test against single keys. - cases = [ - (defaultdict(list), 'defaultdict(list, {})'), - (defaultdict(list, {'key': '-' * 50}), - 'defaultdict(list,\n' - " {'key': '-----------------------------------------" - "---------'})"), - (a, 'defaultdict(defaultdict(...), {})'), - (b, "defaultdict(list, {'key': defaultdict(...)})"), - ] - for obj, expected in cases: - assert_equal(pretty.pretty(obj), expected) - - -def test_collections_ordereddict(): - # Create OrderedDict with cycle - a = OrderedDict() - a['key'] = a - - cases = [ - (OrderedDict(), 'OrderedDict()'), - (OrderedDict((i, i) for i in range(1000, 1010)), - 'OrderedDict([(1000, 1000),\n' - ' (1001, 1001),\n' - ' (1002, 1002),\n' - ' (1003, 1003),\n' - ' (1004, 1004),\n' - ' (1005, 1005),\n' - ' (1006, 1006),\n' - ' (1007, 1007),\n' - ' (1008, 1008),\n' - ' (1009, 1009)])'), - (a, "OrderedDict([('key', OrderedDict(...))])"), - ] - for obj, expected in cases: - assert_equal(pretty.pretty(obj), expected) - - -def test_collections_deque(): - # Create deque with cycle - a = deque() - a.append(a) - - cases = [ - (deque(), 'deque([])'), - (deque(i for i in range(1000, 1020)), - 'deque([1000,\n' - ' 1001,\n' - ' 1002,\n' - ' 1003,\n' - ' 1004,\n' - ' 1005,\n' - ' 1006,\n' - ' 1007,\n' - ' 1008,\n' - ' 1009,\n' - ' 1010,\n' - ' 1011,\n' - ' 1012,\n' - ' 1013,\n' - ' 1014,\n' - ' 1015,\n' - ' 1016,\n' - ' 1017,\n' - ' 1018,\n' - ' 1019])'), - (a, 'deque([deque(...)])'), - ] - for obj, expected in cases: - assert_equal(pretty.pretty(obj), expected) - - -def test_collections_counter(): - class MyCounter(Counter): - pass - cases = [ - (Counter(), 'Counter()'), - (Counter(a=1), "Counter({'a': 1})"), - (MyCounter(a=1), "MyCounter({'a': 1})"), - ] - for obj, expected in cases: - assert_equal(pretty.pretty(obj), expected) - - -def test_cyclic_list(): - x = [] - x.append(x) - assert pretty.pretty(x) == '[[...]]' - - -def test_cyclic_dequeue(): - x = deque() - x.append(x) - assert pretty.pretty(x) == 'deque([deque(...)])' - - -class HashItAnyway(object): - - def __init__(self, value): - self.value = value - - def __hash__(self): - return 0 - - def __eq__(self, other): - return isinstance(other, HashItAnyway) and self.value == other.value - - def __ne__(self, other): - return not self.__eq__(other) - - def _repr_pretty_(self, pretty, cycle): - pretty.pretty(self.value) - - -def test_cyclic_counter(): - c = Counter() - k = HashItAnyway(c) - c[k] = 1 - assert pretty.pretty(c) == 'Counter({Counter(...): 1})' - - -def test_cyclic_dict(): - x = {} - k = HashItAnyway(x) - x[k] = x - assert pretty.pretty(x) == '{{...}: {...}}' - - -def test_cyclic_set(): - x = set() - x.add(HashItAnyway(x)) - assert pretty.pretty(x) == '{{...}}' - - -def test_pprint(): - t = {'hi': 1} - with capture_out() as o: - pretty.pprint(t) - assert o.getvalue().strip() == pretty.pretty(t) - - -class BigList(list): - - def _repr_pretty_(self, printer, cycle): - if cycle: - return '[...]' - else: - with printer.group(open='[', close=']'): - with printer.indent(5): - for v in self: - printer.pretty(v) - printer.breakable(',') - - -def test_print_with_indent(): - pretty.pretty(BigList([1, 2, 3])) - - -class MyException(Exception): - pass - - -def test_exception(): - assert pretty.pretty(ValueError('hi')) == "ValueError('hi')" - assert pretty.pretty(ValueError('hi', 'there')) == \ - "ValueError('hi', 'there')" - assert 'test_pretty.' in pretty.pretty(MyException()) - - -def test_re_evals(): - for r in [ - re.compile(r'hi'), re.compile(r'b\nc', re.MULTILINE), - re.compile(br'hi', 0), re.compile(u'foo', re.MULTILINE | re.UNICODE), - ]: - assert repr(eval(pretty.pretty(r), globals())) == repr(r) - - -class CustomStuff(object): - - def __init__(self): - self.hi = 1 - self.bye = 'fish' - self.spoon = self - - @property - def oops(self): - raise AttributeError('Nope') - - def squirrels(self): - pass - - -def test_custom(): - assert 'bye' not in pretty.pretty(CustomStuff()) - assert 'bye=' in pretty.pretty(CustomStuff(), verbose=True) - assert 'squirrels' not in pretty.pretty(CustomStuff(), verbose=True) - - -def test_print_builtin_function(): - assert pretty.pretty(abs) == '' - - -def test_pretty_function(): - assert '.' in pretty.pretty(test_pretty_function) - - -def test_empty_printer(): - printer = pretty.RepresentationPrinter( - pretty.CUnicodeIO(), - singleton_pprinters={}, - type_pprinters={ - int: pretty._repr_pprint, - list: pretty._repr_pprint, - }, - deferred_pprinters={}, - ) - printer.pretty([1, 2, 3]) - assert printer.output.getvalue() == u'[1, 2, 3]' - - -def test_breakable_at_group_boundary(): - assert '\n' in pretty.pretty([[], '000000'], max_width=5) diff -Nru python-hypothesis-3.44.1/tests/cover/test_provisional_strategies.py python-hypothesis-3.71.11/tests/cover/test_provisional_strategies.py --- python-hypothesis-3.44.1/tests/cover/test_provisional_strategies.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_provisional_strategies.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from binascii import unhexlify - -from hypothesis import given -from hypothesis.provisional import emails, ip4_addr_strings, \ - ip6_addr_strings - - -@given(emails()) -def test_is_valid_email(address): - local, at_, domain = address.rpartition('@') - assert at_ == '@' - assert local - assert domain - - -@given(ip4_addr_strings()) -def test_is_IP4_addr(address): - as_num = [int(n) for n in address.split('.')] - assert len(as_num) == 4 - assert all(0 <= n <= 255 for n in as_num) - - -@given(ip6_addr_strings()) -def test_is_IP6_addr(address): - # Works for non-normalised addresses produced by this strategy, but not - # a particularly general test - assert address == address.upper() - as_hex = address.split(':') - assert len(as_hex) == 8 - assert all(len(part) == 4 for part in as_hex) - raw = unhexlify(address.replace(u':', u'').encode('ascii')) - assert len(raw) == 16 diff -Nru python-hypothesis-3.44.1/tests/cover/test_randomization.py python-hypothesis-3.71.11/tests/cover/test_randomization.py --- python-hypothesis-3.44.1/tests/cover/test_randomization.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_randomization.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import random - -from pytest import raises - -import hypothesis.strategies as st -from hypothesis import Verbosity, find, given, settings - - -def test_seeds_off_random(): - s = settings(max_shrinks=0, database=None) - r = random.getstate() - x = find(st.integers(), lambda x: True, settings=s) - random.setstate(r) - y = find(st.integers(), lambda x: True, settings=s) - assert x == y - - -def test_nesting_with_control_passes_health_check(): - @given(st.integers(0, 100), st.random_module()) - @settings(max_examples=5, database=None, deadline=None) - def test_blah(x, rnd): - @given(st.integers()) - @settings( - max_examples=100, max_shrinks=0, database=None, - verbosity=Verbosity.quiet) - def test_nest(y): - assert y < x - with raises(AssertionError): - test_nest() - test_blah() diff -Nru python-hypothesis-3.44.1/tests/cover/test_random_module.py python-hypothesis-3.71.11/tests/cover/test_random_module.py --- python-hypothesis-3.44.1/tests/cover/test_random_module.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_random_module.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import random - -import pytest - -import hypothesis.strategies as st -from hypothesis import given, reporting -from tests.common.utils import capture_out - - -def test_can_seed_random(): - with capture_out() as out: - with reporting.with_reporter(reporting.default): - with pytest.raises(AssertionError): - @given(st.random_module()) - def test(r): - assert False - test() - assert 'random.seed(0)' in out.getvalue() - - -@given(st.random_module(), st.random_module()) -def test_seed_random_twice(r, r2): - assert repr(r) == repr(r2) - - -@given(st.random_module()) -def test_does_not_fail_health_check_if_randomness_is_used(r): - random.getrandbits(128) diff -Nru python-hypothesis-3.44.1/tests/cover/test_recursive.py python-hypothesis-3.71.11/tests/cover/test_recursive.py --- python-hypothesis-3.44.1/tests/cover/test_recursive.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_recursive.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,57 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import pytest - -import hypothesis.strategies as st -from hypothesis import find, given -from hypothesis.errors import InvalidArgument - - -@given( - st.recursive( - st.booleans(), lambda x: st.lists(x, average_size=20), - max_leaves=10)) -def test_respects_leaf_limit(xs): - def flatten(x): - if isinstance(x, list): - return sum(map(flatten, x), []) - else: - return [x] - assert len(flatten(xs)) <= 10 - - -def test_can_find_nested(): - x = find( - st.recursive(st.booleans(), lambda x: st.tuples(x, x)), - lambda x: isinstance(x, tuple) and isinstance(x[0], tuple) - ) - - assert x == ((False, False), False) - - -def test_recursive_call_validates_expand_returns_strategies(): - with pytest.raises(InvalidArgument): - st.recursive(st.booleans(), lambda x: 1).example() - - -def test_recursive_call_validates_base_is_strategy(): - x = st.recursive(1, lambda x: st.none()) - with pytest.raises(InvalidArgument): - x.example() diff -Nru python-hypothesis-3.44.1/tests/cover/test_reflection.py python-hypothesis-3.71.11/tests/cover/test_reflection.py --- python-hypothesis-3.44.1/tests/cover/test_reflection.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_reflection.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,601 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import sys -from copy import deepcopy -from functools import partial - -import pytest - -from mock import Mock, MagicMock, NonCallableMock, NonCallableMagicMock -from tests.common.utils import raises -from hypothesis.internal.compat import PY3, FullArgSpec, getfullargspec -from hypothesis.internal.reflection import is_mock, proxies, arg_string, \ - required_args, unbind_method, eval_directory, function_digest, \ - fully_qualified_name, source_exec_as_module, \ - convert_keyword_arguments, define_function_signature, \ - convert_positional_arguments, get_pretty_function_description - - -def do_conversion_test(f, args, kwargs): - result = f(*args, **kwargs) - - cargs, ckwargs = convert_keyword_arguments(f, args, kwargs) - assert result == f(*cargs, **ckwargs) - - cargs2, ckwargs2 = convert_positional_arguments(f, args, kwargs) - assert result == f(*cargs2, **ckwargs2) - - -def test_simple_conversion(): - def foo(a, b, c): - return (a, b, c) - - assert convert_keyword_arguments( - foo, (1, 2, 3), {}) == ((1, 2, 3), {}) - assert convert_keyword_arguments( - foo, (), {'a': 3, 'b': 2, 'c': 1}) == ((3, 2, 1), {}) - - do_conversion_test(foo, (1, 0), {'c': 2}) - do_conversion_test(foo, (1,), {'c': 2, 'b': 'foo'}) - - -def test_populates_defaults(): - def bar(x=[], y=1): - pass - - assert convert_keyword_arguments(bar, (), {}) == (([], 1), {}) - assert convert_keyword_arguments(bar, (), {'y': 42}) == (([], 42), {}) - do_conversion_test(bar, (), {}) - do_conversion_test(bar, (1,), {}) - - -def test_leaves_unknown_kwargs_in_dict(): - def bar(x, **kwargs): - pass - - assert convert_keyword_arguments(bar, (1,), {'foo': 'hi'}) == ( - (1,), {'foo': 'hi'} - ) - assert convert_keyword_arguments(bar, (), {'x': 1, 'foo': 'hi'}) == ( - (1,), {'foo': 'hi'} - ) - do_conversion_test(bar, (1,), {}) - do_conversion_test(bar, (), {'x': 1, 'y': 1}) - - -def test_errors_on_bad_kwargs(): - def bar(): - pass - - with raises(TypeError): - convert_keyword_arguments(bar, (), {'foo': 1}) - - -def test_passes_varargs_correctly(): - def foo(*args): - pass - - assert convert_keyword_arguments(foo, (1, 2, 3), {}) == ((1, 2, 3), {}) - - do_conversion_test(foo, (1, 2, 3), {}) - - -def test_errors_if_keyword_precedes_positional(): - def foo(x, y): - pass - with raises(TypeError): - convert_keyword_arguments(foo, (1,), {'x': 2}) - - -def test_errors_if_not_enough_args(): - def foo(a, b, c, d=1): - pass - - with raises(TypeError): - convert_keyword_arguments(foo, (1, 2), {'d': 4}) - - -def test_errors_on_extra_kwargs(): - def foo(a): - pass - - with raises(TypeError) as e: - convert_keyword_arguments(foo, (1,), {'b': 1}) - assert 'keyword' in e.value.args[0] - - with raises(TypeError) as e2: - convert_keyword_arguments(foo, (1,), {'b': 1, 'c': 2}) - assert 'keyword' in e2.value.args[0] - - -def test_positional_errors_if_too_many_args(): - def foo(a): - pass - - with raises(TypeError) as e: - convert_positional_arguments(foo, (1, 2), {}) - assert '2 given' in e.value.args[0] - - -def test_positional_errors_if_too_few_args(): - def foo(a, b, c): - pass - - with raises(TypeError): - convert_positional_arguments(foo, (1, 2), {}) - - -def test_positional_does_not_error_if_extra_args_are_kwargs(): - def foo(a, b, c): - pass - - convert_positional_arguments(foo, (1, 2), {'c': 3}) - - -def test_positional_errors_if_given_bad_kwargs(): - def foo(a): - pass - - with raises(TypeError) as e: - convert_positional_arguments(foo, (), {'b': 1}) - assert 'unexpected keyword argument' in e.value.args[0] - - -def test_positional_errors_if_given_duplicate_kwargs(): - def foo(a): - pass - - with raises(TypeError) as e: - convert_positional_arguments(foo, (2,), {'a': 1}) - assert 'multiple values' in e.value.args[0] - - -def test_names_of_functions_are_pretty(): - assert get_pretty_function_description( - test_names_of_functions_are_pretty - ) == 'test_names_of_functions_are_pretty' - - -class Foo(object): - - @classmethod - def bar(cls): - pass - - def baz(cls): - pass - - def __repr__(self): - return 'SoNotFoo()' - - -def test_class_names_are_not_included_in_class_method_prettiness(): - assert get_pretty_function_description(Foo.bar) == 'bar' - - -def test_repr_is_included_in_bound_method_prettiness(): - assert get_pretty_function_description(Foo().baz) == 'SoNotFoo().baz' - - -def test_class_is_not_included_in_unbound_method(): - assert ( - get_pretty_function_description(Foo.baz) - == 'baz' - ) - - -def test_does_not_error_on_confused_sources(): - def ed(f, *args): - return f - - x = ed( - lambda x, y: ( - x * y - ).conjugate() == x.conjugate() * y.conjugate(), complex, complex) - - get_pretty_function_description(x) - - -def test_digests_are_reasonably_unique(): - assert ( - function_digest(test_simple_conversion) != - function_digest(test_does_not_error_on_confused_sources) - ) - - -def test_digest_returns_the_same_value_for_two_calls(): - assert ( - function_digest(test_simple_conversion) == - function_digest(test_simple_conversion) - ) - - -def test_can_digest_a_built_in_function(): - import math - assert function_digest(math.isnan) != function_digest(range) - - -def test_can_digest_a_unicode_lambda(): - function_digest(lambda x: '☃' in str(x)) - - -def test_can_digest_a_function_with_no_name(): - def foo(x, y): - pass - function_digest(partial(foo, 1)) - - -def test_arg_string_is_in_order(): - def foo(c, a, b, f, a1): - pass - - assert arg_string(foo, (1, 2, 3, 4, 5), {}) == 'c=1, a=2, b=3, f=4, a1=5' - assert arg_string( - foo, (1, 2), - {'b': 3, 'f': 4, 'a1': 5}) == 'c=1, a=2, b=3, f=4, a1=5' - - -def test_varkwargs_are_sorted_and_after_real_kwargs(): - def foo(d, e, f, **kwargs): - pass - - assert arg_string( - foo, (), {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5, 'f': 6} - ) == 'd=4, e=5, f=6, a=1, b=2, c=3' - - -def test_varargs_come_without_equals(): - def foo(a, *args): - pass - - assert arg_string(foo, (1, 2, 3, 4), {}) == '2, 3, 4, a=1' - - -def test_can_mix_varargs_and_varkwargs(): - def foo(*args, **kwargs): - pass - - assert arg_string( - foo, (1, 2, 3), {'c': 7} - ) == '1, 2, 3, c=7' - - -def test_arg_string_does_not_include_unprovided_defaults(): - def foo(a, b, c=9, d=10): - pass - - assert arg_string(foo, (1,), {'b': 1, 'd': 11}) == 'a=1, b=1, d=11' - - -class A(object): - - def f(self): - pass - - def g(self): - pass - - -class B(A): - pass - - -class C(A): - - def f(self): - pass - - -def test_unbind_gives_parent_class_function(): - assert unbind_method(B().f) == unbind_method(A.f) - - -def test_unbind_distinguishes_different_functions(): - assert unbind_method(A.f) != unbind_method(A.g) - - -def test_unbind_distinguishes_overridden_functions(): - assert unbind_method(C().f) != unbind_method(A.f) - - -def universal_acceptor(*args, **kwargs): - return args, kwargs - - -def has_one_arg(hello): - pass - - -def has_two_args(hello, world): - pass - - -def has_a_default(x, y, z=1): - pass - - -def has_varargs(*args): - pass - - -def has_kwargs(**kwargs): - pass - - -@pytest.mark.parametrize('f', [ - has_one_arg, - has_two_args, - has_varargs, - has_kwargs, -]) -def test_copying_preserves_argspec(f): - af = getfullargspec(f) - t = define_function_signature('foo', 'docstring', af)(universal_acceptor) - at = getfullargspec(t) - assert af.args == at.args - assert af.varargs == at.varargs - assert af.varkw == at.varkw - assert len(af.defaults or ()) == len(at.defaults or ()) - assert af.kwonlyargs == at.kwonlyargs - assert af.kwonlydefaults == at.kwonlydefaults - assert af.annotations == at.annotations - - -def test_name_does_not_clash_with_function_names(): - def f(): - pass - - @define_function_signature('f', 'A docstring for f', getfullargspec(f)) - def g(): - pass - g() - - -def test_copying_sets_name(): - f = define_function_signature( - 'hello_world', 'A docstring for hello_world', - getfullargspec(has_two_args))(universal_acceptor) - assert f.__name__ == 'hello_world' - - -def test_copying_sets_docstring(): - f = define_function_signature( - 'foo', 'A docstring for foo', - getfullargspec(has_two_args))(universal_acceptor) - assert f.__doc__ == 'A docstring for foo' - - -def test_uses_defaults(): - f = define_function_signature( - 'foo', 'A docstring for foo', - getfullargspec(has_a_default))(universal_acceptor) - assert f(3, 2) == ((3, 2, 1), {}) - - -def test_uses_varargs(): - f = define_function_signature( - 'foo', 'A docstring for foo', - getfullargspec(has_varargs))(universal_acceptor) - assert f(1, 2) == ((1, 2), {}) - - -DEFINE_FOO_FUNCTION = """ -def foo(x): - return x -""" - - -def test_exec_as_module_execs(): - m = source_exec_as_module(DEFINE_FOO_FUNCTION) - assert m.foo(1) == 1 - - -def test_exec_as_module_caches(): - assert ( - source_exec_as_module(DEFINE_FOO_FUNCTION) is - source_exec_as_module(DEFINE_FOO_FUNCTION) - ) - - -def test_exec_leaves_sys_path_unchanged(): - old_path = deepcopy(sys.path) - source_exec_as_module('hello_world = 42') - assert sys.path == old_path - - -def test_define_function_signature_works_with_conflicts(): - def accepts_everything(*args, **kwargs): - pass - - define_function_signature('hello', 'A docstring for hello', FullArgSpec( - args=('f',), varargs=None, varkw=None, defaults=None, - kwonlyargs=[], kwonlydefaults=None, annotations={} - ))(accepts_everything)(1) - - define_function_signature('hello', 'A docstring for hello', FullArgSpec( - args=(), varargs='f', varkw=None, defaults=None, - kwonlyargs=[], kwonlydefaults=None, annotations={} - ))(accepts_everything)(1) - - define_function_signature('hello', 'A docstring for hello', FullArgSpec( - args=(), varargs=None, varkw='f', defaults=None, - kwonlyargs=[], kwonlydefaults=None, annotations={} - ))(accepts_everything)() - - define_function_signature('hello', 'A docstring for hello', FullArgSpec( - args=('f', 'f_3'), varargs='f_1', varkw='f_2', defaults=None, - kwonlyargs=[], kwonlydefaults=None, annotations={} - ))(accepts_everything)(1, 2) - - -def test_define_function_signature_validates_arguments(): - with raises(ValueError): - define_function_signature('hello_world', None, FullArgSpec( - args=['a b'], varargs=None, varkw=None, defaults=None, - kwonlyargs=[], kwonlydefaults=None, annotations={})) - - -def test_define_function_signature_validates_function_name(): - with raises(ValueError): - define_function_signature('hello world', None, FullArgSpec( - args=['a', 'b'], varargs=None, varkw=None, defaults=None, - kwonlyargs=[], kwonlydefaults=None, annotations={})) - - -class Container(object): - - def funcy(self): - pass - - -def test_fully_qualified_name(): - assert fully_qualified_name(test_copying_preserves_argspec) == \ - 'tests.cover.test_reflection.test_copying_preserves_argspec' - assert fully_qualified_name(Container.funcy) == \ - 'tests.cover.test_reflection.Container.funcy' - assert fully_qualified_name(fully_qualified_name) == \ - 'hypothesis.internal.reflection.fully_qualified_name' - - -def test_qualname_of_function_with_none_module_is_name(): - def f(): - pass - f.__module__ = None - assert fully_qualified_name(f)[-1] == 'f' - - -def test_can_proxy_functions_with_mixed_args_and_varargs(): - def foo(a, *args): - return (a, args) - - @proxies(foo) - def bar(*args, **kwargs): - return foo(*args, **kwargs) - - assert bar(1, 2) == (1, (2,)) - - -def test_can_delegate_to_a_function_with_no_positional_args(): - def foo(a, b): - return (a, b) - - @proxies(foo) - def bar(**kwargs): - return foo(**kwargs) - - assert bar(2, 1) == (2, 1) - - -class Snowman(object): - - def __repr__(self): - return '☃' - - -class BittySnowman(object): - - def __repr__(self): - return '☃' - - -def test_can_handle_unicode_repr(): - def foo(x): - pass - assert arg_string(foo, [Snowman()], {}) == 'x=☃' - assert arg_string(foo, [], {'x': Snowman()}) == 'x=☃' - - -class NoRepr(object): - pass - - -def test_can_handle_repr_on_type(): - def foo(x): - pass - assert arg_string(foo, [Snowman], {}) == 'x=Snowman' - assert arg_string(foo, [NoRepr], {}) == 'x=NoRepr' - - -def test_can_handle_repr_of_none(): - def foo(x): - pass - - assert arg_string(foo, [None], {}) == 'x=None' - assert arg_string(foo, [], {'x': None}) == 'x=None' - - -if not PY3: - def test_can_handle_non_unicode_repr_containing_non_ascii(): - def foo(x): - pass - - assert arg_string(foo, [BittySnowman()], {}) == 'x=☃' - assert arg_string(foo, [], {'x': BittySnowman()}) == 'x=☃' - - -def test_does_not_put_eval_directory_on_path(): - source_exec_as_module("hello = 'world'") - assert eval_directory() not in sys.path - - -def test_kwargs_appear_in_arg_string(): - def varargs(*args, **kwargs): - pass - assert 'x=1' in arg_string(varargs, (), {'x': 1}) - - -def test_is_mock_with_negative_cases(): - assert not is_mock(None) - assert not is_mock(1234) - assert not is_mock(is_mock) - assert not is_mock(BittySnowman()) - assert not is_mock('foobar') - assert not is_mock(Mock(spec=BittySnowman)) - assert not is_mock(MagicMock(spec=BittySnowman)) - - -def test_is_mock_with_positive_cases(): - assert is_mock(Mock()) - assert is_mock(MagicMock()) - assert is_mock(NonCallableMock()) - assert is_mock(NonCallableMagicMock()) - - -class Target(object): - - def __init__(self, a, b): - pass - - def method(self, a, b): - pass - - -@pytest.mark.parametrize('target', [Target, Target(1, 2).method]) -@pytest.mark.parametrize('args,kwargs,expected', [ - ((), {}, set('ab')), - ((1,), {}, set('b')), - ((1, 2), {}, set()), - ((), dict(a=1), set('b')), - ((), dict(b=2), set('a')), - ((), dict(a=1, b=2), set()), -]) -def test_required_args(target, args, kwargs, expected): - # Mostly checking that `self` (and only self) is correctly excluded - assert required_args(target, args, kwargs) == expected diff -Nru python-hypothesis-3.44.1/tests/cover/test_regex.py python-hypothesis-3.71.11/tests/cover/test_regex.py --- python-hypothesis-3.44.1/tests/cover/test_regex.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_regex.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,386 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import re -import sys -import unicodedata - -import pytest - -import hypothesis.strategies as st -from hypothesis import given, assume -from tests.common.debug import find_any, assert_no_examples, \ - assert_all_examples -from hypothesis.internal.compat import PY3, hrange, hunichr -from hypothesis.searchstrategy.regex import SPACE_CHARS, \ - UNICODE_SPACE_CHARS, HAS_WEIRD_WORD_CHARS, UNICODE_WORD_CATEGORIES, \ - UNICODE_DIGIT_CATEGORIES, UNICODE_SPACE_CATEGORIES, \ - UNICODE_WEIRD_NONWORD_CHARS, base_regex_strategy - - -def is_ascii(s): - return all(ord(c) < 128 for c in s) - - -def is_digit(s): - return all(unicodedata.category(c) in UNICODE_DIGIT_CATEGORIES for c in s) - - -def is_space(s): - return all(c in SPACE_CHARS for c in s) - - -def is_unicode_space(s): - return all( - unicodedata.category(c) in UNICODE_SPACE_CATEGORIES or - c in UNICODE_SPACE_CHARS - for c in s - ) - - -def is_word(s): - return all( - c == '_' or ( - (not HAS_WEIRD_WORD_CHARS or - c not in UNICODE_WEIRD_NONWORD_CHARS) and - unicodedata.category(c) in UNICODE_WORD_CATEGORIES - ) - for c in s - ) - - -def ascii_regex(pattern): - flags = re.ASCII if PY3 else 0 - return re.compile(pattern, flags) - - -def unicode_regex(pattern): - return re.compile(pattern, re.UNICODE) - - -def _test_matching_pattern(pattern, isvalidchar, is_unicode=False): - r = unicode_regex(pattern) if is_unicode else ascii_regex(pattern) - - codepoints = hrange(0, sys.maxunicode + 1) \ - if is_unicode else hrange(1, 128) - for c in [hunichr(x) for x in codepoints]: - if isvalidchar(c): - assert r.search(c), ( - '"%s" supposed to match "%s" (%r, category "%s"), ' - "but it doesn't" % (pattern, c, c, unicodedata.category(c)) - ) - else: - assert not r.search(c), ( - '"%s" supposed not to match "%s" (%r, category "%s"), ' - 'but it does' % (pattern, c, c, unicodedata.category(c)) - ) - - -@pytest.mark.parametrize('category,predicate', [ - (r'\w', is_word), (r'\d', is_digit), (r'\s', None)]) -@pytest.mark.parametrize('invert', [False, True]) -@pytest.mark.parametrize('is_unicode', [False, True]) -def test_matching(category, predicate, invert, is_unicode): - if predicate is None: - # Special behaviour due to \x1c, INFORMATION SEPARATOR FOUR - predicate = is_unicode_space if is_unicode else is_space - pred = predicate - if invert: - category = category.swapcase() - - def pred(s): - return not predicate(s) - - _test_matching_pattern(category, pred, is_unicode) - - -@pytest.mark.parametrize('pattern', [ - u'.', # anything - u'a', u'abc', u'[a][b][c]', u'[^a][^b][^c]', # literals - u'[a-z0-9_]', u'[^a-z0-9_]', # range and negative range - u'ab?', u'ab*', u'ab+', # quantifiers - u'ab{5}', u'ab{5,10}', u'ab{,10}', u'ab{5,}', # repeaters - u'ab|cd|ef', # branch - u'(foo)+', u'([\'"])[a-z]+\\1', - u'(?:[a-z])([\'"])[a-z]+\\1', u'(?P[\'"])[a-z]+(?P=foo)', # groups - u'^abc', # beginning - u'\\d', u'[\\d]', u'[^\\D]', u'\\w', u'[\\w]', u'[^\\W]', - u'\\s', u'[\\s]', u'[^\\S]', # categories -]) -@pytest.mark.parametrize('encode', [False, True]) -def test_can_generate(pattern, encode): - if encode: - pattern = pattern.encode('ascii') - assert_all_examples(st.from_regex(pattern), re.compile(pattern).search) - - -@pytest.mark.parametrize('pattern', [ - re.compile(u'a', re.IGNORECASE), - u'(?i)a', - re.compile(u'[ab]', re.IGNORECASE), - u'(?i)[ab]', -]) -def test_literals_with_ignorecase(pattern): - strategy = st.from_regex(pattern) - - find_any(strategy, lambda s: s == u'a') - find_any(strategy, lambda s: s == u'A') - - -@pytest.mark.parametrize('pattern', [ - re.compile(u'\\A[^a][^b]\\Z', re.IGNORECASE), - u'(?i)\\A[^a][^b]\\Z' -]) -def test_not_literal_with_ignorecase(pattern): - assert_all_examples( - st.from_regex(pattern), - lambda s: s[0] not in (u'a', u'A') and s[1] not in (u'b', u'B') - ) - - -def test_any_doesnt_generate_newline(): - assert_all_examples(st.from_regex(u'.'), lambda s: s != u'\n') - - -@pytest.mark.parametrize('pattern', [re.compile(u'.', re.DOTALL), u'(?s).']) -def test_any_with_dotall_generate_newline(pattern): - find_any(st.from_regex(pattern), lambda s: s == u'\n') - - -@pytest.mark.parametrize('pattern', [re.compile(b'.', re.DOTALL), b'(?s).']) -def test_any_with_dotall_generate_newline_binary(pattern): - find_any(st.from_regex(pattern), lambda s: s == b'\n') - - -@pytest.mark.parametrize('pattern', [ - u'\\d', u'[\\d]', u'[^\\D]', - u'\\w', u'[\\w]', u'[^\\W]', - u'\\s', u'[\\s]', u'[^\\S]', -]) -@pytest.mark.parametrize('is_unicode', [False, True]) -@pytest.mark.parametrize('invert', [False, True]) -def test_groups(pattern, is_unicode, invert): - if u'd' in pattern.lower(): - group_pred = is_digit - elif u'w' in pattern.lower(): - group_pred = is_word - else: - # Special behaviour due to \x1c, INFORMATION SEPARATOR FOUR - group_pred = is_unicode_space if is_unicode else is_space - - if invert: - pattern = pattern.swapcase() - _p = group_pred - - def group_pred(s): - return not _p(s) - - pattern = u'^%s\\Z' % (pattern,) - - compiler = unicode_regex if is_unicode else ascii_regex - strategy = st.from_regex(compiler(pattern)) - - find_any(strategy.filter(group_pred), is_ascii) - if is_unicode: - find_any(strategy, lambda s: group_pred(s) and not is_ascii(s)) - - assert_all_examples(strategy, group_pred) - - -def test_caret_in_the_middle_does_not_generate_anything(): - r = re.compile(u'a^b') - - assert_no_examples(st.from_regex(r)) - - -def test_end_with_terminator_does_not_pad(): - assert_all_examples(st.from_regex(u'abc\\Z'), lambda x: x[-3:] == u"abc") - - -def test_end(): - strategy = st.from_regex(u'abc$') - - find_any(strategy, lambda s: s == u'abc') - find_any(strategy, lambda s: s == u'abc\n') - - -def test_groupref_exists(): - assert_all_examples( - st.from_regex(u'^(<)?a(?(1)>)$'), - lambda s: s in (u'a', u'a\n', u'', u'\n') - ) - assert_all_examples( - st.from_regex(u'^(a)?(?(1)b|c)$'), - lambda s: s in (u'ab', u'ab\n', u'c', u'c\n') - ) - - -def test_impossible_negative_lookahead(): - assert_no_examples(st.from_regex(u'(?!foo)foo')) - - -@given(st.from_regex(u"(\\Afoo\\Z)")) -def test_can_handle_boundaries_nested(s): - assert s == u"foo" - - -def test_groupref_not_shared_between_regex(): - # If group references are (incorrectly!) shared between regex, this would - # fail as the would only be one reference. - st.tuples(st.from_regex('(a)\\1'), st.from_regex('(b)\\1')).example() - - -@given(st.data()) -def test_group_ref_is_not_shared_between_identical_regex(data): - pattern = re.compile(u"^(.+)\\1\\Z", re.UNICODE) - x = data.draw(base_regex_strategy(pattern)) - y = data.draw(base_regex_strategy(pattern)) - assume(x != y) - assert pattern.match(x).end() == len(x) - assert pattern.match(y).end() == len(y) - - -@given(st.data()) -def test_does_not_leak_groups(data): - a = data.draw(base_regex_strategy(re.compile(u"^(a)\\Z"))) - assert a == 'a' - b = data.draw(base_regex_strategy(re.compile(u"^(?(1)a|b)(.)\\Z"))) - assert b[0] == 'b' - - -def test_positive_lookbehind(): - find_any(st.from_regex(u'.*(?<=ab)c'), lambda s: s.endswith(u'abc')) - - -def test_positive_lookahead(): - st.from_regex(u'a(?=bc).*').filter( - lambda s: s.startswith(u'abc')).example() - - -def test_negative_lookbehind(): - # no efficient support - strategy = st.from_regex(u'[abc]*(? 10 ** 6: - failing_example[0] = i - assert i not in failing_example - - with capture_out() as o: - with pytest.raises(AssertionError): - test() - assert '@reproduce_failure' in o.getvalue() - - exp = re.compile(r'reproduce_failure\(([^)]+)\)', re.MULTILINE) - extract = exp.search(o.getvalue()) - reproduction = eval(extract.group(0)) - test = reproduction(test) - - with pytest.raises(AssertionError): - test() - - -def test_does_not_print_reproduction_for_simple_examples_by_default(): - @given(st.integers()) - def test(i): - assert False - - with capture_out() as o: - with pytest.raises(AssertionError): - test() - assert '@reproduce_failure' not in o.getvalue() - - -def test_does_print_reproduction_for_simple_data_examples_by_default(): - @given(st.data()) - def test(data): - data.draw(st.integers()) - assert False - - with capture_out() as o: - with pytest.raises(AssertionError): - test() - assert '@reproduce_failure' in o.getvalue() - - -def test_does_not_print_reproduction_for_large_data_examples_by_default(): - @settings(max_shrinks=0) - @given(st.data()) - def test(data): - b = data.draw(st.binary(min_size=1000, max_size=1000)) - if len(zlib.compress(b)) > 1000: - raise ValueError() - - with capture_out() as o: - with pytest.raises(ValueError): - test() - assert '@reproduce_failure' not in o.getvalue() - - -class Foo(object): - def __repr__(self): - return 'not a valid python expression' - - -def test_does_print_reproduction_given_an_invalid_repr(): - @given(st.integers().map(lambda x: Foo())) - def test(i): - raise ValueError() - - with capture_out() as o: - with pytest.raises(ValueError): - test() - - assert '@reproduce_failure' in o.getvalue() - - -def test_does_not_print_reproduction_if_told_not_to(): - @settings(print_blob=PrintSettings.NEVER) - @given(st.integers().map(lambda x: Foo())) - def test(i): - raise ValueError() - - with capture_out() as o: - with pytest.raises(ValueError): - test() - - assert '@reproduce_failure' not in o.getvalue() - - -def test_raises_invalid_if_wrong_version(): - b = b'hello world' - n = len(b) - - @reproduce_failure('1.0.0', encode_failure(b)) - @given(st.binary(min_size=n, max_size=n)) - def test(x): - pass - - with pytest.raises(InvalidArgument): - test() diff -Nru python-hypothesis-3.44.1/tests/cover/test_reusable_values.py python-hypothesis-3.71.11/tests/cover/test_reusable_values.py --- python-hypothesis-3.44.1/tests/cover/test_reusable_values.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_reusable_values.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,94 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import pytest - -import hypothesis.strategies as st -from hypothesis import given, reject, example -from hypothesis.errors import InvalidArgument - -base_reusable_strategies = ( - st.text(), st.binary(), st.dates(), - st.times(), st.timedeltas(), st.booleans(), st.complex_numbers(), - st.floats(), st.floats(-1.0, 1.0), - st.integers(), st.integers(1, 10), st.integers(1), -) - - -@st.deferred -def reusable(): - return st.one_of( - st.sampled_from(base_reusable_strategies), - - st.builds( - st.floats, min_value=st.none() | st.floats(), - max_value=st.none() | st.floats(), allow_infinity=st.booleans(), - allow_nan=st.booleans() - ), - - st.builds(st.just, st.lists(max_size=0)), - st.builds(st.sampled_from, st.lists(st.lists(max_size=0))), - - st.lists(reusable).map(st.one_of), - st.lists(reusable).map(lambda ls: st.tuples(*ls)), - ) - - -assert not reusable.is_empty - - -@example(st.integers(min_value=1)) -@given(reusable) -def test_reusable_strategies_are_all_reusable(s): - try: - s.validate() - except InvalidArgument: - reject() - - assert s.has_reusable_values - - -for s in base_reusable_strategies: - test_reusable_strategies_are_all_reusable = example(s)( - test_reusable_strategies_are_all_reusable - ) - test_reusable_strategies_are_all_reusable = example(st.tuples(s))( - test_reusable_strategies_are_all_reusable - ) - - -def test_composing_breaks_reusability(): - s = st.integers() - assert s.has_reusable_values - assert not s.filter(lambda x: True).has_reusable_values - assert not s.map(lambda x: x).has_reusable_values - assert not s.flatmap(lambda x: st.just(x)).has_reusable_values - - -@pytest.mark.parametrize('strat', [ - st.lists(st.booleans()), st.sets(st.booleans()), - st.dictionaries(st.booleans(), st.booleans()), -]) -def test_mutable_collections_do_not_have_reusable_values(strat): - assert not strat.has_reusable_values - - -def test_recursion_does_not_break_reusability(): - x = st.deferred(lambda: st.none() | st.tuples(x)) - assert x.has_reusable_values diff -Nru python-hypothesis-3.44.1/tests/cover/test_runner_strategy.py python-hypothesis-3.71.11/tests/cover/test_runner_strategy.py --- python-hypothesis-3.44.1/tests/cover/test_runner_strategy.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_runner_strategy.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,73 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from unittest import TestCase - -import pytest - -from hypothesis import strategies as st -from hypothesis import find, given -from hypothesis.errors import InvalidArgument -from hypothesis.stateful import GenericStateMachine - - -def test_cannot_use_without_a_runner(): - @given(st.runner()) - def f(x): - pass - with pytest.raises(InvalidArgument): - f() - - -def test_cannot_use_in_find_without_default(): - with pytest.raises(InvalidArgument): - find(st.runner(), lambda x: True) - - -def test_is_default_in_find(): - t = object() - assert find(st.runner(t), lambda x: True) == t - - -@given(st.runner(1)) -def test_is_default_without_self(runner): - assert runner == 1 - - -class TestStuff(TestCase): - - @given(st.runner()) - def test_runner_is_self(self, runner): - assert runner is self - - @given(st.runner(default=3)) - def test_runner_is_self_even_with_default(self, runner): - assert runner is self - - -class RunnerStateMachine(GenericStateMachine): - - def steps(self): - return st.runner() - - def execute_step(self, step): - assert self is step - - -TestState = RunnerStateMachine.TestCase diff -Nru python-hypothesis-3.44.1/tests/cover/test_sampled_from.py python-hypothesis-3.71.11/tests/cover/test_sampled_from.py --- python-hypothesis-3.44.1/tests/cover/test_sampled_from.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_sampled_from.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,53 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import enum -import collections - -from hypothesis import given, settings -from tests.common.utils import checks_deprecated_behaviour -from hypothesis.strategies import sampled_from - -an_enum = enum.Enum('A', 'a b c') - -an_ordereddict = collections.OrderedDict([('a', 1), ('b', 2), ('c', 3)]) - - -@given(sampled_from((1, 2))) -@settings(min_satisfying_examples=10) -def test_can_handle_sampling_from_fewer_than_min_satisfying(v): - pass - - -@checks_deprecated_behaviour -def test_can_sample_sets_while_deprecated(): - assert sampled_from(set('abc')).example() in 'abc' - - -def test_can_sample_sequence_without_warning(): - sampled_from([1, 2, 3]).example() - - -def test_can_sample_ordereddict_without_warning(): - sampled_from(an_ordereddict).example() - - -@given(sampled_from(an_enum)) -def test_can_sample_enums(member): - assert isinstance(member, an_enum) diff -Nru python-hypothesis-3.44.1/tests/cover/test_searchstrategy.py python-hypothesis-3.71.11/tests/cover/test_searchstrategy.py --- python-hypothesis-3.44.1/tests/cover/test_searchstrategy.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_searchstrategy.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,97 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import functools -from collections import namedtuple - -import pytest - -from hypothesis.types import RandomWithSeed -from tests.common.debug import assert_no_examples -from hypothesis.strategies import just, tuples, randoms, booleans, integers -from hypothesis.internal.compat import text_type -from hypothesis.searchstrategy.strategies import one_of_strategies - - -def test_or_errors_when_given_non_strategy(): - bools = tuples(booleans()) - with pytest.raises(ValueError): - bools | u'foo' - - -def test_joining_zero_strategies_fails(): - with pytest.raises(ValueError): - one_of_strategies(()) - - -SomeNamedTuple = namedtuple(u'SomeNamedTuple', (u'a', u'b')) - - -def last(xs): - t = None - for x in xs: - t = x - return t - - -def test_random_repr_has_seed(): - rnd = randoms().example() - seed = rnd.seed - assert text_type(seed) in repr(rnd) - - -def test_random_only_produces_special_random(): - st = randoms() - assert isinstance(st.example(), RandomWithSeed) - - -def test_just_strategy_uses_repr(): - class WeirdRepr(object): - - def __repr__(self): - return u'ABCDEFG' - - assert repr( - just(WeirdRepr()) - ) == u'just(%r)' % (WeirdRepr(),) - - -def test_can_map(): - s = integers().map(pack=lambda t: u'foo') - assert s.example() == u'foo' - - -def test_example_raises_unsatisfiable_when_too_filtered(): - assert_no_examples(integers().filter(lambda x: False)) - - -def nameless_const(x): - def f(u, v): - return u - return functools.partial(f, x) - - -def test_can_map_nameless(): - f = nameless_const(2) - assert repr(f) in repr(integers().map(f)) - - -def test_can_flatmap_nameless(): - f = nameless_const(just(3)) - assert repr(f) in repr(integers().flatmap(f)) diff -Nru python-hypothesis-3.44.1/tests/cover/test_seed_printing.py python-hypothesis-3.71.11/tests/cover/test_seed_printing.py --- python-hypothesis-3.44.1/tests/cover/test_seed_printing.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_seed_printing.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,123 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import time - -import pytest - -import hypothesis.core as core -import hypothesis.strategies as st -from hypothesis import given, assume, settings -from hypothesis.errors import FailedHealthCheck -from tests.common.utils import all_values, capture_out -from hypothesis.database import InMemoryExampleDatabase -from hypothesis.internal.compat import hrange - - -@pytest.mark.parametrize('in_pytest', [False, True]) -@pytest.mark.parametrize('fail_healthcheck', [False, True]) -def test_prints_seed_only_on_healthcheck( - monkeypatch, in_pytest, fail_healthcheck -): - monkeypatch.setattr(core, 'running_under_pytest', in_pytest) - - strategy = st.integers() - if fail_healthcheck: - def slow_map(i): - time.sleep(10) - return i - strategy = strategy.map(slow_map) - expected_exc = FailedHealthCheck - else: - expected_exc = AssertionError - - @settings(database=None) - @given(strategy) - def test(i): - assert fail_healthcheck - - with capture_out() as o: - with pytest.raises(expected_exc): - test() - - output = o.getvalue() - - seed = test._hypothesis_internal_use_generated_seed - assert seed is not None - if fail_healthcheck: - assert '@seed(%d)' % (seed,) in output - contains_pytest_instruction = ( - '--hypothesis-seed=%d' % (seed,)) in output - assert contains_pytest_instruction == in_pytest - else: - assert '@seed' not in output - - -def test_uses_global_force(monkeypatch): - monkeypatch.setattr(core, 'global_force_seed', 42) - - @given(st.integers()) - def test(i): - raise ValueError() - - output = [] - - for _ in hrange(2): - with capture_out() as o: - with pytest.raises(ValueError): - test() - output.append(o.getvalue()) - - assert output[0] == output[1] - assert '@seed' not in output[0] - - -def test_does_print_on_reuse_from_database(): - passes_healthcheck = False - - database = InMemoryExampleDatabase() - - @settings(database=database) - @given(st.integers()) - def test(i): - assume(passes_healthcheck) - raise ValueError() - - with capture_out() as o: - with pytest.raises(FailedHealthCheck): - test() - - assert '@seed' in o.getvalue() - - passes_healthcheck = True - - with capture_out() as o: - with pytest.raises(ValueError): - test() - - assert all_values(database) - assert '@seed' not in o.getvalue() - - passes_healthcheck = False - - with capture_out() as o: - with pytest.raises(FailedHealthCheck): - test() - - assert '@seed' in o.getvalue() diff -Nru python-hypothesis-3.44.1/tests/cover/test_sets.py python-hypothesis-3.71.11/tests/cover/test_sets.py --- python-hypothesis-3.44.1/tests/cover/test_sets.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_sets.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,52 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import pytest - -from hypothesis import find, given, settings -from hypothesis.errors import InvalidArgument -from hypothesis.strategies import sets, lists, floats, randoms, integers - - -def test_unique_lists_error_on_too_large_average_size(): - with pytest.raises(InvalidArgument): - lists(integers(), unique=True, average_size=10, max_size=5).example() - - -@given(randoms()) -@settings(max_examples=5, deadline=None) -def test_can_draw_sets_of_hard_to_find_elements(rnd): - rarebool = floats(0, 1).map(lambda x: x <= 0.01) - find( - sets(rarebool, min_size=2), lambda x: True, - random=rnd, settings=settings(database=None)) - - -def test_sets_of_small_average_size(): - assert len(sets(integers(), average_size=1.0).example()) <= 10 - - -@given(sets(max_size=0)) -def test_empty_sets(x): - assert x == set() - - -@given(sets(integers(), max_size=2)) -def test_bounded_size_sets(x): - assert len(x) <= 2 diff -Nru python-hypothesis-3.44.1/tests/cover/test_settings.py python-hypothesis-3.71.11/tests/cover/test_settings.py --- python-hypothesis-3.44.1/tests/cover/test_settings.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_settings.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,249 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import os -from tempfile import mkdtemp - -import pytest - -import hypothesis.strategies as st -from hypothesis import given, unlimited -from hypothesis.errors import InvalidState, InvalidArgument, \ - HypothesisDeprecationWarning -from tests.common.utils import checks_deprecated_behaviour -from hypothesis.database import ExampleDatabase, \ - DirectoryBasedExampleDatabase -from hypothesis._settings import Verbosity, settings, default_variable, \ - note_deprecation - - -def test_has_docstrings(): - assert settings.verbosity.__doc__ - - -original_default = settings.get_profile('default').max_examples - - -def setup_function(fn): - settings.load_profile('default') - settings.register_profile('test_settings', settings()) - settings.load_profile('test_settings') - - -def test_cannot_set_non_settings(): - s = settings() - with pytest.raises(AttributeError): - s.databas_file = u'some_file' - - -def test_settings_uses_defaults(): - s = settings() - assert s.max_examples == settings.default.max_examples - - -def test_raises_attribute_error(): - with pytest.raises(AttributeError): - settings().kittens - - -def test_respects_none_database(): - assert settings(database=None).database is None - - -def test_settings_can_be_used_as_context_manager_to_change_defaults(): - with settings(max_examples=12): - assert settings.default.max_examples == 12 - assert settings.default.max_examples == original_default - - -def test_can_repeatedly_push_the_same_thing(): - s = settings(max_examples=12) - t = settings(max_examples=17) - assert settings().max_examples == original_default - with s: - assert settings().max_examples == 12 - with t: - assert settings().max_examples == 17 - with s: - assert settings().max_examples == 12 - with t: - assert settings().max_examples == 17 - assert settings().max_examples == 12 - assert settings().max_examples == 17 - assert settings().max_examples == 12 - assert settings().max_examples == original_default - - -def test_cannot_create_settings_with_invalid_options(): - with pytest.raises(InvalidArgument): - settings(a_setting_with_limited_options=u'spoon') - - -def test_can_set_verbosity(): - settings(verbosity=Verbosity.quiet) - settings(verbosity=Verbosity.normal) - settings(verbosity=Verbosity.verbose) - - -def test_can_not_set_verbosity_to_non_verbosity(): - with pytest.raises(InvalidArgument): - settings(verbosity='kittens') - - -@pytest.mark.parametrize('db', [None, ExampleDatabase()]) -def test_inherits_an_empty_database(db): - assert settings.default.database is not None - s = settings(database=db) - assert s.database is db - with s: - t = settings() - assert t.database is db - - -@pytest.mark.parametrize('db', [None, ExampleDatabase()]) -def test_can_assign_database(db): - x = settings(database=db) - assert x.database is db - - -def test_will_reload_profile_when_default_is_absent(): - original = settings.default - default_variable.value = None - assert settings.default is original - - -def test_load_profile(): - settings.load_profile('default') - assert settings.default.max_examples == 100 - assert settings.default.max_shrinks == 500 - assert settings.default.min_satisfying_examples == 5 - - settings.register_profile( - 'test', - settings( - max_examples=10, - max_shrinks=5 - ) - ) - - settings.load_profile('test') - - assert settings.default.max_examples == 10 - assert settings.default.max_shrinks == 5 - assert settings.default.min_satisfying_examples == 5 - - settings.load_profile('default') - - assert settings.default.max_examples == 100 - assert settings.default.max_shrinks == 500 - assert settings.default.min_satisfying_examples == 5 - - -def test_loading_profile_keeps_expected_behaviour(): - settings.register_profile('ci', settings(max_examples=10000)) - settings.load_profile('ci') - assert settings().max_examples == 10000 - with settings(max_examples=5): - assert settings().max_examples == 5 - assert settings().max_examples == 10000 - - -def test_load_non_existent_profile(): - with pytest.raises(InvalidArgument): - settings.get_profile('nonsense') - - -@pytest.mark.skipif( - os.getenv('HYPOTHESIS_PROFILE') not in (None, 'default'), - reason='Defaults have been overridden') -def test_runs_tests_with_defaults_from_conftest(): - assert settings.default.timeout == -1 - - -def test_cannot_delete_a_setting(): - x = settings() - with pytest.raises(AttributeError): - del x.max_examples - x.max_examples - - x = settings() - with pytest.raises(AttributeError): - del x.foo - - -def test_cannot_set_strict(): - with pytest.raises(HypothesisDeprecationWarning): - settings(strict=True) - - -@checks_deprecated_behaviour -def test_set_deprecated_settings(): - assert settings(timeout=3).timeout == 3 - - -def test_setting_to_future_value_gives_future_value_and_no_error(): - assert settings(timeout=unlimited).timeout == -1 - - -def test_cannot_set_settings(): - x = settings() - with pytest.raises(AttributeError): - x.max_examples = 'foo' - with pytest.raises(AttributeError): - x.database = 'foo' - assert x.max_examples != 'foo' - assert x.database != 'foo' - - -def test_can_have_none_database(): - assert settings(database=None).database is None - - -def test_can_have_none_database_file(): - assert settings(database_file=None).database is None - - -def test_can_override_database_file(): - f = mkdtemp() - x = settings(database_file=f) - assert isinstance(x.database, DirectoryBasedExampleDatabase) - assert x.database.path == f - - -def test_cannot_define_settings_once_locked(): - with pytest.raises(InvalidState): - settings.define_setting('hi', 'there', 4) - - -def test_cannot_assign_default(): - with pytest.raises(AttributeError): - settings.default = settings(max_examples=3) - assert settings().max_examples != 3 - - -def test_does_not_warn_if_quiet(): - with pytest.warns(None) as rec: - note_deprecation('This is bad', settings(verbosity=Verbosity.quiet)) - assert len(rec) == 0 - - -@settings(max_examples=7) -@given(st.builds(lambda: settings.default)) -def test_settings_in_strategies_are_from_test_scope(s): - assert s.max_examples == 7 diff -Nru python-hypothesis-3.44.1/tests/cover/test_setup_teardown.py python-hypothesis-3.71.11/tests/cover/test_setup_teardown.py --- python-hypothesis-3.44.1/tests/cover/test_setup_teardown.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_setup_teardown.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,133 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import pytest - -from hypothesis import given, assume -from hypothesis.strategies import text, integers - - -class HasSetup(object): - - def setup_example(self): - self.setups = getattr(self, u'setups', 0) - self.setups += 1 - - -class HasTeardown(object): - - def teardown_example(self, ex): - self.teardowns = getattr(self, u'teardowns', 0) - self.teardowns += 1 - - -class SomeGivens(object): - - @given(integers()) - def give_me_an_int(self, x): - pass - - @given(text()) - def give_me_a_string(myself, x): - pass - - @given(integers()) - def give_me_a_positive_int(self, x): - assert x >= 0 - - @given(integers().map(lambda x: x.nope)) - def fail_in_reify(self, x): - pass - - @given(integers()) - def assume_some_stuff(self, x): - assume(x > 0) - - @given(integers().filter(lambda x: x > 0)) - def assume_in_reify(self, x): - pass - - -class HasSetupAndTeardown(HasSetup, HasTeardown, SomeGivens): - pass - - -def test_calls_setup_and_teardown_on_self_as_first_argument(): - x = HasSetupAndTeardown() - x.give_me_an_int() - x.give_me_a_string() - assert x.setups > 0 - assert x.teardowns == x.setups - - -def test_calls_setup_and_teardown_on_self_unbound(): - x = HasSetupAndTeardown() - HasSetupAndTeardown.give_me_an_int(x) - assert x.setups > 0 - assert x.teardowns == x.setups - - -def test_calls_setup_and_teardown_on_failure(): - x = HasSetupAndTeardown() - with pytest.raises(AssertionError): - x.give_me_a_positive_int() - assert x.setups > 0 - assert x.teardowns == x.setups - - -def test_still_tears_down_on_error_in_generation(): - x = HasSetupAndTeardown() - with pytest.raises(AttributeError): - x.fail_in_reify() - assert x.setups > 0 - assert x.teardowns == x.setups - - -def test_still_tears_down_on_failed_assume(): - x = HasSetupAndTeardown() - x.assume_some_stuff() - assert x.setups > 0 - assert x.teardowns == x.setups - - -def test_still_tears_down_on_failed_assume_in_reify(): - x = HasSetupAndTeardown() - x.assume_in_reify() - assert x.setups > 0 - assert x.teardowns == x.setups - - -def test_sets_up_without_teardown(): - class Foo(HasSetup, SomeGivens): - pass - - x = Foo() - x.give_me_an_int() - assert x.setups > 0 - assert not hasattr(x, u'teardowns') - - -def test_tears_down_without_setup(): - class Foo(HasTeardown, SomeGivens): - pass - - x = Foo() - x.give_me_an_int() - assert x.teardowns > 0 - assert not hasattr(x, u'setups') diff -Nru python-hypothesis-3.44.1/tests/cover/test_sharing.py python-hypothesis-3.71.11/tests/cover/test_sharing.py --- python-hypothesis-3.44.1/tests/cover/test_sharing.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_sharing.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,76 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import hypothesis.strategies as st -from hypothesis import find, given - -x = st.shared(st.integers()) - - -@given(x, x) -def test_sharing_is_by_instance_by_default(a, b): - assert a == b - - -@given( - st.shared(st.integers(), key='hi'), st.shared(st.integers(), key='hi')) -def test_different_instances_with_the_same_key_are_shared(a, b): - assert a == b - - -def test_different_instances_are_not_shared(): - find( - st.tuples(st.shared(st.integers()), st.shared(st.integers())), - lambda x: x[0] != x[1] - ) - - -def test_different_keys_are_not_shared(): - find( - st.tuples( - st.shared(st.integers(), key=1), - st.shared(st.integers(), key=2)), - lambda x: x[0] != x[1] - ) - - -def test_keys_and_default_are_not_shared(): - find( - st.tuples( - st.shared(st.integers(), key=1), - st.shared(st.integers())), - lambda x: x[0] != x[1] - ) - - -def test_can_simplify_shared_lists(): - xs = find( - st.lists(st.shared(st.integers())), - lambda x: len(x) >= 10 and x[0] != 0 - ) - assert xs == [1] * 10 - - -def test_simplify_shared_linked_to_size(): - xs = find( - st.lists(st.shared(st.integers())), - lambda t: sum(t) >= 1000 - ) - assert sum(xs[:-1]) < 1000 - assert (xs[0] - 1) * len(xs) < 1000 diff -Nru python-hypothesis-3.44.1/tests/cover/test_shrinking_limits.py python-hypothesis-3.71.11/tests/cover/test_shrinking_limits.py --- python-hypothesis-3.44.1/tests/cover/test_shrinking_limits.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_shrinking_limits.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,38 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import hypothesis.strategies as st -from hypothesis import find, settings - - -def test_max_shrinks(): - seen = set() - zero = b'\0' * 100 - - def tracktrue(s): - if s == zero: - return False - seen.add(s) - return True - - find( - st.binary(min_size=100, max_size=100), tracktrue, - settings=settings(max_shrinks=1) - ) - assert len(seen) == 2 diff -Nru python-hypothesis-3.44.1/tests/cover/test_simple_characters.py python-hypothesis-3.71.11/tests/cover/test_simple_characters.py --- python-hypothesis-3.44.1/tests/cover/test_simple_characters.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_simple_characters.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,131 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import unicodedata - -import pytest - -from hypothesis import find -from hypothesis.errors import InvalidArgument -from tests.common.debug import find_any, assert_no_examples -from hypothesis.strategies import characters -from hypothesis.internal.compat import text_type - - -def test_bad_category_arguments(): - with pytest.raises(InvalidArgument): - characters( - whitelist_categories=['foo'], blacklist_categories=['bar'] - ).example() - - -def test_bad_codepoint_arguments(): - with pytest.raises(InvalidArgument): - characters(min_codepoint=42, max_codepoint=24).example() - - -def test_exclude_all_available_range(): - with pytest.raises(InvalidArgument): - characters(min_codepoint=ord('0'), max_codepoint=ord('0'), - blacklist_characters='0').example() - - -def test_when_nothing_could_be_produced(): - with pytest.raises(InvalidArgument): - characters(whitelist_categories=['Cc'], - min_codepoint=ord('0'), max_codepoint=ord('9')).example() - - -def test_characters_of_specific_groups(): - st = characters(whitelist_categories=('Lu', 'Nd')) - - find(st, lambda c: unicodedata.category(c) == 'Lu') - find(st, lambda c: unicodedata.category(c) == 'Nd') - - assert_no_examples( - st, lambda c: unicodedata.category(c) not in ('Lu', 'Nd')) - - -def test_exclude_characters_of_specific_groups(): - st = characters(blacklist_categories=('Lu', 'Nd')) - - find(st, lambda c: unicodedata.category(c) != 'Lu') - find(st, lambda c: unicodedata.category(c) != 'Nd') - - assert_no_examples(st, lambda c: unicodedata.category(c) in ('Lu', 'Nd')) - - -def test_find_one(): - char = find(characters(min_codepoint=48, max_codepoint=48), lambda _: True) - assert char == u'0' - - -def test_find_something_rare(): - st = characters(whitelist_categories=['Zs'], min_codepoint=12288) - - find(st, lambda c: unicodedata.category(c) == 'Zs') - - assert_no_examples(st, lambda c: unicodedata.category(c) != 'Zs') - - -def test_whitelisted_characters_alone(): - with pytest.raises(InvalidArgument): - characters(whitelist_characters=u'te02тест49st').example() - - -def test_whitelisted_characters_overlap_blacklisted_characters(): - good_chars = u'te02тест49st' - bad_chars = u'ts94тсет' - with pytest.raises(InvalidArgument) as exc: - characters(min_codepoint=ord('0'), max_codepoint=ord('9'), - whitelist_characters=good_chars, - blacklist_characters=bad_chars).example() - assert repr(good_chars) in text_type(exc) - assert repr(bad_chars) in text_type(exc) - - -def test_whitelisted_characters_override(): - good_characters = u'teтестst' - st = characters(min_codepoint=ord('0'), max_codepoint=ord('9'), - whitelist_characters=good_characters) - - find_any(st, lambda c: c in good_characters) - find_any(st, lambda c: c in '0123456789') - - assert_no_examples(st, lambda c: c not in good_characters + '0123456789') - - -def test_blacklisted_characters(): - bad_chars = u'te02тест49st' - st = characters(min_codepoint=ord('0'), max_codepoint=ord('9'), - blacklist_characters=bad_chars) - - assert '1' == find(st, lambda c: True) - - assert_no_examples(st, lambda c: c in bad_chars) - - -def test_whitelist_characters_disjoint_blacklist_characters(): - good_chars = u'123abc' - bad_chars = u'456def' - st = characters(min_codepoint=ord('0'), max_codepoint=ord('9'), - blacklist_characters=bad_chars, - whitelist_characters=good_chars) - - assert_no_examples(st, lambda c: c in bad_chars) diff -Nru python-hypothesis-3.44.1/tests/cover/test_simple_collections.py python-hypothesis-3.71.11/tests/cover/test_simple_collections.py --- python-hypothesis-3.44.1/tests/cover/test_simple_collections.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_simple_collections.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,264 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from random import Random -from collections import namedtuple - -import pytest -from flaky import flaky - -from hypothesis import find, given, settings -from tests.common.debug import minimal, find_any -from hypothesis.strategies import none, sets, text, lists, builds, \ - tuples, booleans, integers, frozensets, dictionaries, \ - fixed_dictionaries -from hypothesis.internal.compat import OrderedDict - - -@pytest.mark.parametrize((u'col', u'strat'), [ - ((), tuples()), - ([], lists(max_size=0)), - (set(), sets(max_size=0)), - (frozenset(), frozensets(max_size=0)), - ({}, fixed_dictionaries({})), -]) -def test_find_empty_collection_gives_empty(col, strat): - assert find(strat, lambda x: True) == col - - -@pytest.mark.parametrize((u'coltype', u'strat'), [ - (list, lists), - (set, sets), - (frozenset, frozensets), -]) -def test_find_non_empty_collection_gives_single_zero(coltype, strat): - assert find( - strat(integers()), bool - ) == coltype((0,)) - - -@pytest.mark.parametrize((u'coltype', u'strat'), [ - (list, lists), - (set, sets), - (frozenset, frozensets), -]) -def test_minimizes_to_empty(coltype, strat): - assert find( - strat(integers()), lambda x: True - ) == coltype() - - -def test_minimizes_list_of_lists(): - xs = find(lists(lists(booleans())), lambda x: any(x) and not all(x)) - xs.sort() - assert xs == [[], [False]] - - -def test_minimize_long_list(): - assert find( - lists(booleans(), average_size=100), lambda x: len(x) >= 70 - ) == [False] * 70 - - -def test_minimize_list_of_longish_lists(): - xs = find( - lists(lists(booleans())), - lambda x: len([t for t in x if any(t) and len(t) >= 3]) >= 10) - assert len(xs) == 10 - for x in xs: - assert len(x) == 3 - assert len([t for t in x if t]) == 1 - - -def test_minimize_list_of_fairly_non_unique_ints(): - xs = find(lists(integers()), lambda x: len(set(x)) < len(x)) - assert len(xs) == 2 - - -def test_list_with_complex_sorting_structure(): - xs = find( - lists(lists(booleans())), - lambda x: [list(reversed(t)) for t in x] > x and len(x) > 3) - assert len(xs) == 4 - - -def test_list_with_wide_gap(): - xs = find(lists(integers()), lambda x: x and (max(x) > min(x) + 10 > 0)) - assert len(xs) == 2 - xs.sort() - assert xs[1] == 11 + xs[0] - - -def test_minimize_namedtuple(): - T = namedtuple(u'T', (u'a', u'b')) - tab = find( - builds(T, integers(), integers()), - lambda x: x.a < x.b) - assert tab.b == tab.a + 1 - - -def test_minimize_dict(): - tab = find( - fixed_dictionaries({u'a': booleans(), u'b': booleans()}), - lambda x: x[u'a'] or x[u'b'] - ) - assert not (tab[u'a'] and tab[u'b']) - - -def test_minimize_list_of_sets(): - assert find( - lists(sets(booleans())), - lambda x: len(list(filter(None, x))) >= 3) == ( - [set((False,))] * 3 - ) - - -def test_minimize_list_of_lists(): - assert find( - lists(lists(integers())), - lambda x: len(list(filter(None, x))) >= 3) == ( - [[0]] * 3 - ) - - -def test_minimize_list_of_tuples(): - xs = find( - lists(tuples(integers(), integers())), lambda x: len(x) >= 2) - assert xs == [(0, 0), (0, 0)] - - -def test_minimize_multi_key_dicts(): - assert find( - dictionaries(keys=booleans(), values=booleans()), - bool - ) == {False: False} - - -def test_minimize_dicts_with_incompatible_keys(): - assert find( - fixed_dictionaries({1: booleans(), u'hi': lists(booleans())}), - lambda x: True - ) == {1: False, u'hi': []} - - -def test_multiple_empty_lists_are_independent(): - x = find(lists(lists(max_size=0)), lambda t: len(t) >= 2) - u, v = x - assert u is not v - - -@given(sets(integers(0, 100), min_size=2, max_size=10)) -@settings(max_examples=100) -def test_sets_are_size_bounded(xs): - assert 2 <= len(xs) <= 10 - - -def test_ordered_dictionaries_preserve_keys(): - r = Random() - keys = list(range(100)) - r.shuffle(keys) - x = fixed_dictionaries( - OrderedDict([(k, booleans()) for k in keys])).example() - assert list(x.keys()) == keys - - -@pytest.mark.parametrize(u'n', range(10)) -def test_lists_of_fixed_length(n): - assert find( - lists(integers(), min_size=n, max_size=n), lambda x: True) == [0] * n - - -@pytest.mark.parametrize(u'n', range(10)) -def test_sets_of_fixed_length(n): - x = find( - sets(integers(), min_size=n, max_size=n), lambda x: True) - assert len(x) == n - - if not n: - assert x == set() - else: - assert x == set(range(min(x), min(x) + n)) - - -@pytest.mark.parametrize(u'n', range(10)) -def test_dictionaries_of_fixed_length(n): - x = set(find( - dictionaries(integers(), booleans(), min_size=n, max_size=n), - lambda x: True).keys()) - - if not n: - assert x == set() - else: - assert x == set(range(min(x), min(x) + n)) - - -@pytest.mark.parametrize(u'n', range(10)) -def test_lists_of_lower_bounded_length(n): - x = find( - lists(integers(), min_size=n), lambda x: sum(x) >= 2 * n - ) - assert n <= len(x) <= 2 * n - assert all(t >= 0 for t in x) - assert len(x) == n or all(t > 0 for t in x) - assert sum(x) == 2 * n - - -@pytest.mark.parametrize(u'n', range(10)) -def test_lists_forced_near_top(n): - assert find( - lists(integers(), min_size=n, max_size=n + 2), - lambda t: len(t) == n + 2 - ) == [0] * (n + 2) - - -@flaky(max_runs=5, min_passes=1) -def test_can_find_unique_lists_of_non_set_order(): - ls = minimal( - lists(text(), unique=True), - lambda x: list(set(reversed(x))) != x - ) - assert len(set(ls)) == len(ls) - assert len(ls) == 2 - - -def test_can_find_sets_unique_by_incomplete_data(): - ls = find( - lists(lists(integers(min_value=0), min_size=2), unique_by=max), - lambda x: len(x) >= 10 - ) - assert len(ls) == 10 - assert sorted(list(map(max, ls))) == list(range(10)) - for v in ls: - assert 0 in v - - -def test_can_draw_empty_list_from_unsatisfiable_strategy(): - assert find_any(lists(integers().filter(lambda s: False))) == [] - - -def test_can_draw_empty_set_from_unsatisfiable_strategy(): - assert find_any(sets(integers().filter(lambda s: False))) == set() - - -small_set = sets(none()) - - -@given(lists(small_set, min_size=10)) -def test_small_sized_sets(x): - pass diff -Nru python-hypothesis-3.44.1/tests/cover/test_simple_numbers.py python-hypothesis-3.71.11/tests/cover/test_simple_numbers.py --- python-hypothesis-3.44.1/tests/cover/test_simple_numbers.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_simple_numbers.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,250 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import sys -import math - -import pytest - -from hypothesis import given, settings -from tests.common.debug import minimal -from hypothesis.strategies import lists, floats, randoms, integers, \ - complex_numbers - - -def test_minimize_negative_int(): - assert minimal(integers(), lambda x: x < 0) == -1 - assert minimal(integers(), lambda x: x < -1) == -2 - - -def test_positive_negative_int(): - assert minimal(integers(), lambda x: x > 0) == 1 - assert minimal(integers(), lambda x: x > 1) == 2 - - -boundaries = pytest.mark.parametrize(u'boundary', sorted( - [2 ** i for i in range(10)] + - [2 ** i - 1 for i in range(10)] + - [2 ** i + 1 for i in range(10)] + - [10 ** i for i in range(6)] -)) - - -@boundaries -def test_minimizes_int_down_to_boundary(boundary): - assert minimal(integers(), lambda x: x >= boundary) == boundary - - -@boundaries -def test_minimizes_int_up_to_boundary(boundary): - assert minimal(integers(), lambda x: x <= -boundary) == -boundary - - -@boundaries -def test_minimizes_ints_from_down_to_boundary(boundary): - def is_good(x): - assert x >= boundary - 10 - return x >= boundary - - assert minimal( - integers(min_value=boundary - 10), is_good) == boundary - - assert minimal(integers(min_value=boundary), lambda x: True) == boundary - - -def test_minimizes_negative_integer_range_upwards(): - assert minimal(integers(min_value=-10, max_value=-1)) == -1 - - -@boundaries -def test_minimizes_integer_range_to_boundary(boundary): - assert minimal( - integers(boundary, boundary + 100), lambda x: True - ) == boundary - - -def test_single_integer_range_is_range(): - assert minimal(integers(1, 1), lambda x: True) == 1 - - -def test_minimal_small_number_in_large_range(): - assert minimal( - integers((-2 ** 32), 2 ** 32), lambda x: x >= 101) == 101 - - -def test_minimal_small_sum_float_list(): - xs = minimal( - lists(floats(), min_size=10), - lambda x: sum(x) >= 1.0 - ) - assert sum(xs) <= 2.0 - - -def test_minimals_boundary_floats(): - def f(x): - print(x) - return True - assert -1 <= minimal(floats(min_value=-1, max_value=1), f) <= 1 - - -def test_minimal_non_boundary_float(): - x = minimal(floats(min_value=1, max_value=9), lambda x: x > 2) - assert 2 < x < 3 - - -def test_can_minimal_standard_complex_numbers(): - minimal(complex_numbers(), lambda x: x.imag != 0) == 0j - minimal(complex_numbers(), lambda x: x.real != 0) == 1 - - -def test_minimal_float_is_zero(): - assert minimal(floats(), lambda x: True) == 0.0 - - -def test_negative_floats_simplify_to_zero(): - assert minimal(floats(), lambda x: x <= -1.0) == -1.0 - - -def test_minimal_infinite_float_is_positive(): - assert minimal(floats(), math.isinf) == float(u'inf') - - -def test_can_minimal_infinite_negative_float(): - assert minimal(floats(), lambda x: x < -sys.float_info.max) - - -def test_can_minimal_float_on_boundary_of_representable(): - minimal(floats(), lambda x: x + 1 == x and not math.isinf(x)) - - -def test_minimize_nan(): - assert math.isnan(minimal(floats(), math.isnan)) - - -def test_minimize_very_large_float(): - t = sys.float_info.max / 2 - assert t <= minimal(floats(), lambda x: x >= t) < float(u'inf') - - -def is_integral(value): - try: - return int(value) == value - except (OverflowError, ValueError): - return False - - -def test_can_minimal_float_far_from_integral(): - minimal(floats(), lambda x: not ( - math.isnan(x) or - math.isinf(x) or - is_integral(x * (2 ** 32)) - )) - - -def test_list_of_fractional_float(): - assert set(minimal( - lists(floats(), average_size=20), - lambda x: len([t for t in x if t >= 1.5]) >= 5, - timeout_after=60, - )) in ( - set((1.5,)), - set((1.5, 2.0)), - set((2.0,)), - ) - - -@settings(deadline=None) -@given(randoms()) -def test_minimal_fractional_float(rnd): - assert minimal( - floats(), lambda x: x >= 1.5, random=rnd) in (1.5, 2.0) - - -def test_minimizes_lists_of_negative_ints_up_to_boundary(): - result = minimal( - lists(integers(), min_size=10), - lambda x: len([t for t in x if t <= -1]) >= 10, timeout_after=60) - assert result == [-1] * 10 - - -@pytest.mark.parametrize((u'left', u'right'), [ - (0.0, 5e-324), - (-5e-324, 0.0), - (-5e-324, 5e-324), - (5e-324, 1e-323), -]) -def test_floats_in_constrained_range(left, right): - @given(floats(left, right)) - def test_in_range(r): - assert left <= r <= right - test_in_range() - - -def test_bounds_are_respected(): - assert minimal(floats(min_value=1.0), lambda x: True) == 1.0 - assert minimal(floats(max_value=-1.0), lambda x: True) == -1.0 - - -@pytest.mark.parametrize('k', range(10)) -def test_floats_from_zero_have_reasonable_range(k): - n = 10 ** k - assert minimal(floats(min_value=0.0), lambda x: x >= n) == float(n) - assert minimal(floats(max_value=0.0), lambda x: x <= -n) == float(-n) - - -def test_explicit_allow_nan(): - minimal(floats(allow_nan=True), math.isnan) - - -def test_one_sided_contains_infinity(): - minimal(floats(min_value=1.0), math.isinf) - minimal(floats(max_value=1.0), math.isinf) - - -@given(floats(min_value=0.0, allow_infinity=False)) -def test_no_allow_infinity_upper(x): - assert not math.isinf(x) - - -@given(floats(max_value=0.0, allow_infinity=False)) -def test_no_allow_infinity_lower(x): - assert not math.isinf(x) - - -class TestFloatsAreFloats(object): - - @given(floats()) - def test_unbounded(self, arg): - assert isinstance(arg, float) - - @given(floats(min_value=0, max_value=2 ** 64 - 1)) - def test_int_int(self, arg): - assert isinstance(arg, float) - - @given(floats(min_value=0, max_value=float(2 ** 64 - 1))) - def test_int_float(self, arg): - assert isinstance(arg, float) - - @given(floats(min_value=float(0), max_value=2 ** 64 - 1)) - def test_float_int(self, arg): - assert isinstance(arg, float) - - @given(floats(min_value=float(0), max_value=float(2 ** 64 - 1))) - def test_float_float(self, arg): - assert isinstance(arg, float) diff -Nru python-hypothesis-3.44.1/tests/cover/test_simple_strings.py python-hypothesis-3.71.11/tests/cover/test_simple_strings.py --- python-hypothesis-3.44.1/tests/cover/test_simple_strings.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_simple_strings.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,126 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import unicodedata -from random import Random - -import pytest - -from hypothesis import find, given, settings -from hypothesis.strategies import text, binary, tuples, characters - - -def test_can_minimize_up_to_zero(): - s = find(text(), lambda x: any(lambda t: t <= u'0' for t in x)) - assert s == u'0' - - -def test_minimizes_towards_ascii_zero(): - s = find(text(), lambda x: any(t < u'0' for t in x)) - assert s == chr(ord(u'0') - 1) - - -def test_can_handle_large_codepoints(): - s = find(text(), lambda x: x >= u'☃') - assert s == u'☃' - - -def test_can_find_mixed_ascii_and_non_ascii_strings(): - s = find( - text(), lambda x: ( - any(t >= u'☃' for t in x) and - any(ord(t) <= 127 for t in x))) - assert len(s) == 2 - assert sorted(s) == [u'0', u'☃'] - - -def test_will_find_ascii_examples_given_the_chance(): - s = find( - tuples(text(max_size=1), text(max_size=1)), - lambda x: x[0] and (x[0] < x[1])) - assert ord(s[1]) == ord(s[0]) + 1 - assert u'0' in s - - -def test_finds_single_element_strings(): - assert find(text(), bool, random=Random(4)) == u'0' - - -def test_binary_respects_changes_in_size(): - @given(binary()) - def test_foo(x): - assert len(x) <= 10 - with pytest.raises(AssertionError): - test_foo() - - @given(binary(max_size=10)) - def test_foo(x): - assert len(x) <= 10 - test_foo() - - -@given(text(min_size=1, max_size=1)) -@settings(max_examples=2000) -def test_does_not_generate_surrogates(t): - assert unicodedata.category(t) != u'Cs' - - -def test_does_not_simplify_into_surrogates(): - f = find(text(average_size=25.0), lambda x: x >= u'\udfff') - assert f == u'\ue000' - f = find( - text(average_size=25.0), - lambda x: len([t for t in x if t >= u'\udfff']) >= 10) - assert f == u'\ue000' * 10 - - -@given(text(alphabet=[u'a', u'b'])) -def test_respects_alphabet_if_list(xs): - assert set(xs).issubset(set(u'ab')) - - -@given(text(alphabet=u'cdef')) -def test_respects_alphabet_if_string(xs): - assert set(xs).issubset(set(u'cdef')) - - -@given(text()) -def test_can_encode_as_utf8(s): - s.encode('utf-8') - - -@given(text(characters(blacklist_characters=u'\n'))) -def test_can_blacklist_newlines(s): - assert u'\n' not in s - - -@given(text(characters(blacklist_categories=('Cc', 'Cs')))) -def test_can_exclude_newlines_by_category(s): - assert u'\n' not in s - - -@given(text(characters(max_codepoint=127))) -def test_can_restrict_to_ascii_only(s): - s.encode('ascii') - - -def test_fixed_size_bytes_just_draw_bytes(): - from hypothesis.internal.conjecture.data import ConjectureData - x = ConjectureData.for_buffer(b'foo') - assert x.draw(binary(min_size=3, max_size=3)) == b'foo' diff -Nru python-hypothesis-3.44.1/tests/cover/test_skipping.py python-hypothesis-3.71.11/tests/cover/test_skipping.py --- python-hypothesis-3.44.1/tests/cover/test_skipping.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_skipping.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import unittest - -import pytest - -from hypothesis import given -from hypothesis.core import exceptions_to_reraise -from tests.common.utils import capture_out -from hypothesis.strategies import integers - - -@pytest.mark.parametrize('skip_exception', exceptions_to_reraise) -def test_no_falsifying_example_if_unittest_skip(skip_exception): - """If a ``SkipTest`` exception is raised during a test, Hypothesis should - not continue running the test and shrink process, nor should it print - anything about falsifying examples.""" - - class DemoTest(unittest.TestCase): - - @given(xs=integers()) - def test_to_be_skipped(self, xs): - if xs == 0: - raise skip_exception - else: - assert xs == 0 - - with capture_out() as o: - suite = unittest.defaultTestLoader.loadTestsFromTestCase(DemoTest) - unittest.TextTestRunner().run(suite) - - assert 'Falsifying example' not in o.getvalue() diff -Nru python-hypothesis-3.44.1/tests/cover/test_slippage.py python-hypothesis-3.71.11/tests/cover/test_slippage.py --- python-hypothesis-3.44.1/tests/cover/test_slippage.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_slippage.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,218 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import pytest - -import hypothesis.strategies as st -from hypothesis import given, settings -from hypothesis.errors import Flaky, MultipleFailures -from tests.common.utils import capture_out, non_covering_examples -from hypothesis.database import InMemoryExampleDatabase - - -def test_raises_multiple_failures_with_varying_type(): - target = [None] - - @given(st.integers()) - def test(i): - if abs(i) < 1000: - return - if target[0] is None: - target[0] = i - exc_class = TypeError if target[0] == i else ValueError - raise exc_class() - - with capture_out() as o: - with pytest.raises(MultipleFailures): - test() - - assert 'TypeError' in o.getvalue() - assert 'ValueError' in o.getvalue() - - -def test_raises_multiple_failures_when_position_varies(): - target = [None] - - @given(st.integers()) - def test(i): - if abs(i) < 1000: - return - if target[0] is None: - target[0] = i - if target[0] == i: - raise ValueError('loc 1') - else: - raise ValueError('loc 2') - - with capture_out() as o: - with pytest.raises(MultipleFailures): - test() - assert 'loc 1' in o.getvalue() - assert 'loc 2' in o.getvalue() - - -def test_replays_both_failing_values(): - target = [None] - - @settings(database=InMemoryExampleDatabase()) - @given(st.integers()) - def test(i): - if abs(i) < 1000: - return - if target[0] is None: - target[0] = i - exc_class = TypeError if target[0] == i else ValueError - raise exc_class() - - with pytest.raises(MultipleFailures): - test() - - with pytest.raises(MultipleFailures): - test() - - -@pytest.mark.parametrize('fix', [TypeError, ValueError]) -def test_replays_slipped_examples_once_initial_bug_is_fixed(fix): - target = [] - bug_fixed = False - - @settings(database=InMemoryExampleDatabase()) - @given(st.integers()) - def test(i): - if abs(i) < 1000: - return - if not target: - target.append(i) - if i == target[0]: - if bug_fixed and fix == TypeError: - return - raise TypeError() - if len(target) == 1: - target.append(i) - if bug_fixed and fix == ValueError: - return - if i == target[1]: - raise ValueError() - - with pytest.raises(MultipleFailures): - test() - - bug_fixed = True - - with pytest.raises(ValueError if fix == TypeError else TypeError): - test() - - -def test_garbage_collects_the_secondary_key(): - target = [] - bug_fixed = False - - db = InMemoryExampleDatabase() - - @settings(database=db) - @given(st.integers()) - def test(i): - if bug_fixed: - return - if abs(i) < 1000: - return - if not target: - target.append(i) - if i == target[0]: - raise TypeError() - if len(target) == 1: - target.append(i) - if i == target[1]: - raise ValueError() - - with pytest.raises(MultipleFailures): - test() - - bug_fixed = True - - def count(): - return len(non_covering_examples(db)) - - prev = count() - while prev > 0: - test() - current = count() - assert current < prev - prev = current - - -def test_shrinks_both_failures(): - first_has_failed = [False] - duds = set() - second_target = [None] - - @given(st.integers()) - def test(i): - if i >= 10000: - first_has_failed[0] = True - assert False - assert i < 10000 - if first_has_failed[0]: - if second_target[0] is None: - for j in range(10000): - if j not in duds: - second_target[0] = j - break - assert i < second_target[0] - else: - duds.add(i) - - with capture_out() as o: - with pytest.raises(MultipleFailures): - test() - - assert 'test(i=10000)' in o.getvalue() - assert 'test(i=%d)' % (second_target[0],) in o.getvalue() - - -def test_handles_flaky_tests_where_only_one_is_flaky(): - flaky_fixed = False - - target = [] - flaky_failed_once = [False] - - @settings(database=InMemoryExampleDatabase()) - @given(st.integers()) - def test(i): - if abs(i) < 1000: - return - if not target: - target.append(i) - if i == target[0]: - raise TypeError() - if flaky_failed_once[0] and not flaky_fixed: - return - if len(target) == 1: - target.append(i) - if i == target[1]: - flaky_failed_once[0] = True - raise ValueError() - - with pytest.raises(Flaky): - test() - - flaky_fixed = True - - with pytest.raises(MultipleFailures): - test() diff -Nru python-hypothesis-3.44.1/tests/cover/test_stateful.py python-hypothesis-3.71.11/tests/cover/test_stateful.py --- python-hypothesis-3.44.1/tests/cover/test_stateful.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_stateful.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,682 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import inspect -from collections import namedtuple - -import pytest - -from hypothesis import settings as Settings -from hypothesis import assume -from hypothesis.errors import Flaky, InvalidDefinition -from hypothesis.control import current_build_context -from tests.common.utils import raises, capture_out, \ - checks_deprecated_behaviour -from hypothesis.database import ExampleDatabase -from hypothesis.stateful import Bundle, GenericStateMachine, \ - RuleBasedStateMachine, rule, invariant, precondition, \ - run_state_machine_as_test -from hypothesis.strategies import just, none, lists, binary, tuples, \ - choices, booleans, integers, sampled_from -from hypothesis.internal.compat import print_unicode - - -class SetStateMachine(GenericStateMachine): - - def __init__(self): - self.elements = [] - - def steps(self): - strat = tuples(just(False), integers(0, 5)) - if self.elements: - strat |= tuples(just(True), sampled_from(self.elements)) - return strat - - def execute_step(self, step): - delete, value = step - if delete: - self.elements.remove(value) - assert value not in self.elements - else: - self.elements.append(value) - - -class OrderedStateMachine(GenericStateMachine): - - def __init__(self): - self.counter = 0 - - def steps(self): - return ( - integers(self.counter - 1, self.counter + 50) - ) - - def execute_step(self, step): - assert step >= self.counter - self.counter = step - - -class GoodSet(GenericStateMachine): - - def __init__(self): - self.stuff = set() - - def steps(self): - return tuples(booleans(), integers()) - - def execute_step(self, step): - delete, value = step - if delete: - self.stuff.discard(value) - else: - self.stuff.add(value) - assert delete == (value not in self.stuff) - - -Leaf = namedtuple(u'Leaf', (u'label',)) -Split = namedtuple(u'Split', (u'left', u'right')) - - -class BalancedTrees(RuleBasedStateMachine): - trees = u'BinaryTree' - - @rule(target=trees, x=booleans()) - def leaf(self, x): - return Leaf(x) - - @rule(target=trees, left=Bundle(trees), right=Bundle(trees)) - def split(self, left, right): - return Split(left, right) - - @rule(tree=Bundle(trees)) - def test_is_balanced(self, tree): - if isinstance(tree, Leaf): - return - else: - assert abs(self.size(tree.left) - self.size(tree.right)) <= 1 - self.test_is_balanced(tree.left) - self.test_is_balanced(tree.right) - - def size(self, tree): - if isinstance(tree, Leaf): - return 1 - else: - return 1 + self.size(tree.left) + self.size(tree.right) - - -class DepthCharge(object): - - def __init__(self, value): - if value is None: - self.depth = 0 - else: - self.depth = value.depth + 1 - - -class DepthMachine(RuleBasedStateMachine): - charges = Bundle(u'charges') - - @rule(targets=(charges,), child=charges) - def charge(self, child): - return DepthCharge(child) - - @rule(targets=(charges,)) - def none_charge(self): - return DepthCharge(None) - - @rule(check=charges) - def is_not_too_deep(self, check): - assert check.depth < 3 - - -class MultipleRulesSameFuncMachine(RuleBasedStateMachine): - - def myfunc(self, data): - print_unicode(data) - - rule1 = rule(data=just(u"rule1data"))(myfunc) - rule2 = rule(data=just(u"rule2data"))(myfunc) - - -class PreconditionMachine(RuleBasedStateMachine): - num = 0 - - @rule() - def add_one(self): - self.num += 1 - - @rule() - def set_to_zero(self): - self.num = 0 - - @rule(num=integers()) - @precondition(lambda self: self.num != 0) - def div_by_precondition_after(self, num): - self.num = num / self.num - - @precondition(lambda self: self.num != 0) - @rule(num=integers()) - def div_by_precondition_before(self, num): - self.num = num / self.num - - -class RoseTreeStateMachine(RuleBasedStateMachine): - nodes = Bundle('nodes') - - @rule(target=nodes, source=lists(nodes)) - def bunch(self, source): - return source - - @rule(source=nodes) - def shallow(self, source): - def d(ls): - if not ls: - return 0 - else: - return 1 + max(map(d, ls)) - assert d(source) <= 5 - - -class NotTheLastMachine(RuleBasedStateMachine): - stuff = Bundle('stuff') - - def __init__(self): - super(NotTheLastMachine, self).__init__() - self.last = None - self.bye_called = False - - @rule(target=stuff) - def hi(self): - result = object() - self.last = result - return result - - @precondition(lambda self: not self.bye_called) - @rule(v=stuff) - def bye(self, v): - assert v == self.last - self.bye_called = True - - -bad_machines = ( - OrderedStateMachine, SetStateMachine, BalancedTrees, - DepthMachine, RoseTreeStateMachine, NotTheLastMachine, -) - -for m in bad_machines: - m.TestCase.settings = Settings( - m.TestCase.settings, max_examples=1000, max_iterations=2000 - ) - - -cheap_bad_machines = list(bad_machines) -cheap_bad_machines.remove(BalancedTrees) - - -with_cheap_bad_machines = pytest.mark.parametrize( - u'machine', - cheap_bad_machines, ids=[t.__name__ for t in cheap_bad_machines] -) - - -@pytest.mark.parametrize( - u'machine', - bad_machines, ids=[t.__name__ for t in bad_machines] -) -def test_bad_machines_fail(machine): - test_class = machine.TestCase - try: - with capture_out() as o: - with raises(AssertionError): - test_class().runTest() - except Exception: - print_unicode(o.getvalue()) - raise - v = o.getvalue() - print_unicode(v) - assert u'Step #1' in v - assert u'Step #50' not in v - - -def test_multiple_rules_same_func(): - test_class = MultipleRulesSameFuncMachine.TestCase - with capture_out() as o: - test_class().runTest() - output = o.getvalue() - assert 'rule1data' in output - assert 'rule2data' in output - - -class GivenLikeStateMachine(GenericStateMachine): - - def steps(self): - return lists(booleans(), average_size=25.0) - - def execute_step(self, step): - assume(any(step)) - - -def test_can_get_test_case_off_machine_instance(): - assert GoodSet().TestCase is GoodSet().TestCase - assert GoodSet().TestCase is not None - - -class FlakyDrawLessMachine(GenericStateMachine): - - def steps(self): - cb = current_build_context() - if cb.is_final: - return binary(min_size=1, max_size=1) - else: - return binary(min_size=1024, max_size=1024) - - def execute_step(self, step): - cb = current_build_context() - if not cb.is_final: - assert 0 not in bytearray(step) - - -def test_flaky_draw_less_raises_flaky(): - with raises(Flaky): - FlakyDrawLessMachine.TestCase().runTest() - - -class FlakyStateMachine(GenericStateMachine): - - def steps(self): - return just(()) - - def execute_step(self, step): - assert not any( - t[3] == u'find_breaking_runner' - for t in inspect.getouterframes(inspect.currentframe()) - ) - - -def test_flaky_raises_flaky(): - with raises(Flaky): - FlakyStateMachine.TestCase().runTest() - - -class FlakyRatchettingMachine(GenericStateMachine): - ratchet = 0 - - def steps(self): - FlakyRatchettingMachine.ratchet += 1 - n = FlakyRatchettingMachine.ratchet - return lists(integers(), min_size=n, max_size=n) - - def execute_step(self, step): - assert False - - -def test_ratchetting_raises_flaky(): - with raises(Flaky): - FlakyRatchettingMachine.TestCase().runTest() - - -def test_empty_machine_is_invalid(): - class EmptyMachine(RuleBasedStateMachine): - pass - - with raises(InvalidDefinition): - EmptyMachine.TestCase().runTest() - - -def test_machine_with_no_terminals_is_invalid(): - class NonTerminalMachine(RuleBasedStateMachine): - - @rule(value=Bundle(u'hi')) - def bye(self, hi): - pass - - with raises(InvalidDefinition): - NonTerminalMachine.TestCase().runTest() - - -class DynamicMachine(RuleBasedStateMachine): - - @rule(value=Bundle(u'hi')) - def test_stuff(x): - pass - - -DynamicMachine.define_rule( - targets=(), function=lambda self: 1, arguments={} -) - - -class IntAdder(RuleBasedStateMachine): - pass - - -IntAdder.define_rule( - targets=(u'ints',), function=lambda self, x: x, arguments={ - u'x': integers() - } -) - -IntAdder.define_rule( - targets=(u'ints',), function=lambda self, x, y: x, arguments={ - u'x': integers(), u'y': Bundle(u'ints'), - } -) - - -@checks_deprecated_behaviour -def test_can_choose_in_a_machine(): - class ChoosingMachine(GenericStateMachine): - - def steps(self): - return choices() - - def execute_step(self, choices): - choices([1, 2, 3]) - - run_state_machine_as_test(ChoosingMachine) - - -with Settings(max_examples=10): - TestGoodSets = GoodSet.TestCase - TestGivenLike = GivenLikeStateMachine.TestCase - TestDynamicMachine = DynamicMachine.TestCase - TestIntAdder = IntAdder.TestCase - TestPrecondition = PreconditionMachine.TestCase - - -def test_picks_up_settings_at_first_use_of_testcase(): - assert TestDynamicMachine.settings.max_examples == 10 - - -def test_new_rules_are_picked_up_before_and_after_rules_call(): - class Foo(RuleBasedStateMachine): - pass - Foo.define_rule( - targets=(), function=lambda self: 1, arguments={} - ) - assert len(Foo.rules()) == 1 - Foo.define_rule( - targets=(), function=lambda self: 2, arguments={} - ) - assert len(Foo.rules()) == 2 - - -def test_settings_are_independent(): - s = Settings() - orig = s.max_examples - with s: - class Foo(RuleBasedStateMachine): - pass - Foo.define_rule( - targets=(), function=lambda self: 1, arguments={} - ) - Foo.TestCase.settings = Settings( - Foo.TestCase.settings, max_examples=1000000) - assert s.max_examples == orig - - -def test_minimizes_errors_in_teardown(): - class Foo(GenericStateMachine): - - def __init__(self): - self.counter = 0 - - def steps(self): - return tuples() - - def execute_step(self, value): - self.counter += 1 - - def teardown(self): - assert not self.counter - - runner = Foo.find_breaking_runner() - - f = Foo() - with raises(AssertionError): - runner.run(f, print_steps=True) - assert f.counter == 1 - - -class RequiresInit(GenericStateMachine): - - def __init__(self, threshold): - super(RequiresInit, self).__init__() - self.threshold = threshold - - def steps(self): - return integers() - - def execute_step(self, value): - if value > self.threshold: - raise ValueError(u'%d is too high' % (value,)) - - -def test_can_use_factory_for_tests(): - with raises(ValueError): - run_state_machine_as_test(lambda: RequiresInit(42)) - - -class FailsEventually(GenericStateMachine): - - def __init__(self): - super(FailsEventually, self).__init__() - self.counter = 0 - - def steps(self): - return none() - - def execute_step(self, _): - self.counter += 1 - assert self.counter < 10 - - -FailsEventually.TestCase.settings = Settings( - FailsEventually.TestCase.settings, stateful_step_count=5) - -TestDoesNotFail = FailsEventually.TestCase - - -def test_can_explicitly_pass_settings(): - try: - FailsEventually.TestCase.settings = Settings( - FailsEventually.TestCase.settings, stateful_step_count=15) - run_state_machine_as_test( - FailsEventually, settings=Settings( - stateful_step_count=2, - )) - finally: - FailsEventually.TestCase.settings = Settings( - FailsEventually.TestCase.settings, stateful_step_count=5) - - -def test_saves_failing_example_in_database(): - db = ExampleDatabase(':memory:') - with raises(AssertionError): - run_state_machine_as_test( - SetStateMachine, Settings(database=db)) - assert len(list(db.data.keys())) == 2 - - -def test_can_run_with_no_db(): - with raises(AssertionError): - run_state_machine_as_test( - SetStateMachine, Settings(database=None)) - - -def test_stateful_double_rule_is_forbidden(recwarn): - with pytest.raises(InvalidDefinition): - class DoubleRuleMachine(RuleBasedStateMachine): - - @rule(num=just(1)) - @rule(num=just(2)) - def whatevs(self, num): - pass - - -def test_can_explicitly_call_functions_when_precondition_not_satisfied(): - class BadPrecondition(RuleBasedStateMachine): - - def __init__(self): - super(BadPrecondition, self).__init__() - - @precondition(lambda self: False) - @rule() - def test_blah(self): - raise ValueError() - - @rule() - def test_foo(self): - self.test_blah() - - with pytest.raises(ValueError): - run_state_machine_as_test(BadPrecondition) - - -def test_invariant(): - """If an invariant raise an exception, the exception is propagated.""" - class Invariant(RuleBasedStateMachine): - - def __init__(self): - super(Invariant, self).__init__() - - @invariant() - def test_blah(self): - raise ValueError() - - @rule() - def do_stuff(self): - pass - - with pytest.raises(ValueError): - run_state_machine_as_test(Invariant) - - -def test_no_double_invariant(): - """The invariant decorator can't be applied multiple times to a single - function.""" - with raises(InvalidDefinition): - class Invariant(RuleBasedStateMachine): - - def __init__(self): - super(Invariant, self).__init__() - - @invariant() - @invariant() - def test_blah(self): - pass - - @rule() - def do_stuff(self): - pass - - -def test_invariant_precondition(): - """If an invariant precodition isn't met, the invariant isn't run. - - The precondition decorator can be applied in any order. - - """ - class Invariant(RuleBasedStateMachine): - - def __init__(self): - super(Invariant, self).__init__() - - @invariant() - @precondition(lambda _: False) - def an_invariant(self): - raise ValueError() - - @precondition(lambda _: False) - @invariant() - def another_invariant(self): - raise ValueError() - - @rule() - def do_stuff(self): - pass - - run_state_machine_as_test(Invariant) - - -def test_multiple_invariants(): - """If multiple invariants are present, they all get run.""" - class Invariant(RuleBasedStateMachine): - - def __init__(self): - super(Invariant, self).__init__() - self.first_invariant_ran = False - - @invariant() - def invariant_1(self): - self.first_invariant_ran = True - - @precondition(lambda self: self.first_invariant_ran) - @invariant() - def invariant_2(self): - raise ValueError() - - @rule() - def do_stuff(self): - pass - - with pytest.raises(ValueError): - run_state_machine_as_test(Invariant) - - -def test_explicit_invariant_call_with_precondition(): - """Invariants can be called explicitly even if their precondition is not - satisfied.""" - class BadPrecondition(RuleBasedStateMachine): - - def __init__(self): - super(BadPrecondition, self).__init__() - - @precondition(lambda self: False) - @invariant() - def test_blah(self): - raise ValueError() - - @rule() - def test_foo(self): - self.test_blah() - - with pytest.raises(ValueError): - run_state_machine_as_test(BadPrecondition) - - -def test_invariant_checks_initial_state(): - """Invariants are checked before any rules run.""" - class BadPrecondition(RuleBasedStateMachine): - - def __init__(self): - super(BadPrecondition, self).__init__() - self.num = 0 - - @invariant() - def test_blah(self): - if self.num == 0: - raise ValueError() - - @rule() - def test_foo(self): - self.num += 1 - - with pytest.raises(ValueError): - run_state_machine_as_test(BadPrecondition) diff -Nru python-hypothesis-3.44.1/tests/cover/test_statistical_events.py python-hypothesis-3.71.11/tests/cover/test_statistical_events.py --- python-hypothesis-3.44.1/tests/cover/test_statistical_events.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_statistical_events.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,171 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import re -import time -import traceback - -import pytest - -from hypothesis import strategies as st -from hypothesis import HealthCheck, event, given, example, settings -from hypothesis.statistics import collector - - -def call_for_statistics(test_function): - result = [None] - - def callback(statistics): - result[0] = statistics - - with collector.with_value(callback): - try: - test_function() - except Exception: - traceback.print_exc() - assert result[0] is not None - return result[0] - - -def test_can_callback_with_a_string(): - @given(st.integers()) - def test(i): - event('hi') - - stats = call_for_statistics(test) - - assert any('hi' in s for s in stats.events) - - -counter = 0 -seen = [] - - -class Foo(object): - - def __eq__(self, other): - return True - - def __ne__(self, other): - return False - - def __hash__(self): - return 0 - - def __str__(self): - seen.append(self) - global counter - counter += 1 - return 'COUNTER %d' % (counter,) - - -def test_formats_are_evaluated_only_once(): - global counter - counter = 0 - - @given(st.integers()) - def test(i): - event(Foo()) - - stats = call_for_statistics(test) - - assert any('COUNTER 1' in s for s in stats.events) - assert not any('COUNTER 2' in s for s in stats.events) - - -def test_does_not_report_on_examples(): - @example('hi') - @given(st.integers()) - def test(i): - if isinstance(i, str): - event('boo') - - stats = call_for_statistics(test) - assert not any('boo' in e for e in stats.events) - - -def test_exact_timing(): - @settings(suppress_health_check=[HealthCheck.too_slow], deadline=None) - @given(st.integers()) - def test(i): - time.sleep(0.5) - - stats = call_for_statistics(test) - assert re.match(r'~ 5\d\dms', stats.runtimes) - - -def test_apparently_instantaneous_tests(): - time.freeze() - - @given(st.integers()) - def test(i): - pass - - stats = call_for_statistics(test) - assert stats.runtimes == '< 1ms' - - -def test_flaky_exit(): - first = [True] - - @given(st.integers()) - def test(i): - if i > 1001: - if first[0]: - first[0] = False - print('Hi') - assert False - - stats = call_for_statistics(test) - assert stats.exit_reason == 'test was flaky' - - -@pytest.mark.parametrize('draw_delay', [False, True]) -@pytest.mark.parametrize('test_delay', [False, True]) -def test_draw_time_percentage(draw_delay, test_delay): - time.freeze() - - @st.composite - def s(draw): - if draw_delay: - time.sleep(0.05) - - @given(s()) - def test(_): - if test_delay: - time.sleep(0.05) - - stats = call_for_statistics(test) - if not draw_delay: - assert stats.draw_time_percentage == '~ 0%' - elif test_delay: - assert stats.draw_time_percentage == '~ 50%' - else: - assert stats.draw_time_percentage == '~ 100%' - - -def test_has_lambdas_in_output(): - @given(st.integers().filter(lambda x: x % 2 == 0)) - def test(i): - pass - - stats = call_for_statistics(test) - assert any( - 'lambda x: x % 2 == 0' in e for e in stats.events - ) diff -Nru python-hypothesis-3.44.1/tests/cover/test_streams.py python-hypothesis-3.71.11/tests/cover/test_streams.py --- python-hypothesis-3.44.1/tests/cover/test_streams.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_streams.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,115 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from itertools import islice - -import pytest - -from hypothesis import find, given -from hypothesis.errors import InvalidArgument -from tests.common.utils import checks_deprecated_behaviour -from hypothesis.strategies import text, lists, booleans, streaming -from hypothesis.searchstrategy.streams import Stream - - -@given(lists(booleans())) -def test_stream_give_lists(xs): - s = Stream(iter(xs)) - assert list(s) == xs - assert list(s) == xs - - -@given(lists(booleans())) -def test_can_zip_streams_with_self(xs): - s = Stream(iter(xs)) - assert list(zip(s, s)) == list(zip(xs, xs)) - - -def loop(x): - while True: - yield x - - -def test_can_stream_infinite(): - s = Stream(loop(False)) - assert list(islice(s, 100)) == [False] * 100 - - -@checks_deprecated_behaviour -def test_fetched_repr_is_in_stream_repr(): - @given(streaming(text())) - def test(s): - assert repr(s) == u'Stream(...)' - assert repr(next(iter(s))) in repr(s) - test() - - -def test_cannot_thunk_past_end_of_list(): - with pytest.raises(IndexError): - Stream([1])._thunk_to(5) - - -def test_thunking_evaluates_initial_list(): - x = Stream([1, 2, 3]) - x._thunk_to(1) - assert len(x.fetched) == 1 - - -def test_thunking_map_evaluates_source(): - x = Stream(loop(False)) - y = x.map(lambda t: True) - y[100] - assert y._thunked() == 101 - assert x._thunked() == 101 - - -def test_wrong_index_raises_type_error(): - with pytest.raises(InvalidArgument): - Stream([])[u'kittens'] - - -def test_can_index_into_unindexed(): - x = Stream(loop(1)) - assert x[100] == 1 - - -def test_can_map(): - x = Stream([1, 2, 3]).map(lambda i: i * 2) - assert isinstance(x, Stream) - assert list(x) == [2, 4, 6] - - -@checks_deprecated_behaviour -def test_streaming_errors_in_find(): - with pytest.raises(InvalidArgument): - find(streaming(booleans()), lambda x: True) - - -def test_default_stream_is_empty(): - assert list(Stream()) == [] - - -def test_can_slice_streams(): - assert list(Stream([1, 2, 3])[:2]) == [1, 2] - - -@checks_deprecated_behaviour -def test_validates_argument(): - with pytest.raises(InvalidArgument): - streaming(bool).example() diff -Nru python-hypothesis-3.44.1/tests/cover/test_target_selector.py python-hypothesis-3.71.11/tests/cover/test_target_selector.py --- python-hypothesis-3.44.1/tests/cover/test_target_selector.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_target_selector.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,124 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import attr - -import hypothesis.strategies as st -from hypothesis import given, settings -from hypothesis.internal.compat import hrange -from hypothesis.internal.conjecture.data import Status -from hypothesis.internal.conjecture.engine import TargetSelector, universal - - -@attr.s() -class FakeConjectureData(object): - tags = attr.ib() - - @property - def status(self): - return Status.VALID - - -@st.composite -def fake_randoms(draw): - data = draw(st.data()) - - class FakeRandom(object): - def choice(self, values): - if len(values) == 1: - return values[0] - return data.draw(st.sampled_from(values), label='choice(%r)' % ( - values,)) - return FakeRandom() - - -@settings(deadline=None) -@given(fake_randoms()) -def test_selects_non_universal_tag(rnd): - selector = TargetSelector(rnd) - selector.add(FakeConjectureData({0})) - selector.add(FakeConjectureData(set())) - tag1, x = selector.select() - assert tag1 is not universal - tag2, y = selector.select() - assert tag2 is not universal - assert tag1 != tag2 - assert x != y - - -data_lists = st.lists( - st.builds(FakeConjectureData, st.frozensets(st.integers(0, 10))), - min_size=1) - - -def check_bounded_cycle(selector): - everything = selector.examples_by_tags[universal] - tags = frozenset() - for d in everything: - tags |= d.tags - for _ in hrange(2 * len(tags) + 1): - t, x = selector.select() - tags -= x.tags - if not tags: - break - assert not tags - - -@settings(use_coverage=False, deadline=None) -@given(fake_randoms(), data_lists) -def test_cycles_through_all_tags_in_bounded_time(rnd, datas): - selector = TargetSelector(rnd) - for d in datas: - selector.add(d) - check_bounded_cycle(selector) - - -@settings(use_coverage=False, deadline=None) -@given(fake_randoms(), data_lists, data_lists) -def test_cycles_through_all_tags_in_bounded_time_mixed(rnd, d1, d2): - selector = TargetSelector(rnd) - for d in d1: - selector.add(d) - check_bounded_cycle(selector) - for d in d2: - selector.add(d) - check_bounded_cycle(selector) - - -@settings(deadline=None) -@given(fake_randoms()) -def test_a_negated_tag_is_also_interesting(rnd): - selector = TargetSelector(rnd) - selector.add(FakeConjectureData(tags=frozenset({0}))) - selector.add(FakeConjectureData(tags=frozenset({0}))) - selector.add(FakeConjectureData(tags=frozenset())) - _, data = selector.select() - assert not data.tags - - -@settings(deadline=None) -@given(fake_randoms(), st.integers(1, 10)) -def test_always_starts_with_rare_tags(rnd, n): - selector = TargetSelector(rnd) - selector.add(FakeConjectureData(tags=frozenset({0}))) - for _ in hrange(n): - selector.select() - selector.add(FakeConjectureData(tags=frozenset({1}))) - _, data = selector.select() - assert 1 in data.tags diff -Nru python-hypothesis-3.44.1/tests/cover/test_testdecorators.py python-hypothesis-3.71.11/tests/cover/test_testdecorators.py --- python-hypothesis-3.44.1/tests/cover/test_testdecorators.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_testdecorators.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,526 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import functools -import threading -from collections import namedtuple - -import hypothesis.reporting as reporting -from hypothesis import Verbosity, note, seed, given, assume, reject, \ - settings -from hypothesis.errors import Unsatisfiable -from tests.common.utils import fails, raises, fails_with, capture_out -from hypothesis.strategies import data, just, sets, text, lists, binary, \ - builds, floats, one_of, booleans, integers, frozensets, sampled_from - - -@given(integers(), integers()) -def test_int_addition_is_commutative(x, y): - assert x + y == y + x - - -@fails -@given(text(), text()) -def test_str_addition_is_commutative(x, y): - assert x + y == y + x - - -@fails -@given(binary(), binary()) -def test_bytes_addition_is_commutative(x, y): - assert x + y == y + x - - -@given(integers(), integers(), integers()) -def test_int_addition_is_associative(x, y, z): - assert x + (y + z) == (x + y) + z - - -@fails -@given(floats(), floats(), floats()) -@settings(max_examples=2000,) -def test_float_addition_is_associative(x, y, z): - assert x + (y + z) == (x + y) + z - - -@given(lists(integers())) -def test_reversing_preserves_integer_addition(xs): - assert sum(xs) == sum(reversed(xs)) - - -def test_still_minimizes_on_non_assertion_failures(): - @settings(max_examples=50) - @given(integers()) - def is_not_too_large(x): - if x >= 10: - raise ValueError('No, %s is just too large. Sorry' % x) - - with raises(ValueError) as exinfo: - is_not_too_large() - - assert ' 10 ' in exinfo.value.args[0] - - -@given(integers()) -def test_integer_division_shrinks_positive_integers(n): - assume(n > 0) - assert n / 2 < n - - -class TestCases(object): - - @given(integers()) - def test_abs_non_negative(self, x): - assert abs(x) >= 0 - assert isinstance(self, TestCases) - - @given(x=integers()) - def test_abs_non_negative_varargs(self, x, *args): - assert abs(x) >= 0 - assert isinstance(self, TestCases) - - @given(x=integers()) - def test_abs_non_negative_varargs_kwargs(self, *args, **kw): - assert abs(kw['x']) >= 0 - assert isinstance(self, TestCases) - - @given(x=integers()) - def test_abs_non_negative_varargs_kwargs_only(*args, **kw): - assert abs(kw['x']) >= 0 - assert isinstance(args[0], TestCases) - - @fails - @given(integers()) - def test_int_is_always_negative(self, x): - assert x < 0 - - @fails - @given(floats(), floats()) - def test_float_addition_cancels(self, x, y): - assert x + (y - x) == y - - -@fails -@given(x=integers(min_value=0, max_value=3), name=text()) -def test_can_be_given_keyword_args(x, name): - assume(x > 0) - assert len(name) < x - - -@fails -@given(one_of(floats(), booleans()), one_of(floats(), booleans())) -def test_one_of_produces_different_values(x, y): - assert type(x) == type(y) - - -@given(just(42)) -def test_is_the_answer(x): - assert x == 42 - - -@fails -@given(text(), text()) -def test_text_addition_is_not_commutative(x, y): - assert x + y == y + x - - -@fails -@given(binary(), binary()) -def test_binary_addition_is_not_commutative(x, y): - assert x + y == y + x - - -@given(integers(1, 10)) -def test_integers_are_in_range(x): - assert 1 <= x <= 10 - - -@given(integers(min_value=100)) -def test_integers_from_are_from(x): - assert x >= 100 - - -def test_does_not_catch_interrupt_during_falsify(): - calls = [0] - - @given(integers()) - def flaky_base_exception(x): - if not calls[0]: - calls[0] = 1 - raise KeyboardInterrupt() - with raises(KeyboardInterrupt): - flaky_base_exception() - - -def test_contains_the_test_function_name_in_the_exception_string(): - - calls = [0] - - @given(integers()) - @settings(max_iterations=10, max_examples=10) - def this_has_a_totally_unique_name(x): - calls[0] += 1 - reject() - - with raises(Unsatisfiable) as e: - this_has_a_totally_unique_name() - print('Called %d times' % tuple(calls)) - - assert this_has_a_totally_unique_name.__name__ in e.value.args[0] - - calls2 = [0] - - class Foo(object): - - @given(integers()) - @settings(max_iterations=10, max_examples=10) - def this_has_a_unique_name_and_lives_on_a_class(self, x): - calls2[0] += 1 - reject() - - with raises(Unsatisfiable) as e: - Foo().this_has_a_unique_name_and_lives_on_a_class() - print('Called %d times' % tuple(calls2)) - - assert ( - Foo.this_has_a_unique_name_and_lives_on_a_class.__name__ - ) in e.value.args[0] - - -@given(lists(integers(), unique=True), integers()) -def test_removing_an_element_from_a_unique_list(xs, y): - assume(len(set(xs)) == len(xs)) - - try: - xs.remove(y) - except ValueError: - pass - - assert y not in xs - - -@fails -@given(lists(integers(), average_size=25.0), data()) -def test_removing_an_element_from_a_non_unique_list(xs, data): - y = data.draw(sampled_from(xs)) - xs.remove(y) - assert y not in xs - - -@given(sets(sampled_from(list(range(10))))) -def test_can_test_sets_sampled_from(xs): - assert all(isinstance(x, int) for x in xs) - assert all(0 <= x < 10 for x in xs) - - -mix = one_of(sampled_from([1, 2, 3]), text()) - - -@fails -@given(mix, mix) -def test_can_mix_sampling_with_generating(x, y): - assert type(x) == type(y) - - -@fails -@given(frozensets(integers())) -def test_can_find_large_sum_frozenset(xs): - assert sum(xs) < 100 - - -def test_prints_on_failure_by_default(): - @given(integers(), integers()) - @settings(max_examples=100) - def test_ints_are_sorted(balthazar, evans): - assume(evans >= 0) - assert balthazar <= evans - with raises(AssertionError): - with capture_out() as out: - with reporting.with_reporter(reporting.default): - test_ints_are_sorted() - out = out.getvalue() - lines = [l.strip() for l in out.split('\n')] - assert ( - 'Falsifying example: test_ints_are_sorted(balthazar=1, evans=0)' - in lines) - - -def test_does_not_print_on_success(): - with settings(verbosity=Verbosity.normal): - @given(integers()) - def test_is_an_int(x): - return - - with capture_out() as out: - test_is_an_int() - out = out.getvalue() - lines = [l.strip() for l in out.split(u'\n')] - assert all(not l for l in lines), lines - - -@given(sampled_from([1])) -def test_can_sample_from_single_element(x): - assert x == 1 - - -@fails -@given(lists(integers())) -def test_list_is_sorted(xs): - assert sorted(xs) == xs - - -@fails -@given(floats(1.0, 2.0)) -def test_is_an_endpoint(x): - assert x == 1.0 or x == 2.0 - - -def test_breaks_bounds(): - @fails - @given(x=integers()) - def test_is_bounded(t, x): - assert x < t - for t in [1, 10, 100, 1000]: - test_is_bounded(t) - - -@given(x=booleans()) -def test_can_test_kwargs_only_methods(**kwargs): - assert isinstance(kwargs['x'], bool) - - -@fails_with(UnicodeEncodeError) -@given(text()) -@settings(max_examples=100) -def test_is_ascii(x): - x.encode('ascii') - - -@fails -@given(text()) -def test_is_not_ascii(x): - try: - x.encode('ascii') - assert False - except UnicodeEncodeError: - pass - - -@fails -@given(text()) -def test_can_find_string_with_duplicates(s): - assert len(set(s)) == len(s) - - -@fails -@given(text()) -def test_has_ascii(x): - if not x: - return - ascii_characters = ( - u'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ \t\n' - ) - assert any(c in ascii_characters for c in x) - - -def test_uses_provided_seed(): - import random - random.seed(0) - initial = random.getstate() - - @given(integers()) - @seed(42) - def test_foo(x): - pass - - test_foo() - assert hash(repr(random.getstate())) == hash(repr(initial)) - - -def test_can_derandomize(): - values = [] - - @fails - @given(integers()) - @settings(derandomize=True, database=None) - def test_blah(x): - values.append(x) - assert x > 0 - - test_blah() - assert values - v1 = values - values = [] - test_blah() - assert v1 == values - - -def test_can_run_without_database(): - @given(integers()) - @settings(database=None) - def test_blah(x): - assert False - with raises(AssertionError): - test_blah() - - -def test_can_run_with_database_in_thread(): - results = [] - - @given(integers()) - def test_blah(x): - assert False - - def run_test(): - try: - test_blah() - except AssertionError: - results.append('success') - - # Run once in the main thread and once in another thread. Execution is - # strictly serial, so no need for locking. - run_test() - thread = threading.Thread(target=run_test) - thread.start() - thread.join() - assert results == ['success', 'success'] - - -@given(integers()) -def test_can_call_an_argument_f(f): - # See issue https://github.com/HypothesisWorks/hypothesis-python/issues/38 - # for details - pass - - -Litter = namedtuple('Litter', ('kitten1', 'kitten2')) - - -@given(builds(Litter, integers(), integers())) -def test_named_tuples_are_of_right_type(litter): - assert isinstance(litter, Litter) - - -@fails_with(AttributeError) -@given(integers().map(lambda x: x.nope)) -@settings(perform_health_check=False) -def test_fails_in_reify(x): - pass - - -@given(text(u'a')) -def test_a_text(x): - assert set(x).issubset(set(u'a')) - - -@given(text(u'')) -def test_empty_text(x): - assert not x - - -@given(text(u'abcdefg')) -def test_mixed_text(x): - assert set(x).issubset(set(u'abcdefg')) - - -def test_when_set_to_no_simplifies_runs_failing_example_twice(): - failing = [0] - - @given(integers()) - @settings(max_shrinks=0, max_examples=100) - def foo(x): - if x > 11: - note('Lo') - failing[0] += 1 - assert False - - with settings(verbosity=Verbosity.normal): - with raises(AssertionError): - with capture_out() as out: - foo() - assert failing == [2] - assert 'Falsifying example' in out.getvalue() - assert 'Lo' in out.getvalue() - - -@given(integers()) -@settings(max_examples=1) -def test_should_not_fail_if_max_examples_less_than_min_satisfying(x): - pass - - -@given(integers().filter(lambda x: x % 4 == 0)) -def test_filtered_values_satisfy_condition(i): - assert i % 4 == 0 - - -def nameless_const(x): - def f(u, v): - return u - return functools.partial(f, x) - - -@given(sets(booleans()).map(nameless_const(2))) -def test_can_map_nameless(x): - assert x == 2 - - -@given( - integers(0, 10).flatmap(nameless_const(just(3)))) -def test_can_flatmap_nameless(x): - assert x == 3 - - -def test_can_be_used_with_none_module(): - def test_is_cool(i): - pass - test_is_cool.__module__ = None - test_is_cool = given(integers())(test_is_cool) - test_is_cool() - - -def test_does_not_print_notes_if_all_succeed(): - @given(integers()) - @settings(verbosity=Verbosity.normal) - def test(i): - note('Hi there') - with capture_out() as out: - with reporting.with_reporter(reporting.default): - test() - assert not out.getvalue() - - -def test_prints_notes_once_on_failure(): - @given(lists(integers())) - @settings(database=None, verbosity=Verbosity.normal) - def test(xs): - note('Hi there') - if sum(xs) <= 100: - raise ValueError() - with capture_out() as out: - with reporting.with_reporter(reporting.default): - with raises(ValueError): - test() - lines = out.getvalue().strip().splitlines() - assert lines.count('Hi there') == 1 - - -@given(lists(max_size=0)) -def test_empty_lists(xs): - assert xs == [] diff -Nru python-hypothesis-3.44.1/tests/cover/test_threading.py python-hypothesis-3.71.11/tests/cover/test_threading.py --- python-hypothesis-3.44.1/tests/cover/test_threading.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_threading.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,36 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import threading - -import hypothesis.strategies as st -from hypothesis import given - - -def test_can_run_given_in_thread(): - has_run_successfully = [False] - - @given(st.integers()) - def test(n): - has_run_successfully[0] = True - - t = threading.Thread(target=test) - t.start() - t.join() - assert has_run_successfully[0] diff -Nru python-hypothesis-3.44.1/tests/cover/test_timeout.py python-hypothesis-3.71.11/tests/cover/test_timeout.py --- python-hypothesis-3.44.1/tests/cover/test_timeout.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_timeout.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,105 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import time - -import pytest - -from hypothesis import given, settings -from hypothesis.errors import Unsatisfiable, HypothesisDeprecationWarning -from tests.common.utils import fails, fails_with, validate_deprecation -from hypothesis.strategies import integers - - -def test_hitting_timeout_is_deprecated(): - with validate_deprecation(): - @settings(timeout=0.1) - @given(integers()) - def test_slow_test_times_out(x): - time.sleep(0.05) - - with validate_deprecation(): - with pytest.raises(Unsatisfiable): - test_slow_test_times_out() - - -# Cheap hack to make test functions which fail on their second invocation -calls = [0, 0, 0, 0] - - -with validate_deprecation(): - timeout_settings = settings(timeout=0.2, min_satisfying_examples=2) - - -# The following tests exist to test that verifiers start their timeout -# from when the test first executes, not from when it is defined. -@fails -@given(integers()) -@timeout_settings -def test_slow_failing_test_1(x): - time.sleep(0.05) - assert not calls[0] - calls[0] = 1 - - -@fails -@timeout_settings -@given(integers()) -def test_slow_failing_test_2(x): - time.sleep(0.05) - assert not calls[1] - calls[1] = 1 - - -@fails -@given(integers()) -@timeout_settings -def test_slow_failing_test_3(x): - time.sleep(0.05) - assert not calls[2] - calls[2] = 1 - - -@fails -@timeout_settings -@given(integers()) -def test_slow_failing_test_4(x): - time.sleep(0.05) - assert not calls[3] - calls[3] = 1 - - -with validate_deprecation(): - strict_timeout_settings = settings(timeout=60) - - -# @checks_deprecated_behaviour only works if test passes otherwise -@fails_with(HypothesisDeprecationWarning) -@strict_timeout_settings -@given(integers()) -def test_deprecated_behaviour(i): - time.sleep(100) - - -@fails_with(AssertionError) -@strict_timeout_settings -@given(integers()) -def test_does_not_hide_errors_with_deprecation(i): - time.sleep(100) - assert False diff -Nru python-hypothesis-3.44.1/tests/cover/test_type_lookup.py python-hypothesis-3.71.11/tests/cover/test_type_lookup.py --- python-hypothesis-3.44.1/tests/cover/test_type_lookup.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_type_lookup.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,150 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import pytest - -import hypothesis.strategies as st -from hypothesis import given, infer -from hypothesis.errors import InvalidArgument, ResolutionFailed -from hypothesis.searchstrategy import types -from hypothesis.internal.compat import PY2, integer_types - -# Build a set of all types output by core strategies -blacklist = [ - 'builds', 'iterables', 'permutations', 'random_module', 'randoms', - 'runner', 'sampled_from', 'streaming', 'choices', -] -types_with_core_strat = set(integer_types) -for thing in (getattr(st, name) for name in sorted(st._strategies) - if name in dir(st) and name not in blacklist): - for n in range(3): - try: - ex = thing(*([st.nothing()] * n)).example() - types_with_core_strat.add(type(ex)) - break - except (TypeError, InvalidArgument): - continue - - -@pytest.mark.parametrize('typ', sorted(types_with_core_strat, key=str)) -def test_resolve_core_strategies(typ): - @given(st.from_type(typ)) - def inner(ex): - if PY2 and issubclass(typ, integer_types): - assert isinstance(ex, integer_types) - else: - assert isinstance(ex, typ) - - inner() - - -def test_lookup_knows_about_all_core_strategies(): - cannot_lookup = types_with_core_strat - set(types._global_type_lookup) - assert not cannot_lookup - - -def test_lookup_keys_are_types(): - with pytest.raises(InvalidArgument): - st.register_type_strategy('int', st.integers()) - assert 'int' not in types._global_type_lookup - - -def test_lookup_values_are_strategies(): - with pytest.raises(InvalidArgument): - st.register_type_strategy(int, 42) - assert 42 not in types._global_type_lookup.values() - - -@pytest.mark.parametrize('typ', sorted(types_with_core_strat, key=str)) -def test_lookup_overrides_defaults(typ): - sentinel = object() - try: - strat = types._global_type_lookup[typ] - st.register_type_strategy(typ, st.just(sentinel)) - assert st.from_type(typ).example() is sentinel - finally: - st.register_type_strategy(typ, strat) - st.from_type.__clear_cache() - assert st.from_type(typ).example() is not sentinel - - -class ParentUnknownType(object): - pass - - -class UnknownType(ParentUnknownType): - def __init__(self, arg): - pass - - -def test_custom_type_resolution(): - fails = st.from_type(UnknownType) - with pytest.raises(ResolutionFailed): - fails.example() - sentinel = object() - try: - st.register_type_strategy(UnknownType, st.just(sentinel)) - assert st.from_type(UnknownType).example() is sentinel - # Also covered by registration of child class - assert st.from_type(ParentUnknownType).example() is sentinel - finally: - types._global_type_lookup.pop(UnknownType) - st.from_type.__clear_cache() - fails = st.from_type(UnknownType) - with pytest.raises(ResolutionFailed): - fails.example() - - -def test_errors_if_generic_resolves_empty(): - try: - st.register_type_strategy(UnknownType, lambda _: st.nothing()) - fails_1 = st.from_type(UnknownType) - with pytest.raises(ResolutionFailed): - fails_1.example() - fails_2 = st.from_type(ParentUnknownType) - with pytest.raises(ResolutionFailed): - fails_2.example() - finally: - types._global_type_lookup.pop(UnknownType) - st.from_type.__clear_cache() - - -def test_cannot_register_empty(): - # Cannot register and did not register - with pytest.raises(InvalidArgument): - st.register_type_strategy(UnknownType, st.nothing()) - fails = st.from_type(UnknownType) - with pytest.raises(ResolutionFailed): - fails.example() - assert UnknownType not in types._global_type_lookup - - -def test_pulic_interface_works(): - st.from_type(int).example() - fails = st.from_type('not a type or annotated function') - with pytest.raises(InvalidArgument): - fails.example() - - -def test_given_can_infer_on_py2(): - # Editing annotations before decorating is hilariously awkward, but works! - def inner(a): - pass - inner.__annotations__ = {'a': int} - given(a=infer)(inner)() diff -Nru python-hypothesis-3.44.1/tests/cover/test_uuids.py python-hypothesis-3.71.11/tests/cover/test_uuids.py --- python-hypothesis-3.44.1/tests/cover/test_uuids.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_uuids.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,44 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import pytest - -import hypothesis.strategies as st -from hypothesis import find, given, settings - - -@given(st.lists(st.uuids())) -def test_are_unique(ls): - assert len(set(ls)) == len(ls) - - -@settings(deadline=None) -@given(st.lists(st.uuids()), st.randoms()) -def test_retains_uniqueness_in_simplify(ls, rnd): - ts = find(st.lists(st.uuids()), lambda x: len(x) >= 5, random=rnd) - assert len(ts) == len(set(ts)) == 5 - - -@pytest.mark.parametrize('version', (1, 2, 3, 4, 5)) -def test_can_generate_specified_version(version): - @given(st.uuids(version=version)) - def inner(uuid): - assert version == uuid.version - - inner() diff -Nru python-hypothesis-3.44.1/tests/cover/test_validation.py python-hypothesis-3.71.11/tests/cover/test_validation.py --- python-hypothesis-3.44.1/tests/cover/test_validation.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_validation.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,209 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import pytest - -from hypothesis import find, given -from hypothesis.errors import InvalidArgument -from tests.common.utils import fails_with -from hypothesis.strategies import sets, lists, floats, booleans, \ - integers, recursive, frozensets - - -def test_errors_when_given_varargs(): - @given(integers()) - def has_varargs(*args): - pass - with pytest.raises(InvalidArgument) as e: - has_varargs() - assert u'varargs' in e.value.args[0] - - -def test_varargs_without_positional_arguments_allowed(): - @given(somearg=integers()) - def has_varargs(somearg, *args): - pass - - -def test_errors_when_given_varargs_and_kwargs_with_positional_arguments(): - @given(integers()) - def has_varargs(*args, **kw): - pass - with pytest.raises(InvalidArgument) as e: - has_varargs() - assert u'varargs' in e.value.args[0] - - -def test_varargs_and_kwargs_without_positional_arguments_allowed(): - @given(somearg=integers()) - def has_varargs(*args, **kw): - pass - - -def test_bare_given_errors(): - @given() - def test(): - pass - - with pytest.raises(InvalidArgument): - test() - - -def test_errors_on_unwanted_kwargs(): - @given(hello=int, world=int) - def greet(world): - pass - with pytest.raises(InvalidArgument): - greet() - - -def test_errors_on_too_many_positional_args(): - @given(integers(), int, int) - def foo(x, y): - pass - - with pytest.raises(InvalidArgument): - foo() - - -def test_errors_on_any_varargs(): - @given(integers()) - def oops(*args): - pass - with pytest.raises(InvalidArgument): - oops() - - -def test_can_put_arguments_in_the_middle(): - @given(y=integers()) - def foo(x, y, z): - pass - foo(1, 2) - - -def test_float_ranges(): - with pytest.raises(InvalidArgument): - floats(float(u'nan'), 0).example() - with pytest.raises(InvalidArgument): - floats(1, -1).example() - - -def test_float_range_and_allow_nan_cannot_both_be_enabled(): - with pytest.raises(InvalidArgument): - floats(min_value=1, allow_nan=True).example() - with pytest.raises(InvalidArgument): - floats(max_value=1, allow_nan=True).example() - - -def test_float_finite_range_and_allow_infinity_cannot_both_be_enabled(): - with pytest.raises(InvalidArgument): - floats(0, 1, allow_infinity=True).example() - - -def test_does_not_error_if_min_size_is_bigger_than_default_size(): - lists(integers(), min_size=50).example() - sets(integers(), min_size=50).example() - frozensets(integers(), min_size=50).example() - lists(integers(), min_size=50, unique=True).example() - - -def test_list_unique_and_unique_by_cannot_both_be_enabled(): - @given(lists(integers(), unique=True, unique_by=lambda x: x)) - def boom(t): - pass - with pytest.raises(InvalidArgument) as e: - boom() - assert 'unique ' in e.value.args[0] - assert 'unique_by' in e.value.args[0] - - -def test_an_average_size_must_be_positive(): - with pytest.raises(InvalidArgument): - lists(integers(), average_size=0.0).example() - with pytest.raises(InvalidArgument): - lists(integers(), average_size=-1.0).example() - - -def test_an_average_size_may_be_zero_if_max_size_is(): - lists(integers(), average_size=0.0, max_size=0) - - -def test_min_before_max(): - with pytest.raises(InvalidArgument): - integers(min_value=1, max_value=0).validate() - - -def test_filter_validates(): - with pytest.raises(InvalidArgument): - integers(min_value=1, max_value=0).filter(bool).validate() - - -def test_recursion_validates_base_case(): - with pytest.raises(InvalidArgument): - recursive( - integers(min_value=1, max_value=0), - lists, - ).validate() - - -def test_recursion_validates_recursive_step(): - with pytest.raises(InvalidArgument): - recursive( - integers(), - lambda x: lists(x, min_size=3, max_size=1), - ).validate() - - -@fails_with(InvalidArgument) -@given(x=integers()) -def test_stuff_keyword(x=1): - pass - - -@fails_with(InvalidArgument) -@given(integers()) -def test_stuff_positional(x=1): - pass - - -@fails_with(InvalidArgument) -@given(integers(), integers()) -def test_too_many_positional(x): - pass - - -def test_given_warns_on_use_of_non_strategies(): - @given(bool) - def test(x): - pass - with pytest.raises(InvalidArgument): - test() - - -def test_given_warns_when_mixing_positional_with_keyword(): - @given(booleans(), y=booleans()) - def test(x, y): - pass - with pytest.raises(InvalidArgument): - test() - - -def test_cannot_find_non_strategies(): - with pytest.raises(InvalidArgument): - find(bool, bool) diff -Nru python-hypothesis-3.44.1/tests/cover/test_verbosity.py python-hypothesis-3.71.11/tests/cover/test_verbosity.py --- python-hypothesis-3.44.1/tests/cover/test_verbosity.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_verbosity.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,134 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from contextlib import contextmanager - -import pytest - -from hypothesis import find, given -from hypothesis.errors import InvalidArgument -from tests.common.utils import fails, capture_out -from hypothesis._settings import Verbosity, settings -from hypothesis.reporting import default as default_reporter -from hypothesis.reporting import with_reporter -from hypothesis.strategies import lists, booleans, integers - - -@contextmanager -def capture_verbosity(level): - with capture_out() as o: - with with_reporter(default_reporter): - with settings(verbosity=level): - yield o - - -def test_prints_intermediate_in_success(): - with capture_verbosity(Verbosity.verbose) as o: - @given(booleans()) - def test_works(x): - pass - test_works() - assert 'Trying example' in o.getvalue() - - -def test_does_not_log_in_quiet_mode(): - with capture_verbosity(Verbosity.quiet) as o: - @fails - @given(integers()) - def test_foo(x): - assert False - - test_foo() - assert not o.getvalue() - - -def test_includes_progress_in_verbose_mode(): - with capture_verbosity(Verbosity.verbose) as o: - with settings(verbosity=Verbosity.verbose): - find(lists(integers()), lambda x: sum(x) >= 1000000) - - out = o.getvalue() - assert out - assert u'Shrunk example' in out - assert u'Found satisfying example' in out - - -def test_prints_initial_attempts_on_find(): - - with capture_verbosity(Verbosity.verbose) as o: - with settings(verbosity=Verbosity.verbose): - seen = [] - - def not_first(x): - if not seen: - seen.append(x) - return False - return x not in seen - find(integers(), not_first) - - assert u'Trying example' in o.getvalue() - - -def test_includes_intermediate_results_in_verbose_mode(): - with capture_verbosity(Verbosity.verbose) as o: - @fails - @given(lists(integers())) - def test_foo(x): - assert sum(x) < 1000000 - - test_foo() - lines = o.getvalue().splitlines() - assert len([l for l in lines if u'example' in l]) > 2 - assert len([l for l in lines if u'AssertionError' in l]) - - -VERBOSITIES = [ - Verbosity.quiet, Verbosity.normal, Verbosity.verbose, Verbosity.debug -] - - -def test_verbosity_can_be_accessed_by_name(): - for f in VERBOSITIES: - assert f is Verbosity.by_name(f.name) - - -def test_verbosity_is_sorted(): - assert VERBOSITIES == sorted(VERBOSITIES) - - -def test_hash_verbosity(): - x = {} - for f in VERBOSITIES: - x[f] = f - for k, v in x.items(): - assert k == v - assert k is v - - -def test_verbosities_are_inequal(): - for f in VERBOSITIES: - for g in VERBOSITIES: - if f is not g: - assert f != g - assert (f <= g) or (g <= f) - - -def test_verbosity_of_bad_name(): - with pytest.raises(InvalidArgument): - Verbosity.by_name('cabbage') diff -Nru python-hypothesis-3.44.1/tests/cover/test_weird_settings.py python-hypothesis-3.71.11/tests/cover/test_weird_settings.py --- python-hypothesis-3.44.1/tests/cover/test_weird_settings.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/cover/test_weird_settings.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from hypothesis import strategies as st -from hypothesis import given, settings - - -def test_setting_database_to_none_disables_the_database(): - @given(st.booleans()) - @settings(database_file=None) - def test(b): - pass - test() diff -Nru python-hypothesis-3.44.1/tests/datetime/__init__.py python-hypothesis-3.71.11/tests/datetime/__init__.py --- python-hypothesis-3.44.1/tests/datetime/__init__.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/datetime/__init__.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER diff -Nru python-hypothesis-3.44.1/tests/datetime/test_dates.py python-hypothesis-3.71.11/tests/datetime/test_dates.py --- python-hypothesis-3.44.1/tests/datetime/test_dates.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/datetime/test_dates.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from tests.common.debug import minimal, find_any -from tests.common.utils import checks_deprecated_behaviour -from hypothesis.extra.datetime import dates -from hypothesis.internal.compat import hrange - - -@checks_deprecated_behaviour -def test_can_find_after_the_year_2000(): - assert minimal(dates(), lambda x: x.year > 2000).year == 2001 - - -@checks_deprecated_behaviour -def test_can_find_before_the_year_2000(): - assert minimal(dates(), lambda x: x.year < 2000).year == 1999 - - -@checks_deprecated_behaviour -def test_can_find_each_month(): - for month in hrange(1, 13): - find_any(dates(), lambda x: x.month == month) - - -@checks_deprecated_behaviour -def test_min_year_is_respected(): - assert minimal(dates(min_year=2003)).year == 2003 - - -@checks_deprecated_behaviour -def test_max_year_is_respected(): - assert minimal(dates(max_year=1998)).year == 1998 diff -Nru python-hypothesis-3.44.1/tests/datetime/test_datetime.py python-hypothesis-3.71.11/tests/datetime/test_datetime.py --- python-hypothesis-3.44.1/tests/datetime/test_datetime.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/datetime/test_datetime.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,165 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from datetime import MINYEAR - -import pytz -import pytest -from flaky import flaky - -from hypothesis import find, given, assume, settings, unlimited -from hypothesis.errors import InvalidArgument -from tests.common.debug import minimal, find_any -from tests.common.utils import checks_deprecated_behaviour -from hypothesis.extra.datetime import datetimes -from hypothesis.internal.compat import hrange - - -@checks_deprecated_behaviour -def test_can_find_after_the_year_2000(): - assert minimal(datetimes(), lambda x: x.year > 2000).year == 2001 - - -@checks_deprecated_behaviour -def test_can_find_before_the_year_2000(): - assert minimal(datetimes(), lambda x: x.year < 2000).year == 1999 - - -@checks_deprecated_behaviour -def test_can_find_each_month(): - for month in hrange(1, 13): - find_any(datetimes(), lambda x: x.month == month) - - -@checks_deprecated_behaviour -def test_can_find_midnight(): - datetimes().filter( - lambda x: x.hour == x.minute == x.second == 0 - ).example() - - -@checks_deprecated_behaviour -def test_can_find_non_midnight(): - assert minimal(datetimes(), lambda x: x.hour != 0).hour == 1 - - -@checks_deprecated_behaviour -def test_can_find_off_the_minute(): - find_any(datetimes(), lambda x: x.second != 0) - - -@checks_deprecated_behaviour -def test_can_find_on_the_minute(): - find_any(datetimes(), lambda x: x.second == 0) - - -@checks_deprecated_behaviour -def test_simplifies_towards_midnight(): - d = minimal(datetimes()) - assert d.hour == 0 - assert d.minute == 0 - assert d.second == 0 - assert d.microsecond == 0 - - -@checks_deprecated_behaviour -def test_can_generate_naive_datetime(): - find_any(datetimes(allow_naive=True), lambda d: d.tzinfo is None) - - -@checks_deprecated_behaviour -def test_can_generate_non_naive_datetime(): - assert minimal( - datetimes(allow_naive=True), lambda d: d.tzinfo).tzinfo == pytz.UTC - - -@checks_deprecated_behaviour -def test_can_generate_non_utc(): - datetimes().filter( - lambda d: assume(d.tzinfo) and d.tzinfo.zone != u'UTC' - ).example() - - -@checks_deprecated_behaviour -@given(datetimes(timezones=[])) -def test_naive_datetimes_are_naive(dt): - assert not dt.tzinfo - - -@checks_deprecated_behaviour -@given(datetimes(allow_naive=False)) -def test_timezone_aware_datetimes_are_timezone_aware(dt): - assert dt.tzinfo - - -@checks_deprecated_behaviour -def test_restricts_to_allowed_set_of_timezones(): - timezones = list(map(pytz.timezone, list(pytz.all_timezones)[:3])) - x = minimal(datetimes(timezones=timezones)) - assert any(tz.zone == x.tzinfo.zone for tz in timezones) - - -@checks_deprecated_behaviour -def test_min_year_is_respected(): - assert minimal(datetimes(min_year=2003)).year == 2003 - - -@checks_deprecated_behaviour -def test_max_year_is_respected(): - assert minimal(datetimes(max_year=1998)).year == 1998 - - -@checks_deprecated_behaviour -def test_validates_year_arguments_in_range(): - with pytest.raises(InvalidArgument): - datetimes(min_year=-10 ** 6).example() - with pytest.raises(InvalidArgument): - datetimes(max_year=-10 ** 6).example() - with pytest.raises(InvalidArgument): - datetimes(min_year=10 ** 6).example() - with pytest.raises(InvalidArgument): - datetimes(max_year=10 ** 6).example() - - -@checks_deprecated_behaviour -def test_needs_permission_for_no_timezones(): - with pytest.raises(InvalidArgument): - datetimes(allow_naive=False, timezones=[]).example() - - -@checks_deprecated_behaviour -@flaky(max_runs=3, min_passes=1) -def test_bordering_on_a_leap_year(): - x = find( - datetimes(min_year=2002, max_year=2005), - lambda x: x.month == 2 and x.day == 29, - settings=settings( - database=None, max_examples=10 ** 7, timeout=unlimited) - ) - assert x.year == 2004 - - -@checks_deprecated_behaviour -def test_overflow_in_simplify(): - """This is a test that we don't trigger a pytz bug when we're simplifying - around MINYEAR where valid dates can produce an overflow error.""" - minimal( - datetimes(max_year=MINYEAR), - lambda x: x.tzinfo != pytz.UTC - ) diff -Nru python-hypothesis-3.44.1/tests/datetime/test_times.py python-hypothesis-3.71.11/tests/datetime/test_times.py --- python-hypothesis-3.44.1/tests/datetime/test_times.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/datetime/test_times.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,91 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import pytz - -from hypothesis import given, assume -from tests.common.debug import minimal, find_any -from tests.common.utils import checks_deprecated_behaviour -from hypothesis.extra.datetime import times - - -@checks_deprecated_behaviour -def test_can_find_midnight(): - find_any(times(), lambda x: x.hour == x.minute == x.second == 0) - - -@checks_deprecated_behaviour -def test_can_find_non_midnight(): - assert minimal(times(), lambda x: x.hour != 0).hour == 1 - - -@checks_deprecated_behaviour -def test_can_find_off_the_minute(): - find_any(times(), lambda x: x.second != 0) - - -@checks_deprecated_behaviour -def test_can_find_on_the_minute(): - find_any(times(), lambda x: x.second == 0) - - -@checks_deprecated_behaviour -def test_simplifies_towards_midnight(): - d = minimal(times()) - assert d.hour == 0 - assert d.minute == 0 - assert d.second == 0 - assert d.microsecond == 0 - - -@checks_deprecated_behaviour -def test_can_generate_naive_time(): - find_any(times(allow_naive=True), lambda d: d.tzinfo is not None) - - -@checks_deprecated_behaviour -def test_can_generate_non_naive_time(): - assert minimal( - times(allow_naive=True), lambda d: d.tzinfo).tzinfo == pytz.UTC - - -@checks_deprecated_behaviour -def test_can_generate_non_utc(): - times().filter( - lambda d: assume(d.tzinfo) and d.tzinfo.zone != u'UTC' - ).example() - - -@checks_deprecated_behaviour -@given(times(timezones=[])) -def test_naive_times_are_naive(dt): - assert not dt.tzinfo - - -@checks_deprecated_behaviour -@given(times(allow_naive=False)) -def test_timezone_aware_times_are_timezone_aware(dt): - assert dt.tzinfo - - -@checks_deprecated_behaviour -def test_restricts_to_allowed_set_of_timezones(): - timezones = list(map(pytz.timezone, list(pytz.all_timezones)[:3])) - x = minimal(times(timezones=timezones)) - assert any(tz.zone == x.tzinfo.zone for tz in timezones) diff -Nru python-hypothesis-3.44.1/tests/datetime/test_timezones.py python-hypothesis-3.71.11/tests/datetime/test_timezones.py --- python-hypothesis-3.44.1/tests/datetime/test_timezones.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/datetime/test_timezones.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,94 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import datetime as dt - -import pytz -import pytest - -from hypothesis import given, assume -from hypothesis.errors import InvalidArgument -from tests.common.debug import minimal -from hypothesis.extra.pytz import timezones -from hypothesis.strategies import times, datetimes, sampled_from - - -def test_utc_is_minimal(): - assert pytz.UTC is minimal(timezones()) - - -def test_can_generate_non_naive_time(): - assert minimal(times(timezones=timezones()), - lambda d: d.tzinfo).tzinfo == pytz.UTC - - -def test_can_generate_non_naive_datetime(): - assert minimal(datetimes(timezones=timezones()), - lambda d: d.tzinfo).tzinfo == pytz.UTC - - -@given(datetimes(timezones=timezones())) -def test_timezone_aware_datetimes_are_timezone_aware(dt): - assert dt.tzinfo is not None - - -@given(sampled_from(['min_value', 'max_value']), - datetimes(timezones=timezones())) -def test_datetime_bounds_must_be_naive(name, val): - with pytest.raises(InvalidArgument): - datetimes(**{name: val}).validate() - - -def test_underflow_in_simplify(): - # we shouldn't trigger a pytz bug when we're simplifying - minimal(datetimes(max_value=dt.datetime.min + dt.timedelta(days=3), - timezones=timezones()), - lambda x: x.tzinfo != pytz.UTC) - - -def test_overflow_in_simplify(): - # we shouldn't trigger a pytz bug when we're simplifying - minimal(datetimes(min_value=dt.datetime.max - dt.timedelta(days=3), - timezones=timezones()), - lambda x: x.tzinfo != pytz.UTC) - - -def test_timezones_arg_to_datetimes_must_be_search_strategy(): - with pytest.raises(InvalidArgument): - datetimes(timezones=pytz.all_timezones).validate() - with pytest.raises(InvalidArgument): - tz = [pytz.timezone(t) for t in pytz.all_timezones] - datetimes(timezones=tz).validate() - - -@given(times(timezones=timezones())) -def test_timezone_aware_times_are_timezone_aware(dt): - assert dt.tzinfo is not None - - -def test_can_generate_non_utc(): - times(timezones=timezones()).filter( - lambda d: assume(d.tzinfo) and d.tzinfo.zone != u'UTC' - ).validate() - - -@given(sampled_from(['min_value', 'max_value']), times(timezones=timezones())) -def test_time_bounds_must_be_naive(name, val): - with pytest.raises(InvalidArgument): - times(**{name: val}).validate() diff -Nru python-hypothesis-3.44.1/tests/django/__init__.py python-hypothesis-3.71.11/tests/django/__init__.py --- python-hypothesis-3.44.1/tests/django/__init__.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/django/__init__.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER diff -Nru python-hypothesis-3.44.1/tests/django/manage.py python-hypothesis-3.71.11/tests/django/manage.py --- python-hypothesis-3.44.1/tests/django/manage.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/django/manage.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import os -import sys - -from hypothesis import HealthCheck, settings, unlimited -from tests.common.setup import run - -if __name__ == u'__main__': - run() - - settings.register_profile('default', settings( - timeout=unlimited, use_coverage=False, - suppress_health_check=[HealthCheck.too_slow], - )) - - settings.load_profile(os.getenv('HYPOTHESIS_PROFILE', 'default')) - - os.environ.setdefault( - u'DJANGO_SETTINGS_MODULE', u'tests.django.toys.settings') - - from django.core.management import execute_from_command_line - - execute_from_command_line(sys.argv) diff -Nru python-hypothesis-3.44.1/tests/django/toys/__init__.py python-hypothesis-3.71.11/tests/django/toys/__init__.py --- python-hypothesis-3.44.1/tests/django/toys/__init__.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/django/toys/__init__.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER diff -Nru python-hypothesis-3.44.1/tests/django/toys/settings.py python-hypothesis-3.71.11/tests/django/toys/settings.py --- python-hypothesis-3.44.1/tests/django/toys/settings.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/django/toys/settings.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,105 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -"""Django settings for toys project. - -For more information on this file, see -https://docs.djangoproject.com/en/1.7/topics/settings/ - -For the full list of settings and their values, see -https://docs.djangoproject.com/en/1.7/ref/settings/ - -""" - -# Build paths inside the project like this: os.path.join(BASE_DIR, ...) - -from __future__ import division, print_function, absolute_import - -import os - -BASE_DIR = os.path.dirname(os.path.dirname(__file__)) - - -# Quick-start development settings - unsuitable for production -# See https://docs.djangoproject.com/en/1.7/howto/deployment/checklist/ - -# SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = u'o0zlv@74u4e3s+o0^h$+tlalh&$r(7hbx01g4^h5-3gizj%hub' - -# SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True - -TEMPLATE_DEBUG = True - -ALLOWED_HOSTS = [] - - -# Application definition - -INSTALLED_APPS = ( - u'django.contrib.admin', - u'django.contrib.auth', - u'django.contrib.contenttypes', - u'django.contrib.sessions', - u'django.contrib.messages', - u'django.contrib.staticfiles', - u'tests.django.toystore', -) - -MIDDLEWARE_CLASSES = ( - u'django.contrib.sessions.middleware.SessionMiddleware', - u'django.middleware.common.CommonMiddleware', - u'django.middleware.csrf.CsrfViewMiddleware', - u'django.contrib.auth.middleware.AuthenticationMiddleware', - u'django.contrib.auth.middleware.SessionAuthenticationMiddleware', - u'django.contrib.messages.middleware.MessageMiddleware', - u'django.middleware.clickjacking.XFrameOptionsMiddleware', -) - -ROOT_URLCONF = u'tests.django.toys.urls' - -WSGI_APPLICATION = u'tests.django.toys.wsgi.application' - - -# Database -# https://docs.djangoproject.com/en/1.7/ref/settings/#databases - -DATABASES = { - u'default': { - u'ENGINE': u'django.db.backends.sqlite3', - u'NAME': os.path.join(BASE_DIR, u'db.sqlite3'), - } -} - -# Internationalization -# https://docs.djangoproject.com/en/1.7/topics/i18n/ - -LANGUAGE_CODE = u'en-us' - -TIME_ZONE = u'UTC' - -USE_I18N = True - -USE_L10N = True - -USE_TZ = os.environ.get('HYPOTHESIS_DJANGO_USETZ', 'TRUE') == 'TRUE' - - -# Static files (CSS, JavaScript, Images) -# https://docs.djangoproject.com/en/1.7/howto/static-files/ - -STATIC_URL = u'/static/' diff -Nru python-hypothesis-3.44.1/tests/django/toys/urls.py python-hypothesis-3.71.11/tests/django/toys/urls.py --- python-hypothesis-3.44.1/tests/django/toys/urls.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/django/toys/urls.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from django.contrib import admin -from django.conf.urls import url, include - -patterns, namespace, name = admin.site.urls - -urlpatterns = [ - # Examples: - # url(r'^$', 'toys.views.home', name='home'), - # url(r'^blog/', include('blog.urls')), - - url(r'^admin/', include((patterns, name), namespace=namespace)) -] diff -Nru python-hypothesis-3.44.1/tests/django/toys/wsgi.py python-hypothesis-3.71.11/tests/django/toys/wsgi.py --- python-hypothesis-3.44.1/tests/django/toys/wsgi.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/django/toys/wsgi.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,36 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -"""WSGI config for toys project. - -It exposes the WSGI callable as a module-level variable named ``application``. - -For more information on this file, see -https://docs.djangoproject.com/en/1.7/howto/deployment/wsgi/ - -""" - - -from __future__ import division, print_function, absolute_import - -import os - -from django.core.wsgi import get_wsgi_application - -os.environ.setdefault(u'DJANGO_SETTINGS_MODULE', u'toys.settings') - -application = get_wsgi_application() diff -Nru python-hypothesis-3.44.1/tests/django/toystore/admin.py python-hypothesis-3.71.11/tests/django/toystore/admin.py --- python-hypothesis-3.44.1/tests/django/toystore/admin.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/django/toystore/admin.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import diff -Nru python-hypothesis-3.44.1/tests/django/toystore/__init__.py python-hypothesis-3.71.11/tests/django/toystore/__init__.py --- python-hypothesis-3.44.1/tests/django/toystore/__init__.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/django/toystore/__init__.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER diff -Nru python-hypothesis-3.44.1/tests/django/toystore/models.py python-hypothesis-3.71.11/tests/django/toystore/models.py --- python-hypothesis-3.44.1/tests/django/toystore/models.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/django/toystore/models.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,143 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from django.db import models -from django.core.exceptions import ValidationError - - -class Company(models.Model): - name = models.CharField(max_length=100, unique=True) - - -class Store(models.Model): - name = models.CharField(max_length=100, unique=True) - company = models.ForeignKey(Company, null=False, on_delete=models.CASCADE) - - -class CharmField(models.Field): - - def db_type(self, connection): - return u'char(1)' - - -class CustomishField(models.Field): - - def db_type(self, connection): - return u'char(1)' - - -class Customish(models.Model): - customish = CustomishField() - - -class Customer(models.Model): - name = models.CharField(max_length=100, unique=True) - email = models.EmailField(max_length=100, unique=True) - gender = models.CharField(max_length=50, null=True) - age = models.IntegerField() - birthday = models.DateTimeField() - - -class Charming(models.Model): - charm = CharmField() - - -class CouldBeCharming(models.Model): - charm = CharmField(null=True) - - -class SelfLoop(models.Model): - me = models.ForeignKey(u'self', null=True, on_delete=models.SET_NULL) - - -class LoopA(models.Model): - b = models.ForeignKey(u'LoopB', null=False, on_delete=models.CASCADE) - - -class LoopB(models.Model): - a = models.ForeignKey(u'LoopA', null=True, on_delete=models.SET_NULL) - - -class ManyNumerics(models.Model): - i1 = models.IntegerField() - i2 = models.SmallIntegerField() - i3 = models.BigIntegerField() - - p1 = models.PositiveIntegerField() - p2 = models.PositiveSmallIntegerField() - - d = models.DecimalField(decimal_places=2, max_digits=5) - - -class ManyTimes(models.Model): - time = models.TimeField() - date = models.DateField() - duration = models.DurationField() - - -class OddFields(models.Model): - uuid = models.UUIDField() - slug = models.SlugField() - ipv4 = models.GenericIPAddressField(protocol='IPv4') - ipv6 = models.GenericIPAddressField(protocol='IPv6') - - -class CustomishDefault(models.Model): - customish = CustomishField(default=u'b') - - -class MandatoryComputed(models.Model): - name = models.CharField(max_length=100, unique=True) - company = models.ForeignKey(Company, null=False, on_delete=models.CASCADE) - - def __init__(self, **kw): - if u'company' in kw: - raise RuntimeError() - cname = kw[u'name'] + u'_company' - kw[u'company'] = Company.objects.create(name=cname) - super(MandatoryComputed, self).__init__(**kw) - - -def validate_even(value): - if value % 2 != 0: - raise ValidationError('') - - -class RestrictedFields(models.Model): - text_field_4 = models.TextField(max_length=4, blank=True) - char_field_4 = models.CharField(max_length=4, blank=True) - choice_field_text = models.TextField( - choices=(('foo', 'Foo'), ('bar', 'Bar')) - ) - choice_field_int = models.IntegerField( - choices=((1, 'First'), (2, 'Second')) - ) - null_choice_field_int = models.IntegerField( - choices=((1, 'First'), (2, 'Second')), - null=True, blank=True - ) - choice_field_grouped = models.TextField(choices=( - ('Audio', (('vinyl', 'Vinyl'), ('cd', 'CD'),)), - ('Video', (('vhs', 'VHS Tape'), ('dvd', 'DVD'),)), - ('unknown', 'Unknown'), - )) - even_number_field = models.IntegerField( - validators=[validate_even] - ) - non_blank_text_field = models.TextField(blank=False) diff -Nru python-hypothesis-3.44.1/tests/django/toystore/test_basic_configuration.py python-hypothesis-3.71.11/tests/django/toystore/test_basic_configuration.py --- python-hypothesis-3.44.1/tests/django/toystore/test_basic_configuration.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/django/toystore/test_basic_configuration.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,79 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from unittest import TestCase as VanillaTestCase - -from django.db import IntegrityError - -from hypothesis import HealthCheck, given, settings -from hypothesis.strategies import integers -from hypothesis.extra.django import TestCase, TransactionTestCase -from hypothesis.internal.compat import PYPY -from tests.django.toystore.models import Company - - -class SomeStuff(object): - - @settings(suppress_health_check=[HealthCheck.too_slow]) - @given(integers()) - def test_is_blank_slate(self, unused): - Company.objects.create(name=u'MickeyCo') - - def test_normal_test_1(self): - Company.objects.create(name=u'MickeyCo') - - def test_normal_test_2(self): - Company.objects.create(name=u'MickeyCo') - - -class TestConstraintsWithTransactions(SomeStuff, TestCase): - pass - - -if not PYPY: - # xfail - # This is excessively slow in general, but particularly on pypy. We just - # disable it altogether there as it's a niche case. - class TestConstraintsWithoutTransactions(SomeStuff, TransactionTestCase): - pass - - -class TestWorkflow(VanillaTestCase): - - def test_does_not_break_later_tests(self): - def break_the_db(i): - Company.objects.create(name=u'MickeyCo') - Company.objects.create(name=u'MickeyCo') - - class LocalTest(TestCase): - - @given(integers().map(break_the_db)) - @settings(perform_health_check=False) - def test_does_not_break_other_things(self, unused): - pass - - def test_normal_test_1(self): - Company.objects.create(name=u'MickeyCo') - - t = LocalTest(u'test_normal_test_1') - try: - t.test_does_not_break_other_things() - except IntegrityError: - pass - t.test_normal_test_1() diff -Nru python-hypothesis-3.44.1/tests/django/toystore/test_given_models.py python-hypothesis-3.71.11/tests/django/toystore/test_given_models.py --- python-hypothesis-3.44.1/tests/django/toystore/test_given_models.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/django/toystore/test_given_models.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,154 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import datetime as dt -from uuid import UUID - -from django.conf import settings as django_settings - -from hypothesis import HealthCheck, given, assume, settings -from hypothesis.errors import InvalidArgument -from hypothesis.strategies import just, lists -from hypothesis.extra.django import TestCase, TransactionTestCase -from hypothesis.internal.compat import text_type -from tests.django.toystore.models import Store, Company, Customer, \ - SelfLoop, Customish, ManyTimes, OddFields, ManyNumerics, \ - CustomishField, CouldBeCharming, CustomishDefault, RestrictedFields, \ - MandatoryComputed -from hypothesis.extra.django.models import models, default_value, \ - add_default_field_mapping - -add_default_field_mapping(CustomishField, just(u'a')) - - -class TestGetsBasicModels(TestCase): - - @given(models(Company)) - def test_is_company(self, company): - self.assertIsInstance(company, Company) - self.assertIsNotNone(company.pk) - - @given(models(Store, company=models(Company))) - def test_can_get_a_store(self, store): - assert store.company.pk - - @given(lists(models(Company))) - def test_can_get_multiple_models_with_unique_field(self, companies): - assume(len(companies) > 1) - for c in companies: - self.assertIsNotNone(c.pk) - self.assertEqual( - len({c.pk for c in companies}), len({c.name for c in companies}) - ) - - @settings(suppress_health_check=[HealthCheck.too_slow]) - @given(models(Customer)) - def test_is_customer(self, customer): - self.assertIsInstance(customer, Customer) - self.assertIsNotNone(customer.pk) - self.assertIsNotNone(customer.email) - - @settings(suppress_health_check=[HealthCheck.too_slow]) - @given(models(Customer)) - def test_tz_presence(self, customer): - if django_settings.USE_TZ: - self.assertIsNotNone(customer.birthday.tzinfo) - else: - self.assertIsNone(customer.birthday.tzinfo) - - @given(models(CouldBeCharming)) - def test_is_not_charming(self, not_charming): - self.assertIsInstance(not_charming, CouldBeCharming) - self.assertIsNotNone(not_charming.pk) - self.assertIsNone(not_charming.charm) - - @given(models(SelfLoop)) - def test_sl(self, sl): - self.assertIsNone(sl.me) - - @given(lists(models(ManyNumerics))) - def test_no_overflow_in_integer(self, manyints): - pass - - @given(models(Customish)) - def test_custom_field(self, x): - assert x.customish == u'a' - - def test_mandatory_fields_are_mandatory(self): - self.assertRaises(InvalidArgument, models, Store) - - def test_mandatory_computed_fields_are_mandatory(self): - self.assertRaises(InvalidArgument, models, MandatoryComputed) - - def test_mandatory_computed_fields_may_not_be_provided(self): - mc = models(MandatoryComputed, company=models(Company)) - self.assertRaises(RuntimeError, mc.example) - - @given(models(MandatoryComputed, company=default_value)) - def test_mandatory_computed_field_default(self, x): - assert x.company.name == x.name + u'_company' - - @given(models(CustomishDefault)) - def test_customish_default_generated(self, x): - assert x.customish == u'a' - - @given(models(CustomishDefault, customish=default_value)) - def test_customish_default_not_generated(self, x): - assert x.customish == u'b' - - @given(models(OddFields)) - def test_odd_fields(self, x): - assert isinstance(x.uuid, UUID) - assert isinstance(x.slug, text_type) - assert u' ' not in x.slug - assert isinstance(x.ipv4, str) - assert len(x.ipv4.split('.')) == 4 - assert all(int(i) in range(256) for i in x.ipv4.split('.')) - assert isinstance(x.ipv6, text_type) - assert set(x.ipv6).issubset(set(u'0123456789abcdefABCDEF:.')) - - @given(models(ManyTimes)) - def test_time_fields(self, x): - assert isinstance(x.time, dt.time) - assert isinstance(x.date, dt.date) - assert isinstance(x.duration, dt.timedelta) - - -class TestsNeedingRollback(TransactionTestCase): - - def test_can_get_examples(self): - for _ in range(200): - models(Company).example() - - -class TestRestrictedFields(TestCase): - - @given(models(RestrictedFields)) - def test_constructs_valid_instance(self, instance): - self.assertTrue(isinstance(instance, RestrictedFields)) - instance.full_clean() - self.assertLessEqual(len(instance.text_field_4), 4) - self.assertLessEqual(len(instance.char_field_4), 4) - self.assertIn(instance.choice_field_text, ('foo', 'bar')) - self.assertIn(instance.choice_field_int, (1, 2)) - self.assertIn(instance.null_choice_field_int, (1, 2, None)) - self.assertEqual(instance.choice_field_grouped, - instance.choice_field_grouped.lower()) - self.assertEqual(instance.even_number_field % 2, 0) - self.assertTrue(instance.non_blank_text_field) diff -Nru python-hypothesis-3.44.1/tests/django/toystore/views.py python-hypothesis-3.71.11/tests/django/toystore/views.py --- python-hypothesis-3.44.1/tests/django/toystore/views.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/django/toystore/views.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import diff -Nru python-hypothesis-3.44.1/tests/fakefactory/__init__.py python-hypothesis-3.71.11/tests/fakefactory/__init__.py --- python-hypothesis-3.44.1/tests/fakefactory/__init__.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/fakefactory/__init__.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER diff -Nru python-hypothesis-3.44.1/tests/fakefactory/test_fake_factory.py python-hypothesis-3.71.11/tests/fakefactory/test_fake_factory.py --- python-hypothesis-3.44.1/tests/fakefactory/test_fake_factory.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/fakefactory/test_fake_factory.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,109 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import pytest -from faker.providers import BaseProvider - -from hypothesis import given -from tests.common.debug import minimal -from tests.common.utils import checks_deprecated_behaviour -from hypothesis.extra.fakefactory import fake_factory - - -class KittenProvider(BaseProvider): - - def kittens(self): - return u'meow %d' % (self.random_number(digits=10),) - - -@checks_deprecated_behaviour -def test_kittens_meow(): - @given(fake_factory(u'kittens', providers=[KittenProvider])) - def inner(kitten): - assert u'meow' in kitten - - inner() - - -@checks_deprecated_behaviour -def test_email(): - @given(fake_factory(u'email')) - def inner(email): - assert u'@' in email - - inner() - - -@checks_deprecated_behaviour -def test_english_names_are_ascii(): - @given(fake_factory(u'name', locale=u'en_US')) - def inner(name): - name.encode(u'ascii') - - inner() - - -@checks_deprecated_behaviour -def test_french_names_may_have_an_accent(): - minimal( - fake_factory(u'name', locale=u'fr_FR'), - lambda x: u'é' not in x - ) - - -@checks_deprecated_behaviour -def test_fake_factory_errors_with_both_locale_and_locales(): - with pytest.raises(ValueError): - fake_factory( - u'name', locale=u'fr_FR', locales=[u'fr_FR', u'en_US'] - ) - - -@checks_deprecated_behaviour -def test_fake_factory_errors_with_unsupported_locale(): - with pytest.raises(ValueError): - fake_factory( - u'name', locale=u'badger_BADGER' - ) - - -@checks_deprecated_behaviour -def test_factory_errors_with_source_for_unsupported_locale(): - with pytest.raises(ValueError): - fake_factory(u'state', locale=u'ja_JP') - - -@checks_deprecated_behaviour -def test_fake_factory_errors_if_any_locale_is_unsupported(): - with pytest.raises(ValueError): - fake_factory( - u'name', locales=[u'fr_FR', u'en_US', u'mushroom_MUSHROOM'] - ) - - -@checks_deprecated_behaviour -def test_fake_factory_errors_if_unsupported_method(): - with pytest.raises(ValueError): - fake_factory(u'spoon') - - -@checks_deprecated_behaviour -def test_fake_factory_errors_if_private_ish_method(): - with pytest.raises(ValueError): - fake_factory(u'_Generator__config') diff -Nru python-hypothesis-3.44.1/tests/__init__.py python-hypothesis-3.71.11/tests/__init__.py --- python-hypothesis-3.44.1/tests/__init__.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/__init__.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER diff -Nru python-hypothesis-3.44.1/tests/nocover/__init__.py python-hypothesis-3.71.11/tests/nocover/__init__.py --- python-hypothesis-3.44.1/tests/nocover/__init__.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/nocover/__init__.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER diff -Nru python-hypothesis-3.44.1/tests/nocover/test_boundary_exploration.py python-hypothesis-3.71.11/tests/nocover/test_boundary_exploration.py --- python-hypothesis-3.44.1/tests/nocover/test_boundary_exploration.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/nocover/test_boundary_exploration.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,50 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import pytest - -import hypothesis.strategies as st -from hypothesis import Verbosity, HealthCheck, find, given, reject, \ - settings -from hypothesis.errors import NoSuchExample - - -@pytest.mark.parametrize('strat', [st.text(min_size=5)]) -@settings( - max_shrinks=0, deadline=None, suppress_health_check=[ - HealthCheck.too_slow, HealthCheck.hung_test] -) -@given(st.data()) -def test_explore_arbitrary_function(strat, data): - cache = {} - - def predicate(x): - try: - return cache[x] - except KeyError: - return cache.setdefault(x, data.draw(st.booleans(), label=repr(x))) - - try: - find( - strat, predicate, - settings=settings( - database=None, verbosity=Verbosity.quiet, max_shrinks=1000) - ) - except NoSuchExample: - reject() diff -Nru python-hypothesis-3.44.1/tests/nocover/test_characters.py python-hypothesis-3.71.11/tests/nocover/test_characters.py --- python-hypothesis-3.44.1/tests/nocover/test_characters.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/nocover/test_characters.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import string - -from hypothesis import strategies as st -from hypothesis import given - -IDENTIFIER_CHARS = string.ascii_letters + string.digits + '_' - - -@given(st.characters(blacklist_characters=IDENTIFIER_CHARS)) -def test_large_blacklist(c): - assert c not in IDENTIFIER_CHARS - - -@given(st.data()) -def test_arbitrary_blacklist(data): - blacklist = data.draw( - st.text(st.characters(max_codepoint=1000), min_size=1)) - ords = list(map(ord, blacklist)) - c = data.draw( - st.characters( - blacklist_characters=blacklist, - min_codepoint=max(0, min(ords) - 1), - max_codepoint=max(0, max(ords) + 1), - ) - ) - assert c not in blacklist diff -Nru python-hypothesis-3.44.1/tests/nocover/test_choices.py python-hypothesis-3.71.11/tests/nocover/test_choices.py --- python-hypothesis-3.44.1/tests/nocover/test_choices.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/nocover/test_choices.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,55 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import hypothesis.strategies as st -from hypothesis import given, settings, unlimited -from tests.common.utils import raises, capture_out, \ - checks_deprecated_behaviour -from hypothesis.database import ExampleDatabase -from hypothesis.internal.compat import hrange - - -@checks_deprecated_behaviour -def test_stability(): - @given( - st.lists(st.integers(0, 1000), unique=True, min_size=5), - st.choices(), - ) - @settings( - database=ExampleDatabase(), max_shrinks=10**6, timeout=unlimited, - ) - def test_choose_and_then_fail(ls, choice): - for _ in hrange(100): - choice(ls) - assert False - - # Run once first for easier debugging - with raises(AssertionError): - test_choose_and_then_fail() - - with capture_out() as o: - with raises(AssertionError): - test_choose_and_then_fail() - out1 = o.getvalue() - with capture_out() as o: - with raises(AssertionError): - test_choose_and_then_fail() - out2 = o.getvalue() - assert out1 == out2 - assert 'Choice #100:' in out1 diff -Nru python-hypothesis-3.44.1/tests/nocover/test_collective_minimization.py python-hypothesis-3.71.11/tests/nocover/test_collective_minimization.py --- python-hypothesis-3.44.1/tests/nocover/test_collective_minimization.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/nocover/test_collective_minimization.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,54 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import pytest -from flaky import flaky - -from hypothesis import find, settings -from tests.common import standard_types -from hypothesis.errors import NoSuchExample -from hypothesis.strategies import lists - - -@pytest.mark.parametrize( - u'spec', standard_types, ids=list(map(repr, standard_types))) -@flaky(min_passes=1, max_runs=2) -def test_can_collectively_minimize(spec): - """This should generally exercise strategies' strictly_simpler heuristic by - putting us in a state where example cloning is required to get to the - answer fast enough.""" - n = 10 - - def distinct_reprs(x): - result = set() - for t in x: - result.add(repr(t)) - if len(result) >= 2: - return True - return False - - try: - xs = find( - lists(spec, min_size=n, max_size=n), - distinct_reprs, - settings=settings(max_shrinks=100, max_examples=2000)) - assert len(xs) == n - assert 2 <= len(set((map(repr, xs)))) <= 3 - except NoSuchExample: - pass diff -Nru python-hypothesis-3.44.1/tests/nocover/test_compat.py python-hypothesis-3.71.11/tests/nocover/test_compat.py --- python-hypothesis-3.44.1/tests/nocover/test_compat.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/nocover/test_compat.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,139 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import inspect -import warnings - -import pytest - -from hypothesis import strategies as st -from hypothesis import given -from hypothesis.internal.compat import FullArgSpec, ceil, floor, hrange, \ - qualname, int_to_bytes, integer_types, getfullargspec, \ - int_from_bytes - - -def test_small_hrange(): - assert list(hrange(5)) == [0, 1, 2, 3, 4] - assert list(hrange(3, 5)) == [3, 4] - assert list(hrange(1, 10, 2)) == [1, 3, 5, 7, 9] - - -def test_large_hrange(): - n = 1 << 1024 - assert list(hrange(n, n + 5, 2)) == [n, n + 2, n + 4] - assert list(hrange(n, n)) == [] - - with pytest.raises(ValueError): - hrange(n, n, 0) - - -class Foo(): - - def bar(self): - pass - - -def test_qualname(): - assert qualname(Foo.bar) == u'Foo.bar' - assert qualname(Foo().bar) == u'Foo.bar' - assert qualname(qualname) == u'qualname' - - -def a(b, c, d): - pass - - -def b(c, d, *ar): - pass - - -def c(c, d, *ar, **k): - pass - - -def d(a1, a2=1, a3=2, a4=None): - pass - - -@pytest.mark.parametrize('f', [a, b, c, d]) -def test_agrees_on_argspec(f): - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - basic = inspect.getargspec(f) - full = getfullargspec(f) - assert basic.args == full.args - assert basic.varargs == full.varargs - assert basic.keywords == full.varkw - assert basic.defaults == full.defaults - - -@given(st.binary()) -def test_convert_back(bs): - bs = bytearray(bs) - assert int_to_bytes(int_from_bytes(bs), len(bs)) == bs - - -bytes8 = st.builds(bytearray, st.binary(min_size=8, max_size=8)) - - -@given(bytes8, bytes8) -def test_to_int_in_big_endian_order(x, y): - x, y = sorted((x, y)) - assert 0 <= int_from_bytes(x) <= int_from_bytes(y) - - -ints8 = st.integers(min_value=0, max_value=2 ** 63 - 1) - - -@given(ints8, ints8) -def test_to_bytes_in_big_endian_order(x, y): - x, y = sorted((x, y)) - assert int_to_bytes(x, 8) <= int_to_bytes(y, 8) - - -@pytest.mark.skipif(not hasattr(inspect, 'getfullargspec'), - reason='inspect.getfullargspec only exists under Python 3') -def test_inspection_compat(): - assert getfullargspec is inspect.getfullargspec - - -@pytest.mark.skipif(not hasattr(inspect, 'FullArgSpec'), - reason='inspect.FullArgSpec only exists under Python 3') -def test_inspection_result_compat(): - assert FullArgSpec is inspect.FullArgSpec - - -@given(st.fractions()) -def test_ceil(x): - """The compat ceil function always has the Python 3 semantics. - - Under Python 2, math.ceil returns a float, which cannot represent large - integers - for example, `float(2**53) == float(2**53 + 1)` - and this - is obviously incorrect for unlimited-precision integer operations. - - """ - assert isinstance(ceil(x), integer_types) - assert x <= ceil(x) < x + 1 - - -@given(st.fractions()) -def test_floor(x): - assert isinstance(floor(x), integer_types) - assert x - 1 < floor(x) <= x diff -Nru python-hypothesis-3.44.1/tests/nocover/test_conjecture_engine.py python-hypothesis-3.71.11/tests/nocover/test_conjecture_engine.py --- python-hypothesis-3.44.1/tests/nocover/test_conjecture_engine.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/nocover/test_conjecture_engine.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,120 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from hypothesis import strategies as st -from hypothesis import HealthCheck, given, settings, unlimited -from hypothesis.database import InMemoryExampleDatabase -from hypothesis.internal.compat import hbytes -from tests.cover.test_conjecture_engine import run_to_buffer, slow_shrinker -from hypothesis.internal.conjecture.data import Status -from hypothesis.internal.conjecture.engine import ConjectureRunner - - -@given(st.random_module()) -@settings(max_shrinks=0, deadline=None, perform_health_check=False) -def test_lot_of_dead_nodes(rnd): - @run_to_buffer - def x(data): - for i in range(5): - if data.draw_bytes(1)[0] != i: - data.mark_invalid() - data.mark_interesting() - assert x == hbytes([0, 1, 2, 3, 4]) - - -def test_saves_data_while_shrinking(): - key = b'hi there' - n = 5 - db = InMemoryExampleDatabase() - assert list(db.fetch(key)) == [] - seen = set() - - def f(data): - x = data.draw_bytes(512) - if sum(x) >= 5000 and len(seen) < n: - seen.add(hbytes(x)) - if hbytes(x) in seen: - data.mark_interesting() - runner = ConjectureRunner( - f, settings=settings(database=db), database_key=key) - runner.run() - assert runner.last_data.status == Status.INTERESTING - assert len(seen) == n - in_db = set( - v - for vs in db.data.values() - for v in vs - ) - assert in_db.issubset(seen) - assert in_db == seen - - -@given(st.randoms(), st.random_module()) -@settings( - max_shrinks=0, deadline=None, suppress_health_check=[HealthCheck.hung_test] -) -def test_maliciously_bad_generator(rnd, seed): - @run_to_buffer - def x(data): - for _ in range(rnd.randint(1, 100)): - data.draw_bytes(rnd.randint(1, 10)) - if rnd.randint(0, 1): - data.mark_invalid() - else: - data.mark_interesting() - - -def test_garbage_collects_the_database(): - key = b'hi there' - n = 200 - db = InMemoryExampleDatabase() - - local_settings = settings( - database=db, max_shrinks=n, timeout=unlimited) - - runner = ConjectureRunner( - slow_shrinker(), settings=local_settings, database_key=key) - runner.run() - assert runner.last_data.status == Status.INTERESTING - - def in_db(): - return set( - v - for vs in db.data.values() - for v in vs - ) - - assert len(in_db()) == n + 1 - runner = ConjectureRunner( - lambda data: data.draw_bytes(4), - settings=local_settings, database_key=key) - runner.run() - assert 0 < len(in_db()) < n - - -def test_can_discard(): - n = 32 - - @run_to_buffer - def x(data): - seen = set() - while len(seen) < n: - seen.add(hbytes(data.draw_bytes(1))) - data.mark_interesting() - assert len(x) == n diff -Nru python-hypothesis-3.44.1/tests/nocover/test_coverage.py python-hypothesis-3.71.11/tests/nocover/test_coverage.py --- python-hypothesis-3.44.1/tests/nocover/test_coverage.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/nocover/test_coverage.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,120 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import pytest -from coverage import Coverage - -import hypothesis.strategies as st -from hypothesis import given, settings -from hypothesis.core import escalate_warning -from tests.common.utils import all_values -from hypothesis.database import InMemoryExampleDatabase -from hypothesis.internal.compat import hrange - -pytestmark = pytest.mark.skipif( - not settings.default.use_coverage, - reason='Coverage is disabled for this build.' -) - - -def test_tracks_and_saves_coverage(): - db = InMemoryExampleDatabase() - - def do_nothing(): - """Use in place of pass for empty branches, which don't show up under - coverge.""" - pass - - @settings(database=db) - @given(st.integers()) - def test_branching(i): - if i < -1000: - do_nothing() - elif i > 1000: - do_nothing() - else: - do_nothing() - - test_branching() - - assert len(all_values(db)) == 3 - - -def some_function_to_test(a, b, c): - result = 0 - if a: - result += 1 - if b: - result += 1 - if c: - result += 1 - return result - - -LINE_START = some_function_to_test.__code__.co_firstlineno -with open(__file__) as i: - lines = [l.strip() for l in i] - LINE_END = LINE_START + lines[LINE_START:].index('') - - -@pytest.mark.parametrize('branch', [False, True]) -@pytest.mark.parametrize('timid', [False, True]) -def test_achieves_full_coverage(tmpdir, branch, timid): - @given(st.booleans(), st.booleans(), st.booleans()) - def test(a, b, c): - some_function_to_test(a, b, c) - - cov = Coverage( - config_file=False, data_file=str(tmpdir.join('.coverage')), - branch=branch, timid=timid, - ) - cov._warn = escalate_warning - cov.start() - test() - cov.stop() - - data = cov.get_data() - lines = data.lines(__file__) - for i in hrange(LINE_START + 1, LINE_END + 1): - assert i in lines - - -def rnd(): - import random - return random.gauss(0, 1) - - -@pytest.mark.parametrize('branch', [False, True]) -@pytest.mark.parametrize('timid', [False, True]) -def test_does_not_trace_files_outside_inclusion(tmpdir, branch, timid): - @given(st.booleans()) - def test(a): - rnd() - - cov = Coverage( - config_file=False, data_file=str(tmpdir.join('.coverage')), - branch=branch, timid=timid, include=[__file__], - ) - cov._warn = escalate_warning - cov.start() - test() - cov.stop() - - data = cov.get_data() - assert len(list(data.measured_files())) == 1 diff -Nru python-hypothesis-3.44.1/tests/nocover/test_database_agreement.py python-hypothesis-3.71.11/tests/nocover/test_database_agreement.py --- python-hypothesis-3.44.1/tests/nocover/test_database_agreement.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/nocover/test_database_agreement.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,90 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import os -import shutil -import tempfile - -import hypothesis.strategies as st -from tests.common.utils import validate_deprecation -from hypothesis.database import SQLiteExampleDatabase, \ - InMemoryExampleDatabase, DirectoryBasedExampleDatabase -from hypothesis.stateful import Bundle, RuleBasedStateMachine, rule - - -class DatabaseComparison(RuleBasedStateMachine): - - def __init__(self): - super(DatabaseComparison, self).__init__() - self.tempd = tempfile.mkdtemp() - exampledir = os.path.join(self.tempd, 'examples') - - self.dbs = [ - DirectoryBasedExampleDatabase(exampledir), - InMemoryExampleDatabase(), - DirectoryBasedExampleDatabase(exampledir), - ] - - with validate_deprecation(): - self.dbs.append(SQLiteExampleDatabase(':memory:')) - - keys = Bundle('keys') - values = Bundle('values') - - @rule(target=keys, k=st.binary()) - def k(self, k): - return k - - @rule(target=values, v=st.binary()) - def v(self, v): - return v - - @rule(k=keys, v=values) - def save(self, k, v): - for db in self.dbs: - db.save(k, v) - - @rule(k=keys, v=values) - def delete(self, k, v): - for db in self.dbs: - db.delete(k, v) - - @rule(k1=keys, k2=keys, v=values) - def move(self, k1, k2, v): - for db in self.dbs: - db.move(k1, k2, v) - - @rule(k=keys) - def values_agree(self, k): - last = None - last_db = None - for db in self.dbs: - keys = set(db.fetch(k)) - if last is not None: - assert last == keys, (last_db, db) - last = keys - last_db = db - - def teardown(self): - for d in self.dbs: - d.close() - shutil.rmtree(self.tempd) - - -TestDBs = DatabaseComparison.TestCase diff -Nru python-hypothesis-3.44.1/tests/nocover/test_deferred_strategies.py python-hypothesis-3.71.11/tests/nocover/test_deferred_strategies.py --- python-hypothesis-3.44.1/tests/nocover/test_deferred_strategies.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/nocover/test_deferred_strategies.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,71 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from hypothesis import strategies as st -from hypothesis import Verbosity, find, note, given, settings -from hypothesis.errors import NoSuchExample, Unsatisfiable -from hypothesis.internal.compat import hrange - - -@st.composite -def mutually_recursive_strategies(draw): - strategies = [st.none()] - - def build_strategy_for_indices(base, ixs, deferred): - def f(): - return base(*[strategies[i] for i in ixs]) - f.__name__ = '%s([%s])' % ( - base.__name__, ', '.join( - 'strategies[%d]' % (i,) for i in ixs - )) - if deferred: - return st.deferred(f) - else: - return f() - - n_strategies = draw(st.integers(1, 5)) - - for i in hrange(n_strategies): - base = draw(st.sampled_from((st.one_of, st.tuples))) - indices = draw(st.lists( - st.integers(0, n_strategies), min_size=1)) - if all(j <= i for j in indices): - deferred = draw(st.booleans()) - else: - deferred = True - strategies.append(build_strategy_for_indices(base, indices, deferred)) - return strategies - - -@settings(deadline=None) -@given(mutually_recursive_strategies()) -def test_arbitrary_recursion(strategies): - for i, s in enumerate(strategies): - if i > 0: - note('strategies[%d]=%r' % (i, s)) - - s.validate() - - try: - find(s, lambda x: True, settings=settings( - max_shrinks=0, database=None, verbosity=Verbosity.quiet, - max_examples=1, max_iterations=10, - )) - except (Unsatisfiable, NoSuchExample): - pass diff -Nru python-hypothesis-3.44.1/tests/nocover/test_fixtures.py python-hypothesis-3.71.11/tests/nocover/test_fixtures.py --- python-hypothesis-3.44.1/tests/nocover/test_fixtures.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/nocover/test_fixtures.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,30 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import time - -from tests.common import TIME_INCREMENT - - -def test_time_consistently_increments_in_tests(): - x = time.time() - y = time.time() - z = time.time() - assert y == x + TIME_INCREMENT - assert z == y + TIME_INCREMENT diff -Nru python-hypothesis-3.44.1/tests/nocover/test_floating.py python-hypothesis-3.71.11/tests/nocover/test_floating.py --- python-hypothesis-3.44.1/tests/nocover/test_floating.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/nocover/test_floating.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,161 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -"""Tests for being able to generate weird and wonderful floating point -numbers.""" - - -from __future__ import division, print_function, absolute_import - -import sys -import math - -from hypothesis import HealthCheck, given, assume, settings -from tests.common.utils import fails -from hypothesis.strategies import data, lists, floats - -TRY_HARDER = settings( - max_examples=1000, max_iterations=2000, - suppress_health_check=[HealthCheck.filter_too_much] -) - - -@given(floats()) -@TRY_HARDER -def test_is_float(x): - assert isinstance(x, float) - - -@fails -@given(floats()) -@TRY_HARDER -def test_inversion_is_imperfect(x): - assume(x != 0.0) - y = 1.0 / x - assert x * y == 1.0 - - -@given(floats(-sys.float_info.max, sys.float_info.max)) -def test_largest_range(x): - assert not math.isinf(x) - - -@given(floats()) -@TRY_HARDER -def test_negation_is_self_inverse(x): - assume(not math.isnan(x)) - y = -x - assert -y == x - - -@fails -@given(lists(floats())) -def test_is_not_nan(xs): - assert not any(math.isnan(x) for x in xs) - - -@fails -@given(floats()) -@TRY_HARDER -def test_is_not_positive_infinite(x): - assume(x > 0) - assert not math.isinf(x) - - -@fails -@given(floats()) -@TRY_HARDER -def test_is_not_negative_infinite(x): - assume(x < 0) - assert not math.isinf(x) - - -@fails -@given(floats()) -@TRY_HARDER -def test_is_int(x): - assume(not (math.isinf(x) or math.isnan(x))) - assert x == int(x) - - -@fails -@given(floats()) -@TRY_HARDER -def test_is_not_int(x): - assume(not (math.isinf(x) or math.isnan(x))) - assert x != int(x) - - -@fails -@given(floats()) -@TRY_HARDER -def test_is_in_exact_int_range(x): - assume(not (math.isinf(x) or math.isnan(x))) - assert x + 1 != x - - -# Tests whether we can represent subnormal floating point numbers. -# This is essentially a function of how the python interpreter -# was compiled. -# Everything is terrible -if math.ldexp(0.25, -1022) > 0: - REALLY_SMALL_FLOAT = sys.float_info.min -else: - REALLY_SMALL_FLOAT = sys.float_info.min * 2 - - -@fails -@given(floats()) -@TRY_HARDER -def test_can_generate_really_small_positive_floats(x): - assume(x > 0) - assert x >= REALLY_SMALL_FLOAT - - -@fails -@given(floats()) -@TRY_HARDER -def test_can_generate_really_small_negative_floats(x): - assume(x < 0) - assert x <= -REALLY_SMALL_FLOAT - - -@fails -@given(floats()) -@TRY_HARDER -def test_can_find_floats_that_do_not_round_trip_through_strings(x): - assert float(str(x)) == x - - -@fails -@given(floats()) -@TRY_HARDER -def test_can_find_floats_that_do_not_round_trip_through_reprs(x): - assert float(repr(x)) == x - - -finite_floats = floats(allow_infinity=False, allow_nan=False) - - -@settings(deadline=None) -@given(finite_floats, finite_floats, data()) -def test_floats_are_in_range(x, y, data): - x, y = sorted((x, y)) - assume(x < y) - - t = data.draw(floats(x, y)) - assert x <= t <= y diff -Nru python-hypothesis-3.44.1/tests/nocover/test_float_shrinking.py python-hypothesis-3.71.11/tests/nocover/test_float_shrinking.py --- python-hypothesis-3.44.1/tests/nocover/test_float_shrinking.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/nocover/test_float_shrinking.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,64 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from random import Random - -import pytest - -import hypothesis.strategies as st -from hypothesis import Verbosity, given, assume, example, settings -from tests.common.debug import minimal -from hypothesis.internal.compat import ceil - - -def test_shrinks_to_simple_floats(): - assert minimal(st.floats(), lambda x: x > 1) == 2.0 - assert minimal(st.floats(), lambda x: x > 0) == 1.0 - - -@pytest.mark.parametrize('n', [1, 2, 3, 8, 10]) -def test_can_shrink_in_variable_sized_context(n): - x = minimal(st.lists(st.floats(), min_size=n), any) - assert len(x) == n - assert x.count(0.0) == n - 1 - assert 1 in x - - -@example(1.5) -@given(st.floats(min_value=0, allow_infinity=False, allow_nan=False)) -@settings(use_coverage=False, deadline=None, perform_health_check=False) -def test_shrinks_downwards_to_integers(f): - g = minimal( - st.floats(), lambda x: x >= f, random=Random(0), - settings=settings(verbosity=Verbosity.quiet), - ) - assert g == ceil(f) - - -@example(1) -@given(st.integers(1, 2 ** 16 - 1)) -@settings(use_coverage=False, deadline=None, perform_health_check=False) -def test_shrinks_downwards_to_integers_when_fractional(b): - g = minimal( - st.floats(), - lambda x: assume((0 < x < (2 ** 53)) and int(x) != x) and x >= b, - random=Random(0), - settings=settings(verbosity=Verbosity.quiet), - ) - assert g == b + 0.5 diff -Nru python-hypothesis-3.44.1/tests/nocover/test_large_examples.py python-hypothesis-3.71.11/tests/nocover/test_large_examples.py --- python-hypothesis-3.44.1/tests/nocover/test_large_examples.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/nocover/test_large_examples.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,25 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import hypothesis.strategies as st -from tests.common.debug import find_any - - -def test_can_generate_large_lists_with_min_size(): - find_any(st.lists(st.integers(), min_size=400)) diff -Nru python-hypothesis-3.44.1/tests/nocover/test_pretty_repr.py python-hypothesis-3.71.11/tests/nocover/test_pretty_repr.py --- python-hypothesis-3.44.1/tests/nocover/test_pretty_repr.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/nocover/test_pretty_repr.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,115 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import hypothesis.strategies as st -from hypothesis import given, settings -from hypothesis.errors import InvalidArgument -from hypothesis.control import reject -from hypothesis.internal.compat import OrderedDict - - -def foo(x): - pass - - -def bar(x): - pass - - -def baz(x): - pass - - -fns = [ - foo, bar, baz -] - - -def builds_ignoring_invalid(target, *args, **kwargs): - def splat(value): - try: - result = target(*value[0], **value[1]) - result.validate() - return result - except InvalidArgument: - reject() - return st.tuples( - st.tuples(*args), st.fixed_dictionaries(kwargs)).map(splat) - - -size_strategies = dict( - min_size=st.integers(min_value=0, max_value=100) | st.none(), - max_size=st.integers(min_value=0, max_value=100) | st.none(), - average_size=st.floats(min_value=0.0, max_value=100.0) | st.none() -) - - -values = st.integers() | st.text(average_size=2.0) - - -Strategies = st.recursive( - st.one_of( - st.sampled_from([ - st.none(), st.booleans(), st.randoms(), st.complex_numbers(), - st.randoms(), st.fractions(), st.decimals(), - ]), - st.builds(st.just, values), - st.builds(st.sampled_from, st.lists(values, min_size=1)), - builds_ignoring_invalid(st.floats, st.floats(), st.floats()), - ), - lambda x: st.one_of( - builds_ignoring_invalid(st.lists, x, **size_strategies), - builds_ignoring_invalid(st.sets, x, **size_strategies), - builds_ignoring_invalid( - lambda v: st.tuples(*v), st.lists(x, average_size=2.0)), - builds_ignoring_invalid( - lambda v: st.one_of(*v), - st.lists(x, average_size=2.0, min_size=1)), - builds_ignoring_invalid( - st.dictionaries, x, x, - dict_class=st.sampled_from([dict, OrderedDict]), - min_size=st.integers(min_value=0, max_value=100) | st.none(), - max_size=st.integers(min_value=0, max_value=100) | st.none(), - average_size=st.floats(min_value=0.0, max_value=100.0) | st.none() - ), - st.builds(lambda s, f: s.map(f), x, st.sampled_from(fns)), - ) -) - - -strategy_globals = dict( - (k, getattr(st, k)) - for k in dir(st) -) - -strategy_globals['OrderedDict'] = OrderedDict -strategy_globals['inf'] = float('inf') -strategy_globals['nan'] = float('nan') -strategy_globals['foo'] = foo -strategy_globals['bar'] = bar -strategy_globals['baz'] = baz - - -@given(Strategies) -@settings(max_examples=2000) -def test_repr_evals_to_thing_with_same_repr(strategy): - r = repr(strategy) - via_eval = eval(r, strategy_globals) - r2 = repr(via_eval) - assert r == r2 diff -Nru python-hypothesis-3.44.1/tests/nocover/test_recursive.py python-hypothesis-3.71.11/tests/nocover/test_recursive.py --- python-hypothesis-3.44.1/tests/nocover/test_recursive.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/nocover/test_recursive.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,158 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from random import Random - -from flaky import flaky - -import hypothesis.strategies as st -from hypothesis import find, given, example, settings -from tests.common.debug import find_any -from hypothesis.internal.compat import integer_types - - -def test_can_generate_with_large_branching(): - def flatten(x): - if isinstance(x, list): - return sum(map(flatten, x), []) - else: - return [x] - - xs = find( - st.recursive( - st.integers(), lambda x: st.lists(x, average_size=50), - max_leaves=100), - lambda x: isinstance(x, list) and len(flatten(x)) >= 50 - ) - assert flatten(xs) == [0] * 50 - - -def test_can_generate_some_depth_with_large_branching(): - def depth(x): - if x and isinstance(x, list): - return 1 + max(map(depth, x)) - else: - return 1 - xs = find( - st.recursive(st.integers(), lambda x: st.lists(x, average_size=100)), - lambda x: depth(x) > 1 - ) - assert xs in ([0], [[]]) - - -def test_can_find_quite_broad_lists(): - def breadth(x): - if isinstance(x, list): - return sum(map(breadth, x)) - else: - return 1 - - broad = find( - st.recursive(st.booleans(), lambda x: st.lists(x, max_size=10)), - lambda x: breadth(x) >= 20, - settings=settings(max_examples=10000) - ) - assert breadth(broad) == 20 - - -def test_drawing_many_near_boundary(): - ls = find( - st.lists(st.recursive( - st.booleans(), - lambda x: st.lists(x, min_size=8, max_size=10).map(tuple), - max_leaves=9)), - lambda x: len(set(x)) >= 5, - settings=settings(max_examples=10000, database=None, max_shrinks=2000) - ) - assert len(ls) == 5 - - -@given(st.randoms()) -@settings( - max_examples=50, max_shrinks=0, perform_health_check=False, deadline=None -) -@example(Random(-1363972488426139)) -@example(Random(-4)) -def test_can_use_recursive_data_in_sets(rnd): - nested_sets = st.recursive( - st.booleans(), - lambda js: st.frozensets(js, average_size=2.0), - max_leaves=10 - ) - find_any(nested_sets, random=rnd) - - def flatten(x): - if isinstance(x, bool): - return frozenset((x,)) - else: - result = frozenset() - for t in x: - result |= flatten(t) - if len(result) == 2: - break - return result - assert rnd is not None - x = find( - nested_sets, lambda x: len(flatten(x)) == 2, random=rnd, - settings=settings(database=None, max_shrinks=1000, max_examples=1000)) - assert x in ( - frozenset((False, True)), - frozenset((False, frozenset((True,)))), - frozenset((frozenset((False, True)),)) - ) - - -@flaky(max_runs=2, min_passes=1) -def test_can_form_sets_of_recursive_data(): - trees = st.sets(st.recursive( - st.booleans(), - lambda x: st.lists(x, min_size=5).map(tuple), - max_leaves=20)) - xs = find(trees, lambda x: len(x) >= 5, settings=settings( - database=None, max_shrinks=1000, max_examples=1000 - )) - assert len(xs) == 5 - - -@given(st.randoms()) -@settings( - max_examples=50, max_shrinks=0, perform_health_check=False, deadline=None -) -def test_can_flatmap_to_recursive_data(rnd): - stuff = st.lists(st.integers(), min_size=1).flatmap( - lambda elts: st.recursive( - st.sampled_from(elts), lambda x: st.lists(x, average_size=25), - max_leaves=25 - )) - - def flatten(x): - if isinstance(x, integer_types): - return [x] - else: - return sum(map(flatten, x), []) - - tree = find( - stuff, lambda x: sum(flatten(x)) >= 100, - settings=settings( - database=None, max_shrinks=2000, max_examples=1000, - ), - random=rnd - ) - flat = flatten(tree) - assert (sum(flat) == 1000) or (len(set(flat)) == 1) diff -Nru python-hypothesis-3.44.1/tests/nocover/test_regex.py python-hypothesis-3.71.11/tests/nocover/test_regex.py --- python-hypothesis-3.44.1/tests/nocover/test_regex.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/nocover/test_regex.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,86 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import re -import string - -import hypothesis.strategies as st -from hypothesis import given, assume, reject -from hypothesis.searchstrategy.regex import base_regex_strategy - - -@st.composite -def charset(draw): - negated = draw(st.booleans()) - chars = draw(st.text(string.ascii_letters + string.digits, min_size=1)) - if negated: - return u"[^%s]" % (chars,) - else: - return u"[%s]" % (chars,) - - -COMBINED_MATCHER = re.compile(u"[?+*]{2}") - - -@st.composite -def conservative_regex(draw): - result = draw(st.one_of( - st.just(u"."), - charset(), - CONSERVATIVE_REGEX.map(lambda s: u"(%s)" % (s,)), - CONSERVATIVE_REGEX.map(lambda s: s + u'+'), - CONSERVATIVE_REGEX.map(lambda s: s + u'?'), - CONSERVATIVE_REGEX.map(lambda s: s + u'*'), - st.lists(CONSERVATIVE_REGEX, min_size=1, max_size=3).map(u"|".join), - st.lists(CONSERVATIVE_REGEX, min_size=1, max_size=3).map(u"".join), - )) - assume(COMBINED_MATCHER.search(result) is None) - control = sum( - result.count(c) for c in '?+*' - ) - assume(control <= 3) - return result - - -CONSERVATIVE_REGEX = conservative_regex() - - -@given(st.data()) -def test_conservative_regex_are_correct_by_construction(data): - pattern = re.compile(data.draw(CONSERVATIVE_REGEX)) - pattern = re.compile(pattern) - result = data.draw(base_regex_strategy(pattern)) - assert pattern.search(result) is not None - - -@given(st.data()) -def test_fuzz_stuff(data): - pattern = data.draw( - st.text(min_size=1, max_size=5) | - st.binary(min_size=1, max_size=5) | - CONSERVATIVE_REGEX.filter(bool) - ) - - try: - regex = re.compile(pattern) - except re.error: - reject() - - ex = data.draw(st.from_regex(regex)) - assert regex.search(ex) diff -Nru python-hypothesis-3.44.1/tests/nocover/test_strategy_state.py python-hypothesis-3.71.11/tests/nocover/test_strategy_state.py --- python-hypothesis-3.44.1/tests/nocover/test_strategy_state.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/nocover/test_strategy_state.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,237 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import math -import hashlib -from random import Random - -from hypothesis import Verbosity, seed, given, assume, settings, unlimited -from hypothesis.errors import FailedHealthCheck -from hypothesis.database import ExampleDatabase -from hypothesis.stateful import Bundle, RuleBasedStateMachine, rule -from hypothesis.strategies import data, just, none, text, lists, binary, \ - floats, tuples, booleans, decimals, integers, fractions, \ - float_to_int, int_to_float, sampled_from, complex_numbers -from hypothesis.internal.compat import PYPY - -AVERAGE_LIST_LENGTH = 2 - - -def clamp(lower, value, upper): - """Given a value and optional lower/upper bounds, 'clamp' the value so that - it satisfies lower <= value <= upper.""" - if (lower is not None) and (upper is not None) and (lower > upper): - raise ValueError('Cannot clamp with lower > upper: %r > %r' % - (lower, upper)) - if lower is not None: - value = max(lower, value) - if upper is not None: - value = min(value, upper) - return value - - -class HypothesisSpec(RuleBasedStateMachine): - - def __init__(self): - super(HypothesisSpec, self).__init__() - self.database = None - - strategies = Bundle(u'strategy') - strategy_tuples = Bundle(u'tuples') - objects = Bundle(u'objects') - basic_data = Bundle(u'basic') - varied_floats = Bundle(u'varied_floats') - - def teardown(self): - self.clear_database() - - @rule() - def clear_database(self): - if self.database is not None: - self.database.close() - self.database = None - - @rule() - def set_database(self): - self.teardown() - self.database = ExampleDatabase() - - @rule(strat=strategies, r=integers(), max_shrinks=integers(0, 100)) - def find_constant_failure(self, strat, r, max_shrinks): - with settings( - verbosity=Verbosity.quiet, max_examples=1, - min_satisfying_examples=0, - database=self.database, - max_shrinks=max_shrinks, - ): - @given(strat) - @seed(r) - def test(x): - assert False - - try: - test() - except (AssertionError, FailedHealthCheck): - pass - - @rule( - strat=strategies, r=integers(), p=floats(0, 1), - max_examples=integers(1, 10), max_shrinks=integers(1, 100) - ) - def find_weird_failure(self, strat, r, max_examples, p, max_shrinks): - with settings( - verbosity=Verbosity.quiet, max_examples=max_examples, - min_satisfying_examples=0, - database=self.database, - max_shrinks=max_shrinks, - ): - @given(strat) - @seed(r) - def test(x): - assert Random( - hashlib.md5(repr(x).encode(u'utf-8')).digest() - ).random() <= p - - try: - test() - except (AssertionError, FailedHealthCheck): - pass - - @rule(target=strategies, spec=sampled_from(( - integers(), booleans(), floats(), complex_numbers(), - fractions(), decimals(), text(), binary(), none(), - tuples(), - ))) - def strategy(self, spec): - return spec - - @rule(target=strategies, values=lists(integers() | text(), min_size=1)) - def sampled_from_strategy(self, values): - return sampled_from(values) - - @rule(target=strategies, spec=strategy_tuples) - def strategy_for_tupes(self, spec): - return tuples(*spec) - - @rule( - target=strategies, - source=strategies, - level=integers(1, 10), - mixer=text()) - def filtered_strategy(s, source, level, mixer): - def is_good(x): - return bool(Random( - hashlib.md5((mixer + repr(x)).encode(u'utf-8')).digest() - ).randint(0, level)) - return source.filter(is_good) - - @rule(target=strategies, elements=strategies) - def list_strategy(self, elements): - return lists(elements, average_size=AVERAGE_LIST_LENGTH) - - @rule(target=strategies, left=strategies, right=strategies) - def or_strategy(self, left, right): - return left | right - - @rule(target=varied_floats, source=floats()) - def float(self, source): - return source - - @rule( - target=varied_floats, - source=varied_floats, offset=integers(-100, 100)) - def adjust_float(self, source, offset): - return int_to_float(clamp( - 0, - float_to_int(source) + offset, - 2 ** 64 - 1 - )) - - @rule( - target=strategies, - left=varied_floats, right=varied_floats - ) - def float_range(self, left, right): - for f in (math.isnan, math.isinf): - for x in (left, right): - assume(not f(x)) - left, right = sorted((left, right)) - assert left <= right - return floats(left, right) - - @rule( - target=strategies, - source=strategies, result1=strategies, result2=strategies, - mixer=text(), p=floats(0, 1)) - def flatmapped_strategy(self, source, result1, result2, mixer, p): - assume(result1 is not result2) - - def do_map(value): - rep = repr(value) - random = Random( - hashlib.md5((mixer + rep).encode(u'utf-8')).digest() - ) - if random.random() <= p: - return result1 - else: - return result2 - return source.flatmap(do_map) - - @rule(target=strategies, value=objects) - def just_strategy(self, value): - return just(value) - - @rule(target=strategy_tuples, source=strategies) - def single_tuple(self, source): - return (source,) - - @rule(target=strategy_tuples, left=strategy_tuples, right=strategy_tuples) - def cat_tuples(self, left, right): - return left + right - - @rule(target=objects, strat=strategies, data=data()) - def get_example(self, strat, data): - data.draw(strat) - - @rule(target=strategies, left=integers(), right=integers()) - def integer_range(self, left, right): - left, right = sorted((left, right)) - return integers(left, right) - - @rule(strat=strategies) - def repr_is_good(self, strat): - assert u' at 0x' not in repr(strat) - - -MAIN = __name__ == u'__main__' - -TestHypothesis = HypothesisSpec.TestCase - -TestHypothesis.settings = settings( - TestHypothesis.settings, - stateful_step_count=10 if PYPY else 50, - max_shrinks=500, - timeout=unlimited, - min_satisfying_examples=0, - verbosity=max(TestHypothesis.settings.verbosity, Verbosity.verbose), - max_examples=10000 if MAIN else 200, -) - -if MAIN: - TestHypothesis().runTest() diff -Nru python-hypothesis-3.44.1/tests/nocover/test_streams.py python-hypothesis-3.71.11/tests/nocover/test_streams.py --- python-hypothesis-3.44.1/tests/nocover/test_streams.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/nocover/test_streams.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from itertools import islice - -from hypothesis import HealthCheck, given, settings -from tests.common.utils import checks_deprecated_behaviour -from hypothesis.strategies import integers, streaming -from hypothesis.internal.compat import integer_types - - -@checks_deprecated_behaviour -def test_streams_are_arbitrarily_long(): - @settings(suppress_health_check=[HealthCheck.too_slow]) - @given(streaming(integers())) - def test(ss): - for i in islice(ss, 100): - assert isinstance(i, integer_types) - test() diff -Nru python-hypothesis-3.44.1/tests/nocover/test_target_selector.py python-hypothesis-3.71.11/tests/nocover/test_target_selector.py --- python-hypothesis-3.44.1/tests/nocover/test_target_selector.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/nocover/test_target_selector.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,77 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import hypothesis.strategies as st -from hypothesis.stateful import RuleBasedStateMachine, rule, precondition -from hypothesis.internal.compat import hrange -from tests.cover.test_target_selector import FakeConjectureData, \ - fake_randoms -from hypothesis.internal.conjecture.engine import TargetSelector, universal - - -class TargetSelectorMachine(RuleBasedStateMachine): - def __init__(self): - super(TargetSelectorMachine, self).__init__() - self.target_selector = None - self.data = [] - self.tags = set() - self.tag_intersections = None - - @precondition(lambda self: self.target_selector is None) - @rule(rnd=fake_randoms()) - def initialize(self, rnd): - self.target_selector = TargetSelector(rnd) - - @precondition(lambda self: self.target_selector is not None) - @rule( - data=st.builds(FakeConjectureData, st.frozensets(st.integers(0, 10)))) - def add_data(self, data): - self.target_selector.add(data) - self.data.append(data) - self.tags.update(data.tags) - if self.tag_intersections is None: - self.tag_intersections = data.tags - else: - self.tag_intersections &= data.tags - - @precondition(lambda self: self.data) - @rule() - def select_target(self): - tag, data = self.target_selector.select() - assert self.target_selector.has_tag(tag, data) - if self.tags != self.tag_intersections: - assert tag != universal - - @precondition(lambda self: self.data) - @rule() - def cycle_through_tags(self): - seen = set() - for _ in hrange( - (2 * len(self.tags) + 1) * - (1 + self.target_selector.mutation_counts) - ): - _, data = self.target_selector.select() - seen.update(data.tags) - if seen == self.tags: - break - else: - assert False - - -TestSelector = TargetSelectorMachine.TestCase diff -Nru python-hypothesis-3.44.1/tests/numpy/__init__.py python-hypothesis-3.71.11/tests/numpy/__init__.py --- python-hypothesis-3.44.1/tests/numpy/__init__.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/numpy/__init__.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER diff -Nru python-hypothesis-3.44.1/tests/numpy/test_argument_validation.py python-hypothesis-3.71.11/tests/numpy/test_argument_validation.py --- python-hypothesis-3.44.1/tests/numpy/test_argument_validation.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/numpy/test_argument_validation.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,60 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import pytest - -import hypothesis.strategies as st -import hypothesis.extra.numpy as nps -from hypothesis.errors import InvalidArgument - - -def e(a, **kwargs): - return (a, kwargs) - - -@pytest.mark.parametrize( - ('function', 'kwargs'), [ - e(nps.array_dtypes, min_size=2, max_size=1), - e(nps.array_dtypes, min_size=-1), - e(nps.array_shapes, min_side=2, max_side=1), - e(nps.array_shapes, min_dims=3, max_dims=2), - e(nps.array_shapes, min_dims=0), - e(nps.array_shapes, min_side=0), - e(nps.arrays, dtype=float, shape=(0.5,)), - e(nps.arrays, dtype=object, shape=1), - e(nps.arrays, dtype=object, shape=(), elements=st.none()), - e(nps.arrays, dtype=float, shape=1, fill=3), - e(nps.byte_string_dtypes, min_len=-1), - e(nps.byte_string_dtypes, min_len=2, max_len=1), - e(nps.datetime64_dtypes, max_period=11), - e(nps.datetime64_dtypes, min_period=11), - e(nps.datetime64_dtypes, min_period='Y', max_period='M'), - e(nps.timedelta64_dtypes, max_period=11), - e(nps.timedelta64_dtypes, min_period=11), - e(nps.timedelta64_dtypes, min_period='Y', max_period='M'), - e(nps.unicode_string_dtypes, min_len=-1), - e(nps.unicode_string_dtypes, min_len=2, max_len=1), - e(nps.unsigned_integer_dtypes, endianness=3), - e(nps.unsigned_integer_dtypes, sizes=()), - e(nps.unsigned_integer_dtypes, sizes=(3,)), - ] -) -def test_raise_invalid_argument(function, kwargs): - with pytest.raises(InvalidArgument): - function(**kwargs).example() diff -Nru python-hypothesis-3.44.1/tests/numpy/test_fill_values.py python-hypothesis-3.71.11/tests/numpy/test_fill_values.py --- python-hypothesis-3.44.1/tests/numpy/test_fill_values.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/numpy/test_fill_values.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,61 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import hypothesis.strategies as st -from hypothesis import given -from tests.common.debug import minimal, find_any -from hypothesis.extra.numpy import arrays - - -@given(arrays(object, 100, st.lists(max_size=0))) -def test_generated_lists_are_distinct(ls): - assert len(set(map(id, ls))) == len(ls) - - -@st.composite -def distinct_integers(draw): - used = draw(st.shared(st.builds(set), key='distinct_integers.used')) - i = draw(st.integers(0, 2 ** 64 - 1).filter(lambda x: x not in used)) - used.add(i) - return i - - -@given(arrays('uint64', 10, distinct_integers())) -def test_does_not_reuse_distinct_integers(arr): - assert len(set(arr)) == len(arr) - - -def test_may_reuse_distinct_integers_if_asked(): - find_any( - arrays('uint64', 10, distinct_integers(), fill=distinct_integers()), - lambda x: len(set(x)) < len(x) - ) - - -def test_minimizes_to_fill(): - result = minimal(arrays(float, 10, fill=st.just(3.0))) - assert (result == 3.0).all() - - -@given(arrays( - dtype=float, - elements=st.floats().filter(bool), shape=(3, 3, 3,), fill=st.just(1.0)) -) -def test_fills_everything(x): - assert x.all() diff -Nru python-hypothesis-3.44.1/tests/numpy/test_gen_data.py python-hypothesis-3.71.11/tests/numpy/test_gen_data.py --- python-hypothesis-3.44.1/tests/numpy/test_gen_data.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/numpy/test_gen_data.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,298 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import numpy as np -import pytest -from flaky import flaky - -import hypothesis.strategies as st -import hypothesis.extra.numpy as nps -from hypothesis import given, assume, settings -from hypothesis.errors import InvalidArgument -from tests.common.debug import minimal, find_any -from hypothesis.searchstrategy import SearchStrategy -from hypothesis.internal.compat import text_type, binary_type - -STANDARD_TYPES = list(map(np.dtype, [ - u'int8', u'int32', u'int64', - u'float', u'float32', u'float64', - complex, - u'datetime64', u'timedelta64', - bool, text_type, binary_type -])) - - -@given(nps.nested_dtypes()) -def test_strategies_for_standard_dtypes_have_reusable_values(dtype): - assert nps.from_dtype(dtype).has_reusable_values - - -@pytest.mark.parametrize(u't', STANDARD_TYPES) -def test_produces_instances(t): - @given(nps.from_dtype(t)) - def test_is_t(x): - assert isinstance(x, t.type) - assert x.dtype.kind == t.kind - test_is_t() - - -@given(nps.arrays(float, ())) -def test_empty_dimensions_are_scalars(x): - assert isinstance(x, np.dtype(float).type) - - -@given(nps.arrays(float, (1, 0, 1))) -def test_can_handle_zero_dimensions(x): - assert x.shape == (1, 0, 1) - - -@given(nps.arrays(u'uint32', (5, 5))) -def test_generates_unsigned_ints(x): - assert (x >= 0).all() - - -@given(nps.arrays(int, (1,))) -def test_assert_fits_in_machine_size(x): - pass - - -def test_generates_and_minimizes(): - assert (minimal(nps.arrays(float, (2, 2))) == np.zeros(shape=(2, 2))).all() - - -def test_can_minimize_large_arrays(): - x = minimal( - nps.arrays(u'uint32', 100), lambda x: np.any(x) and not np.all(x), - timeout_after=60 - ) - assert np.logical_or(x == 0, x == 1).all() - assert np.count_nonzero(x) in (1, len(x) - 1) - - -@flaky(max_runs=50, min_passes=1) -def test_can_minimize_float_arrays(): - x = minimal(nps.arrays(float, 50), lambda t: t.sum() >= 1.0) - assert x.sum() in (1, 50) - - -class Foo(object): - pass - - -foos = st.tuples().map(lambda _: Foo()) - - -def test_can_create_arrays_of_composite_types(): - arr = minimal(nps.arrays(object, 100, foos)) - for x in arr: - assert isinstance(x, Foo) - - -def test_can_create_arrays_of_tuples(): - arr = minimal( - nps.arrays(object, 10, st.tuples(st.integers(), st.integers())), - lambda x: all(t0 != t1 for t0, t1 in x)) - assert all(a in ((1, 0), (0, 1)) for a in arr) - - -@given(nps.arrays(object, (2, 2), st.tuples(st.integers()))) -def test_does_not_flatten_arrays_of_tuples(arr): - assert isinstance(arr[0][0], tuple) - - -@given( - nps.arrays(object, (2, 2), st.lists(st.integers(), min_size=1, max_size=1)) -) -def test_does_not_flatten_arrays_of_lists(arr): - assert isinstance(arr[0][0], list) - - -@given(nps.array_shapes()) -def test_can_generate_array_shapes(shape): - assert isinstance(shape, tuple) - assert all(isinstance(i, int) for i in shape) - - -@settings(deadline=None) -@given(st.integers(1, 10), st.integers(0, 9), st.integers(1), st.integers(0)) -def test_minimise_array_shapes(min_dims, dim_range, min_side, side_range): - smallest = minimal(nps.array_shapes(min_dims, min_dims + dim_range, - min_side, min_side + side_range)) - assert len(smallest) == min_dims and all(k == min_side for k in smallest) - - -@given(nps.scalar_dtypes()) -def test_can_generate_scalar_dtypes(dtype): - assert isinstance(dtype, np.dtype) - - -@given(nps.nested_dtypes()) -def test_can_generate_compound_dtypes(dtype): - assert isinstance(dtype, np.dtype) - - -@given(nps.nested_dtypes(max_itemsize=settings.default.buffer_size // 10), - st.data()) -def test_infer_strategy_from_dtype(dtype, data): - # Given a dtype - assert isinstance(dtype, np.dtype) - # We can infer a strategy - strat = nps.from_dtype(dtype) - assert isinstance(strat, SearchStrategy) - # And use it to fill an array of that dtype - data.draw(nps.arrays(dtype, 10, strat)) - - -@given(nps.nested_dtypes()) -def test_np_dtype_is_idempotent(dtype): - assert dtype == np.dtype(dtype) - - -def test_minimise_scalar_dtypes(): - assert minimal(nps.scalar_dtypes()) == np.dtype(u'bool') - - -def test_minimise_nested_types(): - assert minimal(nps.nested_dtypes()) == np.dtype(u'bool') - - -def test_minimise_array_strategy(): - smallest = minimal(nps.arrays( - nps.nested_dtypes(max_itemsize=settings.default.buffer_size // 3**3), - nps.array_shapes(max_dims=3, max_side=3))) - assert smallest.dtype == np.dtype(u'bool') and not smallest.any() - - -@given(nps.array_dtypes(allow_subarrays=False)) -def test_can_turn_off_subarrays(dt): - for field, _ in dt.fields.values(): - assert field.shape == () - - -@given(nps.integer_dtypes(endianness='>')) -def test_can_restrict_endianness(dt): - if dt.itemsize == 1: - assert dt.byteorder == '|' - else: - assert dt.byteorder == '>' - - -@given(nps.integer_dtypes(sizes=8)) -def test_can_specify_size_as_an_int(dt): - assert dt.itemsize == 1 - - -@given(st.data()) -def test_can_draw_shapeless_from_scalars(data): - dt = data.draw(nps.scalar_dtypes()) - result = data.draw(nps.arrays(dtype=dt, shape=())) - assert isinstance(result, dt.type) - - -@given(st.data()) -def test_unicode_string_dtypes_generate_unicode_strings(data): - dt = data.draw(nps.unicode_string_dtypes()) - result = data.draw(nps.from_dtype(dt)) - assert isinstance(result, text_type) - - -@given(st.data()) -def test_byte_string_dtypes_generate_unicode_strings(data): - dt = data.draw(nps.byte_string_dtypes()) - result = data.draw(nps.from_dtype(dt)) - assert isinstance(result, binary_type) - - -@given(nps.arrays(dtype='int8', shape=st.integers(0, 20), unique=True)) -def test_array_values_are_unique(arr): - assert len(set(arr)) == len(arr) - - -def test_may_fill_with_nan_when_unique_is_set(): - find_any( - nps.arrays( - dtype=float, elements=st.floats(allow_nan=False), shape=10, - unique=True, fill=st.just(float('nan'))), - lambda x: np.isnan(x).any() - ) - - -def test_is_still_unique_with_nan_fill(): - @given(nps.arrays( - dtype=float, elements=st.floats(allow_nan=False), shape=10, - unique=True, fill=st.just(float('nan')))) - def test(xs): - assert len(set(xs)) == len(xs) - - test() - - -def test_may_not_fill_with_non_nan_when_unique_is_set(): - @given(nps.arrays( - dtype=float, elements=st.floats(allow_nan=False), shape=10, - unique=True, fill=st.just(0.0))) - def test(arr): - pass - - with pytest.raises(InvalidArgument): - test() - - -def test_may_not_fill_with_non_nan_when_unique_is_set_and_type_is_not_number(): - @given(nps.arrays( - dtype=bytes, shape=10, - unique=True, fill=st.just(b''))) - def test(arr): - pass - - with pytest.raises(InvalidArgument): - test() - - -@given(st.data(), - st.builds('{}[{}]'.format, - st.sampled_from(('datetime64', 'timedelta64')), - st.sampled_from(nps.TIME_RESOLUTIONS) - ).map(np.dtype) - ) -def test_inferring_from_time_dtypes_gives_same_dtype(data, dtype): - ex = data.draw(nps.from_dtype(dtype)) - assert dtype == ex.dtype - - -@given(st.data(), nps.byte_string_dtypes() | nps.unicode_string_dtypes()) -def test_inferred_string_strategies_roundtrip(data, dtype): - # Check that we never generate too-long or nul-terminated strings, which - # cannot be read back out of an array. - arr = np.zeros(shape=1, dtype=dtype) - ex = data.draw(nps.from_dtype(arr.dtype)) - arr[0] = ex - assert arr[0] == ex - - -@given(st.data(), nps.scalar_dtypes()) -def test_all_inferred_scalar_strategies_roundtrip(data, dtype): - # We only check scalars here, because record/compound/nested dtypes always - # give an array of np.void objects. We're interested in whether scalar - # values are safe, not known type coercion. - arr = np.zeros(shape=1, dtype=dtype) - ex = data.draw(nps.from_dtype(arr.dtype)) - assume(ex == ex) # If not, the roundtrip test *should* fail! (eg NaN) - arr[0] = ex - assert arr[0] == ex diff -Nru python-hypothesis-3.44.1/tests/numpy/test_sampled_from.py python-hypothesis-3.71.11/tests/numpy/test_sampled_from.py --- python-hypothesis-3.44.1/tests/numpy/test_sampled_from.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/numpy/test_sampled_from.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import numpy as np - -from hypothesis import given, assume -from hypothesis.extra import numpy as npst -from tests.common.utils import checks_deprecated_behaviour -from hypothesis.strategies import data, sampled_from - - -@given(data(), npst.arrays( - dtype=npst.scalar_dtypes(), - shape=npst.array_shapes(max_dims=1) -)) -def test_can_sample_1D_numpy_array_without_warning(data, arr): - elem = data.draw(sampled_from(arr)) - try: - assume(not np.isnan(elem)) - except TypeError: - pass - assert elem in arr - - -@checks_deprecated_behaviour -@given(data(), npst.arrays( - dtype=npst.scalar_dtypes(), - shape=npst.array_shapes(min_dims=2, max_dims=5) -)) -def test_sampling_multi_dimensional_arrays_is_deprecated(data, arr): - data.draw(sampled_from(arr)) diff -Nru python-hypothesis-3.44.1/tests/pandas/helpers.py python-hypothesis-3.71.11/tests/pandas/helpers.py --- python-hypothesis-3.44.1/tests/pandas/helpers.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/pandas/helpers.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,46 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import numpy as np - -PANDAS_TIME_DTYPES = tuple(map(np.dtype, [ - 'M8[ns]', '>m8[ns]', -])) - - -def supported_by_pandas(dtype): - """Checks whether the dtype is one that can be correctly handled by - Pandas.""" - - # Pandas only supports a limited range of timedelta and datetime dtypes - # compared to the full range that numpy supports and will convert - # everything to those types (possibly increasing precision in the course of - # doing so, which can cause problems if this results in something which - # does not fit into the desired word type. As a result we want to filter - # out any timedelta or datetime dtypes that are not of the desired types. - if dtype.kind in ('m', 'M'): - return dtype in PANDAS_TIME_DTYPES - - # Pandas does not support non-native byte orders and things go amusingly - # wrong in weird places if you try to use them. See - # https://pandas.pydata.org/pandas-docs/stable/gotchas.html#byte-ordering-issues - if dtype.byteorder not in ('|', '='): - return False - return True diff -Nru python-hypothesis-3.44.1/tests/pandas/__init__.py python-hypothesis-3.71.11/tests/pandas/__init__.py --- python-hypothesis-3.44.1/tests/pandas/__init__.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/pandas/__init__.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER diff -Nru python-hypothesis-3.44.1/tests/pandas/test_argument_validation.py python-hypothesis-3.71.11/tests/pandas/test_argument_validation.py --- python-hypothesis-3.44.1/tests/pandas/test_argument_validation.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/pandas/test_argument_validation.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,71 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import hypothesis.strategies as st -import hypothesis.extra.pandas as pdst -from tests.common.arguments import e, argument_validation_test - -BAD_ARGS = [ - e(pdst.data_frames), - e(pdst.data_frames, pdst.columns(1, dtype='not a dtype')), - e(pdst.data_frames, pdst.columns(1, elements='not a strategy')), - e(pdst.data_frames, pdst.columns([[]])), - e(pdst.data_frames, [], index=[]), - e(pdst.data_frames, [], rows=st.fixed_dictionaries({'A': st.just(1)})), - e(pdst.data_frames, pdst.columns(1)), - e(pdst.data_frames, pdst.columns(1, dtype=float, fill=1)), - e(pdst.data_frames, pdst.columns(1, dtype=float, elements=1)), - e(pdst.data_frames, pdst.columns(1, fill=1, dtype=float)), - e(pdst.data_frames, pdst.columns(['A', 'A'], dtype=float)), - e(pdst.data_frames, pdst.columns(1, elements=st.none(), dtype=int)), - e(pdst.data_frames, 1), - e(pdst.data_frames, [1]), - e(pdst.data_frames, pdst.columns(1, dtype='category')), - e(pdst.data_frames, - pdst.columns(['A'], dtype=bool), - rows=st.tuples(st.booleans(), st.booleans())), - e(pdst.data_frames, - pdst.columns(1, elements=st.booleans()), - rows=st.tuples(st.booleans())), - e(pdst.data_frames, rows=st.integers(), index=pdst.range_indexes(0, 0)), - e(pdst.data_frames, rows=st.integers(), index=pdst.range_indexes(1, 1)), - e(pdst.data_frames, pdst.columns(1, dtype=int), rows=st.integers()), - e(pdst.indexes), - e(pdst.indexes, dtype='category'), - e(pdst.indexes, dtype='not a dtype'), - e(pdst.indexes, elements='not a strategy'), - e(pdst.indexes, elements=st.text(), dtype=float), - e(pdst.indexes, elements=st.none(), dtype=int), - e(pdst.indexes, dtype=int, max_size=0, min_size=1), - e(pdst.indexes, dtype=int, unique='true'), - e(pdst.indexes, dtype=int, min_size='0'), - e(pdst.indexes, dtype=int, max_size='1'), - e(pdst.range_indexes, 1, 0), - e(pdst.range_indexes, min_size='0'), - e(pdst.range_indexes, max_size='1'), - e(pdst.series), - e(pdst.series, dtype='not a dtype'), - e(pdst.series, elements='not a strategy'), - e(pdst.series, elements=st.none(), dtype=int), - e(pdst.series, dtype='category'), - e(pdst.series, index='not a strategy'), -] - - -test_raise_invalid_argument = argument_validation_test(BAD_ARGS) diff -Nru python-hypothesis-3.44.1/tests/pandas/test_data_frame.py python-hypothesis-3.71.11/tests/pandas/test_data_frame.py --- python-hypothesis-3.44.1/tests/pandas/test_data_frame.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/pandas/test_data_frame.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,242 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import numpy as np -import pytest - -import hypothesis.strategies as st -import hypothesis.extra.numpy as npst -import hypothesis.extra.pandas as pdst -from hypothesis import given, reject -from hypothesis.types import RandomWithSeed as Random -from tests.common.debug import minimal, find_any -from tests.pandas.helpers import supported_by_pandas - - -@given(pdst.data_frames([ - pdst.column('a', dtype=int), - pdst.column('b', dtype=float), -])) -def test_can_have_columns_of_distinct_types(df): - assert df['a'].dtype == np.dtype(int) - assert df['b'].dtype == np.dtype(float) - - -@given(pdst.data_frames( - [pdst.column(dtype=int)], - index=pdst.range_indexes(min_size=1, max_size=5))) -def test_respects_size_bounds(df): - assert 1 <= len(df) <= 5 - - -@given(pdst.data_frames(pdst.columns(['A', 'B'], dtype=float))) -def test_can_specify_just_column_names(df): - df['A'] - df['B'] - - -@given(pdst.data_frames(pdst.columns(2, dtype=float))) -def test_can_specify_just_column_count(df): - df[0] - df[1] - - -@given(pdst.data_frames( - rows=st.fixed_dictionaries({'A': st.integers(1, 10), 'B': st.floats()})) -) -def test_gets_the_correct_data_shape_for_just_rows(table): - assert table['A'].dtype == np.dtype('int64') - assert table['B'].dtype == np.dtype(float) - - -@given(pdst.data_frames( - columns=pdst.columns(['A', 'B'], dtype=int), - rows=st.lists(st.integers(0, 1000), min_size=2, max_size=2).map(sorted), -)) -def test_can_specify_both_rows_and_columns_list(d): - assert d['A'].dtype == np.dtype(int) - assert d['B'].dtype == np.dtype(int) - for _, r in d.iterrows(): - assert r['A'] <= r['B'] - - -@given(pdst.data_frames( - columns=pdst.columns(['A', 'B'], dtype=int), - rows=st.lists( - st.integers(0, 1000), min_size=2, max_size=2).map(sorted).map(tuple), -)) -def test_can_specify_both_rows_and_columns_tuple(d): - assert d['A'].dtype == np.dtype(int) - assert d['B'].dtype == np.dtype(int) - for _, r in d.iterrows(): - assert r['A'] <= r['B'] - - -@given(pdst.data_frames( - columns=pdst.columns(['A', 'B'], dtype=int), - rows=st.lists(st.integers(0, 1000), min_size=2, max_size=2).map( - lambda x: {'A': min(x), 'B': max(x)}), -)) -def test_can_specify_both_rows_and_columns_dict(d): - assert d['A'].dtype == np.dtype(int) - assert d['B'].dtype == np.dtype(int) - for _, r in d.iterrows(): - assert r['A'] <= r['B'] - - -@given( - pdst.data_frames([pdst.column('A', fill=st.just(float('nan')), - dtype=float, - elements=st.floats(allow_nan=False))], - rows=st.builds(dict))) -def test_can_fill_in_missing_elements_from_dict(df): - assert np.isnan(df['A']).all() - - -subsets = ['', 'A', 'B', 'C', 'AB', 'AC', 'BC', 'ABC'] - - -@pytest.mark.parametrize('disable_fill', subsets) -@pytest.mark.parametrize('non_standard_index', [True, False]) -def test_can_minimize_based_on_two_columns_independently( - disable_fill, non_standard_index -): - columns = [ - pdst.column( - name, dtype=bool, - fill=st.nothing() if name in disable_fill else None, - ) - for name in ['A', 'B', 'C'] - ] - - x = minimal( - pdst.data_frames( - columns, - index=pdst.indexes(dtype=int) if non_standard_index else None, - ), - lambda x: x['A'].any() and x['B'].any() and x['C'].any(), - random=Random(0), - ) - assert len(x['A']) == 1 - assert x['A'][0] == 1 - assert x['B'][0] == 1 - assert x['C'][0] == 1 - - -@st.composite -def column_strategy(draw): - name = draw(st.none() | st.text()) - dtype = draw(npst.scalar_dtypes().filter(supported_by_pandas)) - pass_dtype = not draw(st.booleans()) - if pass_dtype: - pass_elements = not draw(st.booleans()) - else: - pass_elements = True - if pass_elements: - elements = npst.from_dtype(dtype) - else: - elements = None - - unique = draw(st.booleans()) - fill = st.nothing() if draw(st.booleans()) else None - - return pdst.column( - name=name, dtype=dtype, unique=unique, fill=fill, elements=elements) - - -@given(pdst.data_frames(pdst.columns(1, dtype=np.dtype('= '0.19': - assert index.dtype == inferred_dtype - else: - assert index.dtype == converted_dtype - - if unique: - assert len(set(index.values)) == len(index) diff -Nru python-hypothesis-3.44.1/tests/pandas/test_series.py python-hypothesis-3.71.11/tests/pandas/test_series.py --- python-hypothesis-3.44.1/tests/pandas/test_series.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/pandas/test_series.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,70 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import numpy as np - -import pandas -import hypothesis.strategies as st -import hypothesis.extra.numpy as npst -import hypothesis.extra.pandas as pdst -from hypothesis import given, assume -from tests.common.debug import find_any -from tests.pandas.helpers import supported_by_pandas - - -@given(st.data()) -def test_can_create_a_series_of_any_dtype(data): - dtype = np.dtype(data.draw(npst.scalar_dtypes())) - assume(supported_by_pandas(dtype)) - series = data.draw(pdst.series(dtype=dtype)) - assert series.dtype == pandas.Series([], dtype=dtype).dtype - - -@given(pdst.series( - dtype=float, index=pdst.range_indexes(min_size=2, max_size=5))) -def test_series_respects_size_bounds(s): - assert 2 <= len(s) <= 5 - - -def test_can_fill_series(): - nan_backed = pdst.series( - elements=st.floats(allow_nan=False), fill=st.just(float('nan'))) - find_any( - nan_backed, lambda x: np.isnan(x).any() - ) - - -@given(pdst.series(dtype=int)) -def test_can_generate_integral_series(s): - assert s.dtype == np.dtype(int) - - -@given(pdst.series(elements=st.integers(0, 10))) -def test_will_use_dtype_of_elements(s): - assert s.dtype == np.dtype('int64') - - -@given(pdst.series(elements=st.floats(allow_nan=False))) -def test_will_use_a_provided_elements_strategy(s): - assert not np.isnan(s).any() - - -@given(pdst.series(dtype='int8', unique=True)) -def test_unique_series_are_unique(s): - assert len(s) == len(set(s)) diff -Nru python-hypothesis-3.44.1/tests/py2/__init__.py python-hypothesis-3.71.11/tests/py2/__init__.py --- python-hypothesis-3.44.1/tests/py2/__init__.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/py2/__init__.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER diff -Nru python-hypothesis-3.44.1/tests/py2/test_destructuring.py python-hypothesis-3.71.11/tests/py2/test_destructuring.py --- python-hypothesis-3.44.1/tests/py2/test_destructuring.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/py2/test_destructuring.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,38 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import pytest - -from hypothesis import given -from hypothesis.errors import InvalidArgument -from hypothesis.strategies import integers -from hypothesis.internal.reflection import get_pretty_function_description - - -def test_destructuring_lambdas(): - assert get_pretty_function_description(lambda (x, y): 1) == \ - u'lambda (x, y): ' - - -def test_destructuring_not_allowed(): - @given(integers()) - def foo(a, (b, c)): - pass - with pytest.raises(InvalidArgument): - foo() diff -Nru python-hypothesis-3.44.1/tests/py3/__init__.py python-hypothesis-3.71.11/tests/py3/__init__.py --- python-hypothesis-3.44.1/tests/py3/__init__.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/py3/__init__.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER diff -Nru python-hypothesis-3.44.1/tests/py3/test_annotations.py python-hypothesis-3.71.11/tests/py3/test_annotations.py --- python-hypothesis-3.44.1/tests/py3/test_annotations.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/py3/test_annotations.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,123 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import pytest - -import hypothesis.strategies as st -from hypothesis import given -from hypothesis.errors import InvalidArgument -from hypothesis.internal.compat import getfullargspec -from hypothesis.internal.reflection import define_function_signature, \ - convert_positional_arguments, get_pretty_function_description - - -@given(st.integers()) -def test_has_an_annotation(i: int): - pass - - -def universal_acceptor(*args, **kwargs): - return args, kwargs - - -def has_annotation(a: int, *b, c=2) -> None: - pass - - -@pytest.mark.parametrize('f', [ - has_annotation, - lambda *, a: a, - lambda *, a=1: a, -]) -def test_copying_preserves_argspec(f): - af = getfullargspec(f) - t = define_function_signature('foo', 'docstring', af)(universal_acceptor) - at = getfullargspec(t) - assert af.args == at.args[:len(af.args)] - assert af.varargs == at.varargs - assert af.varkw == at.varkw - assert len(af.defaults or ()) == len(at.defaults or ()) - assert af.kwonlyargs == at.kwonlyargs - assert af.kwonlydefaults == at.kwonlydefaults - assert af.annotations == at.annotations - - -@pytest.mark.parametrize('lam,source', [ - ((lambda *z, a: a), - 'lambda *z, a: a'), - ((lambda *z, a=1: a), - 'lambda *z, a=1: a'), - ((lambda *, a: a), - 'lambda *, a: a'), - ((lambda *, a=1: a), - 'lambda *, a=1: a'), -]) -def test_py3only_lambda_formatting(lam, source): - # Testing kwonly lambdas, with and without varargs and default values - assert get_pretty_function_description(lam) == source - - -def test_given_notices_missing_kwonly_args(): - with pytest.raises(InvalidArgument): - @given(a=st.none()) - def reqs_kwonly(*, a, b): - pass - - -def test_converter_handles_kwonly_args(): - def f(*, a, b=2): - pass - - out = convert_positional_arguments(f, (), dict(a=1)) - assert out == ((), dict(a=1, b=2)) - - -def test_converter_notices_missing_kwonly_args(): - def f(*, a, b=2): - pass - - with pytest.raises(TypeError): - assert convert_positional_arguments(f, (), dict()) - - -def pointless_composite(draw: None, strat: bool, nothing: list) -> int: - return 3 - - -def return_annot() -> int: - return 4 # per RFC 1149.5 / xckd 221 - - -def first_annot(draw: None): - pass - - -def test_composite_edits_annotations(): - spec_comp = getfullargspec(st.composite(pointless_composite)) - assert spec_comp.annotations['return'] == int - assert 'nothing' in spec_comp.annotations - assert 'draw' not in spec_comp.annotations - - -@pytest.mark.parametrize('nargs', [1, 2, 3]) -def test_given_edits_annotations(nargs): - spec_given = getfullargspec( - given(*(nargs * [st.none()]))(pointless_composite)) - assert spec_given.annotations.pop('return') is None - assert len(spec_given.annotations) == 3 - nargs diff -Nru python-hypothesis-3.44.1/tests/py3/test_asyncio.py python-hypothesis-3.71.11/tests/py3/test_asyncio.py --- python-hypothesis-3.44.1/tests/py3/test_asyncio.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/py3/test_asyncio.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,65 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import asyncio -import unittest -from unittest import TestCase - -import hypothesis.strategies as st -from hypothesis import given, assume - - -class TestAsyncio(TestCase): - - timeout = 5 - - def setUp(self): - self.loop = asyncio.new_event_loop() - asyncio.set_event_loop(self.loop) - - def tearDown(self): - self.loop.close() - - def execute_example(self, f): - error = None - - def g(): - nonlocal error - try: - x = f() - if x is not None: - yield from x - except BaseException as e: - error = e - coro = asyncio.coroutine(g) - future = asyncio.wait_for(coro(), - timeout=self.timeout) - self.loop.run_until_complete(future) - if error is not None: - raise error - - @given(st.text()) - def test_foo(self, x): - assume(x) - yield from asyncio.sleep(0.001) - assert x - - -if __name__ == '__main__': - unittest.main() diff -Nru python-hypothesis-3.44.1/tests/py3/test_lookup.py python-hypothesis-3.71.11/tests/py3/test_lookup.py --- python-hypothesis-3.44.1/tests/py3/test_lookup.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/py3/test_lookup.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,367 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import io -import sys -import enum -import string -import collections - -import pytest - -import hypothesis.strategies as st -from hypothesis import find, given, infer, assume -from hypothesis.errors import NoExamples, InvalidArgument, ResolutionFailed -from hypothesis.strategies import from_type -from hypothesis.searchstrategy import types -from hypothesis.internal.compat import integer_types, get_type_hints - -typing = pytest.importorskip('typing') -sentinel = object() -generics = sorted((t for t in types._global_type_lookup - if isinstance(t, typing.GenericMeta)), key=str) - - -@pytest.mark.parametrize('typ', generics) -def test_resolve_typing_module(typ): - @given(from_type(typ)) - def inner(ex): - if typ in (typing.BinaryIO, typing.TextIO): - assert isinstance(ex, io.IOBase) - elif typ is typing.Tuple: - # isinstance is incompatible with Tuple on early 3.5 - assert ex == () - elif isinstance(typ, typing._ProtocolMeta): - pass - else: - try: - assert isinstance(ex, typ) - except TypeError: - if sys.version_info[:2] < (3, 6): - pytest.skip() - raise - - inner() - - -@pytest.mark.parametrize('typ', [typing.Any, typing.Union]) -def test_does_not_resolve_special_cases(typ): - with pytest.raises(InvalidArgument): - from_type(typ).example() - - -@pytest.mark.parametrize('typ,instance_of', [ - (typing.Union[int, str], (int, str)), - (typing.Optional[int], (int, type(None))), -]) -def test_specialised_scalar_types(typ, instance_of): - @given(from_type(typ)) - def inner(ex): - assert isinstance(ex, instance_of) - - inner() - - -@pytest.mark.skipif(not hasattr(typing, 'Type'), reason='requires this attr') -def test_typing_Type_int(): - assert from_type(typing.Type[int]).example() is int - - -@pytest.mark.skipif(not hasattr(typing, 'Type'), reason='requires this attr') -def test_typing_Type_Union(): - @given(from_type(typing.Type[typing.Union[str, list]])) - def inner(ex): - assert ex in (str, list) - - inner() - - -@pytest.mark.parametrize('typ,coll_type,instance_of', [ - (typing.Set[int], set, int), - (typing.FrozenSet[int], frozenset, int), - (typing.Dict[int, int], dict, int), - (typing.KeysView[int], type({}.keys()), int), - (typing.ValuesView[int], type({}.values()), int), - (typing.List[int], list, int), - (typing.Tuple[int], tuple, int), - (typing.Tuple[int, ...], tuple, int), - (typing.Iterator[int], typing.Iterator, int), - (typing.Sequence[int], typing.Sequence, int), - (typing.Iterable[int], typing.Iterable, int), - (typing.Mapping[int, None], typing.Mapping, int), - (typing.Container[int], typing.Container, int), - (typing.NamedTuple('A_NamedTuple', (('elem', int),)), tuple, int), -]) -def test_specialised_collection_types(typ, coll_type, instance_of): - @given(from_type(typ)) - def inner(ex): - if sys.version_info[:2] >= (3, 6): - assume(ex) - assert isinstance(ex, coll_type) - assert all(isinstance(elem, instance_of) for elem in ex) - - try: - inner() - except (ResolutionFailed, AssertionError): - if sys.version_info[:2] < (3, 6): - pytest.skip('Hard-to-reproduce bug (early version of typing?)') - raise - - -@pytest.mark.skipif(sys.version_info[:2] < (3, 6), reason='new addition') -def test_36_specialised_collection_types(): - @given(from_type(typing.DefaultDict[int, int])) - def inner(ex): - if sys.version_info[:2] >= (3, 6): - assume(ex) - assert isinstance(ex, collections.defaultdict) - assert all(isinstance(elem, int) for elem in ex) - assert all(isinstance(elem, int) for elem in ex.values()) - - inner() - - -@pytest.mark.skipif(sys.version_info[:3] <= (3, 5, 1), reason='broken') -def test_ItemsView(): - @given(from_type(typing.ItemsView[int, int])) - def inner(ex): - # See https://github.com/python/typing/issues/177 - if sys.version_info[:2] >= (3, 6): - assume(ex) - assert isinstance(ex, type({}.items())) - assert all(isinstance(elem, tuple) and len(elem) == 2 for elem in ex) - assert all(all(isinstance(e, int) for e in elem) for elem in ex) - - inner() - - -def test_Optional_minimises_to_None(): - assert find(from_type(typing.Optional[int]), lambda ex: True) is None - - -@pytest.mark.parametrize('n', range(10)) -def test_variable_length_tuples(n): - type_ = typing.Tuple[int, ...] - try: - from_type(type_).filter(lambda ex: len(ex) == n).example() - except NoExamples: - if sys.version_info[:2] < (3, 6): - pytest.skip() - raise - - -@pytest.mark.skipif(sys.version_info[:3] <= (3, 5, 1), reason='broken') -def test_lookup_overrides_defaults(): - sentinel = object() - try: - st.register_type_strategy(int, st.just(sentinel)) - - @given(from_type(typing.List[int])) - def inner_1(ex): - assert all(elem is sentinel for elem in ex) - - inner_1() - finally: - st.register_type_strategy(int, st.integers()) - st.from_type.__clear_cache() - - @given(from_type(typing.List[int])) - def inner_2(ex): - assert all(isinstance(elem, int) for elem in ex) - - inner_2() - - -def test_register_generic_typing_strats(): - # I don't expect anyone to do this, but good to check it works as expected - try: - # We register sets for the abstract sequence type, which masks subtypes - # from supertype resolution but not direct resolution - st.register_type_strategy( - typing.Sequence, - types._global_type_lookup[typing.Set] - ) - - @given(from_type(typing.Sequence[int])) - def inner_1(ex): - assert isinstance(ex, set) - - @given(from_type(typing.Container[int])) - def inner_2(ex): - assert not isinstance(ex, typing.Sequence) - - @given(from_type(typing.List[int])) - def inner_3(ex): - assert isinstance(ex, list) - - inner_1() - inner_2() - inner_3() - finally: - types._global_type_lookup.pop(typing.Sequence) - st.from_type.__clear_cache() - - -@pytest.mark.parametrize('typ', [ - typing.Sequence, typing.Container, typing.Mapping, typing.Reversible, - typing.SupportsBytes, typing.SupportsAbs, typing.SupportsComplex, - typing.SupportsFloat, typing.SupportsInt, typing.SupportsRound, -]) -def test_resolves_weird_types(typ): - from_type(typ).example() - - -def annotated_func(a: int, b: int=2, *, c: int, d: int=4): - return a + b + c + d - - -def test_issue_946_regression(): - # Turned type hints into kwargs even if the required posarg was passed - st.builds(annotated_func, st.integers()).example() - - -@pytest.mark.parametrize('thing', [ - annotated_func, # Works via typing.get_type_hints - typing.NamedTuple('N', [('a', int)]), # Falls back to inspection - int, # Fails; returns empty dict -]) -def test_can_get_type_hints(thing): - assert isinstance(get_type_hints(thing), dict) - - -def test_force_builds_to_infer_strategies_for_default_args(): - # By default, leaves args with defaults and minimises to 2+4=6 - assert find(st.builds(annotated_func), lambda ex: True) == 6 - # Inferring integers() for args makes it minimise to zero - assert find(st.builds(annotated_func, b=infer, d=infer), - lambda ex: True) == 0 - - -def non_annotated_func(a, b=2, *, c, d=4): - pass - - -def test_cannot_pass_infer_as_posarg(): - with pytest.raises(InvalidArgument): - st.builds(annotated_func, infer).example() - - -def test_cannot_force_inference_for_unannotated_arg(): - with pytest.raises(InvalidArgument): - st.builds(non_annotated_func, a=infer, c=st.none()).example() - with pytest.raises(InvalidArgument): - st.builds(non_annotated_func, a=st.none(), c=infer).example() - - -class UnknownType(object): - def __init__(self, arg): - pass - - -class UnknownAnnotatedType(object): - def __init__(self, arg: int): - pass - - -@given(st.from_type(UnknownAnnotatedType)) -def test_builds_for_unknown_annotated_type(ex): - assert isinstance(ex, UnknownAnnotatedType) - - -def unknown_annotated_func(a: UnknownType, b=2, *, c: UnknownType, d=4): - pass - - -def test_raises_for_arg_with_unresolvable_annotation(): - with pytest.raises(ResolutionFailed): - st.builds(unknown_annotated_func).example() - with pytest.raises(ResolutionFailed): - st.builds(unknown_annotated_func, a=st.none(), c=infer).example() - - -@given(a=infer, b=infer) -def test_can_use_type_hints(a: int, b: float): - assert isinstance(a, int) and isinstance(b, float) - - -def test_error_if_has_unresolvable_hints(): - @given(a=infer) - def inner(a: UnknownType): - pass - with pytest.raises(InvalidArgument): - inner() - - -@pytest.mark.skipif(not hasattr(typing, 'NewType'), reason='test for NewType') -def test_resolves_NewType(): - typ = typing.NewType('T', int) - nested = typing.NewType('NestedT', typ) - uni = typing.NewType('UnionT', typing.Optional[int]) - assert isinstance(from_type(typ).example(), integer_types) - assert isinstance(from_type(nested).example(), integer_types) - assert isinstance(from_type(uni).example(), integer_types + (type(None),)) - - -E = enum.Enum('E', 'a b c') - - -@given(from_type(E)) -def test_resolves_enum(ex): - assert isinstance(ex, E) - - -@pytest.mark.skipif(not hasattr(enum, 'Flag'), reason='test for Flag') -@pytest.mark.parametrize('resolver', [from_type, st.sampled_from]) -def test_resolves_flag_enum(resolver): - # Storing all combinations takes O(2^n) memory. Using an enum of 52 - # members in this test ensures that we won't try! - F = enum.Flag('F', ' '.join(string.ascii_letters)) - # Filter to check that we can generate compound members of enum.Flags - - @given(resolver(F).filter(lambda ex: ex not in tuple(F))) - def inner(ex): - assert isinstance(ex, F) - - inner() - - -class AnnotatedTarget(object): - - def __init__(self, a: int, b: int): - pass - - def method(self, a: int, b: int): - pass - - -@pytest.mark.parametrize('target', [ - AnnotatedTarget, AnnotatedTarget(1, 2).method -]) -@pytest.mark.parametrize('args,kwargs', [ - ((), {}), - ((1,), {}), - ((1, 2), {}), - ((), dict(a=1)), - ((), dict(b=2)), - ((), dict(a=1, b=2)), -]) -def test_required_args(target, args, kwargs): - # Mostly checking that `self` (and only self) is correctly excluded - st.builds(target, *map(st.just, args), - **{k: st.just(v) for k, v in kwargs.items()}).example() diff -Nru python-hypothesis-3.44.1/tests/py3/test_unicode_identifiers.py python-hypothesis-3.71.11/tests/py3/test_unicode_identifiers.py --- python-hypothesis-3.44.1/tests/py3/test_unicode_identifiers.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/py3/test_unicode_identifiers.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,42 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from hypothesis.internal.reflection import proxies - - -def test_can_copy_argspec_of_unicode_args(): - def foo(μ): - return μ - - @proxies(foo) - def bar(μ): - return foo(μ) - - assert bar(1) == 1 - - -def test_can_copy_argspec_of_unicode_name(): - def ā(): - return 1 - - @proxies(ā) - def bar(): - return 2 - - assert bar() == 2 diff -Nru python-hypothesis-3.44.1/tests/pytest/test_capture.py python-hypothesis-3.71.11/tests/pytest/test_capture.py --- python-hypothesis-3.44.1/tests/pytest/test_capture.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/pytest/test_capture.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,135 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import pytest - -from hypothesis.internal.compat import PY2, WINDOWS, hunichr, \ - escape_unicode_characters - -pytest_plugins = str('pytester') - -TESTSUITE = """ -from hypothesis import given, settings, Verbosity -from hypothesis.strategies import integers - -@settings(verbosity=Verbosity.verbose) -@given(integers()) -def test_should_be_verbose(x): - pass - -""" - - -@pytest.mark.parametrize('capture,expected', [ - ('no', True), - ('fd', False), -]) -def test_output_without_capture(testdir, capture, expected): - script = testdir.makepyfile(TESTSUITE) - result = testdir.runpytest(script, '--verbose', '--capture', capture) - out = '\n'.join(result.stdout.lines) - assert 'test_should_be_verbose' in out - assert ('Trying example' in out) == expected - assert result.ret == 0 - - -UNICODE_EMITTING = """ -import pytest -from hypothesis import given, settings, Verbosity -from hypothesis.strategies import text -from hypothesis.internal.compat import PY3 -import sys - -@settings(verbosity=Verbosity.verbose) -def test_emits_unicode(): - @given(text()) - def test_should_emit_unicode(t): - assert all(ord(c) <= 1000 for c in t) - with pytest.raises(AssertionError): - test_should_emit_unicode() -""" - - -@pytest.mark.xfail( - WINDOWS, - reason=( - "Encoding issues in running the subprocess, possibly py.test's fault")) -@pytest.mark.skipif( - PY2, reason="Output streams don't have encodings in python 2") -def test_output_emitting_unicode(testdir, monkeypatch): - monkeypatch.setenv('LC_ALL', 'C') - monkeypatch.setenv('LANG', 'C') - script = testdir.makepyfile(UNICODE_EMITTING) - result = getattr( - testdir, 'runpytest_subprocess', testdir.runpytest)( - script, '--verbose', '--capture=no') - out = '\n'.join(result.stdout.lines) - assert 'test_emits_unicode' in out - assert escape_unicode_characters(hunichr(1001)) in out - assert result.ret == 0 - - -TRACEBACKHIDE_TIMEOUT = """ -from hypothesis import given, settings -from hypothesis.strategies import integers -import time - -@given(integers()) -@settings(timeout=1) -def test_timeout_traceback_is_hidden(i): - time.sleep(1.1) -""" - - -def get_line_num(token, result): - for i, line in enumerate(result.stdout.lines): - if token in line: - return i - assert False, 'Token %r not found' % token - - -def test_timeout_traceback_is_hidden(testdir): - script = testdir.makepyfile(TRACEBACKHIDE_TIMEOUT) - result = testdir.runpytest(script, '--verbose') - def_line = get_line_num('def test_timeout_traceback_is_hidden', result) - timeout_line = get_line_num('Timeout: Ran out of time', result) - # If __tracebackhide__ works, then the Timeout error message will be - # next to the test name. If it doesn't work, then the message will be - # many lines apart with source code dump between them. - assert timeout_line - def_line == 1 - - -TRACEBACKHIDE_HEALTHCHECK = """ -from hypothesis import given, settings -from hypothesis.strategies import integers -import time -@given(integers().map(lambda x: time.sleep(0.2))) -def test_healthcheck_traceback_is_hidden(x): - pass -""" - - -def test_healthcheck_traceback_is_hidden(testdir): - script = testdir.makepyfile(TRACEBACKHIDE_HEALTHCHECK) - result = testdir.runpytest(script, '--verbose') - def_token = '__ test_healthcheck_traceback_is_hidden __' - timeout_token = ': FailedHealthCheck' - def_line = get_line_num(def_token, result) - timeout_line = get_line_num(timeout_token, result) - assert timeout_line - def_line == 6 diff -Nru python-hypothesis-3.44.1/tests/pytest/test_compat.py python-hypothesis-3.71.11/tests/pytest/test_compat.py --- python-hypothesis-3.44.1/tests/pytest/test_compat.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/pytest/test_compat.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import pytest - -from hypothesis import given -from hypothesis.strategies import booleans - - -@given(booleans()) -@pytest.mark.parametrize('hi', (1, 2, 3)) -def test_parametrize_after_given(hi, i): - pass diff -Nru python-hypothesis-3.44.1/tests/pytest/test_doctest.py python-hypothesis-3.71.11/tests/pytest/test_doctest.py --- python-hypothesis-3.44.1/tests/pytest/test_doctest.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/pytest/test_doctest.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -pytest_plugins = 'pytester' - - -def test_can_run_doctests(testdir): - script = testdir.makepyfile( - 'def hi():\n' - ' """\n' - ' >>> i = 5\n' - ' >>> i-1\n' - ' 4"""' - ) - - result = testdir.runpytest(script, '--doctest-modules') - assert result.ret == 0 diff -Nru python-hypothesis-3.44.1/tests/pytest/test_fixtures.py python-hypothesis-3.71.11/tests/pytest/test_fixtures.py --- python-hypothesis-3.44.1/tests/pytest/test_fixtures.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/pytest/test_fixtures.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,81 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import pytest - -from mock import Mock, create_autospec -from hypothesis import given, example -from tests.common.utils import fails -from hypothesis.strategies import integers - - -@pytest.fixture -def infinity(): - return float('inf') - - -@pytest.fixture -def mock_fixture(): - return Mock() - - -@pytest.fixture -def spec_fixture(): - class Foo(): - def __init__(self): - pass - - def bar(self): - return 'baz' - return create_autospec(Foo) - - -@given(integers()) -def test_can_mix_fixture_and_positional_strategy(infinity, xs): - # Hypothesis fills arguments from the right, so if @given() uses - # positional arguments then any strategies need to be on the right. - assert xs <= infinity - - -@given(xs=integers()) -def test_can_mix_fixture_and_keyword_strategy(xs, infinity): - assert xs <= infinity - - -@example(xs=0) -@given(xs=integers()) -def test_can_mix_fixture_example_and_keyword_strategy(xs, infinity): - assert xs <= infinity - - -@fails -@given(integers()) -def test_can_inject_mock_via_fixture(mock_fixture, xs): - """A negative test is better for this one - this condition uncovers a bug - whereby the mock fixture is executed instead of the test body and always - succeeds. If this test fails, then we know we've run the test body instead - of the mock. - """ - assert False - - -@given(integers()) -def test_can_inject_autospecced_mock_via_fixture(spec_fixture, xs): - spec_fixture.bar.return_value = infinity() - assert xs <= spec_fixture.bar() diff -Nru python-hypothesis-3.44.1/tests/pytest/test_mark.py python-hypothesis-3.71.11/tests/pytest/test_mark.py --- python-hypothesis-3.44.1/tests/pytest/test_mark.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/pytest/test_mark.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,64 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -pytest_plugins = str('pytester') - - -TESTSUITE = """ -from hypothesis import given -from hypothesis.strategies import integers - -@given(integers()) -def test_foo(x): - pass - -def test_bar(): - pass -""" - - -def test_can_select_mark(testdir): - script = testdir.makepyfile(TESTSUITE) - result = testdir.runpytest(script, '--verbose', '--strict', '-m', - 'hypothesis') - out = '\n'.join(result.stdout.lines) - assert '1 passed, 1 deselected' in out - - -UNITTEST_TESTSUITE = """ -from hypothesis import given -from hypothesis.strategies import integers -from unittest import TestCase - -class TestStuff(TestCase): - @given(integers()) - def test_foo(self, x): - pass - - def test_bar(self): - pass -""" - - -def test_can_select_mark_on_unittest(testdir): - script = testdir.makepyfile(UNITTEST_TESTSUITE) - result = testdir.runpytest(script, '--verbose', '--strict', '-m', - 'hypothesis') - out = '\n'.join(result.stdout.lines) - assert '1 passed, 1 deselected' in out diff -Nru python-hypothesis-3.44.1/tests/pytest/test_profiles.py python-hypothesis-3.71.11/tests/pytest/test_profiles.py --- python-hypothesis-3.44.1/tests/pytest/test_profiles.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/pytest/test_profiles.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,44 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from hypothesis.extra.pytestplugin import LOAD_PROFILE_OPTION - -pytest_plugins = str('pytester') - -CONFTEST = """ -from hypothesis._settings import settings -settings.register_profile("test", settings(max_examples=1)) -""" - -TESTSUITE = """ -from hypothesis import given -from hypothesis.strategies import integers -from hypothesis._settings import settings - -def test_this_one_is_ok(): - assert settings().max_examples == 1 -""" - - -def test_runs_reporting_hook(testdir): - script = testdir.makepyfile(TESTSUITE) - testdir.makeconftest(CONFTEST) - result = testdir.runpytest(script, LOAD_PROFILE_OPTION, 'test') - out = '\n'.join(result.stdout.lines) - assert '1 passed' in out diff -Nru python-hypothesis-3.44.1/tests/pytest/test_pytest_detection.py python-hypothesis-3.71.11/tests/pytest/test_pytest_detection.py --- python-hypothesis-3.44.1/tests/pytest/test_pytest_detection.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/pytest/test_pytest_detection.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,42 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -"""This module provides the core primitives of Hypothesis, such as given.""" - - -from __future__ import division, print_function, absolute_import - -import sys -import subprocess - -import hypothesis.core as core - - -def test_is_running_under_pytest(): - assert core.running_under_pytest - - -FILE_TO_RUN = """ -import hypothesis.core as core -assert not core.running_under_pytest -""" - - -def test_is_not_running_under_pytest(tmpdir): - pyfile = tmpdir.join('test.py') - pyfile.write(FILE_TO_RUN) - subprocess.check_call([sys.executable, str(pyfile)]) diff -Nru python-hypothesis-3.44.1/tests/pytest/test_reporting.py python-hypothesis-3.71.11/tests/pytest/test_reporting.py --- python-hypothesis-3.44.1/tests/pytest/test_reporting.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/pytest/test_reporting.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,44 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -pytest_plugins = str('pytester') - - -TESTSUITE = """ -from hypothesis import given -from hypothesis.strategies import lists, integers - -@given(integers()) -def test_this_one_is_ok(x): - pass - -@given(lists(integers())) -def test_hi(xs): - assert False -""" - - -def test_runs_reporting_hook(testdir): - script = testdir.makepyfile(TESTSUITE) - result = testdir.runpytest(script, '--verbose') - out = '\n'.join(result.stdout.lines) - assert 'test_this_one_is_ok' in out - assert 'Captured stdout call' not in out - assert 'Falsifying example' in out - assert result.ret != 0 diff -Nru python-hypothesis-3.44.1/tests/pytest/test_runs.py python-hypothesis-3.71.11/tests/pytest/test_runs.py --- python-hypothesis-3.44.1/tests/pytest/test_runs.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/pytest/test_runs.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from hypothesis import given -from tests.common.utils import fails -from hypothesis.strategies import integers - - -@given(integers()) -def test_ints_are_ints(x): - pass - - -@fails -@given(integers()) -def test_ints_are_floats(x): - assert isinstance(x, float) diff -Nru python-hypothesis-3.44.1/tests/pytest/test_seeding.py python-hypothesis-3.71.11/tests/pytest/test_seeding.py --- python-hypothesis-3.44.1/tests/pytest/test_seeding.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/pytest/test_seeding.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,124 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import re - -import pytest - -from hypothesis.internal.compat import hrange - -pytest_plugins = str('pytester') - - -TEST_SUITE = """ -from hypothesis import given, settings, assume -import hypothesis.strategies as st - - -first = None - -@settings(database=None) -@given(st.integers()) -def test_fails_once(some_int): - assume(abs(some_int) > 10000) - global first - if first is None: - first = some_int - - assert some_int != first -""" - - -CONTAINS_SEED_INSTRUCTION = re.compile(r"--hypothesis-seed=\d+", re.MULTILINE) - - -@pytest.mark.parametrize('seed', [0, 42, 'foo']) -def test_runs_repeatably_when_seed_is_set(seed, testdir): - script = testdir.makepyfile(TEST_SUITE) - - results = [ - testdir.runpytest( - script, '--verbose', '--strict', '--hypothesis-seed', str(seed) - ) - for _ in hrange(2) - ] - - for r in results: - for l in r.stdout.lines: - assert '--hypothesis-seed' not in l - - failure_lines = [ - l - for r in results - for l in r.stdout.lines - if 'some_int=' in l - ] - - assert len(failure_lines) == 2 - assert failure_lines[0] == failure_lines[1] - - -HEALTH_CHECK_FAILURE = """ -import os - -from hypothesis import given, strategies as st, assume, reject - -RECORD_EXAMPLES = - -if os.path.exists(RECORD_EXAMPLES): - target = None - with open(RECORD_EXAMPLES, 'r') as i: - seen = set(map(int, i.read().strip().split("\\n"))) -else: - target = open(RECORD_EXAMPLES, 'w') - -@given(st.integers()) -def test_failure(i): - if target is None: - assume(i not in seen) - else: - target.write("%s\\n" % (i,)) - reject() -""" - - -def test_repeats_healthcheck_when_following_seed_instruction(testdir, tmpdir): - health_check_test = HEALTH_CHECK_FAILURE.replace( - '', repr(str(tmpdir.join('seen')))) - - script = testdir.makepyfile(health_check_test) - - initial = testdir.runpytest(script, '--verbose', '--strict',) - - match = CONTAINS_SEED_INSTRUCTION.search('\n'.join(initial.stdout.lines)) - initial_output = '\n'.join(initial.stdout.lines) - - match = CONTAINS_SEED_INSTRUCTION.search(initial_output) - assert match is not None - - rerun = testdir.runpytest(script, '--verbose', '--strict', match.group(0)) - rerun_output = '\n'.join(rerun.stdout.lines) - - assert 'FailedHealthCheck' in rerun_output - assert '--hypothesis-seed' not in rerun_output - - rerun2 = testdir.runpytest( - script, '--verbose', '--strict', '--hypothesis-seed=10') - rerun2_output = '\n'.join(rerun2.stdout.lines) - assert 'FailedHealthCheck' not in rerun2_output diff -Nru python-hypothesis-3.44.1/tests/pytest/test_skipping.py python-hypothesis-3.71.11/tests/pytest/test_skipping.py --- python-hypothesis-3.44.1/tests/pytest/test_skipping.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/pytest/test_skipping.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -pytest_plugins = str('pytester') - - -PYTEST_TESTSUITE = """ -from hypothesis import given -from hypothesis.strategies import integers -import pytest - -@given(xs=integers()) -def test_to_be_skipped(xs): - if xs == 0: - pytest.skip() - else: - assert xs == 0 -""" - - -def test_no_falsifying_example_if_pytest_skip(testdir): - """If ``pytest.skip() is called during a test, Hypothesis should not - continue running the test and shrink process, nor should it print anything - about falsifying examples.""" - script = testdir.makepyfile(PYTEST_TESTSUITE) - result = testdir.runpytest(script, '--verbose', '--strict', '-m', - 'hypothesis') - out = '\n'.join(result.stdout.lines) - assert 'Falsifying example' not in out diff -Nru python-hypothesis-3.44.1/tests/pytest/test_statistics.py python-hypothesis-3.71.11/tests/pytest/test_statistics.py --- python-hypothesis-3.44.1/tests/pytest/test_statistics.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/pytest/test_statistics.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,120 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -from hypothesis.extra.pytestplugin import PRINT_STATISTICS_OPTION - -pytest_plugins = 'pytester' - - -TESTSUITE = """ -from hypothesis import given, settings, assume -from hypothesis.strategies import integers -import time -import warnings -from hypothesis.errors import HypothesisDeprecationWarning - -warnings.simplefilter('always', HypothesisDeprecationWarning) - - -@given(integers()) -def test_all_valid(x): - pass - - -@settings(timeout=0.2, min_satisfying_examples=1) -@given(integers()) -def test_slow(x): - time.sleep(0.1) - - -@settings( - max_examples=1000, min_satisfying_examples=1, perform_health_check=False -) -@given(integers()) -def test_iterations(x): - assume(x % 50 == 0) -""" - - -def test_does_not_run_statistics_by_default(testdir): - script = testdir.makepyfile(TESTSUITE) - result = testdir.runpytest(script) - out = '\n'.join(result.stdout.lines) - assert 'Hypothesis Statistics' not in out - - -def test_prints_statistics_given_option(testdir): - script = testdir.makepyfile(TESTSUITE) - result = testdir.runpytest(script, PRINT_STATISTICS_OPTION) - out = '\n'.join(result.stdout.lines) - assert 'Hypothesis Statistics' in out - assert 'timeout=0.2' in out - assert 'max_examples=100' in out - assert 'max_iterations=1000' in out - assert 'HypothesisDeprecationWarning' in out - - -UNITTEST_TESTSUITE = """ - -from hypothesis import given -from hypothesis.strategies import integers -from unittest import TestCase - - -class TestStuff(TestCase): - @given(integers()) - def test_all_valid(self, x): - pass -""" - - -def test_prints_statistics_for_unittest_tests(testdir): - script = testdir.makepyfile(UNITTEST_TESTSUITE) - result = testdir.runpytest(script, PRINT_STATISTICS_OPTION) - out = '\n'.join(result.stdout.lines) - assert 'Hypothesis Statistics' in out - assert 'TestStuff::test_all_valid' in out - assert 'max_examples=100' in out - - -STATEFUL_TESTSUITE = """ - -from hypothesis import given -from hypothesis.strategies import integers -from hypothesis.stateful import GenericStateMachine - - -class Stuff(GenericStateMachine): - def steps(self): - return integers() - - def execute_step(self, step): - pass - -TestStuff = Stuff.TestCase -""" - - -def test_prints_statistics_for_stateful_tests(testdir): - script = testdir.makepyfile(STATEFUL_TESTSUITE) - result = testdir.runpytest(script, PRINT_STATISTICS_OPTION) - out = '\n'.join(result.stdout.lines) - assert 'Hypothesis Statistics' in out - assert 'TestStuff::runTest' in out - assert 'max_examples=100' in out diff -Nru python-hypothesis-3.44.1/tests/quality/__init__.py python-hypothesis-3.71.11/tests/quality/__init__.py --- python-hypothesis-3.44.1/tests/quality/__init__.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/quality/__init__.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER diff -Nru python-hypothesis-3.44.1/tests/quality/test_discovery_ability.py python-hypothesis-3.71.11/tests/quality/test_discovery_ability.py --- python-hypothesis-3.44.1/tests/quality/test_discovery_ability.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/quality/test_discovery_ability.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,405 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -# -*- coding: utf-8 -*- -"""Statistical tests over the forms of the distributions in the standard set of -definitions. - -These tests all take the form of a classic hypothesis test with the null -hypothesis being that the probability of some event occurring when -drawing data from the distribution produced by some specifier is >= -REQUIRED_P - -""" - - -from __future__ import division, print_function, absolute_import - -import re -import math -import collections - -import hypothesis.internal.reflection as reflection -from hypothesis import settings as Settings -from hypothesis.errors import UnsatisfiedAssumption -from hypothesis.strategies import just, sets, text, lists, floats, \ - one_of, tuples, booleans, integers, sampled_from -from hypothesis.internal.conjecture.data import Status -from hypothesis.internal.conjecture.engine import \ - ConjectureRunner as ConConjectureRunner - -RUNS = 100 -REQUIRED_RUNS = 50 - - -INITIAL_LAMBDA = re.compile(u'^lambda[^:]*:\\s*') - - -def strip_lambda(s): - return INITIAL_LAMBDA.sub(u'', s) - - -class HypothesisFalsified(AssertionError): - pass - - -def define_test(specifier, predicate, condition=None): - def run_test(): - if condition is None: - def _condition(x): - return True - condition_string = u'' - else: - _condition = condition - condition_string = strip_lambda( - reflection.get_pretty_function_description(condition)) - - def test_function(data): - try: - value = data.draw(specifier) - except UnsatisfiedAssumption: - data.mark_invalid() - if not _condition(value): - data.mark_invalid() - if predicate(value): - data.mark_interesting() - - successes = 0 - for _ in range(RUNS): - runner = ConConjectureRunner( - test_function, - settings=Settings( - max_examples=100, - max_iterations=1000, - max_shrinks=0 - )) - runner.run() - if runner.last_data.status == Status.INTERESTING: - successes += 1 - if successes >= REQUIRED_RUNS: - return - event = reflection.get_pretty_function_description(predicate) - if condition is not None: - event += '|' - event += condition_string - - description = ( - u'P(%s) ~ %d / %d = %.2f < %.2f' - ) % ( - event, - successes, RUNS, - successes / RUNS, (REQUIRED_RUNS / RUNS) - ) - raise HypothesisFalsified(description + u' rejected') - return run_test - - -test_can_produce_zero = define_test(integers(), lambda x: x == 0) -test_can_produce_large_magnitude_integers = define_test( - integers(), lambda x: abs(x) > 1000 -) -test_can_produce_large_positive_integers = define_test( - integers(), lambda x: x > 1000 -) -test_can_produce_large_negative_integers = define_test( - integers(), lambda x: x < -1000 -) - - -def long_list(xs): - return len(xs) >= 20 - - -test_can_produce_unstripped_strings = define_test( - text(), lambda x: x != x.strip() -) - -test_can_produce_stripped_strings = define_test( - text(), lambda x: x == x.strip() -) - -test_can_produce_multi_line_strings = define_test( - text(average_size=25.0), lambda x: u'\n' in x -) - -test_can_produce_ascii_strings = define_test( - text(), lambda x: all(ord(c) <= 127 for c in x), -) - -test_can_produce_long_strings_with_no_ascii = define_test( - text(min_size=5), lambda x: all(ord(c) > 127 for c in x), -) - -test_can_produce_short_strings_with_some_non_ascii = define_test( - text(), lambda x: any(ord(c) > 127 for c in x), - condition=lambda x: len(x) <= 3 -) - -test_can_produce_positive_infinity = define_test( - floats(), lambda x: x == float(u'inf') -) - -test_can_produce_negative_infinity = define_test( - floats(), lambda x: x == float(u'-inf') -) - -test_can_produce_nan = define_test( - floats(), math.isnan -) - -test_can_produce_floats_near_left = define_test( - floats(0, 1), - lambda t: t < 0.2 -) - -test_can_produce_floats_near_right = define_test( - floats(0, 1), - lambda t: t > 0.8 -) - -test_can_produce_floats_in_middle = define_test( - floats(0, 1), - lambda t: 0.2 <= t <= 0.8 -) - -test_can_produce_long_lists = define_test( - lists(integers(), average_size=25.0), long_list -) - -test_can_produce_short_lists = define_test( - lists(integers()), lambda x: len(x) <= 10 -) - -test_can_produce_the_same_int_twice = define_test( - tuples(lists(integers(), average_size=25.0), integers()), - lambda t: t[0].count(t[1]) > 1 -) - - -def distorted_value(x): - c = collections.Counter(x) - return min(c.values()) * 3 <= max(c.values()) - - -def distorted(x): - return distorted_value(map(type, x)) - - -test_sampled_from_large_number_can_mix = define_test( - lists(sampled_from(range(50)), min_size=50), - lambda x: len(set(x)) >= 25, -) - - -test_sampled_from_often_distorted = define_test( - lists(sampled_from(range(5))), distorted_value, - condition=lambda x: len(x) >= 3, -) - - -test_non_empty_subset_of_two_is_usually_large = define_test( - sets(sampled_from((1, 2))), - lambda t: len(t) == 2 -) - -test_subset_of_ten_is_sometimes_empty = define_test( - sets(integers(1, 10)), lambda t: len(t) == 0 -) - -test_mostly_sensible_floats = define_test( - floats(), - lambda t: t + 1 > t -) - -test_mostly_largish_floats = define_test( - floats(), - lambda t: t + 1 > 1, - condition=lambda x: x > 0, -) - -test_ints_can_occasionally_be_really_large = define_test( - integers(), - lambda t: t >= 2 ** 63 -) - -test_mixing_is_sometimes_distorted = define_test( - lists(booleans() | tuples(), average_size=25.0), distorted, - condition=lambda x: len(set(map(type, x))) == 2, -) - -test_mixes_2_reasonably_often = define_test( - lists(booleans() | tuples(), average_size=25.0), - lambda x: len(set(map(type, x))) > 1, - condition=bool, -) - -test_partial_mixes_3_reasonably_often = define_test( - lists(booleans() | tuples() | just(u'hi'), average_size=25.0), - lambda x: 1 < len(set(map(type, x))) < 3, - condition=bool, -) - -test_mixes_not_too_often = define_test( - lists(booleans() | tuples(), average_size=25.0), - lambda x: len(set(map(type, x))) == 1, - condition=bool, -) - -test_integers_are_usually_non_zero = define_test( - integers(), lambda x: x != 0 -) - -test_integers_are_sometimes_zero = define_test( - integers(), lambda x: x == 0 -) - -test_integers_are_often_small = define_test( - integers(), lambda x: abs(x) <= 100 -) - - -# This series of tests checks that the one_of() strategy flattens branches -# correctly. We assert that the probability of any branch is >= 0.1, -# approximately (1/8 = 0.125), regardless of how heavily nested it is in the -# strategy. - -# This first strategy chooses an integer between 0 and 7 (inclusive). -one_of_nested_strategy = one_of( - just(0), - one_of( - just(1), - just(2), - one_of( - just(3), - just(4), - one_of( - just(5), - just(6), - just(7) - ) - ) - ) -) - -for i in range(8): - exec('''test_one_of_flattens_branches_%d = define_test( - one_of_nested_strategy, lambda x: x == %d - )''' % (i, i)) - - -xor_nested_strategy = ( - just(0) | ( - just(1) | just(2) | ( - just(3) | just(4) | ( - just(5) | just(6) | just(7) - ) - ) - ) -) - -for i in range(8): - exec('''test_xor_flattens_branches_%d = define_test( - xor_nested_strategy, lambda x: x == %d - )''' % (i, i)) - - -# This strategy tests interactions with `map()`. They generate integers -# from the set {1, 4, 6, 16, 20, 24, 28, 32}. -def double(x): - return x * 2 - - -one_of_nested_strategy_with_map = one_of( - just(1), - one_of( - (just(2) | just(3)).map(double), - one_of( - (just(4) | just(5)).map(double), - one_of( - (just(6) | just(7) | just(8)).map(double) - ) - ).map(double) - ) -) - -for i in (1, 4, 6, 16, 20, 24, 28, 32): - exec('''test_one_of_flattens_map_branches_%d = define_test( - one_of_nested_strategy_with_map, lambda x: x == %d - )''' % (i, i)) - - -# This strategy tests interactions with `flatmap()`. It generates lists -# of length 0-7 (inclusive) in which every element is `None`. -one_of_nested_strategy_with_flatmap = just(None).flatmap( - lambda x: one_of( - just([x] * 0), just([x] * 1), one_of( - just([x] * 2), just([x] * 3), one_of( - just([x] * 4), just([x] * 5), one_of( - just([x] * 6), just([x] * 7), - ) - ) - ) - ) -) - -for i in range(8): - exec('''test_one_of_flattens_flatmap_branches_%d = define_test( - one_of_nested_strategy_with_flatmap, lambda x: len(x) == %d - )''' % (i, i)) - - -xor_nested_strategy_with_flatmap = just(None).flatmap( - lambda x: ( - just([x] * 0) | just([x] * 1) | ( - just([x] * 2) | just([x] * 3) | ( - just([x] * 4) | just([x] * 5) | ( - just([x] * 6) | just([x] * 7) - ) - ) - ) - ) -) - -for i in range(8): - exec('''test_xor_flattens_flatmap_branches_%d = define_test( - xor_nested_strategy_with_flatmap, lambda x: len(x) == %d - )''' % (i, i)) - - -# This strategy tests interactions with `filter()`. It generates the even -# integers {0, 2, 4, 6} in equal measures. -one_of_nested_strategy_with_filter = one_of( - just(0), - just(1), - one_of( - just(2), - just(3), - one_of( - just(4), - just(5), - one_of( - just(6), - just(7), - ) - ) - ) -).filter(lambda x: x % 2 == 0) - -for i in range(4): - exec('''test_one_of_flattens_filter_branches_%d = define_test( - one_of_nested_strategy_with_filter, lambda x: x == 2 * %d - )''' % (i, i)) diff -Nru python-hypothesis-3.44.1/tests/quality/test_shrink_quality.py python-hypothesis-3.71.11/tests/quality/test_shrink_quality.py --- python-hypothesis-3.44.1/tests/quality/test_shrink_quality.py 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tests/quality/test_shrink_quality.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,232 +0,0 @@ -# coding=utf-8 -# -# This file is part of Hypothesis, which may be found at -# https://github.com/HypothesisWorks/hypothesis-python -# -# Most of this work is copyright (C) 2013-2017 David R. MacIver -# (david@drmaciver.com), but it contains contributions by others. See -# CONTRIBUTING.rst for a full list of people who may hold copyright, and -# consult the git log if you need to determine who owns an individual -# contribution. -# -# This Source Code Form is subject to the terms of the Mozilla Public License, -# v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at http://mozilla.org/MPL/2.0/. -# -# END HEADER - -from __future__ import division, print_function, absolute_import - -import sys -from fractions import Fraction -from functools import reduce - -import pytest -from flaky import flaky - -from hypothesis import find, assume, settings -from tests.common import parametrize -from tests.common.debug import minimal -from hypothesis.strategies import just, sets, text, lists, tuples, \ - booleans, integers, fractions, frozensets, dictionaries, \ - sampled_from -from hypothesis.internal.compat import PY3, OrderedDict, hrange - - -def test_integers_from_minimizes_leftwards(): - assert minimal(integers(min_value=101)) == 101 - - -def test_minimal_fractions_1(): - assert minimal(fractions()) == Fraction(0) - - -def test_minimal_fractions_2(): - assert minimal(fractions(), lambda x: x >= 1) == Fraction(1) - - -def test_minimal_fractions_3(): - assert minimal( - lists(fractions()), lambda s: len(s) >= 20) == [Fraction(0)] * 20 - - -def test_minimize_string_to_empty(): - assert minimal(text()) == u'' - - -def test_minimize_one_of(): - for _ in hrange(100): - assert minimal(integers() | text() | booleans()) in ( - 0, u'', False - ) - - -def test_minimize_mixed_list(): - mixed = minimal(lists(integers() | text()), lambda x: len(x) >= 10) - assert set(mixed).issubset(set((0, u''))) - - -def test_minimize_longer_string(): - assert minimal(text(), lambda x: len(x) >= 10) == u'0' * 10 - - -def test_minimize_longer_list_of_strings(): - assert minimal(lists(text()), lambda x: len(x) >= 10) == [u''] * 10 - - -def test_minimize_3_set(): - assert minimal(sets(integers()), lambda x: len(x) >= 3) in ( - set((0, 1, 2)), - set((-1, 0, 1)), - ) - - -def test_minimize_3_set_of_tuples(): - assert minimal( - sets(tuples(integers())), - lambda x: len(x) >= 2) == set(((0,), (1,))) - - -def test_minimize_sets_of_sets(): - elements = integers(1, 100) - size = 10 - set_of_sets = minimal( - sets(frozensets(elements)), lambda s: len(s) >= size - ) - assert frozenset() in set_of_sets - assert len(set_of_sets) == size - for s in set_of_sets: - if len(s) > 1: - assert any( - s != t and t.issubset(s) - for t in set_of_sets - ) - - -def test_can_simplify_flatmap_with_bounded_left_hand_size(): - assert minimal( - booleans().flatmap(lambda x: lists(just(x))), - lambda x: len(x) >= 10) == [False] * 10 - - -def test_can_simplify_across_flatmap_of_just(): - assert minimal(integers().flatmap(just)) == 0 - - -def test_can_simplify_on_right_hand_strategy_of_flatmap(): - assert minimal(integers().flatmap(lambda x: lists(just(x)))) == [] - - -@flaky(min_passes=5, max_runs=5) -def test_can_ignore_left_hand_side_of_flatmap(): - assert minimal( - integers().flatmap(lambda x: lists(integers())), - lambda x: len(x) >= 10 - ) == [0] * 10 - - -def test_can_simplify_on_both_sides_of_flatmap(): - assert minimal( - integers().flatmap(lambda x: lists(just(x))), - lambda x: len(x) >= 10 - ) == [0] * 10 - - -def test_flatmap_rectangles(): - lengths = integers(min_value=0, max_value=10) - - def lists_of_length(n): - return lists(sampled_from('ab'), min_size=n, max_size=n) - - xs = find(lengths.flatmap( - lambda w: lists(lists_of_length(w))), lambda x: ['a', 'b'] in x, - settings=settings(database=None, max_examples=2000) - ) - assert xs == [['a', 'b']] - - -@flaky(min_passes=5, max_runs=5) -@parametrize(u'dict_class', [dict, OrderedDict]) -def test_dictionary(dict_class): - assert minimal(dictionaries( - keys=integers(), values=text(), - dict_class=dict_class)) == dict_class() - - x = minimal( - dictionaries(keys=integers(), values=text(), dict_class=dict_class), - lambda t: len(t) >= 3) - assert isinstance(x, dict_class) - assert set(x.values()) == set((u'',)) - for k in x: - if k < 0: - assert k + 1 in x - if k > 0: - assert k - 1 in x - - -def test_minimize_single_element_in_silly_large_int_range(): - ir = integers(-(2 ** 256), 2 ** 256) - assert minimal(ir, lambda x: x >= -(2 ** 255)) == 0 - - -def test_minimize_multiple_elements_in_silly_large_int_range(): - desired_result = [0] * 20 - - ir = integers(-(2 ** 256), 2 ** 256) - x = minimal( - lists(ir), - lambda x: len(x) >= 20, - timeout_after=20, - ) - assert x == desired_result - - -def test_minimize_multiple_elements_in_silly_large_int_range_min_is_not_dupe(): - ir = integers(0, 2 ** 256) - target = list(range(20)) - - x = minimal( - lists(ir), - lambda x: ( - assume(len(x) >= 20) and all(x[i] >= target[i] for i in target)), - timeout_after=60, - ) - assert x == target - - -@pytest.mark.skipif(PY3, reason=u'Python 3 has better integers') -def test_minimize_long(): - assert minimal( - integers(), lambda x: type(x).__name__ == u'long') == sys.maxint + 1 - - -def test_find_large_union_list(): - def large_mostly_non_overlapping(xs): - union = reduce(set.union, xs) - return len(union) >= 30 - - result = minimal( - lists(sets(integers(), min_size=1), min_size=1), - large_mostly_non_overlapping, timeout_after=120) - assert len(result) == 1 - union = reduce(set.union, result) - assert len(union) == 30 - assert max(union) == min(union) + len(union) - 1 - - -@pytest.mark.parametrize('n', [0, 1, 10, 100, 1000]) -def test_containment(n): - iv = minimal( - tuples(lists(integers()), integers()), - lambda x: x[1] in x[0] and x[1] >= n, - timeout_after=60 - ) - assert iv == ([n], n) - - -def test_duplicate_containment(): - ls, i = minimal( - tuples(lists(integers()), integers()), - lambda s: s[0].count(s[1]) > 1, timeout_after=100) - assert ls == [0, 0] - assert i == 0 diff -Nru python-hypothesis-3.44.1/tooling/README.rst python-hypothesis-3.71.11/tooling/README.rst --- python-hypothesis-3.44.1/tooling/README.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/tooling/README.rst 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,6 @@ +======================== +Hypothesis Build Tooling +======================== + +This is a piece of software for managing Hypothesis's build tasks, releases, +etc. It's very Hypothesis specific, though it may become less so in the future. diff -Nru python-hypothesis-3.44.1/tooling/scripts/common.sh python-hypothesis-3.71.11/tooling/scripts/common.sh --- python-hypothesis-3.44.1/tooling/scripts/common.sh 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/tooling/scripts/common.sh 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,34 @@ +#!/usr/bin/env bash + +# This file is not really a script but is intended for sourcing from other +# scripts so that they can share a common set of paths conveniently. + +set -o errexit +set -o nounset + +HERE="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +ROOT="$(git -C "$HERE" rev-parse --show-toplevel)" + +export ROOT +export BUILD_RUNTIMES=${BUILD_RUNTIMES:-$HOME/.cache/hypothesis-build-runtimes} +export BASE="$BUILD_RUNTIMES" +export PYENV="$BASE/pyenv" +export SNAKEPIT="$BASE/python-versions/" + +# Note: Deliberately ignoring BUILD_RUNTIMES configuration because we don't +# want this to go in cache, because it takes up a huge amount of space and +# slows everything down! +export VIRTUALENVS="${TMPDIR:-/tmp}/.hypothesis-runtimes/virtualenvs/" +export RBENV_VERSION="2.5.1" +export RBENV_ROOT="$BASE/.rbenv" +export INSTALLED_RUBY_DIR="$RBENV_ROOT/versions/$RBENV_VERSION/" + +export GEM_HOME="$INSTALLED_RUBY_DIR" +export GEM_PATH="$GEM_HOME" + +export PATH="$INSTALLED_RUBY_DIR/bin:$HOME/.cargo/bin:$PATH" + +pythonloc() { + VERSION="$1" + echo "$SNAKEPIT/$VERSION" +} diff -Nru python-hypothesis-3.44.1/tooling/scripts/ensure-python.sh python-hypothesis-3.71.11/tooling/scripts/ensure-python.sh --- python-hypothesis-3.44.1/tooling/scripts/ensure-python.sh 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/tooling/scripts/ensure-python.sh 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,66 @@ +#!/usr/bin/env bash + +set -o errexit +set -o nounset +set -x + +HERE="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +# shellcheck source=tooling/scripts/common.sh +source "$HERE/common.sh" + +# This is to guard against multiple builds in parallel. The various installers will tend +# to stomp all over each other if you do this and they haven't previously successfully +# succeeded. We use a lock file to block progress so only one install runs at a time. +# This script should be pretty fast once files are cached, so the loss of concurrency +# is not a major problem. +# This should be using the lockfile command, but that's not available on the +# containerized travis and we can't install it without sudo. +# It is unclear if this is actually useful. I was seeing behaviour that suggested +# concurrent runs of the installer, but I can't seem to find any evidence of this lock +# ever not being acquired. + +VERSION="$1" +TARGET=$(pythonloc "$VERSION") + +if [ ! -e "$TARGET/bin/python" ] ; then + mkdir -p "$BASE" + + LOCKFILE="$BASE/.install-lockfile" + while true; do + if mkdir "$LOCKFILE" 2>/dev/null; then + echo "Successfully acquired installer." + break + else + echo "Failed to acquire lock. Is another installer running? Waiting a bit." + fi + + sleep $(( ( RANDOM % 10 ) + 1 )).$(( RANDOM % 100 ))s + + if (( $(date '+%s') > 300 + $(stat --format=%X "$LOCKFILE") )); then + echo "We've waited long enough" + rm -rf "$LOCKFILE" + fi + done + trap 'rm -rf $LOCKFILE' EXIT + + + if [ ! -d "$PYENV/.git" ]; then + rm -rf "$PYENV" + git clone https://github.com/yyuu/pyenv.git "$PYENV" + else + back=$PWD + cd "$PYENV" + git fetch || echo "Update failed to complete. Ignoring" + git reset --hard origin/master + cd "$back" + fi + + for _ in $(seq 5); do + if "$BASE/pyenv/plugins/python-build/bin/python-build" "$VERSION" "$TARGET" ; then + exit 0 + fi + echo "Command failed. Retrying..." + sleep $(( ( RANDOM % 10 ) + 1 )).$(( RANDOM % 100 ))s + done +fi diff -Nru python-hypothesis-3.44.1/tooling/scripts/ensure-rustup.sh python-hypothesis-3.71.11/tooling/scripts/ensure-rustup.sh --- python-hypothesis-3.44.1/tooling/scripts/ensure-rustup.sh 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/tooling/scripts/ensure-rustup.sh 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +set -o errexit +set -o nounset + +if ! command -v rustup > /dev/null ; then + curl https://sh.rustup.rs -sSf | sh -s -- -y +fi + +if ! rustup show | grep stable > /dev/null ; then + rustup install stable +fi + +rustup default stable + +rustup update stable diff -Nru python-hypothesis-3.44.1/tooling/scripts/install-python.sh python-hypothesis-3.71.11/tooling/scripts/install-python.sh --- python-hypothesis-3.44.1/tooling/scripts/install-python.sh 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/tooling/scripts/install-python.sh 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,113 @@ +#!/usr/bin/env bash + +# Special license: Take literally anything you want out of this file. I don't +# care. Consider it WTFPL licensed if you like. +# Basically there's a lot of suffering encoded here that I don't want you to +# have to go through and you should feel free to use this to avoid some of +# that suffering in advance. + +set -e +set -x + +# OS X seems to have some weird Localse problems on Travis. This attempts to set +# the Locale to known good ones during install + +env | grep UTF + +# This is to guard against multiple builds in parallel. The various installers will tend +# to stomp all over each other if you do this and they haven't previously successfully +# succeeded. We use a lock file to block progress so only one install runs at a time. +# This script should be pretty fast once files are cached, so the lost of concurrency +# is not a major problem. +# This should be using the lockfile command, but that's not available on the +# containerized travis and we can't install it without sudo. +# Is is unclear if this is actually useful. I was seeing behaviour that suggested +# concurrent runs of the installer, but I can't seem to find any evidence of this lock +# ever not being acquired. + +BASE=${BUILD_RUNTIMES-$PWD/.runtimes} + +mkdir -p "$BASE" + +LOCKFILE="$BASE/.install-lockfile" +while true; do + if mkdir "$LOCKFILE" 2>/dev/null; then + echo "Successfully acquired installer." + break + else + echo "Failed to acquire lock. Is another installer running? Waiting a bit." + fi + + sleep $(( ( RANDOM % 10 ) + 1 )).$(( RANDOM % 100 ))s + + if (( $(date '+%s') > 300 + $(stat --format=%X "$LOCKFILE") )); then + echo "We've waited long enough" + rm -rf "$LOCKFILE" + fi +done +trap 'rm -rf $LOCKFILE' EXIT + + +PYENV=$BASE/pyenv + + +if [ ! -d "$PYENV/.git" ]; then + rm -rf "$PYENV" + git clone https://github.com/yyuu/pyenv.git "$BASE/pyenv" +else + back=$PWD + cd "$PYENV" + git fetch || echo "Update failed to complete. Ignoring" + git reset --hard origin/master + cd "$back" +fi + +SNAKEPIT=$BASE/snakepit + +install () { + + VERSION="$1" + ALIAS="$2" + mkdir -p "$BASE/versions" + SOURCE=$BASE/versions/$ALIAS + + if [ ! -e "$SOURCE" ]; then + mkdir -p "$SNAKEPIT" + mkdir -p "$BASE/versions" + "$BASE/pyenv/plugins/python-build/bin/python-build" "$VERSION" "$SOURCE" + fi + rm -f "$SNAKEPIT/$ALIAS" + mkdir -p "$SNAKEPIT" + "$SOURCE/bin/python" -m pip.__main__ install --upgrade pip wheel virtualenv + ln -s "$SOURCE/bin/python" "$SNAKEPIT/$ALIAS" +} + + +for var in "$@"; do + case "${var}" in + 2.7) + install 2.7.14 python2.7 + ;; + 2.7.3) + install 2.7.3 python2.7.3 + ;; + 3.4) + install 3.4.3 python3.4 + ;; + 3.5) + install 3.5.1 python3.5 + ;; + 3.6) + install 3.6.1 python3.6 + ;; + 3.7) + install 3.7.0 python3.7 + ;; + pypy) + install pypy2.7-5.8.0 pypy + ;; + pypy3) + install pypy3.5-5.10.1 pypy3 + ;; + esac +done diff -Nru python-hypothesis-3.44.1/tooling/scripts/tool-hash.py python-hypothesis-3.71.11/tooling/scripts/tool-hash.py --- python-hypothesis-3.44.1/tooling/scripts/tool-hash.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/tooling/scripts/tool-hash.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,26 @@ +#!/usr/bin/env python + +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import sys +import hashlib + +if __name__ == '__main__': + print(hashlib.sha1(sys.stdin.read().encode('utf-8')).hexdigest()[:10]) diff -Nru python-hypothesis-3.44.1/tooling/setup.py python-hypothesis-3.71.11/tooling/setup.py --- python-hypothesis-3.44.1/tooling/setup.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/tooling/setup.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,48 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import os + +import setuptools + + +def local_file(name): + return os.path.relpath(os.path.join(os.path.dirname(__file__), name)) + + +SOURCE = local_file('src') +README = local_file('README.rst') + +setuptools.setup( + name='hypothesis-tooling', + # We don't actually ship this, it just has a setup.py for convenience. + version='0.0.0', + author='David R. MacIver', + author_email='david@drmaciver.com', + packages=setuptools.find_packages(SOURCE), + package_dir={'': SOURCE}, + url=( + 'https://github.com/HypothesisWorks/hypothesis-python/' + 'tree/master/tooling' + ), + license='MPL v2', + description='A library for property based testing', + python_requires='>=3.6', + long_description=open(README).read(), +) diff -Nru python-hypothesis-3.44.1/tooling/src/hypothesistooling/fix_doctests.py python-hypothesis-3.71.11/tooling/src/hypothesistooling/fix_doctests.py --- python-hypothesis-3.44.1/tooling/src/hypothesistooling/fix_doctests.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/tooling/src/hypothesistooling/fix_doctests.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,168 @@ +#!/usr/bin/env python3 + +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import os +import re +import sys +from textwrap import dedent +from subprocess import PIPE, run +from collections import defaultdict +from distutils.version import StrictVersion + +import hypothesistooling as tools +from hypothesistooling.scripts import tool_path +from hypothesistooling.projects.hypothesispython import BASE_DIR + +SPHINXBUILD = tool_path('sphinx-build') + + +def dedent_lines(lines, force_newline=None): + """Remove common leading whitespace from a list of strings.""" + if not lines: + return [] + joiner = '' if lines[0].endswith('\n') else '\n' + lines = dedent(joiner.join(lines)).split('\n') + if force_newline is False: + return lines + if force_newline is True: + return [l + '\n' for l in lines] + return [l + (bool(joiner) * '\n') for l in lines] + + +class FailingExample(object): + + def __init__(self, chunk): + """Turn a chunk of text into an object representing the test.""" + # Determine and save the location of the actual doctest + location, *lines = [l for l in chunk.split('\n') if l.strip()] + self.location = location.strip() + pattern = r'File "(.+?)", line (\d+|\?+), in .+' + file, line = re.match(pattern, self.location).groups() + self.file = os.path.join('docs', file) + self.line = None if '?' in line else int(line) + # Select the expected and returned output of the test + got = lines.index('Got:') + self.expected_lines = dedent_lines( + lines[lines.index('Expected:') + 1:got], force_newline=False + ) + self.got_lines = dedent_lines(lines[got + 1:]) + self.checked_ok = None + self.adjust() + + @property + def indices(self): + return slice(self.line, self.line + len(self.expected_lines)) + + def adjust(self): + if self.line is None and self.file.endswith('.rst'): + # Sphinx reports an unknown line number when the doctest is + # included from a docstring, so docutils must have misreported the + # file location. We thus force it to the most likely candidate: + self.file = 'src/hypothesis/strategies.py' + with open(self.file) as f: + lines = f.read().split('\n') + if self.line is not None: + # The raw line number is the first line of *input*, so adjust to + # first line of output by skipping lines which start with a prompt + while self.line < len(lines): + if not lines[self.line].lstrip().startswith(('>>>', '...')): + break + self.line += 1 + else: + # If the location within a file wasn't reported, we have to go + # looking for it. + stripped = [l.lstrip() for l in lines] + self.line = 0 + while self.expected_lines[0] in stripped[self.line:]: + self.line = stripped[self.line:].index(self.expected_lines[0]) + candidate = dedent_lines(lines[self.indices], + force_newline=False) + if candidate == self.expected_lines: + break + self.line += 1 + # Finally, set the flag for location quality + self.checked_ok = self.expected_lines == dedent_lines( + lines[self.indices], force_newline=False + ) + + def __repr__(self): + return '{}\nExpected: {!r:.60}\nGot: {!r:.60}'.format( + self.location, self.expected_lines, self.got_lines) + + +def get_doctest_output(): + # Return a dict of filename: list of examples, sorted from last to first + # so that replacing them in sequence works + command = run([SPHINXBUILD, '-b', 'doctest', 'docs', 'docs/_build'], + stdout=PIPE, stderr=PIPE, encoding='utf-8', cwd=BASE_DIR) + output = [FailingExample(c) for c in command.stdout.split('*' * 70) + if c.strip().startswith('File "')] + if not all(ex.checked_ok for ex in output): + broken = '\n'.join(ex.location for ex in output if not ex.checked_ok) + print('Could not find some tests:\n' + broken) + sys.exit(1) + tests = defaultdict(set) + for ex in output: + tests[ex.file].add(ex) + return {fname: sorted(examples, key=lambda x: x.line, reverse=True) + for fname, examples in tests.items()} + + +def indent_like(lines, like): + """Indent ``lines`` to the same level as ``like``.""" + prefix = len(like[0].rstrip()) - len(dedent_lines(like)[0].rstrip()) + return [prefix * ' ' + l for l in dedent_lines(lines, force_newline=True) + if l.strip()] + + +def main(): + version = run([SPHINXBUILD, '--version'], stdout=PIPE, cwd=BASE_DIR, + encoding='utf-8').stdout.lstrip('sphinx-build ') + if StrictVersion(version) < '1.7': + print('This script requires Sphinx 1.7 or later; got %s.\n' % version) + sys.exit(2) + failing = get_doctest_output() + if not failing: + print('All doctests are OK') + sys.exit(0) + if tools.has_uncommitted_changes(BASE_DIR): + print('Cannot fix doctests in place with uncommited changes') + sys.exit(1) + + for fname, examples in failing.items(): + with open(fname) as f: + lines = f.readlines() + for ex in examples: + # Note: can't indent earlier, as we don't know file indentation + lines[ex.indices] = indent_like(ex.got_lines, lines[ex.indices]) + with open(fname, 'w') as f: + f.writelines(lines) + + still_failing = get_doctest_output() + if still_failing: + print('Fixes failed: script broken or flaky tests.\n', still_failing) + sys.exit(1) + print('All failing doctests have been fixed.') + sys.exit(0) + + +if __name__ == '__main__': + main() diff -Nru python-hypothesis-3.44.1/tooling/src/hypothesistooling/__init__.py python-hypothesis-3.71.11/tooling/src/hypothesistooling/__init__.py --- python-hypothesis-3.44.1/tooling/src/hypothesistooling/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/tooling/src/hypothesistooling/__init__.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,244 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import os +import shlex +import subprocess + + +def current_branch(): + return subprocess.check_output([ + 'git', 'rev-parse', '--abbrev-ref', 'HEAD' + ]).decode('ascii').strip() + + +def tags(): + result = [t.decode('ascii') for t in subprocess.check_output([ + 'git', 'tag' + ]).split(b'\n')] + assert len(set(result)) == len(result) + return set(result) + + +ROOT = subprocess.check_output([ + 'git', '-C', os.path.dirname(__file__), 'rev-parse', '--show-toplevel', +]).decode('ascii').strip() + + +REPO_TESTS = os.path.join(ROOT, 'whole-repo-tests') + +PYUP_FILE = os.path.join(ROOT, '.pyup.yml') + + +def hash_for_name(name): + return subprocess.check_output([ + 'git', 'rev-parse', name + ]).decode('ascii').strip() + + +def is_ancestor(a, b): + check = subprocess.call([ + 'git', 'merge-base', '--is-ancestor', a, b + ]) + assert 0 <= check <= 1 + return check == 0 + + +def merge_base(a, b): + return subprocess.check_output([ + 'git', 'merge-base', a, b, + ]).strip() + + +def point_of_divergence(): + return merge_base('HEAD', 'origin/master') + + +def has_changes(files): + return subprocess.call([ + 'git', 'diff', '--no-patch', '--exit-code', point_of_divergence(), + 'HEAD', '--', *files, + ]) != 0 + + +def has_uncommitted_changes(filename): + return subprocess.call([ + 'git', 'diff', '--exit-code', filename + ]) != 0 + + +def git(*args): + subprocess.check_call(('git',) + args) + + +def configure_git(): + git('config', 'user.name', 'Travis CI on behalf of David R. MacIver') + git('config', 'user.email', 'david@drmaciver.com') + git('config', 'core.sshCommand', 'ssh -i deploy_key') + git( + 'remote', 'add', 'ssh-origin', + 'git@github.com:HypothesisWorks/hypothesis.git' + ) + + +def create_tag(tagname): + assert tagname not in tags() + git('tag', tagname) + + +def push_tag(tagname): + assert_can_release() + subprocess.check_call([ + 'ssh-agent', 'sh', '-c', + 'ssh-add %s && ' % (shlex.quote(DEPLOY_KEY),) + + 'git push ssh-origin HEAD:master &&' + + 'git push ssh-origin %s' % (shlex.quote(tagname),) + ]) + + +def assert_can_release(): + assert not IS_PULL_REQUEST, 'Cannot release from pull requests' + assert has_travis_secrets(), 'Cannot release without travis secure vars' + + +def has_travis_secrets(): + return os.environ.get('TRAVIS_SECURE_ENV_VARS', None) == 'true' + + +def build_jobs(): + """Query the Travis API to find out what the state of the other build jobs + is. + + Note: This usage of Travis has been somewhat reverse engineered due + to a certain dearth of documentation as to what values what takes + when. + """ + import requests + + build_id = os.environ['TRAVIS_BUILD_ID'] + + url = 'https://api.travis-ci.org/builds/%s' % (build_id,) + data = requests.get(url, headers={ + 'Accept': 'application/vnd.travis-ci.2+json' + }).json() + + matrix = data['jobs'] + + jobs = {} + + for m in matrix: + name = m['config']['env'].replace('TASK=', '') + status = m['state'] + jobs.setdefault(status, []).append(name) + return jobs + + +def modified_files(): + files = set() + for command in [ + ['git', 'diff', '--name-only', '--diff-filter=d', + point_of_divergence(), 'HEAD'], + ['git', 'diff', '--name-only'] + ]: + diff_output = subprocess.check_output(command).decode('ascii') + for l in diff_output.split('\n'): + filepath = l.strip() + if filepath: + assert os.path.exists(filepath), filepath + files.add(filepath) + return files + + +def all_files(): + return [ + f for f in subprocess.check_output( + ['git', 'ls-files']).decode('ascii').splitlines() + if os.path.exists(f) + ] + + +def changed_files_from_master(): + """Returns a list of files which have changed between a branch and + master.""" + files = set() + command = ['git', 'diff', '--name-only', 'HEAD', 'master'] + diff_output = subprocess.check_output(command).decode('ascii') + for line in diff_output.splitlines(): + filepath = line.strip() + if filepath: + files.add(filepath) + return files + + +SECRETS_BASE = os.path.join(ROOT, 'secrets') +SECRETS_TAR = SECRETS_BASE + '.tar' +ENCRYPTED_SECRETS = SECRETS_TAR + '.enc' + +SECRETS = os.path.join(ROOT, 'secrets') + +DEPLOY_KEY = os.path.join(SECRETS, 'deploy_key') +PYPIRC = os.path.join(SECRETS, '.pypirc') + +RUBYGEMS_API_KEY = os.path.join(SECRETS, 'api_key.yaml') +CARGO_API_KEY = os.path.join(SECRETS, 'cargo-credentials') + + +SECRET_FILES = [ + DEPLOY_KEY, PYPIRC, RUBYGEMS_API_KEY, CARGO_API_KEY +] + + +def decrypt_secrets(): + subprocess.check_call([ + 'openssl', 'aes-256-cbc', + '-K', os.environ['encrypted_b8618e5d043b_key'], + '-iv', os.environ['encrypted_b8618e5d043b_iv'], + '-in', ENCRYPTED_SECRETS, + '-out', SECRETS_TAR, + '-d' + ]) + + subprocess.check_call(['tar', '-xvf', SECRETS_TAR], cwd=ROOT) + + missing_files = [ + os.path.basename(f) for f in SECRET_FILES if not os.path.exists(f) + ] + + assert not missing_files, missing_files + os.chmod(DEPLOY_KEY, int('0600', 8)) + + +IS_TRAVIS_PULL_REQUEST = ( + os.environ.get('TRAVIS_EVENT_TYPE') == 'pull_request' +) + +IS_CIRCLE_PULL_REQUEST = ( + os.environ.get('CIRCLE_BRANCH') == 'master' and + os.environ.get('CI_PULL_REQUESTS', '') != '' +) + + +IS_PULL_REQUEST = IS_TRAVIS_PULL_REQUEST or IS_CIRCLE_PULL_REQUEST + + +def all_projects(): + import hypothesistooling.projects.conjecturerust as cr + import hypothesistooling.projects.hypothesispython as hp + import hypothesistooling.projects.hypothesisruby as hr + return [cr, hp, hr] diff -Nru python-hypothesis-3.44.1/tooling/src/hypothesistooling/installers.py python-hypothesis-3.71.11/tooling/src/hypothesistooling/installers.py --- python-hypothesis-3.44.1/tooling/src/hypothesistooling/installers.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/tooling/src/hypothesistooling/installers.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,134 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +"""Module for obtaining various versions of Python. + +Currently this is a thin shim around pyenv, but it would be nice to have +this work on Windows as well by using Anaconda (as our build already +does). +""" + +from __future__ import division, print_function, absolute_import + +import os +import subprocess + +import hypothesistooling.scripts as scripts +from hypothesistooling import git +from hypothesistooling.junkdrawer import once + +HOME = os.environ['HOME'] + + +def __python_executable(version): + return os.path.join(scripts.SNAKEPIT, version, 'bin', 'python') + + +def python_executable(version): + ensure_python(version) + return __python_executable(version) + + +PYTHONS = set() + + +def ensure_python(version): + if version in PYTHONS: + return + scripts.run_script('ensure-python.sh', version) + target = __python_executable(version) + assert os.path.exists(target), target + PYTHONS.add(version) + + +STACK = os.path.join(HOME, '.local', 'bin', 'stack') +GHC = os.path.join(HOME, '.local', 'bin', 'ghc') +SHELLCHECK = os.path.join(HOME, '.local', 'bin', 'shellcheck') + + +def ensure_stack(): + if os.path.exists(STACK): + return + subprocess.check_call('mkdir -p ~/.local/bin', shell=True) + subprocess.check_call( + 'curl -L https://www.stackage.org/stack/linux-x86_64 ' + '| tar xz --wildcards --strip-components=1 -C $HOME' + "/.local/bin '*/stack'", shell=True + ) + + +@once +def update_stack(): + ensure_stack() + subprocess.check_call([STACK, 'update']) + + +@once +def ensure_ghc(): + if os.path.exists(GHC): + return + update_stack() + subprocess.check_call([STACK, 'setup']) + + +@once +def ensure_shellcheck(): + if os.path.exists(SHELLCHECK): + return + update_stack() + ensure_ghc() + subprocess.check_call([STACK, 'install', 'ShellCheck']) + + +@once +def ensure_rustup(): + scripts.run_script('ensure-rustup.sh') + + +RUBY_BUILD = os.path.join(scripts.RBENV_ROOT, 'plugins', 'ruby-build') + +RUBY_BIN_DIR = os.path.join(scripts.INSTALLED_RUBY_DIR, 'bin') + +BUNDLER_EXECUTABLE = os.path.join(RUBY_BIN_DIR, 'bundle') +GEM_EXECUTABLE = os.path.join(RUBY_BIN_DIR, 'gem') + +RBENV_COMMAND = os.path.join(scripts.RBENV_ROOT, 'bin', 'rbenv') + + +@once +def ensure_ruby(): + if not os.path.exists(scripts.RBENV_ROOT): + git('clone', 'https://github.com/rbenv/rbenv.git', scripts.RBENV_ROOT) + + if not os.path.exists(RUBY_BUILD): + git('clone', 'https://github.com/rbenv/ruby-build.git', RUBY_BUILD) + + if not os.path.exists( + os.path.join(scripts.RBENV_ROOT, 'versions', scripts.RBENV_VERSION) + ): + subprocess.check_call( + [RBENV_COMMAND, 'install', scripts.RBENV_VERSION]) + + if not ( + os.path.exists(BUNDLER_EXECUTABLE) and + subprocess.call([BUNDLER_EXECUTABLE, 'version']) == 0 + ): + subprocess.check_call( + [GEM_EXECUTABLE, 'install', 'bundler'] + ) + + assert os.path.exists(BUNDLER_EXECUTABLE) diff -Nru python-hypothesis-3.44.1/tooling/src/hypothesistooling/junkdrawer.py python-hypothesis-3.71.11/tooling/src/hypothesistooling/junkdrawer.py --- python-hypothesis-3.44.1/tooling/src/hypothesistooling/junkdrawer.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/tooling/src/hypothesistooling/junkdrawer.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,59 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +"""Dumping ground module for things that don't have anywhere better to go. + +See https://twitter.com/betsythemuffin/status/1003313844108824584 +""" + +from __future__ import division, print_function, absolute_import + +import os +import ast +from contextlib import contextmanager + + +@contextmanager +def in_dir(d): + prev = os.getcwd() + try: + os.chdir(d) + yield + finally: + os.chdir(prev) + + +def once(fn): + def accept(): + if accept.has_been_called: + return + fn() + accept.has_been_called = True + accept.has_been_called = False + accept.__name__ = fn.__name__ + return accept + + +def unlink_if_present(path): + try: + os.unlink(path) + except FileNotFoundError: + pass + + +def unquote_string(s): + return ast.literal_eval(s) diff -Nru python-hypothesis-3.44.1/tooling/src/hypothesistooling/__main__.py python-hypothesis-3.71.11/tooling/src/hypothesistooling/__main__.py --- python-hypothesis-3.44.1/tooling/src/hypothesistooling/__main__.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/tooling/src/hypothesistooling/__main__.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,565 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import os +import sys +import shlex +import subprocess +from glob import glob +from datetime import datetime + +import hypothesistooling as tools +import hypothesistooling.installers as install +import hypothesistooling.releasemanagement as rm +import hypothesistooling.projects.conjecturerust as cr +import hypothesistooling.projects.hypothesisruby as hr +import hypothesistooling.projects.hypothesispython as hp +from hypothesistooling import fix_doctests as fd +from hypothesistooling.scripts import pip_tool + +TASKS = {} +BUILD_FILES = tuple(os.path.join(tools.ROOT, f) for f in [ + 'tooling', '.travis.yml', +]) + + +def task(if_changed=()): + if isinstance(if_changed, str): + if_changed = (if_changed,) + + def accept(fn): + def wrapped(*args, **kwargs): + if if_changed and tools.IS_PULL_REQUEST: + if not tools.has_changes(if_changed + BUILD_FILES): + print('Skipping task due to no changes in %s' % ( + ', '.join(if_changed), + )) + return + fn(*args, **kwargs) + wrapped.__name__ = fn.__name__ + + name = fn.__name__.replace('_', '-') + + if name != '': + TASKS[name] = wrapped + + return wrapped + return accept + + +@task() +def check_installed(): + """No-op task that can be used to test for a successful install (so we + don't fail to run if a previous install failed midway).""" + + +@task() +def lint(): + pip_tool( + 'flake8', + *[f for f in tools.all_files() if f.endswith('.py')], + '--config', os.path.join(tools.ROOT, '.flake8'), + ) + + +HEAD = tools.hash_for_name('HEAD') +MASTER = tools.hash_for_name('origin/master') + + +def do_release(package): + if not package.has_release(): + print('No release for %s' % (package.__name__,)) + return + + os.chdir(package.BASE_DIR) + + print('Updating changelog and version') + package.update_changelog_and_version() + + print('Committing changes') + rm.commit_pending_release(package) + + print('Building distribution') + package.build_distribution() + + print('Looks good to release!') + + tag_name = package.tag_name() + + print('Creating tag %s' % (tag_name,)) + + tools.create_tag(tag_name) + tools.push_tag(tag_name) + + print('Uploading distribution') + package.upload_distribution() + + +@task() +def deploy(): + print('Current head: ', HEAD) + print('Current master:', MASTER) + + if not tools.is_ancestor(HEAD, MASTER): + print('Not deploying due to not being on master') + sys.exit(0) + + if not tools.has_travis_secrets(): + print('Running without access to secure variables, so no deployment') + sys.exit(0) + + print('Decrypting secrets') + tools.decrypt_secrets() + tools.configure_git() + + for project in tools.all_projects(): + do_release(project) + + sys.exit(0) + + +CURRENT_YEAR = datetime.utcnow().year + + +HEADER = """ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-%(year)s David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER""".strip() % { + 'year': CURRENT_YEAR, +} + + +@task() +def format(): + def should_format_file(path): + if os.path.basename(path) in ( + 'header.py', 'test_lambda_formatting.py' + ): + return False + if 'vendor' in path.split(os.path.sep): + return False + return path.endswith('.py') + + changed = tools.modified_files() + + format_all = os.environ.get('FORMAT_ALL', '').lower() == 'true' + if 'scripts/header.py' in changed: + # We've changed the header, so everything needs its header updated. + format_all = True + if 'requirements/tools.txt' in changed: + # We've changed the tools, which includes a lot of our formatting + # logic, so we need to rerun formatters. + format_all = True + + files = tools.all_files() if format_all else changed + + files_to_format = [f for f in sorted(files) if should_format_file(f)] + + if not files_to_format: + return + + for f in files_to_format: + print(f) + lines = [] + with open(f, encoding='utf-8') as o: + shebang = None + first = True + header_done = False + for l in o.readlines(): + if first: + first = False + if l[:2] == '#!': + shebang = l + continue + if 'END HEADER' in l and not header_done: + lines = [] + header_done = True + else: + lines.append(l) + source = ''.join(lines).strip() + with open(f, 'w', encoding='utf-8') as o: + if shebang is not None: + o.write(shebang) + o.write('\n') + o.write(HEADER) + if source: + o.write('\n\n') + o.write(source) + o.write('\n') + pip_tool( + 'isort', '-p', 'hypothesis', '-ls', '-m', '2', '-w', '75', '-a', + 'from __future__ import absolute_import, print_function, division', + *files_to_format, + ) + + pip_tool('pyformat', '-i', *files_to_format) + + +VALID_STARTS = ( + '# coding=utf-8', + '#!/usr/bin/env python', +) + + +@task() +def check_format(): + format() + n = max(map(len, VALID_STARTS)) + bad = False + for f in tools.all_files(): + if not f.endswith('.py'): + continue + with open(f, 'r', encoding='utf-8') as i: + start = i.read(n) + if not any(start.startswith(s) for s in VALID_STARTS): + print( + '%s has incorrect start %r' % (f, start), file=sys.stderr) + bad = True + if bad: + sys.exit(1) + check_not_changed() + + +def check_not_changed(): + subprocess.check_call(['git', 'diff', '--exit-code']) + + +@task() +def fix_doctests(): + fd.main() + + +@task() +def compile_requirements(upgrade=False): + if upgrade: + extra = ['--upgrade'] + else: + extra = [] + + os.chdir(tools.ROOT) + + for f in glob(os.path.join('requirements', '*.in')): + base, _ = os.path.splitext(f) + pip_tool('pip-compile', *extra, f, '--output-file', base + '.txt') + + +@task() +def upgrade_requirements(): + compile_requirements(upgrade=True) + + +def is_pyup_branch(): + return ( + os.environ['TRAVIS_EVENT_TYPE'] == 'pull_request' and + os.environ['TRAVIS_PULL_REQUEST_BRANCH'].startswith( + 'pyup-scheduled-update') + ) + + +def push_pyup_requirements_commit(): + """Because pyup updates each package individually, it can create a + requirements.txt with an incompatible set of versions. + + Depending on the changes, pyup might also have introduced + whitespace errors. + + If we've recompiled requirements.txt in Travis and made changes, + and this is a PR where pyup is running, push a consistent set of + versions as a new commit to the PR. + """ + if is_pyup_branch(): + print('Pushing new requirements, as this is a pyup pull request') + + print('Decrypting secrets') + tools.decrypt_secrets() + tools.configure_git() + + print('Creating commit') + tools.git('add', '--update', 'requirements') + tools.git( + 'commit', '-m', + 'Bump requirements for pyup pull request' + ) + + print('Pushing to GitHub') + subprocess.check_call([ + 'ssh-agent', 'sh', '-c', + 'ssh-add %s && ' % (shlex.quote(tools.DEPLOY_KEY),) + + 'git push ssh-origin HEAD:%s' % ( + os.environ['TRAVIS_PULL_REQUEST_BRANCH'], + ) + ]) + + +@task() +def check_requirements(): + if is_pyup_branch(): + compile_requirements(upgrade=True) + else: + compile_requirements(upgrade=False) + + if tools.has_uncommitted_changes('requirements'): + push_pyup_requirements_commit() + sys.exit(1) + else: + sys.exit(0) + + +@task(if_changed=hp.HYPOTHESIS_PYTHON) +def documentation(): + os.chdir(hp.HYPOTHESIS_PYTHON) + try: + if hp.has_release(): + hp.update_changelog_and_version() + pip_tool( + # See http://www.sphinx-doc.org/en/stable/man/sphinx-build.html + 'sphinx-build', '-n', '-W', '--keep-going', '-T', '-E', + '-b', 'html', 'docs', 'docs/_build/html' + ) + finally: + subprocess.check_call([ + 'git', 'checkout', 'docs/changes.rst', 'src/hypothesis/version.py' + ]) + + +def run_tox(task, version): + python = install.python_executable(version) + + # Create a version of the name that tox will pick up for the correct + # interpreter alias. + linked_version = os.path.basename(python) + ALIASES[version] + try: + os.symlink(python, linked_version) + except FileExistsError: + pass + + os.chdir(hp.HYPOTHESIS_PYTHON) + env = dict(os.environ) + python = install.python_executable(version) + + env['PATH'] = os.path.dirname(python) + ':' + env['PATH'] + print(env['PATH']) + + pip_tool('tox', '-e', task, env=env) + + +PY27 = '2.7.14' +PY34 = '3.4.8' +PY35 = '3.5.5' +PY36 = '3.6.5' +PY37 = '3.7.0' +PYPY2 = 'pypy2.7-5.10.0' +PYPY3 = 'pypy3.5-5.10.1' + + +@task() +def install_core(): + install.python_executable(PY27) + install.python_executable(PY36) + + +ALIASES = { + PYPY2: 'pypy', + PYPY3: 'pypy3', +} + +for n in [PY27, PY34, PY35, PY36, PY37]: + major, minor, patch = n.split('.') + ALIASES[n] = 'python%s.%s' % (major, minor) + + +python_tests = task(if_changed=( + hp.PYTHON_SRC, + hp.PYTHON_TESTS, + os.path.join(hp.HYPOTHESIS_PYTHON, 'scripts'), +)) + + +@python_tests +def check_py27(): + run_tox('py27-full', PY27) + + +@python_tests +def check_py34(): + run_tox('py34-full', PY34) + + +@python_tests +def check_py35(): + run_tox('py35-full', PY35) + + +@python_tests +def check_py36(): + run_tox('py36-full', PY36) + + +@python_tests +def check_py37(): + run_tox('py37-full', PY37) + + +@python_tests +def check_pypy(): + run_tox('pypy-full', PYPY2) + + +@python_tests +def check_pypy3(): + run_tox('pypy3-full', PYPY3) + + +@python_tests +def check_py27_typing(): + run_tox('py27typing', PY27) + + +@python_tests +def check_pypy_with_tracer(): + run_tox('pypy-with-tracer', PYPY2) + + +def standard_tox_task(name): + TASKS['check-' + name] = python_tests(lambda: run_tox(name, PY36)) + + +standard_tox_task('nose') +standard_tox_task('pytest30') +standard_tox_task('faker070') +standard_tox_task('faker-latest') +standard_tox_task('django21') +standard_tox_task('django20') +standard_tox_task('django111') + +for n in [19, 20, 21, 22, 23]: + standard_tox_task('pandas%d' % (n,)) + +standard_tox_task('coverage') + + +@task() +def check_quality(): + run_tox('quality', PY36) + + +examples_task = task(if_changed=(hp.PYTHON_SRC, os.path.join( + hp.HYPOTHESIS_PYTHON, 'examples') +)) + + +@examples_task +def check_examples2(): + run_tox('examples2', PY27) + + +@examples_task +def check_examples3(): + run_tox('examples2', PY36) + + +@python_tests +def check_unicode(): + run_tox('unicode', PY27) + + +@task() +def check_whole_repo_tests(): + install.ensure_shellcheck() + subprocess.check_call([ + sys.executable, '-m', 'pytest', tools.REPO_TESTS + ]) + + +@task() +def shell(): + import IPython + IPython.start_ipython([]) + + +def ruby_task(fn): + return task(if_changed=(hr.HYPOTHESIS_RUBY,))(fn) + + +@ruby_task +def lint_ruby(): + hr.rake_task('checkformat') + + +@ruby_task +def check_ruby_tests(): + hr.rake_task('test') + + +@task() +def python(*args): + os.execv(sys.executable, (sys.executable,) + args) + + +@task() +def bundle(*args): + hr.bundle(*args) + + +rust_task = task(if_changed=(cr.BASE_DIR,)) + + +@rust_task +def check_rust_tests(): + cr.cargo('test') + + +if __name__ == '__main__': + if 'SNAKEPIT' not in os.environ: + print( + 'This module should not be executed directly, but instead via ' + 'build.sh (which sets up its environment)' + ) + sys.exit(1) + + if len(sys.argv) > 1: + task_to_run = sys.argv[1] + args = sys.argv[2:] + else: + task_to_run = os.environ.get('TASK') + args = () + + if task_to_run is None: + print( + 'No task specified. Either pass the task to run as an ' + 'argument or as an environment variable TASK.') + sys.exit(1) + + try: + TASKS[task_to_run](*args) + except subprocess.CalledProcessError as e: + sys.exit(e.returncode) diff -Nru python-hypothesis-3.44.1/tooling/src/hypothesistooling/projects/conjecturerust.py python-hypothesis-3.71.11/tooling/src/hypothesistooling/projects/conjecturerust.py --- python-hypothesis-3.44.1/tooling/src/hypothesistooling/projects/conjecturerust.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/tooling/src/hypothesistooling/projects/conjecturerust.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,119 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import os +import subprocess + +import hypothesistooling as tools +import hypothesistooling.installers as install +import hypothesistooling.releasemanagement as rm +from hypothesistooling.junkdrawer import in_dir, unquote_string, \ + unlink_if_present + +PACKAGE_NAME = 'conjecture-rust' + +CONJECTURE_RUST = os.path.join(tools.ROOT, PACKAGE_NAME) + +BASE_DIR = CONJECTURE_RUST + +TAG_PREFIX = PACKAGE_NAME + '-' + +RELEASE_FILE = os.path.join(BASE_DIR, 'RELEASE.md') +CHANGELOG_FILE = os.path.join(BASE_DIR, 'CHANGELOG.md') + +CARGO_FILE = os.path.join(BASE_DIR, 'Cargo.toml') + +SRC = os.path.join(BASE_DIR, 'lib') + + +def has_release(): + """Is there a version of this package ready to release?""" + return os.path.exists(RELEASE_FILE) + + +def update_changelog_and_version(): + """Update the changelog and version based on the current release file.""" + release_type, release_contents = rm.parse_release_file(RELEASE_FILE) + version = current_version() + version_info = rm.parse_version(version) + + version, version_info = rm.bump_version_info(version_info, release_type) + + rm.replace_assignment(CARGO_FILE, 'version', repr(version)) + + rm.update_markdown_changelog( + CHANGELOG_FILE, + name='Conjecture for Rust', + version=version, + entry=release_contents, + ) + os.unlink(RELEASE_FILE) + + +def cargo(*args): + install.ensure_rustup() + with in_dir(BASE_DIR): + subprocess.check_call(('cargo',) + args) + + +IN_TEST = False + + +def build_distribution(): + """Build the crate.""" + if IN_TEST: + cargo('package', '--allow-dirty') + else: + cargo('package') + + +def tag_name(): + """The tag name for the upcoming release.""" + return TAG_PREFIX + current_version() + + +def has_source_changes(): + """Returns True if any source files have changed.""" + return tools.has_changes([SRC]) + + +def current_version(): + """Returns the current version as specified by the Cargo.toml.""" + return unquote_string(rm.extract_assignment(CARGO_FILE, 'version')) + + +CARGO_CREDENTIALS = os.path.expanduser('~/.cargo/credentials') + + +def upload_distribution(): + """Upload the built package to crates.io.""" + tools.assert_can_release() + + # Yes, cargo really will only look in this file. Yes this is terrible. + # This only runs on Travis, so we may be assumed to own it, but still. + unlink_if_present(CARGO_CREDENTIALS) + + # symlink so that the actual secret credentials can't be leaked via the + # cache. + os.symlink(tools.CARGO_API_KEY, CARGO_CREDENTIALS) + + # Give the key the right permissions. + os.chmod(CARGO_CREDENTIALS, int('0600', 8)) + + cargo('publish') diff -Nru python-hypothesis-3.44.1/tooling/src/hypothesistooling/projects/hypothesispython.py python-hypothesis-3.71.11/tooling/src/hypothesistooling/projects/hypothesispython.py --- python-hypothesis-3.44.1/tooling/src/hypothesistooling/projects/hypothesispython.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/tooling/src/hypothesistooling/projects/hypothesispython.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,192 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import os +import re +import sys +import shutil +import subprocess + +import requests + +import hypothesistooling as tools +import hypothesistooling.releasemanagement as rm + +PACKAGE_NAME = 'hypothesis-python' + +HYPOTHESIS_PYTHON = os.path.join(tools.ROOT, PACKAGE_NAME) +PYTHON_TAG_PREFIX = 'hypothesis-python-' + + +BASE_DIR = HYPOTHESIS_PYTHON + +PYTHON_SRC = os.path.join(HYPOTHESIS_PYTHON, 'src') +PYTHON_TESTS = os.path.join(HYPOTHESIS_PYTHON, 'tests') + +RELEASE_FILE = os.path.join(HYPOTHESIS_PYTHON, 'RELEASE.rst') + +assert os.path.exists(PYTHON_SRC) + + +__version__ = None +__version_info__ = None + +VERSION_FILE = os.path.join(PYTHON_SRC, 'hypothesis/version.py') + +with open(VERSION_FILE) as o: + exec(o.read()) + +assert __version__ is not None +assert __version_info__ is not None + + +def has_release(): + return os.path.exists(RELEASE_FILE) + + +def parse_release_file(): + return rm.parse_release_file(RELEASE_FILE) + + +def has_source_changes(): + return tools.has_changes([PYTHON_SRC]) + + +CHANGELOG_ANCHOR = re.compile(r"^\.\. _v\d+\.\d+\.\d+:$") +CHANGELOG_BORDER = re.compile(r"^-+$") +CHANGELOG_HEADER = re.compile(r"^\d+\.\d+\.\d+ - \d\d\d\d-\d\d-\d\d$") + + +def update_changelog_and_version(): + global __version_info__ + global __version__ + + contents = changelog() + assert '\r' not in contents + lines = contents.split('\n') + for i, l in enumerate(lines): + if CHANGELOG_ANCHOR.match(l): + assert CHANGELOG_BORDER.match(lines[i + 2]), repr(lines[i + 2]) + assert CHANGELOG_HEADER.match(lines[i + 3]), repr(lines[i + 3]) + assert CHANGELOG_BORDER.match(lines[i + 4]), repr(lines[i + 4]) + beginning = '\n'.join(lines[:i]) + rest = '\n'.join(lines[i:]) + assert '\n'.join((beginning, rest)) == contents + break + + release_type, release_contents = parse_release_file() + + new_version_string, new_version_info = rm.bump_version_info( + __version_info__, release_type) + + __version_info__ = new_version_info + __version__ = new_version_string + + rm.replace_assignment( + VERSION_FILE, '__version_info__', repr(new_version_info)) + + heading_for_new_version = ' - '.join(( + new_version_string, rm.release_date_string())) + border_for_new_version = '-' * len(heading_for_new_version) + + new_changelog_parts = [ + beginning.strip(), + '', + '.. _v%s:' % (new_version_string), + '', + border_for_new_version, + heading_for_new_version, + border_for_new_version, + '', + release_contents, + '', + rest + ] + + with open(CHANGELOG_FILE, 'w') as o: + o.write('\n'.join(new_changelog_parts)) + + +CHANGELOG_FILE = os.path.join(HYPOTHESIS_PYTHON, 'docs', 'changes.rst') +DIST = os.path.join(HYPOTHESIS_PYTHON, 'dist') + + +def changelog(): + with open(CHANGELOG_FILE) as i: + return i.read() + + +def build_distribution(): + if os.path.exists(DIST): + shutil.rmtree(DIST) + + subprocess.check_output([ + sys.executable, 'setup.py', 'sdist', '--dist-dir', DIST, + ]) + + +def upload_distribution(): + tools.assert_can_release() + subprocess.check_call([ + sys.executable, '-m', 'twine', 'upload', + '--config-file', tools.PYPIRC, + os.path.join(DIST, '*'), + ]) + # Create a GitHub release, to trigger Zenodo DOI minting. See + # https://developer.github.com/v3/repos/releases/#create-a-release + requests.post( + 'https://api.github.com/repos/HypothesisWorks/hypothesis/releases', + json=dict( + tag_name=tag_name(), + name='Hypothesis for Python - version ' + current_version(), + body=('You can [read the changelog for this release here](' + 'https://hypothesis.readthedocs.io/en/latest/changes.html#v' + '%s).' % (current_version().replace('.', '-'),)), + ), + timeout=120, # seconds + # Scoped personal access token, stored in Travis environ variable + auth=('Zac-HD', os.environ['Zac_release_token']), + ).raise_for_status() + + +def current_version(): + return __version__ + + +def latest_version(): + versions = [] + + for t in tools.tags(): + if t.startswith(PYTHON_TAG_PREFIX): + t = t[len(PYTHON_TAG_PREFIX):] + else: + continue + assert t == t.strip() + parts = t.split('.') + assert len(parts) == 3 + v = tuple(map(int, parts)) + versions.append((v, t)) + + _, latest = max(versions) + + return latest + + +def tag_name(): + return PYTHON_TAG_PREFIX + __version__ diff -Nru python-hypothesis-3.44.1/tooling/src/hypothesistooling/projects/hypothesisruby.py python-hypothesis-3.71.11/tooling/src/hypothesistooling/projects/hypothesisruby.py --- python-hypothesis-3.44.1/tooling/src/hypothesistooling/projects/hypothesisruby.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/tooling/src/hypothesistooling/projects/hypothesisruby.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,178 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import os +import subprocess +from glob import glob + +import hypothesistooling as tools +import hypothesistooling.installers as install +import hypothesistooling.releasemanagement as rm +import hypothesistooling.projects.conjecturerust as cr +from hypothesistooling.junkdrawer import once, in_dir, unlink_if_present + +PACKAGE_NAME = 'hypothesis-ruby' + +HYPOTHESIS_RUBY = os.path.join(tools.ROOT, PACKAGE_NAME) + +BASE_DIR = HYPOTHESIS_RUBY + +TAG_PREFIX = PACKAGE_NAME + '-' + +RELEASE_FILE = os.path.join(BASE_DIR, 'RELEASE.md') +CHANGELOG_FILE = os.path.join(BASE_DIR, 'CHANGELOG.md') +GEMSPEC_FILE = os.path.join(BASE_DIR, 'hypothesis-specs.gemspec') +CARGO_FILE = os.path.join(BASE_DIR, 'Cargo.toml') +GEMFILE_LOCK_FILE = os.path.join(BASE_DIR, 'Gemfile.lock') +CONJECTURE_CARGO_FILE = cr.CARGO_FILE + +RUST_SRC = os.path.join(BASE_DIR, 'src') +RUBY_SRC = os.path.join(BASE_DIR, 'lib') + + +def has_release(): + """Is there a version of this package ready to release?""" + return os.path.exists(RELEASE_FILE) + + +def parse_release_file(): + return rm.parse_release_file(RELEASE_FILE) + + +def update_changelog_and_version(): + """Update the changelog and version based on the current release file.""" + release_type, release_contents = parse_release_file() + version = current_version() + version_info = rm.parse_version(version) + + version, version_info = rm.bump_version_info(version_info, release_type) + + rm.replace_assignment(GEMSPEC_FILE, 's.version', repr(version)) + rm.replace_assignment( + GEMSPEC_FILE, 's.date', repr(rm.release_date_string()) + ) + + rm.update_markdown_changelog( + CHANGELOG_FILE, + name='Hypothesis for Ruby', + version=version, + entry=release_contents, + ) + os.unlink(RELEASE_FILE) + + +LOCAL_PATH_DEPENDENCY = "{ path = '../conjecture-rust' }" + + +def update_conjecture_dependency(dependency): + rm.replace_assignment( + CARGO_FILE, 'conjecture', + dependency + ) + + +def build_distribution(): + """Build the rubygem.""" + current_dependency = rm.extract_assignment(CARGO_FILE, 'conjecture') + + assert current_dependency == LOCAL_PATH_DEPENDENCY, ( + 'Cargo file in a bad state. Expected conjecture dependency to be %s ' + 'but it was instead %s' + ) % (LOCAL_PATH_DEPENDENCY, current_dependency) + + conjecture_version = cr.current_version() + + # Update to use latest version of conjecture-rust. + try: + update_conjecture_dependency(repr(conjecture_version)) + rake_task('gem') + finally: + update_conjecture_dependency(LOCAL_PATH_DEPENDENCY) + + +def tag_name(): + """The tag name for the upcoming release.""" + return TAG_PREFIX + current_version() + + +def has_source_changes(): + """Returns True if any source files have changed.""" + return tools.has_changes([RUST_SRC, RUBY_SRC]) or cr.has_release() + + +def current_version(): + """Returns the current version as specified by the gemspec.""" + ensure_bundler() + return subprocess.check_output([ + install.BUNDLER_EXECUTABLE, 'exec', 'ruby', '-e', + RUBY_TO_PRINT_VERSION + ]).decode('ascii').strip() + + +def bundle(*args): + ensure_bundler() + bundle_command(*args) + + +def bundle_command(*args): + with in_dir(BASE_DIR): + subprocess.check_call([ + install.BUNDLER_EXECUTABLE, *args + ]) + + +def rake_task(*args): + bundle('exec', 'rake', *args) + + +@once +def ensure_bundler(): + install.ensure_rustup() + install.ensure_ruby() + bundle_command('install') + + +RUBY_TO_PRINT_VERSION = """ +require 'rubygems' +spec = Gem::Specification::load(%r) +puts spec.version +""".strip().replace('\n', '; ') % (GEMSPEC_FILE,) + + +RUBYGEMS_CREDENTIALS = os.path.expanduser('~/.gem/credentials') + + +def upload_distribution(): + """Upload the built package to rubygems.""" + tools.assert_can_release() + + # Yes, rubygems really will only look in this file. Yes this is terrible. + # This only runs on Travis, so we may be assumed to own it, but still. + unlink_if_present(RUBYGEMS_CREDENTIALS) + + # symlink so that the actual secret credentials can't be leaked via the + # cache. + os.symlink(tools.RUBYGEMS_API_KEY, RUBYGEMS_CREDENTIALS) + + # Give the key the right permissions. + os.chmod(RUBYGEMS_CREDENTIALS, int('0600', 8)) + + subprocess.check_call([ + install.GEM_EXECUTABLE, 'push', *glob('hypothesis-specs-*.gem') + ]) diff -Nru python-hypothesis-3.44.1/tooling/src/hypothesistooling/projects/__init__.py python-hypothesis-3.71.11/tooling/src/hypothesistooling/projects/__init__.py --- python-hypothesis-3.44.1/tooling/src/hypothesistooling/projects/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/tooling/src/hypothesistooling/projects/__init__.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,16 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER diff -Nru python-hypothesis-3.44.1/tooling/src/hypothesistooling/releasemanagement.py python-hypothesis-3.71.11/tooling/src/hypothesistooling/releasemanagement.py --- python-hypothesis-3.44.1/tooling/src/hypothesistooling/releasemanagement.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/tooling/src/hypothesistooling/releasemanagement.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,196 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +"""Helpful common code for release management tasks that is shared across +multiple projects. + +Note that most code in here is brittle and specific to our build and +probably makes all sorts of undocumented assumptions, even as it looks +like a nice tidy reusable set of functionality. +""" + + +from __future__ import division, print_function, absolute_import + +import re +from datetime import datetime + +import hypothesistooling as tools + +__RELEASE_DATE_STRING = None + + +def release_date_string(): + """Returns a date string that represents what should be considered "today" + for the purposes of releasing, and ensure that we don't change part way + through a release.""" + global __RELEASE_DATE_STRING + if __RELEASE_DATE_STRING is None: + __RELEASE_DATE_STRING = datetime.utcnow().strftime('%Y-%m-%d') + return __RELEASE_DATE_STRING + + +def assignment_matcher(name): + """ + Matches a single line of the form (some space)name = (some value). e.g. + " foo = 1". + The whole line up to the assigned value is the first matching group, + the rest of the line is the second matching group. + i.e. group 1 is the assignment, group 2 is the value. In the above + example group 1 would be " foo = " and group 2 would be "1" + """ + return re.compile(r'\A(\s*%s\s*=\s*)(.+)\Z' % (re.escape(name),)) + + +def extract_assignment_from_string(contents, name): + lines = contents.split('\n') + + matcher = assignment_matcher(name) + + for i, l in enumerate(lines): + match = matcher.match(l) + if match is not None: + return match[2].strip() + + raise ValueError('Key %s not found in %s' % ( + name, contents + )) + + +def extract_assignment(filename, name): + with open(filename) as i: + return extract_assignment_from_string(i.read(), name) + + +def replace_assignment_in_string(contents, name, value): + lines = contents.split('\n') + + matcher = assignment_matcher(name) + + count = 0 + + for i, l in enumerate(lines): + match = matcher.match(l) + if match is not None: + count += 1 + lines[i] = match[1] + value + + if count == 0: + raise ValueError('Key %s not found in %s' % ( + name, contents + )) + if count > 1: + raise ValueError('Key %s found %d times in %s' % ( + name, count, contents + )) + + return '\n'.join(lines) + + +def replace_assignment(filename, name, value): + """Replaces a single assignment of the form key = value in a file with a + new value, attempting to preserve the existing format. + + This is fairly fragile - in particular it knows nothing about + the file format. The existing value is simply the rest of the line after + the last space after the equals. + """ + with open(filename) as i: + contents = i.read() + result = replace_assignment_in_string(contents, name, value) + with open(filename, 'w') as o: + o.write(result) + + +RELEASE_TYPE = re.compile(r"^RELEASE_TYPE: +(major|minor|patch)") + + +MAJOR = 'major' +MINOR = 'minor' +PATCH = 'patch' + + +VALID_RELEASE_TYPES = (MAJOR, MINOR, PATCH) + + +def parse_release_file(filename): + with open(filename) as i: + return parse_release_file_contents(i.read(), filename) + + +def parse_release_file_contents(release_contents, filename): + release_lines = [l.rstrip() for l in release_contents.split('\n')] + + m = RELEASE_TYPE.match(release_lines[0]) + if m is not None: + release_type = m.group(1) + if release_type not in VALID_RELEASE_TYPES: + raise ValueError('Unrecognised release type %r' % (release_type,)) + del release_lines[0] + release_contents = '\n'.join(release_lines).strip() + else: + raise ValueError( + '%s does not start by specifying release type. The first ' + 'line of the file should be RELEASE_TYPE: followed by one of ' + 'major, minor, or patch, to specify the type of release that ' + 'this is (i.e. which version number to increment). Instead the ' + 'first line was %r' % (filename, release_lines[0],) + ) + + return release_type, release_contents + + +def bump_version_info(version_info, release_type): + new_version = list(version_info) + bump = VALID_RELEASE_TYPES.index(release_type) + new_version[bump] += 1 + for i in range(bump + 1, len(new_version)): + new_version[i] = 0 + new_version = tuple(new_version) + new_version_string = '.'.join(map(str, new_version)) + return new_version_string, new_version + + +def update_markdown_changelog(changelog, name, version, entry): + with open(changelog) as i: + prev_contents = i.read() + + title = '# %(name)s %(version)s (%(date)s)\n\n' % { + 'name': name, 'version': version, 'date': release_date_string(), + } + + with open(changelog, 'w') as o: + o.write(title) + o.write(entry.strip()) + o.write('\n\n') + o.write(prev_contents) + + +def parse_version(version): + return tuple(map(int, version.split('.'))) + + +def commit_pending_release(project): + """Create a commit with the new release.""" + tools.git('rm', project.RELEASE_FILE) + tools.git('add', '-u', project.BASE_DIR) + + tools.git( + 'commit', '-m', + 'Bump %s version to %s and update changelog' + '\n\n[skip ci]' % (project.PACKAGE_NAME, project.current_version(),) + ) diff -Nru python-hypothesis-3.44.1/tooling/src/hypothesistooling/scripts.py python-hypothesis-3.71.11/tooling/src/hypothesistooling/scripts.py --- python-hypothesis-3.44.1/tooling/src/hypothesistooling/scripts.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/tooling/src/hypothesistooling/scripts.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,80 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import os +import re +import sys +import shlex +import subprocess + +from hypothesistooling import ROOT + + +def print_command(command, args): + args = list(args) + ranges = [] + for i, v in enumerate(args): + if os.path.exists(v): + if not ranges or ranges[-1][-1] < i - 1: + ranges.append([i, i]) + elif ranges[-1][-1] + 1 == i: + ranges[-1][-1] += 1 + for i, j in ranges: + if j > i: + args[i] = '...' + for k in range(i + 1, j + 1): + args[k] = None + args = [v for v in args if v is not None] + print(command, *map(shlex.quote, args)) + + +def run_script(script, *args, **kwargs): + print_command(script, args) + return subprocess.check_call( + [os.path.join(SCRIPTS, script), *args], **kwargs + ) + + +SCRIPTS = os.path.join(ROOT, 'tooling', 'scripts') +COMMON = os.path.join(SCRIPTS, 'common.sh') + + +def __calc_script_variables(): + exports = re.compile(r"export ([A-Z_]+)(=|$)") + + with open(COMMON) as i: + common = i.read() + + for name, _ in exports.findall(common): + globals()[name] = os.environ[name] + + +__calc_script_variables() + + +def tool_path(name): + return os.path.join(os.path.dirname(sys.executable), name) + + +def pip_tool(name, *args, **kwargs): + print_command(name, args) + r = subprocess.call([tool_path(name), *args], **kwargs) + + if r != 0: + sys.exit(r) diff -Nru python-hypothesis-3.44.1/tox.ini python-hypothesis-3.71.11/tox.ini --- python-hypothesis-3.44.1/tox.ini 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/tox.ini 1970-01-01 00:00:00.000000000 +0000 @@ -1,205 +0,0 @@ -[tox] -envlist = py{27,34,35,36,py}-{brief,prettyquick,full,custom,benchmark} -toxworkdir={env:TOX_WORK_DIR:.tox} - -passenv= - HOME - LC_ALL - COVERAGE_FILE - -setenv= - PYTHONWARNINGS={env:PYTHONWARNINGS:error::DeprecationWarning,error::FutureWarning} - -[testenv] -deps = - -rrequirements/test.txt - benchmark: pytest-benchmark==3.0.0 -whitelist_externals= - bash -setenv= - brief: HYPOTHESIS_PROFILE=speedy -passenv= - HOME - TOXENV -commands = - full: bash scripts/basic-test.sh - brief: python -m pytest tests/cover/test_testdecorators.py {posargs} - prettyquick: python -m pytest tests/cover/ - custom: python -m pytest {posargs} - benchmark: python -m pytest benchmarks - -[testenv:quality] -deps= - -rrequirements/test.txt -commands= - python -m pytest tests/quality/ - -[testenv:oldpy27] -basepython=python2.7.3 -deps= - -rrequirements/test.txt -commands= - python -m pytest tests/cover/ - -[testenv:py27typing] -basepython=python2.7 -deps= - -rrequirements/test.txt - -rrequirements/typing.txt -commands= - python -m pytest tests/cover/ - -[testenv:unicode] -basepython=python2.7 -deps = - unicode-nazi -setenv= - UNICODENAZI=true - PYTHONPATH=. -commands= - python scripts/unicodechecker.py - -[testenv:faker070] -deps = - -rrequirements/test.txt -commands = - pip install --no-binary :all: Faker==0.7.0 - python -m pytest tests/fakefactory - -[testenv:faker-latest] -deps = - -rrequirements/test.txt -commands = - pip install --no-binary :all: Faker - python -m pytest tests/fakefactory - - -[testenv:pandas18] -deps = - -rrequirements/test.txt - pandas~=0.18.1 -commands = - python -m pytest tests/pandas - -[testenv:pandas19] -deps = - -rrequirements/test.txt - pandas~=0.19.2 -commands = - python -m pytest tests/pandas - -[testenv:pandas20] -deps = - -rrequirements/test.txt - pandas~=0.20.3 -commands = - python -m pytest tests/pandas - -[testenv:pandas21] -deps = - -rrequirements/test.txt - pandas~=0.21.0 -commands = - python -m pytest tests/pandas - - -[testenv:django18] -setenv= - PYTHONWARNINGS={env:PYTHONWARNINGS:} -commands = - pip install .[pytz] - pip install django~=1.8.18 - python -m tests.django.manage test tests.django - -[testenv:django110] -setenv= - PYTHONWARNINGS={env:PYTHONWARNINGS:} -commands = - pip install .[pytz] - pip install --no-binary :all: .[fakefactory] - pip install django~=1.10.8 - python -m tests.django.manage test tests.django - -[testenv:django111] -commands = - pip install .[pytz] - pip install --no-binary :all: .[fakefactory] - pip install django~=1.11.7 - python -m tests.django.manage test tests.django - -[testenv:nose] -deps = - nose -commands= - nosetests tests/cover/test_testdecorators.py - -[testenv:pytest30] -deps = - -rrequirements/test.txt -commands= - python -m pytest tests/pytest tests/cover/test_testdecorators.py - -[testenv:pytest28] -deps = - -rrequirements/test.txt -commands= - python -m pytest tests/pytest tests/cover/test_testdecorators.py - -[testenv:docs] -deps = sphinx -commands=sphinx-build -W -b html -d docs/_build/doctrees docs docs/_build/html - - -[testenv:coverage] -deps = - -rrequirements/test.txt - -rrequirements/coverage.txt -setenv= - HYPOTHESIS_INTERNAL_COVERAGE=true -commands = - python -m coverage --version - python -m coverage debug sys - python -m coverage run --rcfile=.coveragerc -m pytest -n0 --strict tests/cover tests/datetime tests/py3 tests/numpy tests/pandas --maxfail=1 --ff {posargs} - python -m coverage report -m --fail-under=100 --show-missing - python scripts/validate_branch_check.py - - -[testenv:pure-tracer] -deps = - -rrequirements/test.txt -setenv= - HYPOTHESIS_FORCE_PURE_TRACER=true -commands = - python -m pytest tests/cover tests/nocover/test_coverage.py -n 0 {posargs} - - -[testenv:pypy-with-tracer] -setenv= - HYPOTHESIS_PROFILE=with_coverage -basepython=pypy -deps = - -rrequirements/test.txt -commands = - python -m pytest tests/cover/test_testdecorators.py tests/nocover/test_coverage.py -n 0 {posargs} - - -[testenv:examples3] -setenv= - HYPOTHESIS_STRICT_MODE=true -deps= - -rrequirements/test.txt -commands= - python -m pytest examples - - -[testenv:examples2] -setenv= - HYPOTHESIS_STRICT_MODE=true -basepython=python2.7 -deps= - -rrequirements/test.txt -commands= - python -m pytest examples - -[pytest] -addopts=--strict --tb=short -vv -p pytester --runpytest=subprocess --durations=20 -n 2 diff -Nru python-hypothesis-3.44.1/.travis.yml python-hypothesis-3.71.11/.travis.yml --- python-hypothesis-3.44.1/.travis.yml 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/.travis.yml 2018-09-24 10:46:59.000000000 +0000 @@ -14,64 +14,83 @@ cache: apt: true directories: + - $HOME/.cargo + - $HOME/.rustup - $HOME/.runtimes - $HOME/.venv + - $HOME/.gem - $HOME/.cache/pip - $HOME/wheelhouse - $HOME/.stack - $HOME/.local + - vendor/bundle env: global: - BUILD_RUNTIMES=$HOME/.runtimes - FORMAT_ALL=true - matrix: - # Core tests that we want to run first. - - TASK=check-pyup-yml - - TASK=check-release-file - - TASK=check-shellcheck - - TASK=documentation - - TASK=lint - - TASK=doctest - - TASK=check-rst - - TASK=check-format - - TASK=check-benchmark - - TASK=check-coverage - - TASK=check-requirements - - TASK=check-pypy - - TASK=check-py27 - - TASK=check-py36 - - TASK=check-quality - - # Less important tests that will probably - # pass whenever the above do but are still - # worth testing. - - TASK=check-unicode - - TASK=check-ancient-pip - - TASK=check-pure-tracer - - TASK=check-py273 - - TASK=check-py27-typing - - TASK=check-py34 - - TASK=check-py35 - - TASK=check-nose - - TASK=check-pytest28 - - TASK=check-faker070 - - TASK=check-faker-latest - - TASK=check-django18 - - TASK=check-django110 - - TASK=check-django111 - - TASK=check-pandas19 - - TASK=check-pandas20 - - TASK=check-pandas21 - - TASK=deploy +jobs: + include: + # Prechecks that we want to run first. + - stage: precheck + env: TASK=check-whole-repo-tests + - env: TASK=documentation + - env: TASK=lint + - env: TASK=lint-ruby + - env: TASK=check-format + - env: TASK=check-requirements + - env: TASK=check-rust-tests + + - stage: main + env: TASK=check-coverage + - env: TASK=check-pypy + - env: TASK=check-pypy3 + - env: TASK=check-py36 + - env: TASK=check-py27 + - env: TASK=check-ruby-tests + - env: TASK=check-quality + - env: TASK=check-py34 + - env: TASK=check-py35 + - env: TASK=check-py37 + sudo: required + dist: xenial + + # Less important tests that will probably + # pass whenever the above do but are still + # worth testing. + - stage: extras + env: TASK=check-unicode + - env: TASK=check-py27-typing + - env: TASK=check-nose + - env: TASK=check-pytest30 + - env: TASK=check-faker070 + - env: TASK=check-faker-latest + - env: TASK=check-django21 + - env: TASK=check-django20 + - env: TASK=check-django111 + - env: TASK=check-pandas19 + - env: TASK=check-pandas20 + - env: TASK=check-pandas21 + - env: TASK=check-pandas22 + - env: TASK=check-pandas23 + + - stage: deploy + env: TASK=deploy script: - - python scripts/run_travis_make_task.py + - ./build.sh matrix: fast_finish: true +stages: + - precheck + - main + - extras + - name: deploy + if: type = push + notifications: email: recipients: diff -Nru python-hypothesis-3.44.1/Vagrantfile python-hypothesis-3.71.11/Vagrantfile --- python-hypothesis-3.44.1/Vagrantfile 2017-12-17 23:37:13.000000000 +0000 +++ python-hypothesis-3.71.11/Vagrantfile 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -# -*- mode: ruby -*- -# vi: set ft=ruby : - -# This is a trivial Vagrantfile designed to simplify development of Hypothesis on Windows, -# where the normal make based build system doesn't work, or anywhere else where you would -# prefer a clean environment for Hypothesis development. It doesn't do anything more than spin -# up a suitable local VM for use with vagrant ssh. You should then use the Makefile from within -# that VM. - -PROVISION = <> $HOME/.bashrc -fi - -cd /vagrant/ - -make install-tools - -PROVISION - -Vagrant.configure(2) do |config| - - config.vm.provider "virtualbox" do |v| - v.memory = 1024 - end - - config.vm.box = "ubuntu/trusty64" - - config.vm.provision "shell", inline: PROVISION, privileged: false -end diff -Nru python-hypothesis-3.44.1/whole-repo-tests/test_deploy.py python-hypothesis-3.71.11/whole-repo-tests/test_deploy.py --- python-hypothesis-3.44.1/whole-repo-tests/test_deploy.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/whole-repo-tests/test_deploy.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,51 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import os + +import pytest + +import hypothesistooling as tools +import hypothesistooling.__main__ as main +import hypothesistooling.releasemanagement as rm + + +@pytest.mark.parametrize('project', [ + p for p in tools.all_projects() if p.has_release() +]) +def test_release_file_exists_and_is_valid(project, monkeypatch): + assert not tools.has_uncommitted_changes(project.BASE_DIR) + + monkeypatch.setattr(tools, 'create_tag', lambda *args, **kwargs: None) + monkeypatch.setattr(tools, 'push_tag', lambda name: None) + monkeypatch.setattr(rm, 'commit_pending_release', lambda p: None) + monkeypatch.setattr(project, 'upload_distribution', lambda: None) + monkeypatch.setattr(project, 'IN_TEST', True, raising=False) + + try: + main.do_release(project) + + with open(project.CHANGELOG_FILE) as i: + changelog = i.read() + assert project.current_version() in changelog + assert rm.release_date_string() in changelog + + finally: + tools.git('checkout', project.BASE_DIR) + os.chdir(tools.ROOT) diff -Nru python-hypothesis-3.44.1/whole-repo-tests/test_doctests.py python-hypothesis-3.71.11/whole-repo-tests/test_doctests.py --- python-hypothesis-3.44.1/whole-repo-tests/test_doctests.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/whole-repo-tests/test_doctests.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,33 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import os + +from hypothesistooling.scripts import pip_tool +from hypothesistooling.projects.hypothesispython import BASE_DIR + + +def test_doctests(): + env = dict(os.environ) + env['PYTHONPATH'] = 'src' + + pip_tool( + 'sphinx-build', '-W', '-b', 'doctest', '-d', 'docs/_build/doctrees', + 'docs', 'docs/_build/html', env=env, cwd=BASE_DIR, + ) diff -Nru python-hypothesis-3.44.1/whole-repo-tests/test_pyup_yml.py python-hypothesis-3.71.11/whole-repo-tests/test_pyup_yml.py --- python-hypothesis-3.44.1/whole-repo-tests/test_pyup_yml.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/whole-repo-tests/test_pyup_yml.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,33 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import yaml +from pyup.config import Config + +import hypothesistooling as tools + + +def test_pyup_yml_is_valid(): + with open(tools.PYUP_FILE, 'r') as i: + data = yaml.safe_load(i.read()) + config = Config() + config.update_config(data) + + assert config.is_valid_schedule(), \ + 'Schedule %r is invalid' % (config.schedule,) diff -Nru python-hypothesis-3.44.1/whole-repo-tests/test_release_files.py python-hypothesis-3.71.11/whole-repo-tests/test_release_files.py --- python-hypothesis-3.44.1/whole-repo-tests/test_release_files.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/whole-repo-tests/test_release_files.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,32 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import pytest + +import hypothesistooling as tools +import hypothesistooling.releasemanagement as rm + + +@pytest.mark.parametrize('project', tools.all_projects()) +def test_release_file_exists_and_is_valid(project): + if project.has_source_changes(): + assert project.has_release(), \ + 'There are source changes but no RELEASE.rst. Please create ' \ + 'one to describe your changes.' + rm.parse_release_file(project.RELEASE_FILE) diff -Nru python-hypothesis-3.44.1/whole-repo-tests/test_release_management.py python-hypothesis-3.71.11/whole-repo-tests/test_release_management.py --- python-hypothesis-3.44.1/whole-repo-tests/test_release_management.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/whole-repo-tests/test_release_management.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,105 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import pytest + +from hypothesistooling.releasemanagement import bump_version_info, \ + release_date_string, update_markdown_changelog, \ + parse_release_file_contents +from hypothesistooling.releasemanagement import \ + replace_assignment_in_string as replace + + +def parse_release(contents): + return parse_release_file_contents(contents, '') + + +def test_update_single_line(): + assert replace('a = 1', 'a', '2') == 'a = 2' + + +def test_update_without_spaces(): + assert replace('a=1', 'a', '2') == 'a=2' + + +def test_update_in_middle(): + assert replace('a = 1\nb=2\nc = 3', 'b', '4') == 'a = 1\nb=4\nc = 3' + + +def test_quotes_string_to_assign(): + assert replace('a.c = 1', 'a.c', '2') == 'a.c = 2' + with pytest.raises(ValueError): + replace('abc = 1', 'a.c', '2') + + +def test_duplicates_are_errors(): + with pytest.raises(ValueError): + replace('a = 1\na=1', 'a', '2') + + +def test_missing_is_error(): + with pytest.raises(ValueError): + replace('', 'a', '1') + + +def test_bump_minor_version(): + assert bump_version_info((1, 1, 1), 'minor')[0] == '1.2.0' + + +def test_parse_release_file(): + assert parse_release('RELEASE_TYPE: patch\nhi') == ('patch', 'hi') + assert parse_release('RELEASE_TYPE: minor\n\n\n\nhi') == \ + ('minor', 'hi') + assert parse_release('RELEASE_TYPE: major\n \n\nhi') == \ + ('major', 'hi') + + +def test_invalid_release(): + with pytest.raises(ValueError): + parse_release('RELEASE_TYPE: wrong\nstuff') + + with pytest.raises(ValueError): + parse_release('') + + +TEST_CHANGELOG = """ +# A test project 1.2.3 (%s) + +some stuff happened + +# some previous log entry +""" % (release_date_string(),) + + +def test_update_changelog(tmpdir): + path = tmpdir.join('CHANGELOG.md') + path.write('# some previous log entry\n') + update_markdown_changelog( + str(path), 'A test project', '1.2.3', 'some stuff happened' + ) + assert path.read().strip() == TEST_CHANGELOG.strip() + + +def test_changelog_parsing_strips_trailing_whitespace(): + header = 'RELEASE_TYPE: patch\n\n' + contents = 'Adds a feature\n indented.\n' + level, out = parse_release( + header + contents.replace('feature', 'feature ') + ) + assert contents.strip() == out diff -Nru python-hypothesis-3.44.1/whole-repo-tests/test_rst_is_valid.py python-hypothesis-3.71.11/whole-repo-tests/test_rst_is_valid.py --- python-hypothesis-3.44.1/whole-repo-tests/test_rst_is_valid.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/whole-repo-tests/test_rst_is_valid.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,43 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import os + +import hypothesistooling as tools +import hypothesistooling.projects.hypothesispython as hp +from hypothesistooling.scripts import pip_tool + + +def is_sphinx(f): + f = os.path.abspath(f) + return f.startswith(os.path.join(hp.HYPOTHESIS_PYTHON, 'docs')) + + +ALL_RST = [ + f for f in tools.all_files() + if os.path.basename(f) != 'RELEASE.rst' and f.endswith('.rst') +] + + +def test_passes_rst_lint(): + pip_tool('rst-lint', *[f for f in ALL_RST if not is_sphinx(f)]) + + +def test_passes_flake8(): + pip_tool('flake8', '--select=W191,W291,W292,W293,W391', *ALL_RST) diff -Nru python-hypothesis-3.44.1/whole-repo-tests/test_secrets.py python-hypothesis-3.71.11/whole-repo-tests/test_secrets.py --- python-hypothesis-3.44.1/whole-repo-tests/test_secrets.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/whole-repo-tests/test_secrets.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,34 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import os + +import pytest + +import hypothesistooling as tools + + +@pytest.mark.skipif( + os.environ.get('TRAVIS_SECURE_ENV_VARS', None) != 'true', + reason='Not running in an environment with travis secure vars' +) +def test_can_descrypt_secrets(): + tools.decrypt_secrets() + + assert os.path.exists(tools.DEPLOY_KEY) diff -Nru python-hypothesis-3.44.1/whole-repo-tests/test_security.py python-hypothesis-3.71.11/whole-repo-tests/test_security.py --- python-hypothesis-3.44.1/whole-repo-tests/test_security.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/whole-repo-tests/test_security.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,27 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +from hypothesistooling.scripts import pip_tool +from hypothesistooling.projects.hypothesispython import PYTHON_SRC + + +def test_bandit_passes_on_hypothesis(): + # pypi.org/project/bandit has the table of error codes, or `bandit --help` + pip_tool('bandit', '--skip', 'B101,B102,B110,B303,B311', + '--recursive', PYTHON_SRC) diff -Nru python-hypothesis-3.44.1/whole-repo-tests/test_shellcheck.py python-hypothesis-3.71.11/whole-repo-tests/test_shellcheck.py --- python-hypothesis-3.44.1/whole-repo-tests/test_shellcheck.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/whole-repo-tests/test_shellcheck.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,32 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import subprocess + +import hypothesistooling as tools +import hypothesistooling.installers as install + +SCRIPTS = [ + f for f in tools.all_files() + if f.endswith('.sh') +] + + +def test_all_shell_scripts_are_valid(): + subprocess.check_call([install.SHELLCHECK, *SCRIPTS], cwd=tools.ROOT) diff -Nru python-hypothesis-3.44.1/whole-repo-tests/test_type_hints.py python-hypothesis-3.71.11/whole-repo-tests/test_type_hints.py --- python-hypothesis-3.44.1/whole-repo-tests/test_type_hints.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/whole-repo-tests/test_type_hints.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,74 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import os +import subprocess + +import pytest + +from hypothesistooling.scripts import pip_tool, tool_path +from hypothesistooling.projects.hypothesispython import PYTHON_SRC + + +def test_mypy_passes_on_hypothesis(): + pip_tool('mypy', PYTHON_SRC) + + +def get_mypy_analysed_type(fname, val): + out = subprocess.Popen( + [tool_path('mypy'), fname], + stdout=subprocess.PIPE, encoding='utf-8', universal_newlines=True, + # We set the MYPYPATH explicitly, because PEP561 discovery wasn't + # working in CI as of mypy==0.600 - hopefully a temporary workaround. + env=dict(os.environ, MYPYPATH=PYTHON_SRC), + ).stdout.read() + assert len(out.splitlines()) == 1 + # See https://mypy.readthedocs.io/en/latest/common_issues.html#reveal-type + # The shell output for `reveal_type([1, 2, 3])` looks like a literal: + # file.py:2: error: Revealed type is 'builtins.list[builtins.int*]' + typ = out.split('error: Revealed type is ')[1].strip().strip("'") + qualname = 'hypothesis.searchstrategy.strategies.SearchStrategy' + assert typ.startswith(qualname) + return typ[len(qualname) + 1:-1].replace('builtins.', '').replace('*', '') + + +@pytest.mark.parametrize('val,expect', [ + ('integers()', 'int'), + ('text()', 'str'), + ('integers().map(str)', 'str'), + ('booleans().filter(bool)', 'bool'), + ('lists(none())', 'list[None]'), + ('dictionaries(integers(), datetimes())', 'dict[int, datetime.datetime]'), + # Ex`-1 stands for recursion in the whole type, i.e. Ex`0 == Union[...] + ('recursive(integers(), lists)', 'Union[list[Ex`-1], int]'), + # See https://github.com/python/mypy/issues/5269 - fix the hints on + # `one_of` and document the minimum Mypy version when the issue is fixed. + ('one_of(integers(), text())', 'Any'), +]) +def test_revealed_types(tmpdir, val, expect): + """Check that Mypy picks up the expected `X` in SearchStrategy[`X`].""" + f = tmpdir.join(expect + '.py') + f.write( + 'from hypothesis.strategies import *\n' + 's = {}\n' + 'reveal_type(s)\n' + .format(val) + ) + got = get_mypy_analysed_type(str(f.realpath()), val) + assert got == expect diff -Nru python-hypothesis-3.44.1/whole-repo-tests/test_version_sync.py python-hypothesis-3.71.11/whole-repo-tests/test_version_sync.py --- python-hypothesis-3.44.1/whole-repo-tests/test_version_sync.py 1970-01-01 00:00:00.000000000 +0000 +++ python-hypothesis-3.71.11/whole-repo-tests/test_version_sync.py 2018-09-24 10:46:59.000000000 +0000 @@ -0,0 +1,32 @@ +# coding=utf-8 +# +# This file is part of Hypothesis, which may be found at +# https://github.com/HypothesisWorks/hypothesis-python +# +# Most of this work is copyright (C) 2013-2018 David R. MacIver +# (david@drmaciver.com), but it contains contributions by others. See +# CONTRIBUTING.rst for a full list of people who may hold copyright, and +# consult the git log if you need to determine who owns an individual +# contribution. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# END HEADER + +from __future__ import division, print_function, absolute_import + +import toml + +from hypothesistooling.projects.hypothesisruby import CARGO_FILE, \ + GEMFILE_LOCK_FILE + + +def test_helix_version_sync(): + cargo = toml.load(CARGO_FILE) + helix_version = cargo['dependencies']['helix'] + gem_lock = open(GEMFILE_LOCK_FILE).read() + assert 'helix_runtime (%s)' % (helix_version,) in gem_lock, \ + 'helix version must be the same in %s and %s' % \ + (CARGO_FILE, GEMFILE_LOCK_FILE)