mirror of
https://github.com/kennethreitz/heroku-buildpack-python.git
synced 2026-06-05 23:10:16 +00:00
Compare commits
1198 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3b2c0b5df9 | |||
| 49b9eaa93e | |||
| 677dfeec11 | |||
| c77a1877d3 | |||
| 1c51f5d84e | |||
| 6922a82536 | |||
| 9cc5bf1a85 | |||
| 012cb8a4df | |||
| fab60ae6ab | |||
| cd52da6155 | |||
| acd9347930 | |||
| d7e2f0fb08 | |||
| a3ed9c7155 | |||
| 8db1f07fba | |||
| 17081d0328 | |||
| 9a6fa0478a | |||
| 573ded6d41 | |||
| b4ec35433a | |||
| cf1148f0a8 | |||
| a0649b1e50 | |||
| 2f2fd24421 | |||
| f754ae16bb | |||
| cef1be80a5 | |||
| c0571d86bf | |||
| d82eddca03 | |||
| 119e8145c3 | |||
| 99dae0f671 | |||
| f54dfff8a9 | |||
| c9760ae0ee | |||
| 98ff1670b3 | |||
| bdd466f838 | |||
| 324ebc9223 | |||
| 42ec6d8701 | |||
| 19513067bb | |||
| 753c912ecc | |||
| 4e8c469ec7 | |||
| 852723f867 | |||
| 94514a8179 | |||
| 7d57744c0a | |||
| a41ddf6bd1 | |||
| 197b7bae3f | |||
| f468739cfb | |||
| 555d5bd2be | |||
| 0a4d32c8a5 | |||
| 1a1cedfc21 | |||
| d35ee2c14c | |||
| 554a8bbae6 | |||
| 6572ad3d44 | |||
| 35cabaeebc | |||
| 300285a92d | |||
| 7a6f1eb010 | |||
| 66d754978e | |||
| 9c222a9350 | |||
| 7f4273f47f | |||
| dd707c21e3 | |||
| 7833743f96 | |||
| 5a9155e311 | |||
| 857c47ad66 | |||
| 87cf6073dc | |||
| 36dd089808 | |||
| c58f52e06e | |||
| 265a95d3b6 | |||
| 290c1377fb | |||
| 8e42040d01 | |||
| d8755e6791 | |||
| 364a1fafd9 | |||
| 251b7f7960 | |||
| 6d491f9f2b | |||
| 7cfbce82fd | |||
| d520ca4291 | |||
| bf252422fc | |||
| d7874d583b | |||
| d32dc82e1c | |||
| bd048d50b5 | |||
| 26b2eeee20 | |||
| e527457ba3 | |||
| 1b7bd02bf2 | |||
| de9b0b9383 | |||
| 991f4126d7 | |||
| 076a457ad9 | |||
| 264f74d159 | |||
| 9f89c4e744 | |||
| 8d2788094b | |||
| e2f4fd442a | |||
| 1bccc03b30 | |||
| adac27fa9c | |||
| d1c30fd24b | |||
| a1cfa41cb2 | |||
| 57e9bb0054 | |||
| 8e34179b1c | |||
| c03cb26961 | |||
| 127ff904d6 | |||
| 6c53bd1cd6 | |||
| d8307c29ba | |||
| f526673903 | |||
| 85f10b7d59 | |||
| bbbadc83e4 | |||
| 9c2b033042 | |||
| e427d5111e | |||
| ab724138c1 | |||
| e36b580615 | |||
| f8a1761165 | |||
| 521bb00247 | |||
| 5cd4245412 | |||
| 40daa84ccc | |||
| f0ea766900 | |||
| 89125df805 | |||
| 83ee7d90d7 | |||
| bb87f5ed56 | |||
| 424e1c351d | |||
| 83bde7ccea | |||
| 7fab8ce2c2 | |||
| d4326fad0f | |||
| a0d4da00e6 | |||
| f72c34a5dd | |||
| 2bc41d20b8 | |||
| 3cce589cec | |||
| 70758edd49 | |||
| ba7a9cd565 | |||
| 37a7afbe2d | |||
| b0138c26e6 | |||
| d653377faf | |||
| 0b87419166 | |||
| d832b7425e | |||
| 2991dce623 | |||
| 28b67dd208 | |||
| 24f73fbc2d | |||
| ffd0bb57ee | |||
| 75870dd412 | |||
| 831d73e302 | |||
| 0cf2e2849d | |||
| 6ba8d47927 | |||
| af940b5390 | |||
| 819bc2da5b | |||
| 2dad2e73f3 | |||
| e550b32ea8 | |||
| 6af8d81086 | |||
| 0ed4089cb9 | |||
| f09191ec8b | |||
| aef7b65b95 | |||
| 5438aab121 | |||
| a259143c0b | |||
| 0896d6a0c4 | |||
| 39f2efe296 | |||
| d047f26ad4 | |||
| 998f996a32 | |||
| c620980e5a | |||
| 2983fcfbea | |||
| e3511e7202 | |||
| 692f040618 | |||
| 8645a965aa | |||
| 3a483865e8 | |||
| 6ea6a0ccaf | |||
| 6bc94eaf6e | |||
| 49e409cb64 | |||
| 2693de45c7 | |||
| 88f711b6e7 | |||
| a7976fc177 | |||
| 8a837a23e7 | |||
| f37597ad9d | |||
| 928a664544 | |||
| 9fb715ef1c | |||
| 3cff2e39fe | |||
| 653a5be104 | |||
| 67ade52e95 | |||
| ab3e365ff6 | |||
| 902672e934 | |||
| 6207b3506b | |||
| 5446d448fd | |||
| 366def6c16 | |||
| a84fc7a248 | |||
| e4aa40216b | |||
| 87d03e62d7 | |||
| 92b4f5e8aa | |||
| 19cd447b83 | |||
| 570182b6b7 | |||
| 0a6ed0de43 | |||
| 0b7a1fc14e | |||
| 2c69e3b98f | |||
| 86f43fa02a | |||
| 03b95247c3 | |||
| 0e8a11b836 | |||
| 4c9de740d2 | |||
| 9b45baa41c | |||
| ecfaeb2fd2 | |||
| cef0b1703a | |||
| 18317ef606 | |||
| 4896396a51 | |||
| be4f207aac | |||
| af15be61b8 | |||
| 39d64c5fd1 | |||
| 645cf5e338 | |||
| 7430c48b72 | |||
| 783d9e4b12 | |||
| eab957c8c9 | |||
| 6e80c391a8 | |||
| 58bae65a28 | |||
| 70d8c7a625 | |||
| 66611ca21a | |||
| 20fe371ac7 | |||
| d23143b801 | |||
| c98615cdd0 | |||
| 0749a04773 | |||
| a4f072714d | |||
| 427ec9e431 | |||
| 168939d14f | |||
| 58ecbd8a73 | |||
| 10eb361975 | |||
| 1242d71382 | |||
| 6ef93693c5 | |||
| 69b8b25322 | |||
| b706cd13f7 | |||
| 724e51b5c7 | |||
| 7b4835a98e | |||
| 477773b331 | |||
| c98c481f24 | |||
| 462fe074f9 | |||
| 70bfc5eab3 | |||
| a4d2592438 | |||
| 8306f84236 | |||
| 6952a2e728 | |||
| 7142c747f4 | |||
| 11db8e126a | |||
| 6f1fce3cdb | |||
| b2e12f9ec8 | |||
| 44f8e393d6 | |||
| b8cbc64d20 | |||
| 5d51be5679 | |||
| d550b8cd15 | |||
| 25b28af19d | |||
| dbe2cdac37 | |||
| 767af30453 | |||
| df02e34a5b | |||
| 26c918863e | |||
| 1c458cee2e | |||
| 433570c27b | |||
| 30cb4ecef3 | |||
| 84e2a51337 | |||
| f1c2bc39d2 | |||
| ad53dc61f0 | |||
| 8598296756 | |||
| f5ef10326e | |||
| 16ec3c8325 | |||
| 49676e12af | |||
| 0aa123995b | |||
| cd4d811d4f | |||
| 76ebf9279b | |||
| 3c3e621040 | |||
| 40e91ffa67 | |||
| 72710696a0 | |||
| d27228999d | |||
| a4e8ba3cdf | |||
| e27b5656fd | |||
| f132d3198a | |||
| 6afd6bbce9 | |||
| 6fa14b55d3 | |||
| 8f4eb44d36 | |||
| 67f4c4238a | |||
| ffb89feb0d | |||
| 45b00e32a7 | |||
| 90edd88b22 | |||
| 2533cc68c1 | |||
| a11a765b93 | |||
| 6505f98bae | |||
| eb3e7851f7 | |||
| 78b6142d18 | |||
| af58f322e2 | |||
| e4bcc68c9a | |||
| 9a024b8595 | |||
| 581177b219 | |||
| 669f0b0e2a | |||
| e5ac89c4df | |||
| 1e8ad56b0f | |||
| b6607f0f42 | |||
| 8615bf5272 | |||
| 7f475977b5 | |||
| 53eee452eb | |||
| 031c9d576f | |||
| b0568b5f90 | |||
| 359a3b0d61 | |||
| d46e0efc16 | |||
| b97a104ad6 | |||
| a2ee94a8fb | |||
| 3b35c2c296 | |||
| 97834d305a | |||
| 86a53e6479 | |||
| 8c746e3e17 | |||
| b1d1a7cca5 | |||
| f172a83d48 | |||
| 4346b41c70 | |||
| 195ed4ae15 | |||
| e4fee65430 | |||
| 4f10a7e14a | |||
| a637ec3d11 | |||
| 1dd7be4250 | |||
| c2b9121436 | |||
| 567120b4bc | |||
| b61a395cd0 | |||
| 2a3962aea7 | |||
| 364ddc98b7 | |||
| d93d283be2 | |||
| 42141c2bf9 | |||
| d82c898509 | |||
| 6545d71b46 | |||
| 93b707eae5 | |||
| 8d358218f8 | |||
| b84b168be8 | |||
| 35c810e46d | |||
| e1ea2f9354 | |||
| 7db6ea33ac | |||
| a53826a673 | |||
| b7ecb49a96 | |||
| 911140b3ac | |||
| f1c4efb464 | |||
| 5a979874ad | |||
| a32ca25520 | |||
| e304089c3e | |||
| 5d8932e5ee | |||
| 7770ab8ff2 | |||
| 277294817a | |||
| 25b17d51c3 | |||
| ac103519f8 | |||
| e8b8af045f | |||
| 0bb6d6e2bd | |||
| 0184dcac24 | |||
| 558e748e9e | |||
| dec86fbc2e | |||
| ddc310084b | |||
| 2a6053ec2c | |||
| 86e0e29a41 | |||
| bc754f402b | |||
| ea5bc23a76 | |||
| 46ecf15337 | |||
| d020d20bde | |||
| 01ff4269f2 | |||
| f507bb0c05 | |||
| 9179b3cac0 | |||
| 5be33758ed | |||
| 41a44272d2 | |||
| 6b3f63252f | |||
| c9acc4154b | |||
| d5fed79e86 | |||
| 05edd6b065 | |||
| d96914ab2e | |||
| 4c4e192317 | |||
| 2963d2520b | |||
| 85686805a7 | |||
| eef41088b1 | |||
| f7387427c8 | |||
| 23e1164c93 | |||
| fd4ab23f50 | |||
| c78bf77055 | |||
| 5e212e4db8 | |||
| 9f666cee79 | |||
| 69e9368c2d | |||
| 4513dd7522 | |||
| 8b3e99adb3 | |||
| c5972cdb74 | |||
| 7b9bc848ee | |||
| 921a4c31a8 | |||
| 67063fc34f | |||
| 21dd1782fa | |||
| beb8c70585 | |||
| b46cc0c6da | |||
| 74af94132a | |||
| 24cc273800 | |||
| c0fbb0723a | |||
| 6ab397db10 | |||
| d8623ae454 | |||
| e6d395fa27 | |||
| e77090b6b8 | |||
| c61f907079 | |||
| bd90eecd8c | |||
| 44b2ef0c4e | |||
| 38d73effc1 | |||
| 6f6b75bb1f | |||
| cd90c7d1d8 | |||
| ce3c68538d | |||
| b6adf5223b | |||
| 0818d5428f | |||
| 1d8afb452e | |||
| 1c82d820c9 | |||
| 7cf8712d3c | |||
| 2b62692ab2 | |||
| 9188d94723 | |||
| 2ba3e06f4e | |||
| 6d78f7e3ed | |||
| 1e5ff1f8c9 | |||
| 83538ca6ec | |||
| 619bd638b0 | |||
| 5c359ba0fa | |||
| 27f019105e | |||
| eb572b5ab4 | |||
| 67c3d38a03 | |||
| 8f4ca7f624 | |||
| ce3bdb37ba | |||
| a91e9c2fc1 | |||
| da96cdf21e | |||
| 0b2e4e9b22 | |||
| 129ce5f0df | |||
| 25f7421573 | |||
| 8c654b658c | |||
| ed3691a0aa | |||
| ded2c5156a | |||
| 7c3a6303d1 | |||
| 591ed6b150 | |||
| c1c4f50ef6 | |||
| 2b29e7efeb | |||
| 9f089b18e6 | |||
| 9a1e43b8f2 | |||
| ac1ba4271c | |||
| af77d9baf8 | |||
| 706e6bab4f | |||
| b6fff224dd | |||
| 61d3d9580d | |||
| 69b88cb075 | |||
| a00133892d | |||
| 5eb337b80d | |||
| d6212b46ce | |||
| 3558766ae8 | |||
| 34f4dc43d6 | |||
| 0024336558 | |||
| c60c5321df | |||
| 0ba69875f5 | |||
| c8812c7e15 | |||
| 7d4093795b | |||
| 628ad0cb8b | |||
| 77ddd7c8a6 | |||
| c53d54f203 | |||
| ed6fe287c4 | |||
| 4f5a88a05a | |||
| 347c0eba81 | |||
| 14b482603e | |||
| 58ce002d35 | |||
| 7fd3a047fd | |||
| 26b4bfbab6 | |||
| 9e00de4e56 | |||
| afa8a0f75f | |||
| 52b8ae82b8 | |||
| e6c339ebae | |||
| 3ea0735768 | |||
| 54b930bba3 | |||
| bf202224b7 | |||
| cead16eb57 | |||
| 5c91c81968 | |||
| 42594a47c1 | |||
| 9d20adca1a | |||
| 181c09cfb7 | |||
| 770947d6e6 | |||
| 0a78bd001e | |||
| 5a1ece3955 | |||
| 8266b99d1e | |||
| e27470778c | |||
| 8ef4a006e0 | |||
| 4fdaf14ded | |||
| f1da8d4b5c | |||
| eb9689c0a2 | |||
| 6fe7c6bde0 | |||
| a1b372ac66 | |||
| ddead6457a | |||
| 92b4385890 | |||
| 7074d5cb50 | |||
| 2b1f1182c3 | |||
| 38fc8f4fe7 | |||
| a203495532 | |||
| 33a69d7f52 | |||
| fe3f12c430 | |||
| aeb1a297d3 | |||
| 4c1972c0b9 | |||
| 74f0f319dc | |||
| 683bba59d7 | |||
| f890cdb889 | |||
| b3a98641f5 | |||
| ecbcfff5cb | |||
| 085d295342 | |||
| e842703721 | |||
| c229070c21 | |||
| 67867f1083 | |||
| 91b76c4ca9 | |||
| d2b82441fe | |||
| 532b36f5f7 | |||
| abe34011e5 | |||
| 4b57be0ae1 | |||
| d8a75c56d0 | |||
| 27ce818f3d | |||
| f582b2f4fa | |||
| c46a779ea1 | |||
| 06a7d9e187 | |||
| ca773cf957 | |||
| 26b54b690c | |||
| 871d5b5935 | |||
| 0382c31225 | |||
| 4a856ff5b3 | |||
| e247704dfb | |||
| c8b031fafc | |||
| 68b740cce6 | |||
| e856e787aa | |||
| 7e4159e297 | |||
| d9a73b847e | |||
| 3dbeec8db1 | |||
| 8ec0b5f0dd | |||
| 3c2839147f | |||
| a51c162444 | |||
| 14096e0ca5 | |||
| 2631f5204b | |||
| f3b1e54df4 | |||
| 536b10b249 | |||
| b22aa3b3a7 | |||
| eb395a94f9 | |||
| b2597c45d8 | |||
| 1525c1fb3a | |||
| fd17f5a470 | |||
| ac923205d0 | |||
| 6617a3cac5 | |||
| 64a4f51e1b | |||
| 6305ed415a | |||
| 3dff0d48fe | |||
| 6f94b366f8 | |||
| 6bb89e6693 | |||
| 6252e80aa6 | |||
| b22ef82b4f | |||
| 129bced2dd | |||
| c82415733d | |||
| ee93719b79 | |||
| 361eb53257 | |||
| bf9fe3badf | |||
| 9178962b84 | |||
| 2b4a68c8c8 | |||
| f38eec962f | |||
| a313e66d93 | |||
| c755286323 | |||
| 0d219f5d2e | |||
| 28bdeb6f4b | |||
| 496a1ad7d8 | |||
| 57dec77718 | |||
| 4dc60cb4ca | |||
| f5f67653f8 | |||
| b7fd5915a5 | |||
| 72f7c510b9 | |||
| ac62aa01d5 | |||
| a727daa6ff | |||
| 2187855da2 | |||
| fb1ed99470 | |||
| be68853991 | |||
| c9d794dc76 | |||
| c1cc0910c5 | |||
| 61095f726d | |||
| 721d062421 | |||
| f38c90b1d5 | |||
| 8c0284dbe8 | |||
| f8f4facdca | |||
| e97f13395f | |||
| dc87fca814 | |||
| aafd7caf77 | |||
| ef964bfc1a | |||
| e5ae885ae1 | |||
| 2291255133 | |||
| d48294f940 | |||
| ef87cce5a9 | |||
| 63048e641d | |||
| 91aa427137 | |||
| 811c1ceeb6 | |||
| 8c2e95fb46 | |||
| d47fb9f718 | |||
| 4625eca277 | |||
| b2abb41a38 | |||
| b228d36041 | |||
| 7680aea223 | |||
| 771042a619 | |||
| b1f7713916 | |||
| 7b0c04b95b | |||
| 9f09c934bf | |||
| 88bad450fd | |||
| 7614f77431 | |||
| 761f27958a | |||
| 52347a0c98 | |||
| e2e97b774a | |||
| 4f0f97959f | |||
| 93f4eeb227 | |||
| ec769e00bb | |||
| ade975d48f | |||
| 16a07abd51 | |||
| 2bc071b323 | |||
| 3c07ec133e | |||
| 5c74244695 | |||
| 4e877e4f11 | |||
| 51ec7e3741 | |||
| 1f983fea40 | |||
| a26f0374ec | |||
| a0029a8411 | |||
| 2de3b6cf1c | |||
| fd19ec2c6a | |||
| 6aec3ed37a | |||
| 7f7f0f7e3d | |||
| dd210c9002 | |||
| 2ae4bd156f | |||
| 8740fcdbad | |||
| fb18948243 | |||
| e104d36785 | |||
| 1786231a49 | |||
| fa8e09ae9c | |||
| 2dd212d020 | |||
| 15acd305d1 | |||
| 5a65a39c5e | |||
| f18754f8f0 | |||
| e860234d05 | |||
| 50d61d2935 | |||
| 47c40ce086 | |||
| 2032942b61 | |||
| 0076fe4f53 | |||
| 9b18412ecc | |||
| 5f0ba6a371 | |||
| 1e2953b22e | |||
| e27ad6f919 | |||
| bfa7180b7b | |||
| 24ae4f9bda | |||
| cbb7512c9a | |||
| 869576e8ab | |||
| 9187dccb54 | |||
| eb6193d13e | |||
| a43eaaaf81 | |||
| c31574d7d6 | |||
| 3a42f565cb | |||
| 8f1942a9a5 | |||
| ab05b61638 | |||
| 5c4a414cb7 | |||
| 0e11dbadbf | |||
| 96cf5718b2 | |||
| d3f8351744 | |||
| 9d903fd92f | |||
| f77d8aaec3 | |||
| 4c2b867172 | |||
| 1bdf4a0c64 | |||
| c2b1465548 | |||
| f4471062a9 | |||
| f843a95343 | |||
| 1605422808 | |||
| 5ee2bdbd10 | |||
| f4c7160763 | |||
| 3e81740517 | |||
| a8e065969f | |||
| 688d167190 | |||
| 4553dafeca | |||
| 8aeceb00e4 | |||
| 022aa736ec | |||
| 2cad413958 | |||
| f5fb42e535 | |||
| 4995eeec41 | |||
| 0961b59420 | |||
| 1fdeedf112 | |||
| 43c7079a07 | |||
| 097f64721a | |||
| b3b6c78657 | |||
| fcfc2f8651 | |||
| 1f9b0bfe02 | |||
| 533def6b57 | |||
| 826193ef5a | |||
| 631aa4b356 | |||
| 067422b4b4 | |||
| 7ec8f12648 | |||
| 731a0cb0bf | |||
| ebd97e9b93 | |||
| 9fcf81c170 | |||
| 1f2cb16dbb | |||
| 827306728f | |||
| f6076cb7f0 | |||
| 694386e233 | |||
| f11928af11 | |||
| acda8f640a | |||
| 4ff3a5d818 | |||
| 314b729c8a | |||
| 9fb676aba9 | |||
| b91741d10d | |||
| f3787356b6 | |||
| def3136c85 | |||
| abb0c9b384 | |||
| 87b2891c1a | |||
| 52c34ef64f | |||
| 40bc836a55 | |||
| d2738ece19 | |||
| f758a5d738 | |||
| 63edc5d89b | |||
| 0db1584f21 | |||
| 1ed173f21d | |||
| b17f3f51f7 | |||
| 4f0556cce7 | |||
| b55a5e5ec8 | |||
| 68acbb064d | |||
| 92df76793f | |||
| 5cda51c7a5 | |||
| 659a406eb8 | |||
| 4cf2dd5b32 | |||
| 100a5ba0bc | |||
| ab16abaa88 | |||
| 989dd1dd2a | |||
| 0468ef22c4 | |||
| 6238994a17 | |||
| 7ba2fe66a0 | |||
| dfaec438d9 | |||
| aaeef59ff6 | |||
| 4d35f5129a | |||
| 84f610347c | |||
| 44bfda1320 | |||
| 330524adba | |||
| 85bddf8f00 | |||
| 7b0d891f4d | |||
| 84f0e2feba | |||
| 76309c35ec | |||
| 3f6b453c0a | |||
| 43dbb49103 | |||
| f08f93f347 | |||
| e0c852f4b9 | |||
| 15373996f4 | |||
| ff1e8da0cb | |||
| 99f7f5b9f1 | |||
| 656f390de8 | |||
| 42a7e79359 | |||
| bf084cc2ac | |||
| eaaba665bc | |||
| 94d311134c | |||
| 0d49ae9851 | |||
| a5c39384a8 | |||
| cb6bc30bc6 | |||
| 82c72a94d9 | |||
| f327afd364 | |||
| d94f4c5bbc | |||
| 8be04ea656 | |||
| de7c16d942 | |||
| 5ea843458a | |||
| 758941d12f | |||
| e01d5bc18b | |||
| 2c16539190 | |||
| ed79e61a2f | |||
| b7bcc69722 | |||
| 3dde375d0b | |||
| 483e30a5ba | |||
| e783556e6b | |||
| 5645a433dc | |||
| 715ab8b96a | |||
| 5f96190eb5 | |||
| c579162ef9 | |||
| a5cca6de75 | |||
| b7f1157693 | |||
| ae7b6fc715 | |||
| e0c3b72950 | |||
| 566f7f4555 | |||
| 4ff62b2b41 | |||
| d47970fd81 | |||
| 69bdca063f | |||
| 63cea99415 | |||
| 5ecd27e3b8 | |||
| 206a2dbc04 | |||
| 2a083791b6 | |||
| d5b2b0b464 | |||
| 2eab1ad845 | |||
| 2b16420d41 | |||
| 9fa0889499 | |||
| 99b17fabeb | |||
| 933d3014d7 | |||
| 018e0f31de | |||
| cf1647e937 | |||
| b9f154bf38 | |||
| 4cc18ce0af | |||
| f5ea1c24a3 | |||
| 952b0bb735 | |||
| 8b7edad8a2 | |||
| 02787ac910 | |||
| bcc3ba09ca | |||
| 31e65dc58b | |||
| 9a227e6c73 | |||
| ddc9c24d34 | |||
| 42488a2be7 | |||
| 839486c25b | |||
| 5d56200179 | |||
| fef1d4f7c0 | |||
| 43defcc17e | |||
| f78460e2a7 | |||
| 3448923b69 | |||
| 58a13bc268 | |||
| c18038f986 | |||
| d4356a1f4c | |||
| 3c8f478b65 | |||
| 23493302e6 | |||
| 35ceaf728d | |||
| 5c9412fc33 | |||
| 825c9329eb | |||
| 9ebb990716 | |||
| f964209589 | |||
| 2e699d392e | |||
| 431ecee509 | |||
| 90696215ae | |||
| 5b55261700 | |||
| 727ff90acf | |||
| 0060fdacd8 | |||
| 85ad1fa988 | |||
| 56c022ca41 | |||
| f68e0989ea | |||
| 7381117bb8 | |||
| c9209ebb3d | |||
| 35345d11f5 | |||
| 6ee17b4c26 | |||
| 86267f93a1 | |||
| 50642e7069 | |||
| 8349f291d2 | |||
| 1aad21382e | |||
| 686ee087a5 | |||
| f137ba213a | |||
| 5ae51010cc | |||
| 29d8e7f670 | |||
| 5be3e0ce52 | |||
| ddde30a12e | |||
| 2db5578998 | |||
| 290250836f | |||
| 0ff4df4dc3 | |||
| 9177aa2c08 | |||
| ad791dc7f8 | |||
| 6b298ff7f3 | |||
| 01e30e938c | |||
| e81632e05e | |||
| 4ab3358851 | |||
| 4ded988907 | |||
| 8637dc05c0 | |||
| 6f65ad0b97 | |||
| c5ec378ea7 | |||
| 37013c2eca | |||
| 54a8a6407e | |||
| 69360fb804 | |||
| 92d296ec24 | |||
| 99557332a0 | |||
| a3d9c5a1b2 | |||
| 235ff64a38 | |||
| 0f7fca9e03 | |||
| 161bf49a3a | |||
| 7ac90f19dd | |||
| 90cc426c82 | |||
| 550a239553 | |||
| 57fea1bd6f | |||
| d758545164 | |||
| 5935632b8b | |||
| 8f3a7b7947 | |||
| 2f47bd12fd | |||
| 86fb607dd4 | |||
| 80823b1e16 | |||
| ff6f56b8c5 | |||
| 5393ba3cb4 | |||
| 4ade6c0457 | |||
| e5c389e677 | |||
| ea27b5a77c | |||
| 18c19e4466 | |||
| 0ea950ee52 | |||
| 2d3033fc71 | |||
| 1687f1cffe | |||
| 2f0263a5b8 | |||
| dfbf20acd2 | |||
| 0b9019ab71 | |||
| b0fc2245f4 | |||
| 113c669041 | |||
| b8b5e12a4a | |||
| bece3de495 | |||
| 89120f7797 | |||
| 99e035495b | |||
| 0c56b0c35c | |||
| 111f92e368 | |||
| 03e666ffea | |||
| 40598be9d4 | |||
| 8f057f3c9b | |||
| 972e6f8054 | |||
| aeb7ef392a | |||
| 930a63d55c | |||
| 544de727a0 | |||
| 466e6b5fe3 | |||
| 1abaaf6cf1 | |||
| 48bd910207 | |||
| 87c580f819 | |||
| db1df1ac67 | |||
| 4005d7ea50 | |||
| d29d4404c3 | |||
| 33779576bd | |||
| 3bddd66637 | |||
| e00a407c91 | |||
| 117dcff4e1 | |||
| 7243afd5b5 | |||
| 0a75bc9744 | |||
| ca3b3808b9 | |||
| 287b398826 | |||
| 76d2eda80e | |||
| 880c498c3f | |||
| 12f053ef7f | |||
| 35ee2f60bd | |||
| 3e480e9aea | |||
| 46ba98a4ee | |||
| 958de9441a | |||
| 74312f5487 | |||
| ecf5278679 | |||
| 863abfb00e | |||
| f782693537 | |||
| a2c2411109 | |||
| 712f02e359 | |||
| 61477e515a | |||
| be9343534a | |||
| 2b4e9be4ad | |||
| 382dff7e3b | |||
| 6f2012c1c9 | |||
| c71fe81f8d | |||
| 91586d6690 | |||
| 046726b864 | |||
| ddf353cff5 | |||
| 160497cb64 | |||
| 6194f94aa7 | |||
| e288332f0e | |||
| e4979f33e3 | |||
| 03c3aebca8 | |||
| 487a5ffb95 | |||
| 01d15d4d0e | |||
| 6655794b4d | |||
| 4beb57a5a0 | |||
| bac517e755 | |||
| 62b68cfcd9 | |||
| 481e800a7c | |||
| 9a7c6c339d | |||
| 23340bcfee | |||
| 102979e985 | |||
| ab9a4fbe5f | |||
| aad72f8e81 | |||
| 72295bf186 | |||
| c45a2c14b2 | |||
| ee177b28ff | |||
| 2e0f2f59a0 | |||
| 9856efa7c4 | |||
| 34878b9638 | |||
| 27abdfe7d7 | |||
| 3b0bdba799 | |||
| b547d8c30c | |||
| 1bd317cd50 | |||
| 60b57fd368 | |||
| 27a22e8ccb | |||
| 0378bbb491 | |||
| bccec5cee9 | |||
| d6fbb29977 | |||
| 9d0bf98a52 | |||
| 795272d625 | |||
| c3866f80b6 | |||
| 580a662f36 | |||
| 5767e0df04 | |||
| eeb63f215a | |||
| 5a6e4e49b4 | |||
| b6eada4e67 | |||
| bbe0acf001 | |||
| 05e65801fa | |||
| 08338a4a26 | |||
| bf913e0016 | |||
| 774ceb3367 | |||
| 335a14c714 | |||
| 4dea56d4a0 | |||
| c9916dd2e3 | |||
| 662a311f95 | |||
| bfd6ea22ca | |||
| c5d7991468 | |||
| c4404694e1 | |||
| e914736956 | |||
| 23833dda9b | |||
| 15573b9d3f | |||
| 86661c1cda | |||
| 9cbace7f76 | |||
| 74cb870488 | |||
| ae9b83f07c | |||
| d70c681c32 | |||
| c312d917a1 | |||
| 5d2ecd2f1f | |||
| a1e1dbd865 | |||
| 12f28894ce | |||
| 538ef6e378 | |||
| 1588ea44b2 | |||
| 3cc9098e25 | |||
| 436e945a91 | |||
| f9b83a4e95 | |||
| b1f8bf9f5e | |||
| 7af5175942 | |||
| c24a9096de | |||
| 36d27c46ed | |||
| 713fa36bca | |||
| 20249f9672 | |||
| 8b55e73f77 | |||
| 2058b3c5bf | |||
| 4eb17eb9a9 | |||
| 7138b7afb2 | |||
| fe9b9401d3 | |||
| 8c870cabfb | |||
| b8182c077a | |||
| fbbdadd347 | |||
| b54faf36f5 | |||
| a0dc2a6f33 | |||
| f775fca31c | |||
| efebff4ce8 | |||
| 94b2ab43a5 | |||
| a21dbc2da1 | |||
| cf5a9d26d1 | |||
| ef4772b87a | |||
| ffda318476 | |||
| 6aff0d0197 | |||
| b9ebd33703 | |||
| 61e17df22d | |||
| b88d0ad800 | |||
| 7e24f94164 | |||
| 3a239aa71a | |||
| 0e1ae7a798 | |||
| 133c308796 | |||
| 7ea8c861a2 | |||
| 20e0af2bf4 | |||
| 5d0ed4e7cd | |||
| 144629d7dc | |||
| cf36e8c7cb | |||
| 233df5d59d | |||
| 375796063b | |||
| d8a70de8a8 | |||
| f1ee7fc04f | |||
| e8585fb4a7 | |||
| e10cc01f7e | |||
| 79d6db74b1 | |||
| 69d607a76e | |||
| 2c03d89213 | |||
| 11bf9833da | |||
| d2d37255d5 | |||
| bea5b4919e | |||
| b67a040474 | |||
| d40199ec00 | |||
| 6f7390921c | |||
| e5fa0473de | |||
| 889b777eeb | |||
| 8d4626ef81 | |||
| 7c7d2bc959 | |||
| d76a7c5ea2 | |||
| 3641a97b5f | |||
| 5e818e85f3 | |||
| c9d10077af | |||
| 6394214b55 | |||
| bfa26b8b05 | |||
| 15172c86b9 | |||
| daa85630c7 | |||
| 9914e50d8a | |||
| ef59b5ad6b | |||
| 98741a0606 | |||
| 6aadf1683a | |||
| e10cb6bfb1 | |||
| 2fd6d7e1f8 | |||
| 30c12d9c63 | |||
| 3313891205 | |||
| 1e914b8558 | |||
| b9fc30f592 | |||
| e8e67fe093 | |||
| 66e49c764c | |||
| 322d19689f | |||
| 07a6853585 | |||
| f34599c5ad | |||
| 97c5f0944d | |||
| 1e598e2511 | |||
| 966a5e35db | |||
| d760946828 | |||
| 3dda7c3731 | |||
| 3441833521 | |||
| 603950ca65 | |||
| a946ce09c0 | |||
| c196347e58 | |||
| 979491a631 | |||
| fef3581417 | |||
| f6d948b0e0 | |||
| 2f42fdb282 | |||
| b16261c158 | |||
| 3e1d657888 | |||
| 06946d3632 | |||
| cd8530a5c2 | |||
| 91015bd2c1 | |||
| 907b66624b | |||
| 193352c616 | |||
| 2e551e9c4e | |||
| 58c625affd | |||
| b13702972d | |||
| 8c16776d72 | |||
| 7e4405989a | |||
| 15b819703a | |||
| bf2372101f | |||
| d87f88ee4d | |||
| 24266be8db | |||
| 3187d73b64 | |||
| 48f52668be | |||
| f7ef15d7d0 | |||
| d084ac8a58 | |||
| 077d93e283 | |||
| 71409e7712 | |||
| 61a7ad7116 | |||
| d1ab3939e9 | |||
| 0f2f10557c | |||
| ad748743cd | |||
| 844a8daad6 | |||
| 93cc65adfc | |||
| 3a1aa3f6af | |||
| 5b5f124082 | |||
| cd17d3948c | |||
| 7c49ceaf2c | |||
| a156996d61 | |||
| 9438005891 | |||
| aefde88d24 | |||
| 347bca0de4 | |||
| a0f2073eb1 | |||
| 1b0fd2e4b6 | |||
| 4be3d87e04 | |||
| 5ffe9203d3 | |||
| 24cd70dc95 | |||
| 6e9b241fb2 | |||
| 4cc660a3a7 | |||
| 7c48f6d17b | |||
| c4d7ae49ba | |||
| 26dd3828df | |||
| ead7b1a04a | |||
| 1ddd5c2515 | |||
| e1fcbc067a | |||
| 9bf33597c3 | |||
| 17a8e05a90 | |||
| 7a01a6850c | |||
| 6fdcc392dd | |||
| 3e5bea876d | |||
| 976089104b | |||
| a8220a20ba | |||
| 123639b436 | |||
| 7b1b24860a | |||
| 2e192e79a6 | |||
| 9662b9a2f0 | |||
| 8f5385f9ca | |||
| 0b46e1d807 | |||
| 35a1b8dd62 | |||
| 760b17431a | |||
| 4d3a352889 | |||
| 3fa65989ea | |||
| 1553d4dbc3 | |||
| ac766e2615 | |||
| fee800cb21 | |||
| 7fd0e8de3c | |||
| 1dd1afc972 | |||
| c1e8b1d80c | |||
| fb19d5fec2 | |||
| b2f01679a5 | |||
| c5703462c2 | |||
| deeea09e5d | |||
| b39ffa8fa3 | |||
| 0b1926f089 | |||
| f05fc7b559 | |||
| 37590bf0e0 | |||
| fd25ce1a0d | |||
| f581e1c685 | |||
| 977c4816ed | |||
| 7a022245d4 | |||
| 503377a00b | |||
| a624be1e20 | |||
| 41ad52e495 | |||
| eaae6b90d4 | |||
| 746ba06894 | |||
| faa349ca19 | |||
| 825d41695d | |||
| de0b6556b6 | |||
| 8486015d7c | |||
| ce268a3c8f | |||
| 8072330640 | |||
| 327b1dea25 | |||
| 8f29269e41 | |||
| 1b4d14e24c | |||
| 710f932184 | |||
| 02e410fd20 | |||
| c90128faf6 | |||
| c5ff543a69 | |||
| 639d1dc9cc | |||
| 118cc029fb | |||
| 54545df970 | |||
| 4c94607882 | |||
| ff893b7a72 | |||
| 034fbc1c8f | |||
| 2eb941b077 | |||
| bedd8ea111 | |||
| 9ed91cd53a | |||
| 17d97cde49 | |||
| 09eff5f4d7 | |||
| 3400cebfd2 | |||
| ac4fb2ad9d | |||
| 13186e4674 | |||
| aaa3f1ee1a | |||
| 74cad013b9 | |||
| 8ec956758e | |||
| c0b4a0e3c7 | |||
| 8566a65067 | |||
| 9c82d44129 | |||
| 4e2dd4b6cf | |||
| f9f9ae54fa | |||
| a00b4900cd | |||
| cd01dc0c17 | |||
| 2750238a0c | |||
| f2596e4cbc | |||
| b6955dd9b6 | |||
| 36994d02b3 | |||
| 9902caea79 |
@@ -1 +1,2 @@
|
||||
*.pyc
|
||||
site
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
language: bash
|
||||
sudo: required
|
||||
services:
|
||||
- docker
|
||||
install: docker pull heroku/cedar:14
|
||||
script: make test
|
||||
+204
@@ -0,0 +1,204 @@
|
||||
# Python Buildpack Changelog
|
||||
|
||||
## 99
|
||||
|
||||
Cleanup.
|
||||
|
||||
## 98
|
||||
|
||||
Official NLTK support and other improvements.
|
||||
|
||||
- Support for `nltk.txt` file for declaring corpora to be downloaded.
|
||||
- Leading zeros for auto-set WEB_CONCURRENCY.
|
||||
|
||||
## 97
|
||||
|
||||
Improved egg-link functionality.
|
||||
|
||||
## 96
|
||||
|
||||
Bugfix.
|
||||
|
||||
## 95
|
||||
|
||||
Improved output support.
|
||||
|
||||
## v94
|
||||
|
||||
Improved support for PyPy.
|
||||
|
||||
## v93
|
||||
|
||||
Improved support for PyPy.
|
||||
|
||||
## v92
|
||||
|
||||
Improved cache functionality and fix egg-links regression.
|
||||
|
||||
## v91
|
||||
|
||||
Bugfix, rolled back to v88.
|
||||
|
||||
## v90
|
||||
|
||||
Bugfix.
|
||||
|
||||
## v89
|
||||
|
||||
Improved cache functionality and fix egg-links regression.
|
||||
|
||||
## v88
|
||||
|
||||
Fixed bug with editable pip installations.
|
||||
|
||||
## v87
|
||||
|
||||
Updated default Python 2.7.13.
|
||||
|
||||
- Python 2.7.13 uses UCS-4 build, more compatibile with linux wheels.
|
||||
- Updated setuptools to v32.1.0.
|
||||
|
||||
## v86
|
||||
|
||||
Refactor and multi-buildpack compatibility.
|
||||
|
||||
## v85
|
||||
|
||||
Packaging fix.
|
||||
|
||||
## v84
|
||||
|
||||
Updated pip and setuptools.
|
||||
|
||||
- Updated pip to v9.0.1.
|
||||
- Updated setuptools to v28.8.0.
|
||||
|
||||
## v83
|
||||
|
||||
Support for Heroku CI.
|
||||
|
||||
- Cffi support for argon2
|
||||
|
||||
## v82 (2016-08-22)
|
||||
|
||||
Update to library detection mechnisms (pip-pop).
|
||||
|
||||
- Updated setuptools to v25.5.0
|
||||
|
||||
## v81 (2016-06-28)
|
||||
|
||||
Updated default Python to 2.7.11.
|
||||
|
||||
- Updated pip to v8.1.2.
|
||||
- Updated setuptools to v23.1.0.
|
||||
|
||||
## v80 (2016-04-05)
|
||||
|
||||
Improved pip-pop compatibility with latest pip releases.
|
||||
|
||||
## v79 (2016-03-22)
|
||||
|
||||
Compatibility improvements with heroku-apt-buildpack.
|
||||
|
||||
## v78 (2016-03-18)
|
||||
|
||||
Added automatic configuration of Gunicorn's `FORWARDED_ALLOW_IPS` setting.
|
||||
|
||||
Improved detection of libffi dependency when using bcrypt via `Django[bcrypt]`.
|
||||
|
||||
Improved GDAL support.
|
||||
|
||||
- GDAL dependency detection now checks for pygdal and is case-insensitive.
|
||||
- The vendored GDAL library has been updated to 1.11.1.
|
||||
- GDAL bootstrapping now also installs the GEOS and Proj.4 libraries.
|
||||
|
||||
Updated pip to 8.1.1 and setuptools to 20.3.
|
||||
|
||||
## v77 (2016-02-10)
|
||||
|
||||
Improvements to warnings and minor bugfix.
|
||||
|
||||
## v76 (2016-02-08)
|
||||
|
||||
Improved Django collectstatic support.
|
||||
|
||||
- `$ python manage.py collectstatic` will only be run if `Django` is present in `requirements.txt`.
|
||||
- If collectstatic fails, the build fails. Full traceback is provided.
|
||||
- `$DISABLE_COLLECTSTATIC`: skip collectstatic step completely (not new).
|
||||
- `$DEBUG_COLLECTSTATIC`: echo environment variables upon collectstatic failure.
|
||||
- Updated build output style.
|
||||
- New warning for outdated Python (via pip `InsecurePlatform` warning).
|
||||
|
||||
## v75 (2016-01-29)
|
||||
|
||||
Updated pip and Setuptools.
|
||||
|
||||
## v74 (2015-12-29)
|
||||
|
||||
Added warnings for lack of Procfile.
|
||||
|
||||
## v72 (2015-12-07)
|
||||
|
||||
Updated default Python to 2.7.11.
|
||||
|
||||
## v72 (2015-12-03)
|
||||
|
||||
Added friendly warnings for common build failures.
|
||||
|
||||
## v70 (2015-10-29)
|
||||
|
||||
Improved compatibility with multi and node.js buildpacks.
|
||||
|
||||
## v69 (2015-10-12)
|
||||
|
||||
Revert to v66.
|
||||
|
||||
## v68 (2015-10-12)
|
||||
|
||||
Fixed .heroku/venv error with modern apps.
|
||||
|
||||
## v67 (2015-10-12)
|
||||
|
||||
Further improved cache compatibility with multi and node.js buildpacks.
|
||||
|
||||
## v66 (2015-10-09)
|
||||
|
||||
Improved compatibility with multi and node.js buildpacks.
|
||||
|
||||
## v65 (2015-10-08)
|
||||
|
||||
Reverted v64.
|
||||
|
||||
## v64 (2015-10-08)
|
||||
|
||||
Improved compatibility with multi and node.js buildpacks.
|
||||
|
||||
## v63 (2015-10-08)
|
||||
|
||||
Updated Pip and Setuptools.
|
||||
|
||||
- Setuptools updated to v18.3.2
|
||||
- Pip updated to v7.1.2
|
||||
|
||||
|
||||
## v62 (2015-08-07)
|
||||
|
||||
Updated Pip and Setuptools.
|
||||
|
||||
- Setuptools updated to v18.1
|
||||
- Pip updated to v7.1.0
|
||||
|
||||
## v61 (2015-06-30)
|
||||
|
||||
Updated Pip and Setuptools.
|
||||
|
||||
- Setuptools updated to v18.0.1
|
||||
- Pip updated to v7.0.3
|
||||
|
||||
## v60 (2015-05-27)
|
||||
|
||||
Default Python is now latest 2.7.10. Updated Pip and Distribute.
|
||||
|
||||
- Default Python version is v2.7.10
|
||||
- Setuptools updated to v16.0
|
||||
- Pip updated to v7.0.1
|
||||
@@ -1,19 +0,0 @@
|
||||
## v3 (12/07/2011)
|
||||
|
||||
Bugfixes:
|
||||
|
||||
* Better django setup.py injection.
|
||||
|
||||
## v2 (11/15/2011)
|
||||
|
||||
Features:
|
||||
|
||||
* Support for pylibmc and libmemcached +sasl.
|
||||
|
||||
Bugfixes:
|
||||
|
||||
* Detect when virtualenv is checked in and alert user.
|
||||
|
||||
## v1 (10/01/2011)
|
||||
|
||||
* Conception.
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
FROM heroku/heroku:16-build
|
||||
|
||||
WORKDIR /app
|
||||
ENV WORKSPACE_DIR=/app/builds
|
||||
|
||||
RUN apt-get update && apt-get install -y python-pip
|
||||
|
||||
# Install bob-builder application
|
||||
RUN pip install bob-builder==0.0.5
|
||||
|
||||
COPY . /app
|
||||
@@ -0,0 +1,9 @@
|
||||
MIT License:
|
||||
|
||||
Copyright (C) 2016 Heroku, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
@@ -0,0 +1,14 @@
|
||||
# These targets are not files
|
||||
.PHONY: tests
|
||||
|
||||
test: test-cedar-14
|
||||
|
||||
test-cedar-14:
|
||||
@echo "Running tests in docker (cedar-14)..."
|
||||
@docker run -v $(shell pwd):/buildpack:ro --rm -it -e "STACK=cedar-14" heroku/cedar:14 bash -c 'cp -r /buildpack /buildpack_test; cd /buildpack_test/; test/run;'
|
||||
@echo ""
|
||||
|
||||
tools:
|
||||
git clone https://github.com/kennethreitz/pip-pop.git
|
||||
mv pip-pop/bin/* vendor/pip-pop/
|
||||
rm -fr pip-pop
|
||||
@@ -0,0 +1,56 @@
|
||||

|
||||
|
||||
# Heroku Buildpack: Python
|
||||
|
||||
[](https://travis-ci.org/heroku/heroku-buildpack-python)
|
||||
|
||||
This is the official [Heroku buildpack](https://devcenter.heroku.com/articles/buildpacks) for Python apps, powered by [pip](https://pip.pypa.io/) and other excellent software.
|
||||
|
||||
Recommended web frameworks include **Django** and **Flask**. The recommended webserver is **Gunicorn**. There are no restrictions around what software can be used (as long as it's pip-installable). Web processes must bind to `$PORT`, and only the HTTP protocol is permitted for incoming connections.
|
||||
|
||||
Some Python packages with obscure C dependencies (e.g. scipy) are [not compatible](https://devcenter.heroku.com/articles/python-c-deps).
|
||||
|
||||
See it in Action
|
||||
----------------
|
||||
|
||||
Deploying a Python application couldn't be easier:
|
||||
|
||||
$ ls
|
||||
Procfile requirements.txt web.py
|
||||
|
||||
$ heroku create --buildpack heroku/python
|
||||
|
||||
$ git push heroku master
|
||||
...
|
||||
-----> Python app detected
|
||||
-----> Installing python-2.7.13
|
||||
$ pip install -r requirements.txt
|
||||
Collecting requests (from -r requirements.txt (line 1))
|
||||
Downloading requests-2.12.4-py2.py3-none-any.whl (576KB)
|
||||
Installing collected packages: requests
|
||||
Successfully installed requests-2.12.4
|
||||
|
||||
-----> Discovering process types
|
||||
Procfile declares types -> (none)
|
||||
|
||||
A `requirements.txt` file must be present at the root of your application's repository.
|
||||
|
||||
You can also specify the latest production release of this buildpack for upcoming builds of an existing application:
|
||||
|
||||
$ heroku buildpacks:set heroku/python
|
||||
|
||||
|
||||
Specify a Python Runtime
|
||||
------------------------
|
||||
|
||||
Specific versions of the Python runtime can be specified with a `runtime.txt` file:
|
||||
|
||||
$ cat runtime.txt
|
||||
python-3.6.0
|
||||
|
||||
Runtime options include:
|
||||
|
||||
- `python-2.7.13`
|
||||
- `python-3.6.0`
|
||||
- `pypy-5.6.0` (unsupported, experimental)
|
||||
- `pypy3-5.5.0` (unsupported, experimental)
|
||||
@@ -1,43 +0,0 @@
|
||||
Heroku buildpack: Python
|
||||
========================
|
||||
|
||||
This is a [Heroku buildpack](http://devcenter.heroku.com/articles/buildpack) for Python apps.
|
||||
It uses [virtualenv](http://www.virtualenv.org/) and [pip](http://www.pip-installer.org/).
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
Example usage:
|
||||
|
||||
$ ls
|
||||
Procfile requirements.txt web.py
|
||||
|
||||
$ heroku create --stack cedar --buildpack git@github.com:heroku/heroku-buildpack-python.git
|
||||
|
||||
$ git push heroku master
|
||||
...
|
||||
-----> Heroku receiving push
|
||||
-----> Fetching custom build pack... done
|
||||
-----> Python app detected
|
||||
-----> Preparing virtualenv version 1.6.4
|
||||
New python executable in ./bin/python
|
||||
Installing setuptools............done.
|
||||
Installing pip...............done.
|
||||
-----> Installing dependencies using pip version 1.0.2
|
||||
Downloading/unpacking Flask==0.7.2 (from -r requirements.txt (line 1))
|
||||
Downloading/unpacking Werkzeug>=0.6.1 (from Flask==0.7.2->-r requirements.txt (line 1))
|
||||
Downloading/unpacking Jinja2>=2.4 (from Flask==0.7.2->-r requirements.txt (line 1))
|
||||
Installing collected packages: Flask, Werkzeug, Jinja2
|
||||
Successfully installed Flask Werkzeug Jinja2
|
||||
Cleaning up...
|
||||
|
||||
The buildpack will detect your app as Python if it has the file `requirements.txt` in the root. It will detect your app as Python/Django if there is an additional `settings.py` in a project subdirectory.
|
||||
|
||||
It will use virtualenv and pip to install your dependencies, vendoring a copy of the Python runtime into your slug. The `bin/`, `include/` and `lib/` directories will be cached between builds to allow for faster pip install time.
|
||||
|
||||
Hacking
|
||||
-------
|
||||
|
||||
To use this buildpack, fork it on Github. Push up changes to your fork, then create a test app with `--buildpack <your-github-url>` and push to it.
|
||||
|
||||
To change the vendored virtualenv, unpack the desired version to the `src/` folder, and update the virtualenv() function in `bin/compile` to prepend the virtualenv module directory to the path. The virtualenv release vendors its own versions of pip and setuptools.
|
||||
+211
-107
@@ -1,153 +1,257 @@
|
||||
#!/usr/bin/env bash
|
||||
# bin/compile <build-dir> <cache-dir>
|
||||
|
||||
# The Heroku Python Buildpack. This script accepts parameters for a build
|
||||
# directory, a cache directory, and a directory for app environment variables.
|
||||
|
||||
# Warning: there are a few hacks in this script to accommodate excellent builds
|
||||
# on Heroku. No guarantee for external compatibility is made. However,
|
||||
# everything should work fine outside of the Heroku environment, if the
|
||||
# environment is setup correctly.
|
||||
|
||||
# Usage:
|
||||
#
|
||||
# $ bin/compile <build-dir> <cache-dir> <env-path>
|
||||
|
||||
# Fail fast and fail hard.
|
||||
set -eo pipefail
|
||||
|
||||
[ "$BUILDPACK_XTRACE" ] && set -o xtrace
|
||||
|
||||
# Prepend proper path for virtualenv hackery. This will be deprecated soon.
|
||||
export PATH=:/usr/local/bin:$PATH
|
||||
|
||||
# Paths.
|
||||
BIN_DIR=$(cd $(dirname $0); pwd) # absolute path
|
||||
ROOT_DIR=$(dirname $BIN_DIR)
|
||||
BUILD_DIR=$1
|
||||
CACHE_DIR=$2
|
||||
ENV_DIR=$3
|
||||
|
||||
NAME=$($BIN_DIR/detect $BUILD_DIR)
|
||||
PIP_DOWNLOAD_CACHE=${PIP_DOWNLOAD_CACHE:-$CACHE_DIR/pip_downloads}
|
||||
VIRTUALENV_DIRS="bin include lib"
|
||||
VENDORED_MEMCACHED="http://cl.ly/0a191R3K160t1w1P0N25/vendor-libmemcached.tar.gz"
|
||||
# Static configurations for virtualenv caches.
|
||||
VIRTUALENV_LOC=".heroku/venv"
|
||||
LEGACY_TRIGGER="lib/python2.7"
|
||||
|
||||
indent() {
|
||||
RE="s/^/ /"
|
||||
[ $(uname) == "Darwin" ] && sed -l "$RE" || sed -u "$RE"
|
||||
}
|
||||
DEFAULT_PYTHON_VERSION="python-2.7.13"
|
||||
DEFAULT_PYTHON_STACK="cedar-14"
|
||||
PYTHON_EXE="/app/.heroku/python/bin/python"
|
||||
PIP_VERSION="9.0.1"
|
||||
SETUPTOOLS_VERSION="32.1.0"
|
||||
|
||||
virtualenv() {
|
||||
python - "$@" <<EOF
|
||||
import sys
|
||||
sys.path.insert(0, "$ROOT_DIR/src/virtualenv-1.6.4")
|
||||
import virtualenv
|
||||
virtualenv.main()
|
||||
EOF
|
||||
}
|
||||
# Common Problem Warnings
|
||||
export WARNINGS_LOG=$(mktemp)
|
||||
export RECOMMENDED_PYTHON_VERSION=$DEFAULT_PYTHON_VERSION
|
||||
|
||||
# Setup bpwatch
|
||||
export PATH=$PATH:$ROOT_DIR/vendor/bpwatch
|
||||
LOGPLEX_KEY="t.b90d9d29-5388-4908-9737-b4576af1d4ce"
|
||||
export BPWATCH_STORE_PATH=$CACHE_DIR/bpwatch.json
|
||||
BUILDPACK_VERSION=v28
|
||||
|
||||
# Setup pip-pop (pip-diff)
|
||||
export PATH=$PATH:$ROOT_DIR/vendor/pip-pop
|
||||
|
||||
# Support Anvil Build_IDs
|
||||
[ ! "$SLUG_ID" ] && SLUG_ID="defaultslug"
|
||||
[ ! "$REQUEST_ID" ] && REQUEST_ID=$SLUG_ID
|
||||
[ ! "$STACK" ] && STACK=$DEFAULT_PYTHON_STACK
|
||||
|
||||
# Sanitizing environment variables.
|
||||
unset GIT_DIR PYTHONHOME PYTHONPATH
|
||||
unset RECEIVE_DATA RUN_KEY BUILD_INFO DEPLOY LOG_TOKEN DYNO
|
||||
unset CYTOKINE_LOG_FILE GEM_PATH
|
||||
|
||||
# Setup buildpack instrumentation.
|
||||
bpwatch init $LOGPLEX_KEY
|
||||
bpwatch build python $BUILDPACK_VERSION $REQUEST_ID
|
||||
|
||||
bpwatch start compile
|
||||
|
||||
# Syntax sugar.
|
||||
source $BIN_DIR/utils
|
||||
|
||||
# Import collection of warnings.
|
||||
source $BIN_DIR/warnings
|
||||
|
||||
# we need to put a bunch of symlinks in there later
|
||||
mkdir -p /app/.heroku
|
||||
|
||||
# Set up outputs under new context
|
||||
PROFILE_PATH="$BUILD_DIR/.profile.d/python.sh"
|
||||
EXPORT_PATH="$BIN_DIR/../export"
|
||||
GUNICORN_PROFILE_PATH="$BUILD_DIR/.profile.d/python.gunicorn.sh"
|
||||
|
||||
# We'll need to send these statics to other scripts we `source`.
|
||||
export BUILD_DIR CACHE_DIR BIN_DIR PROFILE_PATH EXPORT_PATH
|
||||
|
||||
# Prepend proper environment variables for Python use.
|
||||
export PATH=/app/.heroku/python/bin:/app/.heroku/vendor/bin:$PATH
|
||||
export PYTHONUNBUFFERED=1
|
||||
export LANG=en_US.UTF-8
|
||||
export C_INCLUDE_PATH=/app/.heroku/vendor/include:/app/.heroku/python/include:$C_INCLUDE_PATH
|
||||
export CPLUS_INCLUDE_PATH=/app/.heroku/vendor/include:/app/.heroku/python/include:$CPLUS_INCLUDE_PATH
|
||||
export LIBRARY_PATH=/app/.heroku/vendor/lib:/app/.heroku/python/lib:$LIBRARY_PATH
|
||||
export LD_LIBRARY_PATH=/app/.heroku/vendor/lib:/app/.heroku/python/lib:$LD_LIBRARY_PATH
|
||||
export PKG_CONFIG_PATH=/app/.heroku/vendor/lib/pkg-config:/app/.heroku/python/lib/pkg-config:$PKG_CONFIG_PATH
|
||||
|
||||
# Switch to the repo's context.
|
||||
cd $BUILD_DIR
|
||||
|
||||
# reject a non-packaged Django app
|
||||
if [ "$NAME" = "Python" ]; then
|
||||
[ -f manage.py ] && [ -f settings.py ] && { echo " ! Django app must be in a package subdirectory"; exit 1; }
|
||||
# Warn for lack of Procfile.
|
||||
if [[ ! -f Procfile ]]; then
|
||||
puts-warn 'Warning: Your application is missing a Procfile. This file tells Heroku how to run your application.'
|
||||
puts-warn 'Learn more: https://devcenter.heroku.com/articles/procfile'
|
||||
fi
|
||||
|
||||
# warn a checked-in virtualenv
|
||||
if [ -d "lib" ] || [ -d "bin" ]; then
|
||||
echo " ! You have a virtualenv checked in. You should ignore the appropriate paths in your repo. See http://devcenter.heroku.com/articles/gitignore for more info.";
|
||||
fi
|
||||
# Experimental pre_compile hook.
|
||||
bpwatch start pre_compile
|
||||
source $BIN_DIR/steps/hooks/pre_compile
|
||||
bpwatch stop pre_compile
|
||||
|
||||
# reject a conflicting checked-in virtualenv
|
||||
if [ -f "lib/python2.7" ]; then
|
||||
echo " ! Checked-in virtualenv conflict."
|
||||
exit 1;
|
||||
# If no requirements.txt file given, assume `setup.py develop` is intended.
|
||||
if [ ! -f requirements.txt ]; then
|
||||
echo "-e ." > requirements.txt
|
||||
fi
|
||||
|
||||
|
||||
# copy artifacts out of cache if exists
|
||||
# Sticky runtimes.
|
||||
if [ -f $CACHE_DIR/.heroku/python-version ]; then
|
||||
DEFAULT_PYTHON_VERSION=$(cat $CACHE_DIR/.heroku/python-version)
|
||||
fi
|
||||
|
||||
# Stack fallback for non-declared caches.
|
||||
if [ -f $CACHE_DIR/.heroku/python-stack ]; then
|
||||
CACHED_PYTHON_STACK=$(cat $CACHE_DIR/.heroku/python-stack)
|
||||
else
|
||||
CACHED_PYTHON_STACK=$STACK
|
||||
fi
|
||||
|
||||
# If no runtime given, assume default version.
|
||||
if [ ! -f runtime.txt ]; then
|
||||
echo $DEFAULT_PYTHON_VERSION > runtime.txt
|
||||
fi
|
||||
|
||||
# Prepare the cache.
|
||||
mkdir -p $CACHE_DIR
|
||||
for dir in $VIRTUALENV_DIRS; do
|
||||
cp -R $CACHE_DIR/$dir . &> /dev/null || true
|
||||
done
|
||||
|
||||
echo "-----> Preparing virtualenv version $(virtualenv --version)"
|
||||
virtualenv --no-site-packages . | indent
|
||||
# Purge "old-style" virtualenvs.
|
||||
bpwatch start clear_old_venvs
|
||||
[ -d $CACHE_DIR/$LEGACY_TRIGGER ] && rm -fr $CACHE_DIR/.heroku/bin $CACHE_DIR/.heroku/lib $CACHE_DIR/.heroku/include
|
||||
[ -d $CACHE_DIR/$VIRTUALENV_LOC ] && rm -fr $CACHE_DIR/.heroku/venv $CACHE_DIR/.heroku/src
|
||||
bpwatch stop clear_old_venvs
|
||||
|
||||
# create set-aside .heroku folder.
|
||||
mkdir .heroku
|
||||
# Restore old artifacts from the cache.
|
||||
bpwatch start restore_cache
|
||||
mkdir -p .heroku
|
||||
|
||||
|
||||
# if pylibmc within requirements, use vendored libmemcached
|
||||
if (grep -Fxiq "pylibmc" requirements.txt) || (grep -Fiq "pylibmc=" requirements.txt)
|
||||
then
|
||||
echo "-----> Noticed pylibmc. Bootstrapping libmemcached."
|
||||
cd .heroku
|
||||
|
||||
if [ -d "vendor/lib/sasl2" ]; then
|
||||
export LIBMEMCACHED=$(pwd)/vendor
|
||||
else
|
||||
curl -s -L -O $VENDORED_MEMCACHED
|
||||
tar -zxvf vendor-libmemcached.tar.gz > /dev/null
|
||||
rm vendor-libmemcached.tar.gz
|
||||
export LIBMEMCACHED=$(pwd)/vendor
|
||||
cp -R $CACHE_DIR/.heroku/python .heroku/ &> /dev/null || true
|
||||
cp -R $CACHE_DIR/.heroku/python-stack .heroku/ &> /dev/null || true
|
||||
cp -R $CACHE_DIR/.heroku/python-version .heroku/ &> /dev/null || true
|
||||
cp -R $CACHE_DIR/.heroku/vendor .heroku/ &> /dev/null || true
|
||||
cp -R $CACHE_DIR/.heroku/venv .heroku/ &> /dev/null || true
|
||||
if [[ -d $CACHE_DIR/.heroku/src ]]; then
|
||||
cp -R $CACHE_DIR/.heroku/src .heroku/ &> /dev/null || true
|
||||
fi
|
||||
|
||||
export LIBMEMCACHED=$(pwd)/vendor
|
||||
cd ..
|
||||
bpwatch stop restore_cache
|
||||
|
||||
mkdir -p $(dirname $PROFILE_PATH)
|
||||
mkdir -p /app/.heroku/src
|
||||
|
||||
if [[ $BUILD_DIR != '/app' ]]; then
|
||||
# python expects to reside in /app, so set up symlinks
|
||||
# we will not remove these later so subsequent buildpacks can still invoke it
|
||||
ln -nsf $BUILD_DIR/.heroku/python /app/.heroku/python
|
||||
ln -nsf $BUILD_DIR/.heroku/vendor /app/.heroku/vendor
|
||||
ln -nsf $BUILD_DIR/.heroku/venv /app/.heroku/venv
|
||||
# Note: .heroku/src is copied in later.
|
||||
fi
|
||||
|
||||
# Install Python.
|
||||
source $BIN_DIR/steps/python
|
||||
|
||||
# Sanity check for setuptools/distribute.
|
||||
source $BIN_DIR/steps/setuptools
|
||||
|
||||
# if Django, append settings
|
||||
if [ "$NAME" = "Python/Django" ]; then
|
||||
echo "-----> Django settings injection"
|
||||
# Uninstall removed dependencies with Pip.
|
||||
source $BIN_DIR/steps/pip-uninstall
|
||||
|
||||
SETTINGS_FILE=$(ls **/settings.py | head -1)
|
||||
PROJECT=$(dirname $SETTINGS_FILE)
|
||||
echo "Injecting code into $SETTINGS_FILE to read from DATABASE_URL" | indent
|
||||
# Mercurial support.
|
||||
source $BIN_DIR/steps/mercurial
|
||||
|
||||
cat >>$SETTINGS_FILE <<EOF
|
||||
# Pylibmc support.
|
||||
source $BIN_DIR/steps/pylibmc
|
||||
|
||||
import os
|
||||
import sys
|
||||
import urlparse
|
||||
urlparse.uses_netloc.append('postgres')
|
||||
urlparse.uses_netloc.append('mysql')
|
||||
# Libffi support.
|
||||
source $BIN_DIR/steps/cryptography
|
||||
|
||||
try:
|
||||
# Support for Geo libraries.
|
||||
sub-env $BIN_DIR/steps/geo-libs
|
||||
|
||||
# Check to make sure DATABASES is set in settings.py file.
|
||||
# If not default to {}
|
||||
# GDAL support.
|
||||
source $BIN_DIR/steps/gdal
|
||||
|
||||
if 'DATABASES' not in locals():
|
||||
DATABASES = {}
|
||||
# Install dependencies with Pip (where the magic happens).
|
||||
source $BIN_DIR/steps/pip-install
|
||||
|
||||
if 'DATABASE_URL' in os.environ:
|
||||
url = urlparse.urlparse(os.environ['DATABASE_URL'])
|
||||
# Support for NLTK corpora.
|
||||
sub-env $BIN_DIR/steps/nltk
|
||||
|
||||
# Ensure default database exists.
|
||||
DATABASES['default'] = DATABASES.get('default', {})
|
||||
# Support for pip install -e.
|
||||
rm -fr $BUILD_DIR/.heroku/src
|
||||
deep-cp /app/.heroku/src $BUILD_DIR/.heroku/src
|
||||
|
||||
# Update with environment configuration.
|
||||
DATABASES['default'].update({
|
||||
'NAME': url.path[1:],
|
||||
'USER': url.username,
|
||||
'PASSWORD': url.password,
|
||||
'HOST': url.hostname,
|
||||
'PORT': url.port,
|
||||
})
|
||||
if url.scheme == 'postgres':
|
||||
DATABASES['default']['ENGINE'] = 'django.db.backends.postgresql_psycopg2'
|
||||
# Django collectstatic support.
|
||||
sub-env $BIN_DIR/steps/collectstatic
|
||||
|
||||
if url.scheme == 'mysql':
|
||||
DATABASES['default']['ENGINE'] = 'django.db.backends.mysql'
|
||||
except:
|
||||
print 'Unexpected error:', sys.exc_info()
|
||||
# Create .profile script for application runtime environment variables.
|
||||
set-env PATH '$HOME/.heroku/python/bin:$PATH'
|
||||
set-env PYTHONUNBUFFERED true
|
||||
set-env PYTHONHOME /app/.heroku/python
|
||||
set-env LIBRARY_PATH '/app/.heroku/vendor/lib:/app/.heroku/python/lib:$LIBRARY_PATH'
|
||||
set-env LD_LIBRARY_PATH '/app/.heroku/vendor/lib:/app/.heroku/python/lib:$LD_LIBRARY_PATH'
|
||||
set-default-env LANG en_US.UTF-8
|
||||
set-default-env PYTHONHASHSEED random
|
||||
set-default-env PYTHONPATH /app/
|
||||
|
||||
EOF
|
||||
fi
|
||||
# Install sane-default script for $WEB_CONCURRENCY and $FORWARDED_ALLOW_IPS.
|
||||
cp $ROOT_DIR/vendor/python.gunicorn.sh $GUNICORN_PROFILE_PATH
|
||||
|
||||
if (grep -Fiq "hg+" requirements.txt) then
|
||||
PIP_DOWNLOAD_CACHE=$PIP_DOWNLOAD_CACHE bin/pip install --use-mirrors mercurial | indent
|
||||
source bin/activate
|
||||
fi
|
||||
|
||||
echo "-----> Installing dependencies using pip version $(bin/pip --version | awk '{print $2}')"
|
||||
PIP_DOWNLOAD_CACHE=$PIP_DOWNLOAD_CACHE bin/pip install --use-mirrors -r requirements.txt | indent
|
||||
# Experimental post_compile hook.
|
||||
bpwatch start post_compile
|
||||
source $BIN_DIR/steps/hooks/post_compile
|
||||
bpwatch stop post_compile
|
||||
|
||||
set +e
|
||||
OUT=$(virtualenv --relocatable .)
|
||||
[ $? -ne 0 ] && {
|
||||
echo " ! Error making virtualenv relocatable"
|
||||
echo "$OUT" | indent
|
||||
exit 1
|
||||
}
|
||||
# rewrite build dir in egg links to /app so things are found at runtime
|
||||
find .heroku/python/lib/python*/site-packages/ -name "*.pth" -print0 2> /dev/null | xargs -r -0 -n 1 sed -i -e "s#$(pwd)#/app#" &> /dev/null
|
||||
set -e
|
||||
|
||||
# store new artifacts in cache
|
||||
for dir in $VIRTUALENV_DIRS; do
|
||||
rm -rf $CACHE_DIR/$dir
|
||||
cp -R $dir $CACHE_DIR/
|
||||
done
|
||||
set +e
|
||||
# Support for PyPy
|
||||
find .heroku/python/lib-python/*/site-packages/ -name "*.pth" -print0 2> /dev/null | xargs -r -0 -n 1 sed -i -e "s#$(pwd)#/app#" &> /dev/null
|
||||
set -e
|
||||
|
||||
# Store new artifacts in cache.
|
||||
bpwatch start dump_cache
|
||||
|
||||
rm -rf $CACHE_DIR/.heroku/python
|
||||
rm -rf $CACHE_DIR/.heroku/python-version
|
||||
rm -rf $CACHE_DIR/.heroku/python-stack
|
||||
rm -rf $CACHE_DIR/.heroku/vendor
|
||||
rm -rf $CACHE_DIR/.heroku/venv
|
||||
rm -rf $CACHE_DIR/.heroku/src
|
||||
|
||||
mkdir -p $CACHE_DIR/.heroku
|
||||
cp -R .heroku/python $CACHE_DIR/.heroku/
|
||||
cp -R .heroku/python-version $CACHE_DIR/.heroku/
|
||||
cp -R .heroku/python-stack $CACHE_DIR/.heroku/ &> /dev/null || true
|
||||
cp -R .heroku/vendor $CACHE_DIR/.heroku/ &> /dev/null || true
|
||||
cp -R .heroku/venv $CACHE_DIR/.heroku/ &> /dev/null || true
|
||||
if [[ -d .heroku/src ]]; then
|
||||
cp -R .heroku/src $CACHE_DIR/.heroku/ &> /dev/null || true
|
||||
fi
|
||||
|
||||
bpwatch stop dump_cache
|
||||
|
||||
# Fin.
|
||||
bpwatch stop compile
|
||||
|
||||
+18
-4
@@ -1,8 +1,22 @@
|
||||
#!/usr/bin/env bash
|
||||
# bin/detect <build-dir>
|
||||
|
||||
# This script serves as the
|
||||
# [**Python Buildpack**](https://github.com/heroku/heroku-buildpack-python)
|
||||
# detector.
|
||||
#
|
||||
# A [buildpack](https://devcenter.heroku.com/articles/buildpacks) is an
|
||||
# adapter between a Python application and Heroku's runtime.
|
||||
|
||||
# ## Usage
|
||||
# Compiling an app into a slug is simple:
|
||||
#
|
||||
# $ bin/detect <build-dir> <cache-dir>
|
||||
|
||||
BUILD_DIR=$1
|
||||
[ -f $BUILD_DIR/requirements.txt ] || exit 1 # fail fast if no requirements.txt
|
||||
|
||||
# 'Python/Django' if there is a [mysite]/settings.py file present; otherwise 'Python'
|
||||
ls $BUILD_DIR/**/settings.py &> /dev/null && echo Python/Django || echo Python
|
||||
# Exit early if app is clearly not Python.
|
||||
if [ ! -f $BUILD_DIR/requirements.txt ] && [ ! -f $BUILD_DIR/setup.py ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo Python
|
||||
|
||||
+7
-14
@@ -3,28 +3,21 @@
|
||||
|
||||
BIN_DIR=$(cd $(dirname $0); pwd) # absolute path
|
||||
BUILD_DIR=$1
|
||||
NAME=$($BIN_DIR/detect $BUILD_DIR) || exit 1
|
||||
|
||||
MANAGE_FILE=$(cd $BUILD_DIR && find . -maxdepth 3 -type f -name 'manage.py' | head -1)
|
||||
MANAGE_FILE=${MANAGE_FILE:2}
|
||||
|
||||
cat <<EOF
|
||||
---
|
||||
config_vars:
|
||||
PATH: bin:/usr/local/bin:/usr/bin:/bin
|
||||
PYTHONUNBUFFERED: true
|
||||
LIBRARY_PATH: .heroku/vendor/lib
|
||||
LD_LIBRARY_PATH: .heroku/vendor/lib
|
||||
|
||||
EOF
|
||||
|
||||
|
||||
[ "$NAME" = "Python/Django" ] || exit 0
|
||||
|
||||
SETTINGS_FILE=$(cd $BUILD_DIR && ls **/settings.py | head -1)
|
||||
PROJECT=$(dirname $SETTINGS_FILE)
|
||||
|
||||
if [[ $MANAGE_FILE ]]; then
|
||||
cat <<EOF
|
||||
|
||||
addons:
|
||||
shared-database:5mb
|
||||
|
||||
default_process_types:
|
||||
web: python $PROJECT/manage.py runserver 0.0.0.0:\$PORT --noreload
|
||||
- heroku-postgresql
|
||||
EOF
|
||||
fi
|
||||
|
||||
Executable
+67
@@ -0,0 +1,67 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Django Collectstatic runner. If you have Django installed, collectstatic will
|
||||
# automatically be executed as part of the build process. If collectstatic
|
||||
# fails, your build fails.
|
||||
|
||||
# This functionality will only activate if Django is in requirements.txt.
|
||||
|
||||
# Runtime arguments:
|
||||
# - $DISABLE_COLLECTSTATIC: disables this functionality.
|
||||
# - $DEBUG_COLLECTSTATIC: upon failure, print out environment variables.
|
||||
|
||||
source $BIN_DIR/utils
|
||||
|
||||
# Location of 'manage.py', if it exists.
|
||||
MANAGE_FILE=$(find . -maxdepth 3 -type f -name 'manage.py' -printf '%d\t%P\n' | sort -nk1 | cut -f2 | head -1)
|
||||
MANAGE_FILE=${MANAGE_FILE:-fakepath}
|
||||
|
||||
# Legacy file-based support for $DISABLE_COLLECTSTATIC
|
||||
[ -f .heroku/collectstatic_disabled ] && DISABLE_COLLECTSTATIC=1
|
||||
|
||||
# Ensure that Django is explicitly specified in requirements.txt
|
||||
pip-grep -s requirements.txt django Django && DJANGO_INSTALLED=1
|
||||
|
||||
bpwatch start collectstatic # metrics collection
|
||||
|
||||
if [ ! "$DISABLE_COLLECTSTATIC" ] && [ -f "$MANAGE_FILE" ] && [ "$DJANGO_INSTALLED" ]; then
|
||||
set +e
|
||||
|
||||
puts-cmd "python $MANAGE_FILE collectstatic --noinput"
|
||||
|
||||
# Run collectstatic, cleanup some of the noisy output.
|
||||
python $MANAGE_FILE collectstatic --noinput --traceback 2>&1 | sed '/^Post-processed/d;/^Copying/d;/^$/d' | indent
|
||||
COLLECTSTATIC_STATUS="${PIPESTATUS[0]}"
|
||||
|
||||
set -e
|
||||
|
||||
# Display a warning if collectstatic failed.
|
||||
[ $COLLECTSTATIC_STATUS -ne 0 ] && {
|
||||
|
||||
echo
|
||||
echo " ! Error while running '$ python $MANAGE_FILE collectstatic --noinput'."
|
||||
echo " See traceback above for details."
|
||||
echo
|
||||
echo " You may need to update application code to resolve this error."
|
||||
echo " Or, you can disable collectstatic for this application:"
|
||||
echo
|
||||
echo " $ heroku config:set DISABLE_COLLECTSTATIC=1"
|
||||
echo
|
||||
echo " https://devcenter.heroku.com/articles/django-assets"
|
||||
|
||||
# Additionally, dump out the environment, if debug mode is on.
|
||||
if [ "$DEBUG_COLLECTSTATIC" ]; then
|
||||
echo
|
||||
echo "****** Collectstatic environment variables:"
|
||||
echo
|
||||
env | indent
|
||||
fi
|
||||
|
||||
# Abort the build.
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo
|
||||
fi
|
||||
|
||||
bpwatch stop collectstatic # metrics collection
|
||||
Executable
+35
@@ -0,0 +1,35 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# This script serves as the Cryptography build step of the
|
||||
# [**Python Buildpack**](https://github.com/heroku/heroku-buildpack-python)
|
||||
# compiler.
|
||||
#
|
||||
# A [buildpack](https://devcenter.heroku.com/articles/buildpacks) is an
|
||||
# adapter between a Python application and Heroku's runtime.
|
||||
#
|
||||
# This script is invoked by [`bin/compile`](/).
|
||||
|
||||
# The location of the pre-compiled libffi binary.
|
||||
VENDORED_LIBFFI="https://lang-python.s3.amazonaws.com/$STACK/libraries/vendor/libffi.tar.gz"
|
||||
|
||||
PKG_CONFIG_PATH="/app/.heroku/vendor/lib/pkgconfig:$PKG_CONFIG_PATH"
|
||||
|
||||
# Syntax sugar.
|
||||
source $BIN_DIR/utils
|
||||
|
||||
bpwatch start libffi_install
|
||||
|
||||
# If a package using cffi exists within requirements, use vendored libffi.
|
||||
if (pip-grep -s requirements.txt argon2-cffi bcrypt cffi cryptography django[argon2] Django[argon2] django[bcrypt] Django[bcrypt] PyNaCl pyOpenSSL PyOpenSSL requests[security] misaka &> /dev/null) then
|
||||
|
||||
if [ ! -d ".heroku/vendor/lib/libffi-3.1" ]; then
|
||||
echo "-----> Noticed cffi. Bootstrapping libffi."
|
||||
mkdir -p .heroku/vendor
|
||||
# Download and extract libffi into target vendor directory.
|
||||
curl $VENDORED_LIBFFI -s | tar zxv -C .heroku/vendor &> /dev/null
|
||||
fi
|
||||
|
||||
export LIBFFI=$(pwd)/vendor
|
||||
fi
|
||||
|
||||
bpwatch stop libffi_install
|
||||
Executable
+35
@@ -0,0 +1,35 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# This script serves as the GDAL build step of the
|
||||
# [**Python Buildpack**](https://github.com/heroku/heroku-buildpack-python)
|
||||
# compiler.
|
||||
#
|
||||
# A [buildpack](https://devcenter.heroku.com/articles/buildpacks) is an
|
||||
# adapter between a Python application and Heroku's runtime.
|
||||
#
|
||||
# This script is invoked by [`bin/compile`](/).
|
||||
|
||||
# The location of the pre-compiled cryptography binary.
|
||||
VENDORED_GDAL="https://lang-python.s3.amazonaws.com/$STACK/libraries/vendor/gdal.tar.gz"
|
||||
|
||||
PKG_CONFIG_PATH="/app/.heroku/vendor/lib/pkgconfig:$PKG_CONFIG_PATH"
|
||||
|
||||
# Syntax sugar.
|
||||
source $BIN_DIR/utils
|
||||
|
||||
bpwatch start gdal_install
|
||||
|
||||
# If GDAL exists within requirements, use vendored gdal.
|
||||
if (pip-grep -s requirements.txt GDAL gdal pygdal &> /dev/null) then
|
||||
|
||||
if [ ! -f ".heroku/vendor/bin/gdalserver" ]; then
|
||||
echo "-----> Noticed GDAL. Bootstrapping gdal."
|
||||
mkdir -p .heroku/vendor
|
||||
# Download and extract cryptography into target vendor directory.
|
||||
curl $VENDORED_GDAL -s | tar zxv -C .heroku/vendor &> /dev/null
|
||||
fi
|
||||
|
||||
export GDAL=$(pwd)/vendor
|
||||
fi
|
||||
|
||||
bpwatch stop gdal_install
|
||||
Executable
+39
@@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# This script serves as the GDAL build step of the
|
||||
# [**Python Buildpack**](https://github.com/heroku/heroku-buildpack-python)
|
||||
# compiler.
|
||||
#
|
||||
# A [buildpack](https://devcenter.heroku.com/articles/buildpacks) is an
|
||||
# adapter between a Python application and Heroku's runtime.
|
||||
#
|
||||
# This script is invoked by [`bin/compile`](/).
|
||||
|
||||
# The location of the pre-compiled cryptography binary.
|
||||
VENDORED_GDAL="https://lang-python.s3.amazonaws.com/$STACK/libraries/vendor/gdal.tar.gz"
|
||||
VENDORED_GEOS="https://lang-python.s3.amazonaws.com/$STACK/libraries/vendor/geos.tar.gz"
|
||||
VENDORED_PROJ="https://lang-python.s3.amazonaws.com/$STACK/libraries/vendor/proj.tar.gz"
|
||||
|
||||
PKG_CONFIG_PATH="/app/.heroku/vendor/lib/pkgconfig:$PKG_CONFIG_PATH"
|
||||
|
||||
# Syntax sugar.
|
||||
source $BIN_DIR/utils
|
||||
|
||||
bpwatch start geo_libs_install
|
||||
|
||||
# If GDAL exists within requirements, use vendored gdal.
|
||||
if [[ "$BUILD_WITH_GEO_LIBRARIES" ]]; then
|
||||
|
||||
if [ ! -f ".heroku/vendor/bin/proj" ]; then
|
||||
echo "-----> Bootstrapping gdal, geos, proj."
|
||||
mkdir -p .heroku/vendor
|
||||
# Download and extract cryptography into target vendor directory.
|
||||
curl $VENDORED_GDAL -s | tar zxv -C .heroku/vendor &> /dev/null
|
||||
curl $VENDORED_GEOS -s | tar zxv -C .heroku/vendor &> /dev/null
|
||||
curl $VENDORED_PROJ -s | tar zxv -C .heroku/vendor &> /dev/null
|
||||
fi
|
||||
|
||||
export GDAL=$(pwd)/vendor
|
||||
fi
|
||||
|
||||
bpwatch stop geo_libs_install
|
||||
Executable
+7
@@ -0,0 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [ -f bin/post_compile ]; then
|
||||
echo "-----> Running post-compile hook"
|
||||
chmod +x bin/post_compile
|
||||
sub-env bin/post_compile
|
||||
fi
|
||||
Executable
+7
@@ -0,0 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [ -f bin/pre_compile ]; then
|
||||
echo "-----> Running pre-compile hook"
|
||||
chmod +x bin/pre_compile
|
||||
sub-env bin/pre_compile
|
||||
fi
|
||||
Executable
+6
@@ -0,0 +1,6 @@
|
||||
# Install Mercurial if it appears to be required.
|
||||
if (grep -Fiq "hg+" requirements.txt) then
|
||||
bpwatch start mercurial_install
|
||||
/app/.heroku/python/bin/pip install mercurial | cleanup | indent
|
||||
bpwatch stop mercurial_install
|
||||
fi
|
||||
Executable
+33
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# This script serves as the NLTK build step of the
|
||||
# [**Python Buildpack**](https://github.com/heroku/heroku-buildpack-python)
|
||||
# compiler.
|
||||
#
|
||||
# A [buildpack](https://devcenter.heroku.com/articles/buildpacks) is an
|
||||
# adapter between a Python application and Heroku's runtime.
|
||||
#
|
||||
# This script is invoked by [`bin/compile`](/).
|
||||
|
||||
# Syntax sugar.
|
||||
source $BIN_DIR/utils
|
||||
|
||||
bpwatch start nltk_download
|
||||
|
||||
# Check that nltk was installed by pip, otherwise obviously not needed
|
||||
python -m nltk.downloader -h >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
puts-step "Downloading NLTK corpora..."
|
||||
nltk_packages_definition="$BUILD_DIR/nltk.txt"
|
||||
if [ -f "$nltk_packages_definition" ]; then
|
||||
nltk_packages=$(tr "\n" " " < "$nltk_packages_definition")
|
||||
puts-step "Downloading NLTK packages: $nltk_packages"
|
||||
python -m nltk.downloader -d $BUILD_DIR/.heroku/python/nltk_data $nltk_packages | indent
|
||||
set-env NLTK_DATA "/app/.heroku/python/nltk_data"
|
||||
else
|
||||
puts-warn "nltk.txt not found, not downloading any corpora"
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
bpwatch stop nltk_download
|
||||
Executable
+38
@@ -0,0 +1,38 @@
|
||||
# Install dependencies with Pip.
|
||||
puts-cmd "pip install -r requirements.txt"
|
||||
|
||||
set +e
|
||||
# delete any existing egg links, to uninstall exisisting installations.
|
||||
find .heroku/python/lib/python*/site-packages/ -name "*.egg-link" -delete 2> /dev/null
|
||||
find .heroku/python/lib/python*/site-packages/ -name "*.pth" -print0 2> /dev/null | xargs -r -0 -n 1 sed -i -e "s#/app/#/$(pwd)/#" &> /dev/null
|
||||
set -e
|
||||
|
||||
set +e
|
||||
# Support for the above, for PyPy.
|
||||
find .heroku/python/lib-python/*/site-packages/ -name "*.egg-link" -print0 2> /dev/null | xargs -r -0 -n 1 sed -i -e "s#/app/#$(pwd)/#" &> /dev/null
|
||||
find .heroku/python/lib-python/*/site-packages/ -name "*.pth" -print0 2> /dev/null | xargs -r -0 -n 1 sed -i -e "s#/app/#/$(pwd)/#" &> /dev/null
|
||||
set -e
|
||||
|
||||
[ ! "$FRESH_PYTHON" ] && bpwatch start pip_install
|
||||
[ "$FRESH_PYTHON" ] && bpwatch start pip_install_first
|
||||
|
||||
set +e
|
||||
/app/.heroku/python/bin/pip install -r $BUILD_DIR/requirements.txt --exists-action=w --src=/app/.heroku/src --disable-pip-version-check --no-cache-dir 2>&1 | tee $WARNINGS_LOG | cleanup | indent
|
||||
PIP_STATUS="${PIPESTATUS[0]}"
|
||||
set -e
|
||||
|
||||
show-warnings
|
||||
|
||||
if [[ ! $PIP_STATUS -eq 0 ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
# Smart Requirements handling
|
||||
cp requirements.txt .heroku/python/requirements-declared.txt
|
||||
/app/.heroku/python/bin/pip freeze --disable-pip-version-check > .heroku/python/requirements-installed.txt
|
||||
|
||||
[ ! "$FRESH_PYTHON" ] && bpwatch stop pip_install
|
||||
[ "$FRESH_PYTHON" ] && bpwatch stop pip_install_first
|
||||
|
||||
echo
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
set +e
|
||||
# Install dependencies with Pip.
|
||||
bpwatch start pip_uninstall
|
||||
if [[ -f .heroku/python/requirements-declared.txt ]]; then
|
||||
|
||||
cp .heroku/python/requirements-declared.txt requirements-declared.txt
|
||||
|
||||
pip-diff --stale requirements-declared.txt requirements.txt --exclude setuptools pip wheel > .heroku/python/requirements-stale.txt
|
||||
|
||||
rm -fr requirements-declared.txt
|
||||
|
||||
if [[ -s .heroku/python/requirements-stale.txt ]]; then
|
||||
puts-step "Uninstalling stale dependencies"
|
||||
/app/.heroku/python/bin/pip uninstall -r .heroku/python/requirements-stale.txt -y --exists-action=w | cleanup | indent
|
||||
fi
|
||||
fi
|
||||
bpwatch stop pip_uninstall
|
||||
set -e
|
||||
Executable
+34
@@ -0,0 +1,34 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# This script serves as the Pylibmc build step of the
|
||||
# [**Python Buildpack**](https://github.com/heroku/heroku-buildpack-python)
|
||||
# compiler.
|
||||
#
|
||||
# A [buildpack](https://devcenter.heroku.com/articles/buildpacks) is an
|
||||
# adapter between a Python application and Heroku's runtime.
|
||||
#
|
||||
# This script is invoked by [`bin/compile`](/).
|
||||
|
||||
# The location of the pre-compiled libmemcached binary.
|
||||
VENDORED_MEMCACHED="https://lang-python.s3.amazonaws.com/$STACK/libraries/vendor/libmemcache.tar.gz"
|
||||
|
||||
# Syntax sugar.
|
||||
source $BIN_DIR/utils
|
||||
|
||||
|
||||
bpwatch start pylibmc_install
|
||||
|
||||
# If pylibmc exists within requirements, use vendored libmemcached.
|
||||
if (pip-grep -s requirements.txt pylibmc &> /dev/null) then
|
||||
|
||||
if [ ! -d ".heroku/vendor/lib/sasl2" ]; then
|
||||
echo "-----> Noticed pylibmc. Bootstrapping libmemcached."
|
||||
mkdir -p .heroku/vendor
|
||||
# Download and extract libmemcached into target vendor directory.
|
||||
curl $VENDORED_MEMCACHED -s | tar zxv -C .heroku/vendor &> /dev/null
|
||||
fi
|
||||
|
||||
export LIBMEMCACHED=$(pwd)/vendor
|
||||
fi
|
||||
|
||||
bpwatch stop pylibmc_install
|
||||
Executable
+78
@@ -0,0 +1,78 @@
|
||||
set +e
|
||||
PYTHON_VERSION=$(cat runtime.txt)
|
||||
|
||||
# Install Python.
|
||||
if [ -f .heroku/python-version ]; then
|
||||
if [ ! $(cat .heroku/python-version) = $PYTHON_VERSION ]; then
|
||||
bpwatch start uninstall_python
|
||||
puts-step "Found $(cat .heroku/python-version), removing"
|
||||
rm -fr .heroku/python
|
||||
bpwatch stop uninstall_python
|
||||
else
|
||||
SKIP_INSTALL=1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! $STACK = $CACHED_PYTHON_STACK ]; then
|
||||
bpwatch start uninstall_python
|
||||
rm -fr .heroku/python .heroku/python-stack .heroku/vendor
|
||||
unset SKIP_INSTALL
|
||||
bpwatch stop uninstall_python
|
||||
fi
|
||||
|
||||
|
||||
if [ ! "$SKIP_INSTALL" ]; then
|
||||
bpwatch start install_python
|
||||
puts-step "Installing $PYTHON_VERSION"
|
||||
|
||||
# Prepare destination directory.
|
||||
mkdir -p .heroku/python
|
||||
|
||||
curl https://lang-python.s3.amazonaws.com/$STACK/runtimes/$PYTHON_VERSION.tar.gz -s | tar zxv -C .heroku/python &> /dev/null
|
||||
if [[ $? != 0 ]] ; then
|
||||
puts-warn "Requested runtime ($PYTHON_VERSION) is not available for this stack ($STACK)."
|
||||
puts-warn "Aborting. More info: https://devcenter.heroku.com/articles/python-support"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
bpwatch stop install_python
|
||||
|
||||
# Record for future reference.
|
||||
echo $PYTHON_VERSION > .heroku/python-version
|
||||
echo $STACK > .heroku/python-stack
|
||||
FRESH_PYTHON=true
|
||||
|
||||
hash -r
|
||||
fi
|
||||
|
||||
# If Pip isn't up to date:
|
||||
if [ "$FRESH_PYTHON" ] || [[ ! $(pip --version) == *$PIP_VERSION* ]]; then
|
||||
WORKING_DIR=$(pwd)
|
||||
|
||||
bpwatch start prepare_environment
|
||||
|
||||
TMPTARDIR=$(mktemp -d)
|
||||
trap "rm -rf $TMPTARDIR" RETURN
|
||||
|
||||
bpwatch start install_setuptools
|
||||
# Prepare it for the real world
|
||||
# puts-step "Installing Setuptools ($SETUPTOOLS_VERSION)"
|
||||
tar zxf $ROOT_DIR/vendor/setuptools-$SETUPTOOLS_VERSION.tar.gz -C $TMPTARDIR
|
||||
cd $TMPTARDIR/setuptools-$SETUPTOOLS_VERSION/
|
||||
python setup.py install &> /dev/null
|
||||
cd $WORKING_DIR
|
||||
bpwatch stop install_setuptoools
|
||||
|
||||
bpwatch start install_pip
|
||||
# puts-step "Installing Pip ($PIP_VERSION)"
|
||||
tar zxf $ROOT_DIR/vendor/pip-$PIP_VERSION.tar.gz -C $TMPTARDIR
|
||||
cd $TMPTARDIR/pip-$PIP_VERSION/
|
||||
python setup.py install &> /dev/null
|
||||
cd $WORKING_DIR
|
||||
|
||||
bpwatch stop install_pip
|
||||
bpwatch stop prepare_environment
|
||||
fi
|
||||
|
||||
set -e
|
||||
hash -r
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Syntax sugar.
|
||||
source $BIN_DIR/utils
|
||||
|
||||
if (pip-grep -s requirements.txt setuptools distribute &> /dev/null) then
|
||||
|
||||
puts-warn 'The package setuptools/distribute is listed in requirements.txt.'
|
||||
puts-warn 'Please remove to ensure expected behavior. '
|
||||
|
||||
fi
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Syntax sugar.
|
||||
BIN_DIR=$(cd $(dirname $0); pwd) # absolute path
|
||||
source $BIN_DIR/utils
|
||||
|
||||
DISABLE_COLLECTSTATIC=1 "$(dirname ${0:-})/compile" "$1" "$2" "$3"
|
||||
|
||||
if [[ -f "$1/requirements-test.txt" ]]; then
|
||||
/app/.heroku/python/bin/pip install -r "$1/requirements-test.txt" --exists-action=w --src=./.heroku/src --disable-pip-version-check --no-cache-dir 2>&1 | cleanup | indent
|
||||
fi
|
||||
@@ -0,0 +1,110 @@
|
||||
shopt -s extglob
|
||||
|
||||
if [ $(uname) == Darwin ]; then
|
||||
sed() { command sed -l "$@"; }
|
||||
else
|
||||
sed() { command sed -u "$@"; }
|
||||
fi
|
||||
|
||||
# Syntax sugar.
|
||||
indent() {
|
||||
sed "s/^/ /"
|
||||
}
|
||||
|
||||
# Clean up pip output
|
||||
cleanup() {
|
||||
sed -e 's/\.\.\.\+/.../g' | sed -e '/already satisfied/Id' | sed -e '/No files were found to uninstall/Id' | sed -e '/Overwriting/Id' | sed -e '/python executable/Id' | sed -e '/no previously-included files/Id'
|
||||
}
|
||||
|
||||
# Buildpack Indented line.
|
||||
puts-line() {
|
||||
echo " $@"
|
||||
}
|
||||
|
||||
# Buildpack Steps.
|
||||
puts-step() {
|
||||
echo "-----> $@"
|
||||
}
|
||||
|
||||
# Buildpack Warnings.
|
||||
puts-warn() {
|
||||
echo " ! $@"
|
||||
}
|
||||
|
||||
# Buildpack Commands.
|
||||
puts-cmd() {
|
||||
echo " $ $@"
|
||||
}
|
||||
|
||||
# Usage: $ set-env key value
|
||||
set-env() {
|
||||
echo "export $1=$2" >> $PROFILE_PATH
|
||||
echo "export $1=$2" >> $EXPORT_PATH
|
||||
}
|
||||
|
||||
# Usage: $ set-default-env key value
|
||||
set-default-env() {
|
||||
echo "export $1=\${$1:-$2}" >> $PROFILE_PATH
|
||||
echo "export $1=\${$1:-$2}" >> $EXPORT_PATH
|
||||
}
|
||||
|
||||
# Usage: $ un-set-env key
|
||||
un-set-env() {
|
||||
echo "unset $1" >> $PROFILE_PATH
|
||||
}
|
||||
|
||||
# Does some serious copying.
|
||||
deep-cp() {
|
||||
declare source="$1" target="$2"
|
||||
|
||||
mkdir -p "$target"
|
||||
|
||||
# cp doesn't like being called without source params,
|
||||
# so make sure they expand to something first.
|
||||
# subshell to avoid surprising caller with shopts.
|
||||
(
|
||||
shopt -s nullglob dotglob
|
||||
set -- "$source"/!(tmp|.|..)
|
||||
[[ $# == 0 ]] || cp -a "$@" "$target"
|
||||
)
|
||||
}
|
||||
|
||||
# Does some serious moving.
|
||||
deep-mv() {
|
||||
deep-cp "$1" "$2"
|
||||
deep-rm "$1"
|
||||
}
|
||||
|
||||
# Does some serious deleting.
|
||||
deep-rm() {
|
||||
# subshell to avoid surprising caller with shopts.
|
||||
(
|
||||
shopt -s dotglob
|
||||
rm -rf "$1"/!(.curlrc|.netrc|tmp|.|..)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
sub-env() {
|
||||
|
||||
WHITELIST=${2:-''}
|
||||
BLACKLIST=${3:-'^(GIT_DIR|PYTHONHOME|LD_LIBRARY_PATH|LIBRARY_PATH|PATH)$'}
|
||||
|
||||
# Python-specific variables.
|
||||
export PYHONHOME=$BUILD_DIR/.heroku/python
|
||||
export PYTHONPATH=$BUILD_DIR/
|
||||
|
||||
(
|
||||
if [ -d "$ENV_DIR" ]; then
|
||||
for e in $(ls $ENV_DIR); do
|
||||
echo "$e" | grep -E "$WHITELIST" | grep -qvE "$BLACKLIST" &&
|
||||
export "$e=$(cat $ENV_DIR/$e)"
|
||||
:
|
||||
done
|
||||
fi
|
||||
|
||||
$1
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
Executable
+49
@@ -0,0 +1,49 @@
|
||||
shopt -s extglob
|
||||
|
||||
old-platform() {
|
||||
if grep -qi 'InsecurePlatformWarning' "$WARNINGS_LOG"; then
|
||||
echo
|
||||
puts-warn "Hello! It looks like your application is using an outdated version of Python."
|
||||
puts-warn "This caused the security warning you saw above during the 'pip install' step."
|
||||
puts-warn "We recommend '$RECOMMENDED_PYTHON_VERSION', which you can specify in a 'runtime.txt' file."
|
||||
puts-warn " -- Much Love, Heroku."
|
||||
fi
|
||||
}
|
||||
|
||||
pylibmc-missing() {
|
||||
if grep -qi 'fatal error: libmemcached/memcached.h: No such file or directory' "$WARNINGS_LOG"; then
|
||||
echo
|
||||
puts-warn "Hello! There was a problem with your build related to libmemcache."
|
||||
puts-warn "The Python library 'pylibmc' must be explicitly specified in 'requirements.txt' in order to build correctly."
|
||||
puts-warn "Once you do that, everything should work as expected. -- Much Love, Heroku."
|
||||
fi
|
||||
}
|
||||
|
||||
scipy-included() {
|
||||
if grep -qi 'running setup.py install for scipy' "$WARNINGS_LOG"; then
|
||||
echo
|
||||
puts-warn "Hello! It looks like you're trying to use scipy on Heroku."
|
||||
puts-warn "Unfortunately, at this time, we do not directly support this library."
|
||||
puts-warn "There is, however, a buildpack available that makes it possible to use it on Heroku."
|
||||
puts-warn "You can learn more here: https://devcenter.heroku.com/articles/python-c-deps"
|
||||
puts-warn "Sorry for the inconvenience. -- Much Love, Heroku."
|
||||
fi
|
||||
}
|
||||
|
||||
distribute-included() {
|
||||
if grep -qi 'Running setup.py install for distribute' "$WARNINGS_LOG"; then
|
||||
echo
|
||||
puts-warn "Hello! Your requirements.txt file contains the distribute package."
|
||||
puts-warn "This library is automatically installed by Heroku and shouldn't be in"
|
||||
puts-warn "Your requirements.txt file. This can cause unexpected behavior."
|
||||
puts-warn " -- Much Love, Heroku."
|
||||
fi
|
||||
}
|
||||
|
||||
show-warnings() {
|
||||
old-platform
|
||||
pylibmc-missing
|
||||
scipy-included
|
||||
distribute-included
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
# Python Buildpack Binaries
|
||||
|
||||
|
||||
To get started with it, create an app on Heroku inside a clone of this repository, and set your S3 config vars:
|
||||
|
||||
$ heroku create --buildpack https://github.com/heroku/heroku-buildpack-python#not-heroku
|
||||
$ heroku config:set WORKSPACE_DIR=builds
|
||||
$ heroku config:set AWS_ACCESS_KEY_ID=<your_aws_key>
|
||||
$ heroku config:set AWS_SECRET_ACCESS_KEY=<your_aws_secret>
|
||||
$ heroku config:set S3_BUCKET=<your_s3_bucket_name>
|
||||
|
||||
|
||||
Then, shell into an instance and run a build by giving the name of the formula inside `builds`:
|
||||
|
||||
$ heroku run bash
|
||||
Running `bash` attached to terminal... up, run.6880
|
||||
~ $ bob build runtimes/python-2.7.6
|
||||
|
||||
Fetching dependencies... found 2:
|
||||
- libraries/sqlite
|
||||
|
||||
Building formula runtimes/python-2.7.6:
|
||||
=== Building Python 2.7.6
|
||||
Fetching Python v2.7.6 source...
|
||||
Compiling...
|
||||
|
||||
If this works, run `bob deploy` instead of `bob build` to have the result uploaded to S3 for you.
|
||||
|
||||
To speed things up drastically, it'll usually be a good idea to `heroku run bash --size PX` instead.
|
||||
|
||||
Enjoy :)
|
||||
Executable
+22
@@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build Path: /app/.heroku/python/
|
||||
|
||||
OUT_PREFIX=$1
|
||||
|
||||
echo "Building SQLite..."
|
||||
|
||||
|
||||
SOURCE_TARBALL='https://www.sqlite.org/sqlite-autoconf-3070900.tar.gz'
|
||||
|
||||
curl $SOURCE_TARBALL | tar xz
|
||||
# jx
|
||||
mv sqlite-autoconf-3070900 sqlite
|
||||
|
||||
cd sqlite
|
||||
./configure --prefix=$OUT_PREFIX
|
||||
make
|
||||
make install
|
||||
|
||||
# Cleanup
|
||||
cd ..
|
||||
rm -fr sqlite
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build Path: /app/.heroku/vendor/
|
||||
|
||||
OUT_PREFIX=$1
|
||||
|
||||
# Use new path, containing autoconf.
|
||||
export PATH="/app/.heroku/python/bin/:$PATH"
|
||||
hash -r
|
||||
|
||||
|
||||
echo "Building gdal..."
|
||||
|
||||
SOURCE_TARBALL='http://download.osgeo.org/gdal/1.11.1/gdal-1.11.1.tar.gz'
|
||||
|
||||
curl -L $SOURCE_TARBALL | tar zx
|
||||
|
||||
cd gdal-1.11.1
|
||||
./configure --prefix=$OUT_PREFIX &&
|
||||
make
|
||||
make install
|
||||
|
||||
# Cleanup
|
||||
cd ..
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build Path: /app/.heroku/vendor/
|
||||
|
||||
OUT_PREFIX=$1
|
||||
|
||||
# Use new path, containing autoconf.
|
||||
export PATH="/app/.heroku/python/bin/:$PATH"
|
||||
hash -r
|
||||
|
||||
|
||||
echo "Building geos..."
|
||||
|
||||
SOURCE_TARBALL='http://download.osgeo.org/geos/geos-3.4.2.tar.bz2'
|
||||
|
||||
curl -L $SOURCE_TARBALL | tar xj
|
||||
|
||||
cd geos-3.4.2
|
||||
./configure --prefix=$OUT_PREFIX &&
|
||||
make
|
||||
make install
|
||||
|
||||
# Cleanup
|
||||
cd ..
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build Path: /app/.heroku/vendor/
|
||||
|
||||
OUT_PREFIX=$1
|
||||
|
||||
# Skip the build for heroku-16.
|
||||
if [[ $S3_PREFIX == "heroku-16" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Use new path, containing autoconf.
|
||||
export PATH="/app/.heroku/python/bin/:$PATH"
|
||||
hash -r
|
||||
|
||||
|
||||
echo "Building libffi..."
|
||||
|
||||
SOURCE_TARBALL='ftp://sourceware.org/pub/libffi/libffi-3.1.tar.gz'
|
||||
|
||||
curl -L $SOURCE_TARBALL | tar x
|
||||
|
||||
cd libffi-3.1
|
||||
./configure --prefix=$OUT_PREFIX --disable-static &&
|
||||
make
|
||||
make install
|
||||
|
||||
# Cleanup
|
||||
cd ..
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build Path: /app/.heroku/vendor/
|
||||
|
||||
OUT_PREFIX=$1
|
||||
|
||||
# Skip the build for heroku-16.
|
||||
if [[ $S3_PREFIX == "heroku-16" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# fail hard
|
||||
set -o pipefail
|
||||
# fail harder
|
||||
set -eux
|
||||
|
||||
DEFAULT_VERSION="1.0.18"
|
||||
dep_version=${VERSION:-$DEFAULT_VERSION}
|
||||
dep_dirname=libmemcached-${dep_version}
|
||||
dep_archive_name=${dep_dirname}.tar.gz
|
||||
dep_url=https://launchpad.net/libmemcached/1.0/${dep_version}/+download/${dep_archive_name}
|
||||
|
||||
# SASL Support.
|
||||
echo "-----> Building cyrus-sasl 2.1.26..."
|
||||
|
||||
curl -LO ftp://ftp.cyrusimap.org/cyrus-sasl/cyrus-sasl-2.1.26.tar.gz
|
||||
# FTP doesn't play well with piping into tar xz
|
||||
tar xzf cyrus-sasl-2.1.26.tar.gz
|
||||
|
||||
pushd cyrus-sasl-2.1.26
|
||||
./configure --prefix=${OUT_PREFIX} --with-plugindir=${OUT_PREFIX}lib/sasl2 --with-configdir=${OUT_PREFIX}lib/sasl2
|
||||
|
||||
make -s -j 9
|
||||
make install -s
|
||||
popd
|
||||
|
||||
echo "-----> Building libmemcached ${dep_version}..."
|
||||
|
||||
curl -L ${dep_url} | tar xz
|
||||
pushd ${dep_dirname}
|
||||
CPPFLAGS=-I${OUT_PREFIX}/include LDFLAGS=-L${OUT_PREFIX}/lib ./configure --prefix=${OUT_PREFIX} --without-memcached
|
||||
make -s -j 9
|
||||
make install -s
|
||||
popd
|
||||
|
||||
echo "-----> Done."
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build Path: /app/.heroku/vendor/
|
||||
|
||||
OUT_PREFIX=$1
|
||||
|
||||
# Use new path, containing autoconf.
|
||||
export PATH="/app/.heroku/python/bin/:$PATH"
|
||||
hash -r
|
||||
|
||||
|
||||
echo "Building gdal..."
|
||||
|
||||
SOURCE_TARBALL='http://download.osgeo.org/proj/proj-4.8.0.tar.gz'
|
||||
|
||||
curl -L $SOURCE_TARBALL | tar zx
|
||||
|
||||
cd proj-4.8.0
|
||||
./configure --prefix=$OUT_PREFIX &&
|
||||
make
|
||||
make install
|
||||
|
||||
# Cleanup
|
||||
cd ..
|
||||
Executable
+14
@@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build Path: /app/.heroku/python/
|
||||
# Build Deps: libraries/sqlite
|
||||
|
||||
# NOTICE: This formula only works for the cedar-14 stack, not cedar.
|
||||
|
||||
OUT_PREFIX=$1
|
||||
|
||||
echo "Building PyPy..."
|
||||
SOURCE_TARBALL='https://bitbucket.org/pypy/pypy/downloads/pypy2-v5.3.1-linux64.tar.bz2'
|
||||
curl -L $SOURCE_TARBALL | tar jx
|
||||
cp -R pypy2-v5.3.1-linux64/* $OUT_PREFIX
|
||||
|
||||
ln $OUT_PREFIX/bin/pypy $OUT_PREFIX/bin/python
|
||||
Executable
+14
@@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build Path: /app/.heroku/python/
|
||||
# Build Deps: libraries/sqlite
|
||||
|
||||
# NOTICE: This formula only works for the cedar-14 stack, not cedar.
|
||||
|
||||
OUT_PREFIX=$1
|
||||
|
||||
echo "Building PyPy..."
|
||||
SOURCE_TARBALL='https://bitbucket.org/pypy/pypy/downloads/pypy2-v5.6.0-linux64.tar.bz2'
|
||||
curl -L $SOURCE_TARBALL | tar jx
|
||||
cp -R pypy2-v5.6.0-linux64/* $OUT_PREFIX
|
||||
|
||||
ln $OUT_PREFIX/bin/pypy $OUT_PREFIX/bin/python
|
||||
Executable
+14
@@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build Path: /app/.heroku/python/
|
||||
# Build Deps: libraries/sqlite
|
||||
|
||||
# NOTICE: This formula only works for the cedar-14 stack, not cedar.
|
||||
|
||||
OUT_PREFIX=$1
|
||||
|
||||
echo "Building PyPy..."
|
||||
SOURCE_TARBALL='https://bitbucket.org/pypy/pypy/downloads/pypy3-2.4.0-linux64.tar.bz2'
|
||||
curl -L $SOURCE_TARBALL | tar jx
|
||||
cp -R pypy3-2.4.0-linux64/* $OUT_PREFIX
|
||||
|
||||
ln $OUT_PREFIX/bin/pypy3 $OUT_PREFIX/bin/python
|
||||
Executable
+14
@@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build Path: /app/.heroku/python/
|
||||
# Build Deps: libraries/sqlite
|
||||
|
||||
# NOTICE: This formula only works for the cedar-14 stack, not cedar.
|
||||
|
||||
OUT_PREFIX=$1
|
||||
|
||||
echo "Building PyPy..."
|
||||
SOURCE_TARBALL='https://bitbucket.org/pypy/pypy/downloads/pypy3.3-v5.5.0-alpha-linux64.tar.bz2'
|
||||
curl -L $SOURCE_TARBALL | tar jx
|
||||
cp -R pypy3-v5.5.0-linux64/* $OUT_PREFIX
|
||||
|
||||
ln $OUT_PREFIX/bin/pypy3 $OUT_PREFIX/bin/python
|
||||
Executable
+15
@@ -0,0 +1,15 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build Path: /app/.heroku/python/
|
||||
# Build Deps: libraries/sqlite
|
||||
|
||||
OUT_PREFIX=$1
|
||||
|
||||
echo "Building Python..."
|
||||
SOURCE_TARBALL='https://python.org/ftp/python/2.7.10/Python-2.7.10.tgz'
|
||||
curl -L $SOURCE_TARBALL | tar xz
|
||||
mv Python-2.7.10 src
|
||||
cd src
|
||||
|
||||
./configure --prefix=$OUT_PREFIX --with-ensurepip=no
|
||||
make
|
||||
make install
|
||||
Executable
+15
@@ -0,0 +1,15 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build Path: /app/.heroku/python/
|
||||
# Build Deps: libraries/sqlite
|
||||
|
||||
OUT_PREFIX=$1
|
||||
|
||||
echo "Building Python..."
|
||||
SOURCE_TARBALL='https://python.org/ftp/python/2.7.11/Python-2.7.11.tgz'
|
||||
curl -L $SOURCE_TARBALL | tar xz
|
||||
mv Python-2.7.11 src
|
||||
cd src
|
||||
|
||||
./configure --prefix=$OUT_PREFIX --with-ensurepip=no
|
||||
make
|
||||
make install
|
||||
Executable
+15
@@ -0,0 +1,15 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build Path: /app/.heroku/python/
|
||||
# Build Deps: libraries/sqlite
|
||||
|
||||
OUT_PREFIX=$1
|
||||
|
||||
echo "Building Python..."
|
||||
SOURCE_TARBALL='https://python.org/ftp/python/2.7.12/Python-2.7.12.tgz'
|
||||
curl -L $SOURCE_TARBALL | tar xz
|
||||
mv Python-2.7.12 src
|
||||
cd src
|
||||
|
||||
./configure --prefix=$OUT_PREFIX --with-ensurepip=no
|
||||
make
|
||||
make install
|
||||
Executable
+15
@@ -0,0 +1,15 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build Path: /app/.heroku/python/
|
||||
# Build Deps: libraries/sqlite
|
||||
|
||||
OUT_PREFIX=$1
|
||||
|
||||
echo "Building Python..."
|
||||
SOURCE_TARBALL='https://python.org/ftp/python/2.7.13/Python-2.7.13.tgz'
|
||||
curl -L $SOURCE_TARBALL | tar xz
|
||||
mv Python-2.7.13 src
|
||||
cd src
|
||||
|
||||
./configure --prefix=$OUT_PREFIX --enable-unicode=ucs4 --with-ensurepip=no
|
||||
make
|
||||
make install
|
||||
Executable
+15
@@ -0,0 +1,15 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build Path: /app/.heroku/python/
|
||||
# Build Deps: libraries/sqlite
|
||||
|
||||
OUT_PREFIX=$1
|
||||
|
||||
echo "Building Python..."
|
||||
SOURCE_TARBALL='https://python.org/ftp/python/2.7.9/Python-2.7.9.tgz'
|
||||
curl -L $SOURCE_TARBALL | tar xz
|
||||
mv Python-2.7.9 src
|
||||
cd src
|
||||
|
||||
./configure --prefix=$OUT_PREFIX --with-ensurepip=no
|
||||
make
|
||||
make install
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build Path: /app/.heroku/python/
|
||||
# Build Deps: libraries/sqlite
|
||||
|
||||
OUT_PREFIX=$1
|
||||
|
||||
echo "Building Python..."
|
||||
SOURCE_TARBALL='https://python.org/ftp/python/3.5.2/Python-3.5.2.tgz'
|
||||
curl -L $SOURCE_TARBALL | tar xz
|
||||
mv Python-3.5.2 src
|
||||
cd src
|
||||
|
||||
./configure --prefix=$OUT_PREFIX --with-ensurepip=no
|
||||
make
|
||||
make install
|
||||
|
||||
# ln $OUT_PREFIX/bin/python3 $OUT_PREFIX/bin/python
|
||||
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build Path: /app/.heroku/python/
|
||||
# Build Deps: libraries/sqlite
|
||||
|
||||
OUT_PREFIX=$1
|
||||
|
||||
echo "Building Python..."
|
||||
SOURCE_TARBALL='https://python.org/ftp/python/3.6.0/Python-3.6.0.tgz'
|
||||
curl -L $SOURCE_TARBALL | tar xz
|
||||
mv Python-3.6.0 src
|
||||
cd src
|
||||
|
||||
./configure --prefix=$OUT_PREFIX --with-ensurepip=no
|
||||
make
|
||||
make install
|
||||
|
||||
ln $OUT_PREFIX/bin/python3 $OUT_PREFIX/bin/python
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
bob-builder==0.0.5
|
||||
@@ -1,29 +0,0 @@
|
||||
Author
|
||||
------
|
||||
|
||||
Ian Bicking
|
||||
|
||||
Maintainers
|
||||
-----------
|
||||
|
||||
Brian Rosner
|
||||
Carl Meyer
|
||||
Jannis Leidel
|
||||
|
||||
Contributors
|
||||
------------
|
||||
|
||||
Antonio Cuni
|
||||
Armin Ronacher
|
||||
Christopher Nilsson
|
||||
Curt Micol
|
||||
Douglas Creager
|
||||
Jeff Hammel
|
||||
Jorge Vargas
|
||||
Josh Bronson
|
||||
Kumar McMillan
|
||||
Lars Francke
|
||||
Philip Jenvey
|
||||
Ronny Pfannschmidt
|
||||
Tarek Ziadé
|
||||
Vinay Sajip
|
||||
@@ -1,22 +0,0 @@
|
||||
Copyright (c) 2007 Ian Bicking and Contributors
|
||||
Copyright (c) 2009 Ian Bicking, The Open Planning Project
|
||||
Copyright (c) 2011 The virtualenv developers
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
@@ -1,9 +0,0 @@
|
||||
recursive-include docs *.txt
|
||||
recursive-include scripts *
|
||||
recursive-include virtualenv_support *.egg *.tar.gz
|
||||
recursive-exclude virtualenv_support *.py
|
||||
recursive-exclude docs/_templates *.*
|
||||
include virtualenv_support/__init__.py
|
||||
include *.py
|
||||
include AUTHORS.txt
|
||||
include LICENSE.txt
|
||||
@@ -1,827 +0,0 @@
|
||||
Metadata-Version: 1.0
|
||||
Name: virtualenv
|
||||
Version: 1.6.4
|
||||
Summary: Virtual Python Environment builder
|
||||
Home-page: http://www.virtualenv.org
|
||||
Author: Jannis Leidel, Carl Meyer and Brian Rosner
|
||||
Author-email: python-virtualenv@groups.google.com
|
||||
License: MIT
|
||||
Description:
|
||||
|
||||
Status and License
|
||||
------------------
|
||||
|
||||
``virtualenv`` is a successor to `workingenv
|
||||
<http://cheeseshop.python.org/pypi/workingenv.py>`_, and an extension
|
||||
of `virtual-python
|
||||
<http://peak.telecommunity.com/DevCenter/EasyInstall#creating-a-virtual-python>`_.
|
||||
|
||||
It was written by Ian Bicking, sponsored by the `Open Planning
|
||||
Project <http://openplans.org>`_ and is now maintained by a
|
||||
`group of developers <https://github.com/pypa/virtualenv/raw/master/AUTHORS.txt>`_.
|
||||
It is licensed under an
|
||||
`MIT-style permissive license <https://github.com/pypa/virtualenv/raw/master/LICENSE.txt>`_.
|
||||
|
||||
You can install it with ``easy_install virtualenv``, or the `latest
|
||||
development version <https://github.com/pypa/virtualenv/tarball/develop#egg=virtualenv-dev>`_
|
||||
with ``easy_install virtualenv==dev``.
|
||||
|
||||
What It Does
|
||||
------------
|
||||
|
||||
``virtualenv`` is a tool to create isolated Python environments.
|
||||
|
||||
The basic problem being addressed is one of dependencies and versions,
|
||||
and indirectly permissions. Imagine you have an application that
|
||||
needs version 1 of LibFoo, but another application requires version
|
||||
2. How can you use both these applications? If you install
|
||||
everything into ``/usr/lib/python2.7/site-packages`` (or whatever your
|
||||
platform's standard location is), it's easy to end up in a situation
|
||||
where you unintentionally upgrade an application that shouldn't be
|
||||
upgraded.
|
||||
|
||||
Or more generally, what if you want to install an application *and
|
||||
leave it be*? If an application works, any change in its libraries or
|
||||
the versions of those libraries can break the application.
|
||||
|
||||
Also, what if you can't install packages into the global
|
||||
``site-packages`` directory? For instance, on a shared host.
|
||||
|
||||
In all these cases, ``virtualenv`` can help you. It creates an
|
||||
environment that has its own installation directories, that doesn't
|
||||
share libraries with other virtualenv environments (and optionally
|
||||
doesn't access the globally installed libraries either).
|
||||
|
||||
The basic usage is::
|
||||
|
||||
$ python virtualenv.py ENV
|
||||
|
||||
If you install it you can also just do ``virtualenv ENV``.
|
||||
|
||||
This creates ``ENV/lib/pythonX.X/site-packages``, where any libraries you
|
||||
install will go. It also creates ``ENV/bin/python``, which is a Python
|
||||
interpreter that uses this environment. Anytime you use that interpreter
|
||||
(including when a script has ``#!/path/to/ENV/bin/python`` in it) the libraries
|
||||
in that environment will be used.
|
||||
|
||||
It also installs either `Setuptools
|
||||
<http://peak.telecommunity.com/DevCenter/setuptools>`_ or `distribute
|
||||
<http://pypi.python.org/pypi/distribute>`_ into the environment. To use
|
||||
Distribute instead of setuptools, just call virtualenv like this::
|
||||
|
||||
$ python virtualenv.py --distribute ENV
|
||||
|
||||
You can also set the environment variable VIRTUALENV_USE_DISTRIBUTE.
|
||||
|
||||
A new virtualenv also includes the `pip <http://pypy.python.org/pypi/pip>`_
|
||||
installer, so you can use `ENV/bin/pip`` to install additional packages into
|
||||
the environment.
|
||||
|
||||
Windows Notes
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
Some paths within the virtualenv are slightly different on Windows: scripts and
|
||||
executables on Windows go in ``ENV\Scripts\`` instead of ``ENV/bin/`` and
|
||||
libraries go in ``ENV\Lib\`` rather than ``ENV/lib/``.
|
||||
|
||||
To create a virtualenv under a path with spaces in it on Windows, you'll need
|
||||
the `win32api <http://sourceforge.net/projects/pywin32/>`_ library installed.
|
||||
|
||||
PyPy Support
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Beginning with virtualenv version 1.5 `PyPy <http://pypy.org>`_ is
|
||||
supported. To use PyPy 1.4 or 1.4.1, you need a version of virtualenv >= 1.5.
|
||||
To use PyPy 1.5, you need a version of virtualenv >= 1.6.1.
|
||||
|
||||
Creating Your Own Bootstrap Scripts
|
||||
-----------------------------------
|
||||
|
||||
While this creates an environment, it doesn't put anything into the
|
||||
environment. Developers may find it useful to distribute a script
|
||||
that sets up a particular environment, for example a script that
|
||||
installs a particular web application.
|
||||
|
||||
To create a script like this, call
|
||||
``virtualenv.create_bootstrap_script(extra_text)``, and write the
|
||||
result to your new bootstrapping script. Here's the documentation
|
||||
from the docstring:
|
||||
|
||||
Creates a bootstrap script, which is like this script but with
|
||||
extend_parser, adjust_options, and after_install hooks.
|
||||
|
||||
This returns a string that (written to disk of course) can be used
|
||||
as a bootstrap script with your own customizations. The script
|
||||
will be the standard virtualenv.py script, with your extra text
|
||||
added (your extra text should be Python code).
|
||||
|
||||
If you include these functions, they will be called:
|
||||
|
||||
``extend_parser(optparse_parser)``:
|
||||
You can add or remove options from the parser here.
|
||||
|
||||
``adjust_options(options, args)``:
|
||||
You can change options here, or change the args (if you accept
|
||||
different kinds of arguments, be sure you modify ``args`` so it is
|
||||
only ``[DEST_DIR]``).
|
||||
|
||||
``after_install(options, home_dir)``:
|
||||
|
||||
After everything is installed, this function is called. This
|
||||
is probably the function you are most likely to use. An
|
||||
example would be::
|
||||
|
||||
def after_install(options, home_dir):
|
||||
if sys.platform == 'win32':
|
||||
bin = 'Scripts'
|
||||
else:
|
||||
bin = 'bin'
|
||||
subprocess.call([join(home_dir, bin, 'easy_install'),
|
||||
'MyPackage'])
|
||||
subprocess.call([join(home_dir, bin, 'my-package-script'),
|
||||
'setup', home_dir])
|
||||
|
||||
This example immediately installs a package, and runs a setup
|
||||
script from that package.
|
||||
|
||||
Bootstrap Example
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
Here's a more concrete example of how you could use this::
|
||||
|
||||
import virtualenv, textwrap
|
||||
output = virtualenv.create_bootstrap_script(textwrap.dedent("""
|
||||
import os, subprocess
|
||||
def after_install(options, home_dir):
|
||||
etc = join(home_dir, 'etc')
|
||||
if not os.path.exists(etc):
|
||||
os.makedirs(etc)
|
||||
subprocess.call([join(home_dir, 'bin', 'easy_install'),
|
||||
'BlogApplication'])
|
||||
subprocess.call([join(home_dir, 'bin', 'paster'),
|
||||
'make-config', 'BlogApplication',
|
||||
join(etc, 'blog.ini')])
|
||||
subprocess.call([join(home_dir, 'bin', 'paster'),
|
||||
'setup-app', join(etc, 'blog.ini')])
|
||||
"""))
|
||||
f = open('blog-bootstrap.py', 'w').write(output)
|
||||
|
||||
Another example is available `here
|
||||
<https://svn.openplans.org/svn/fassembler/trunk/fassembler/create-venv-script.py>`_.
|
||||
|
||||
activate script
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
In a newly created virtualenv there will be a ``bin/activate`` shell
|
||||
script, or a ``Scripts/activate.bat`` batch file on Windows.
|
||||
|
||||
On Posix systems you can do::
|
||||
|
||||
$ source bin/activate
|
||||
|
||||
This will change your ``$PATH`` to point to the virtualenv's ``bin/``
|
||||
directory. (You have to use ``source`` because it changes your shell
|
||||
environment in-place.) This is all it does; it's purely a convenience. If
|
||||
you directly run a script or the python interpreter from the virtualenv's
|
||||
``bin/`` directory (e.g. ``path/to/env/bin/pip`` or
|
||||
``/path/to/env/bin/python script.py``) there's no need for activation.
|
||||
|
||||
After activating an environment you can use the function ``deactivate`` to
|
||||
undo the changes to your ``$PATH``.
|
||||
|
||||
The ``activate`` script will also modify your shell prompt to indicate
|
||||
which environment is currently active. You can disable this behavior,
|
||||
which can be useful if you have your own custom prompt that already
|
||||
displays the active environment name. To do so, set the
|
||||
``VIRTUAL_ENV_DISABLE_PROMPT`` environment variable to any non-empty
|
||||
value before running the ``activate`` script.
|
||||
|
||||
On Windows you just do::
|
||||
|
||||
> \path\to\env\Scripts\activate.bat
|
||||
|
||||
And use ``deactivate.bat`` to undo the changes.
|
||||
|
||||
The ``--no-site-packages`` Option
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If you build with ``virtualenv --no-site-packages ENV`` it will *not*
|
||||
inherit any packages from ``/usr/lib/python2.5/site-packages`` (or
|
||||
wherever your global site-packages directory is). This can be used if
|
||||
you don't have control over site-packages and don't want to depend on
|
||||
the packages there, or you just want more isolation from the global
|
||||
system.
|
||||
|
||||
Using Virtualenv without ``bin/python``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Sometimes you can't or don't want to use the Python interpreter
|
||||
created by the virtualenv. For instance, in a `mod_python
|
||||
<http://www.modpython.org/>`_ or `mod_wsgi <http://www.modwsgi.org/>`_
|
||||
environment, there is only one interpreter.
|
||||
|
||||
Luckily, it's easy. You must use the custom Python interpreter to
|
||||
*install* libraries. But to *use* libraries, you just have to be sure
|
||||
the path is correct. A script is available to correct the path. You
|
||||
can setup the environment like::
|
||||
|
||||
activate_this = '/path/to/env/bin/activate_this.py'
|
||||
execfile(activate_this, dict(__file__=activate_this))
|
||||
|
||||
This will change ``sys.path`` and even change ``sys.prefix``, but also allow
|
||||
you to use an existing interpreter. Items in your environment will show up
|
||||
first on ``sys.path``, before global items. However, global items will
|
||||
always be accessible -- this technique does not support the
|
||||
``--no-site-packages`` flag. Also, this cannot undo the activation of other
|
||||
environments, or modules that have been imported. You shouldn't try to, for
|
||||
instance, activate an environment before a web request; you should activate
|
||||
*one* environment as early as possible, and not do it again in that process.
|
||||
|
||||
Making Environments Relocatable
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Note: this option is somewhat experimental, and there are probably
|
||||
caveats that have not yet been identified. Also this does not
|
||||
currently work on Windows.
|
||||
|
||||
Normally environments are tied to a specific path. That means that
|
||||
you cannot move an environment around or copy it to another computer.
|
||||
You can fix up an environment to make it relocatable with the
|
||||
command::
|
||||
|
||||
$ virtualenv --relocatable ENV
|
||||
|
||||
This will make some of the files created by setuptools or distribute
|
||||
use relative paths, and will change all the scripts to use ``activate_this.py``
|
||||
instead of using the location of the Python interpreter to select the
|
||||
environment.
|
||||
|
||||
**Note:** you must run this after you've installed *any* packages into
|
||||
the environment. If you make an environment relocatable, then
|
||||
install a new package, you must run ``virtualenv --relocatable``
|
||||
again.
|
||||
|
||||
Also, this **does not make your packages cross-platform**. You can
|
||||
move the directory around, but it can only be used on other similar
|
||||
computers. Some known environmental differences that can cause
|
||||
incompatibilities: a different version of Python, when one platform
|
||||
uses UCS2 for its internal unicode representation and another uses
|
||||
UCS4 (a compile-time option), obvious platform changes like Windows
|
||||
vs. Linux, or Intel vs. ARM, and if you have libraries that bind to C
|
||||
libraries on the system, if those C libraries are located somewhere
|
||||
different (either different versions, or a different filesystem
|
||||
layout).
|
||||
|
||||
Currently the ``--no-site-packages`` option will not be honored if you
|
||||
use this on an environment.
|
||||
|
||||
The ``--extra-search-dir`` Option
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
When it creates a new environment, virtualenv installs either
|
||||
setuptools or distribute, and pip. In normal operation, the latest
|
||||
releases of these packages are fetched from the `Python Package Index
|
||||
<http://pypi.python.org>`_ (PyPI). In some circumstances, this
|
||||
behavior may not be wanted, for example if you are using virtualenv
|
||||
during a deployment and do not want to depend on Internet access and
|
||||
PyPI availability.
|
||||
|
||||
As an alternative, you can provide your own versions of setuptools,
|
||||
distribute and/or pip on the filesystem, and tell virtualenv to use
|
||||
those distributions instead of downloading them from the Internet. To
|
||||
use this feature, pass one or more ``--extra-search-dir`` options to
|
||||
virtualenv like this::
|
||||
|
||||
$ virtualenv --extra-search-dir=/path/to/distributions ENV
|
||||
|
||||
The ``/path/to/distributions`` path should point to a directory that
|
||||
contains setuptools, distribute and/or pip distributions. Setuptools
|
||||
distributions must be ``.egg`` files; distribute and pip distributions
|
||||
should be `.tar.gz` source distributions.
|
||||
|
||||
Virtualenv will still download these packages if no satisfactory local
|
||||
distributions are found.
|
||||
|
||||
If you are really concerned about virtualenv fetching these packages
|
||||
from the Internet and want to ensure that it never will, you can also
|
||||
provide an option ``--never-download`` like so::
|
||||
|
||||
$ virtualenv --extra-search-dir=/path/to/distributions --never-download ENV
|
||||
|
||||
If this option is provided, virtualenv will never try to download
|
||||
setuptools/distribute or pip. Instead, it will exit with status code 1
|
||||
if it fails to find local distributions for any of these required
|
||||
packages.
|
||||
|
||||
Compare & Contrast with Alternatives
|
||||
------------------------------------
|
||||
|
||||
There are several alternatives that create isolated environments:
|
||||
|
||||
* ``workingenv`` (which I do not suggest you use anymore) is the
|
||||
predecessor to this library. It used the main Python interpreter,
|
||||
but relied on setting ``$PYTHONPATH`` to activate the environment.
|
||||
This causes problems when running Python scripts that aren't part of
|
||||
the environment (e.g., a globally installed ``hg`` or ``bzr``). It
|
||||
also conflicted a lot with Setuptools.
|
||||
|
||||
* `virtual-python
|
||||
<http://peak.telecommunity.com/DevCenter/EasyInstall#creating-a-virtual-python>`_
|
||||
is also a predecessor to this library. It uses only symlinks, so it
|
||||
couldn't work on Windows. It also symlinks over the *entire*
|
||||
standard library and global ``site-packages``. As a result, it
|
||||
won't see new additions to the global ``site-packages``.
|
||||
|
||||
This script only symlinks a small portion of the standard library
|
||||
into the environment, and so on Windows it is feasible to simply
|
||||
copy these files over. Also, it creates a new/empty
|
||||
``site-packages`` and also adds the global ``site-packages`` to the
|
||||
path, so updates are tracked separately. This script also installs
|
||||
Setuptools automatically, saving a step and avoiding the need for
|
||||
network access.
|
||||
|
||||
* `zc.buildout <http://pypi.python.org/pypi/zc.buildout>`_ doesn't
|
||||
create an isolated Python environment in the same style, but
|
||||
achieves similar results through a declarative config file that sets
|
||||
up scripts with very particular packages. As a declarative system,
|
||||
it is somewhat easier to repeat and manage, but more difficult to
|
||||
experiment with. ``zc.buildout`` includes the ability to setup
|
||||
non-Python systems (e.g., a database server or an Apache instance).
|
||||
|
||||
I *strongly* recommend anyone doing application development or
|
||||
deployment use one of these tools.
|
||||
|
||||
Contributing
|
||||
------------
|
||||
|
||||
Refer to the `contributing to pip`_ documentation - it applies equally to
|
||||
virtualenv.
|
||||
|
||||
Virtualenv's release schedule is tied to pip's -- each time there's a new pip
|
||||
release, there will be a new virtualenv release that bundles the new version of
|
||||
pip.
|
||||
|
||||
.. _contributing to pip: http://www.pip-installer.org/en/latest/how-to-contribute.html
|
||||
|
||||
Running the tests
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
Virtualenv's test suite is small and not yet at all comprehensive, but we aim
|
||||
to grow it.
|
||||
|
||||
The easy way to run tests (handles test dependencies automatically)::
|
||||
|
||||
$ python setup.py test
|
||||
|
||||
If you want to run only a selection of the tests, you'll need to run them
|
||||
directly with nose instead. Create a virtualenv, and install required
|
||||
packages::
|
||||
|
||||
$ pip install nose mock
|
||||
|
||||
Run nosetests::
|
||||
|
||||
$ nosetests
|
||||
|
||||
Or select just a single test file to run::
|
||||
|
||||
$ nosetests tests.test_virtualenv
|
||||
|
||||
|
||||
Other Documentation and Links
|
||||
-----------------------------
|
||||
|
||||
* James Gardner has written a tutorial on using `virtualenv with
|
||||
Pylons
|
||||
<http://wiki.pylonshq.com/display/pylonscookbook/Using+a+Virtualenv+Sandbox>`_.
|
||||
|
||||
* `Blog announcement
|
||||
<http://blog.ianbicking.org/2007/10/10/workingenv-is-dead-long-live-virtualenv/>`_.
|
||||
|
||||
* Doug Hellmann wrote a description of his `command-line work flow
|
||||
using virtualenv (virtualenvwrapper)
|
||||
<http://www.doughellmann.com/articles/CompletelyDifferent-2008-05-virtualenvwrapper/index.html>`_
|
||||
including some handy scripts to make working with multiple
|
||||
environments easier. He also wrote `an example of using virtualenv
|
||||
to try IPython
|
||||
<http://www.doughellmann.com/articles/CompletelyDifferent-2008-02-ipython-and-virtualenv/index.html>`_.
|
||||
|
||||
* Chris Perkins created a `showmedo video including virtualenv
|
||||
<http://showmedo.com/videos/video?name=2910000&fromSeriesID=291>`_.
|
||||
|
||||
* `Using virtualenv with mod_wsgi
|
||||
<http://code.google.com/p/modwsgi/wiki/VirtualEnvironments>`_.
|
||||
|
||||
* `virtualenv commands
|
||||
<http://thisismedium.com/tech/extending-virtualenv/>`_ for some more
|
||||
workflow-related tools around virtualenv.
|
||||
|
||||
Changes & News
|
||||
--------------
|
||||
|
||||
Next release (1.7) schedule
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Beta release mid-July 2011, final release early August.
|
||||
|
||||
1.6.4 (2011-07-21)
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Restored ability to run on Python 2.4, too.
|
||||
|
||||
1.6.3 (2011-07-16)
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Restored ability to run on Python < 2.7.
|
||||
|
||||
1.6.2 (2011-07-16)
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Updated embedded distribute release to 0.6.19.
|
||||
|
||||
* Updated embedded pip release to 1.0.2.
|
||||
|
||||
* Fixed #141 - Be smarter about finding pkg_resources when using the
|
||||
non-default Python intepreter (by using the ``-p`` option).
|
||||
|
||||
* Fixed #112 - Fixed path in docs.
|
||||
|
||||
* Fixed #109 - Corrected doctests of a Logger method.
|
||||
|
||||
* Fixed #118 - Fixed creating virtualenvs on platforms that use the
|
||||
"posix_local" install scheme, such as Ubuntu with Python 2.7.
|
||||
|
||||
* Add missing library to Python 3 virtualenvs (``_dummy_thread``).
|
||||
|
||||
|
||||
1.6.1 (2011-04-30)
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Start to use git-flow.
|
||||
|
||||
* Added support for PyPy 1.5
|
||||
|
||||
* Fixed #121 -- added sanity-checking of the -p argument. Thanks Paul Nasrat.
|
||||
|
||||
* Added progress meter for pip installation as well as setuptools. Thanks Ethan
|
||||
Jucovy.
|
||||
|
||||
* Added --never-download and --search-dir options. Thanks Ethan Jucovy.
|
||||
|
||||
1.6
|
||||
~~~
|
||||
|
||||
* Added Python 3 support! Huge thanks to Vinay Sajip and Vitaly Babiy.
|
||||
|
||||
* Fixed creation of virtualenvs on Mac OS X when standard library modules
|
||||
(readline) are installed outside the standard library.
|
||||
|
||||
* Updated bundled pip to 1.0.
|
||||
|
||||
1.5.2
|
||||
~~~~~
|
||||
|
||||
* Moved main repository to Github: https://github.com/pypa/virtualenv
|
||||
|
||||
* Transferred primary maintenance from Ian to Jannis Leidel, Carl Meyer and Brian Rosner
|
||||
|
||||
* Fixed a few more pypy related bugs.
|
||||
|
||||
* Updated bundled pip to 0.8.2.
|
||||
|
||||
* Handed project over to new team of maintainers.
|
||||
|
||||
* Moved virtualenv to Github at https://github.com/pypa/virtualenv
|
||||
|
||||
1.5.1
|
||||
~~~~~
|
||||
|
||||
* Added ``_weakrefset`` requirement for Python 2.7.1.
|
||||
|
||||
* Fixed Windows regression in 1.5
|
||||
|
||||
1.5
|
||||
~~~
|
||||
|
||||
* Include pip 0.8.1.
|
||||
|
||||
* Add support for PyPy.
|
||||
|
||||
* Uses a proper temporary dir when installing environment requirements.
|
||||
|
||||
* Add ``--prompt`` option to be able to override the default prompt prefix.
|
||||
|
||||
* Fix an issue with ``--relocatable`` on Windows.
|
||||
|
||||
* Fix issue with installing the wrong version of distribute.
|
||||
|
||||
* Add fish and csh activate scripts.
|
||||
|
||||
1.4.9
|
||||
~~~~~
|
||||
|
||||
* Include pip 0.7.2
|
||||
|
||||
1.4.8
|
||||
~~~~~
|
||||
|
||||
* Fix for Mac OS X Framework builds that use
|
||||
``--universal-archs=intel``
|
||||
|
||||
* Fix ``activate_this.py`` on Windows.
|
||||
|
||||
* Allow ``$PYTHONHOME`` to be set, so long as you use ``source
|
||||
bin/activate`` it will get unset; if you leave it set and do not
|
||||
activate the environment it will still break the environment.
|
||||
|
||||
* Include pip 0.7.1
|
||||
|
||||
1.4.7
|
||||
~~~~~
|
||||
|
||||
* Include pip 0.7
|
||||
|
||||
1.4.6
|
||||
~~~~~
|
||||
|
||||
* Allow ``activate.sh`` to skip updating the prompt (by setting
|
||||
``$VIRTUAL_ENV_DISABLE_PROMPT``).
|
||||
|
||||
1.4.5
|
||||
~~~~~
|
||||
|
||||
* Include pip 0.6.3
|
||||
|
||||
* Fix ``activate.bat`` and ``deactivate.bat`` under Windows when
|
||||
``PATH`` contained a parenthesis
|
||||
|
||||
1.4.4
|
||||
~~~~~
|
||||
|
||||
* Include pip 0.6.2 and Distribute 0.6.10
|
||||
|
||||
* Create the ``virtualenv`` script even when Setuptools isn't
|
||||
installed
|
||||
|
||||
* Fix problem with ``virtualenv --relocate`` when ``bin/`` has
|
||||
subdirectories (e.g., ``bin/.svn/``); from Alan Franzoni.
|
||||
|
||||
* If you set ``$VIRTUALENV_USE_DISTRIBUTE`` then virtualenv will use
|
||||
Distribute by default (so you don't have to remember to use
|
||||
``--distribute``).
|
||||
|
||||
1.4.3
|
||||
~~~~~
|
||||
|
||||
* Include pip 0.6.1
|
||||
|
||||
1.4.2
|
||||
~~~~~
|
||||
|
||||
* Fix pip installation on Windows
|
||||
|
||||
* Fix use of stand-alone ``virtualenv.py`` (and boot scripts)
|
||||
|
||||
* Exclude ~/.local (user site-packages) from environments when using
|
||||
``--no-site-packages``
|
||||
|
||||
1.4.1
|
||||
~~~~~
|
||||
|
||||
* Include pip 0.6
|
||||
|
||||
1.4
|
||||
~~~
|
||||
|
||||
* Updated setuptools to 0.6c11
|
||||
|
||||
* Added the --distribute option
|
||||
|
||||
* Fixed packaging problem of support-files
|
||||
|
||||
1.3.4
|
||||
~~~~~
|
||||
|
||||
* Virtualenv now copies the actual embedded Python binary on
|
||||
Mac OS X to fix a hang on Snow Leopard (10.6).
|
||||
|
||||
* Fail more gracefully on Windows when ``win32api`` is not installed.
|
||||
|
||||
* Fix site-packages taking precedent over Jython's ``__classpath__``
|
||||
and also specially handle the new ``__pyclasspath__`` entry in
|
||||
``sys.path``.
|
||||
|
||||
* Now copies Jython's ``registry`` file to the virtualenv if it exists.
|
||||
|
||||
* Better find libraries when compiling extensions on Windows.
|
||||
|
||||
* Create ``Scripts\pythonw.exe`` on Windows.
|
||||
|
||||
* Added support for the Debian/Ubuntu
|
||||
``/usr/lib/pythonX.Y/dist-packages`` directory.
|
||||
|
||||
* Set ``distutils.sysconfig.get_config_vars()['LIBDIR']`` (based on
|
||||
``sys.real_prefix``) which is reported to help building on Windows.
|
||||
|
||||
* Make ``deactivate`` work on ksh
|
||||
|
||||
* Fixes for ``--python``: make it work with ``--relocatable`` and the
|
||||
symlink created to the exact Python version.
|
||||
|
||||
1.3.3
|
||||
~~~~~
|
||||
|
||||
* Use Windows newlines in ``activate.bat``, which has been reported to help
|
||||
when using non-ASCII directory names.
|
||||
|
||||
* Fixed compatibility with Jython 2.5b1.
|
||||
|
||||
* Added a function ``virtualenv.install_python`` for more fine-grained
|
||||
access to what ``virtualenv.create_environment`` does.
|
||||
|
||||
* Fix `a problem <https://bugs.launchpad.net/virtualenv/+bug/241581>`_
|
||||
with Windows and paths that contain spaces.
|
||||
|
||||
* If ``/path/to/env/.pydistutils.cfg`` exists (or
|
||||
``/path/to/env/pydistutils.cfg`` on Windows systems) then ignore
|
||||
``~/.pydistutils.cfg`` and use that other file instead.
|
||||
|
||||
* Fix ` a problem
|
||||
<https://bugs.launchpad.net/virtualenv/+bug/340050>`_ picking up
|
||||
some ``.so`` libraries in ``/usr/local``.
|
||||
|
||||
1.3.2
|
||||
~~~~~
|
||||
|
||||
* Remove the ``[install] prefix = ...`` setting from the virtualenv
|
||||
``distutils.cfg`` -- this has been causing problems for a lot of
|
||||
people, in rather obscure ways.
|
||||
|
||||
* If you use a `boot script <./index.html#boot-script>`_ it will attempt to import ``virtualenv``
|
||||
and find a pre-downloaded Setuptools egg using that.
|
||||
|
||||
* Added platform-specific paths, like ``/usr/lib/pythonX.Y/plat-linux2``
|
||||
|
||||
1.3.1
|
||||
~~~~~
|
||||
|
||||
* Real Python 2.6 compatibility. Backported the Python 2.6 updates to
|
||||
``site.py``, including `user directories
|
||||
<http://docs.python.org/dev/whatsnew/2.6.html#pep-370-per-user-site-packages-directory>`_
|
||||
(this means older versions of Python will support user directories,
|
||||
whether intended or not).
|
||||
|
||||
* Always set ``[install] prefix`` in ``distutils.cfg`` -- previously
|
||||
on some platforms where a system-wide ``distutils.cfg`` was present
|
||||
with a ``prefix`` setting, packages would be installed globally
|
||||
(usually in ``/usr/local/lib/pythonX.Y/site-packages``).
|
||||
|
||||
* Sometimes Cygwin seems to leave ``.exe`` off ``sys.executable``; a
|
||||
workaround is added.
|
||||
|
||||
* Fix ``--python`` option.
|
||||
|
||||
* Fixed handling of Jython environments that use a
|
||||
jython-complete.jar.
|
||||
|
||||
1.3
|
||||
~~~
|
||||
|
||||
* Update to Setuptools 0.6c9
|
||||
* Added an option ``virtualenv --relocatable EXISTING_ENV``, which
|
||||
will make an existing environment "relocatable" -- the paths will
|
||||
not be absolute in scripts, ``.egg-info`` and ``.pth`` files. This
|
||||
may assist in building environments that can be moved and copied.
|
||||
You have to run this *after* any new packages installed.
|
||||
* Added ``bin/activate_this.py``, a file you can use like
|
||||
``execfile("path_to/activate_this.py",
|
||||
dict(__file__="path_to/activate_this.py"))`` -- this will activate
|
||||
the environment in place, similar to what `the mod_wsgi example
|
||||
does <http://code.google.com/p/modwsgi/wiki/VirtualEnvironments>`_.
|
||||
* For Mac framework builds of Python, the site-packages directory
|
||||
``/Library/Python/X.Y/site-packages`` is added to ``sys.path``, from
|
||||
Andrea Rech.
|
||||
* Some platform-specific modules in Macs are added to the path now
|
||||
(``plat-darwin/``, ``plat-mac/``, ``plat-mac/lib-scriptpackages``),
|
||||
from Andrea Rech.
|
||||
* Fixed a small Bashism in the ``bin/activate`` shell script.
|
||||
* Added ``__future__`` to the list of required modules, for Python
|
||||
2.3. You'll still need to backport your own ``subprocess`` module.
|
||||
* Fixed the ``__classpath__`` entry in Jython's ``sys.path`` taking
|
||||
precedent over virtualenv's libs.
|
||||
|
||||
1.2
|
||||
~~~
|
||||
|
||||
* Added a ``--python`` option to select the Python interpreter.
|
||||
* Add ``warnings`` to the modules copied over, for Python 2.6 support.
|
||||
* Add ``sets`` to the module copied over for Python 2.3 (though Python
|
||||
2.3 still probably doesn't work).
|
||||
|
||||
1.1.1
|
||||
~~~~~
|
||||
|
||||
* Added support for Jython 2.5.
|
||||
|
||||
1.1
|
||||
~~~
|
||||
|
||||
* Added support for Python 2.6.
|
||||
* Fix a problem with missing ``DLLs/zlib.pyd`` on Windows. Create
|
||||
* ``bin/python`` (or ``bin/python.exe``) even when you run virtualenv
|
||||
with an interpreter named, e.g., ``python2.4``
|
||||
* Fix MacPorts Python
|
||||
* Added --unzip-setuptools option
|
||||
* Update to Setuptools 0.6c8
|
||||
* If the current directory is not writable, run ez_setup.py in ``/tmp``
|
||||
* Copy or symlink over the ``include`` directory so that packages will
|
||||
more consistently compile.
|
||||
|
||||
1.0
|
||||
~~~
|
||||
|
||||
* Fix build on systems that use ``/usr/lib64``, distinct from
|
||||
``/usr/lib`` (specifically CentOS x64).
|
||||
* Fixed bug in ``--clear``.
|
||||
* Fixed typos in ``deactivate.bat``.
|
||||
* Preserve ``$PYTHONPATH`` when calling subprocesses.
|
||||
|
||||
0.9.2
|
||||
~~~~~
|
||||
|
||||
* Fix include dir copying on Windows (makes compiling possible).
|
||||
* Include the main ``lib-tk`` in the path.
|
||||
* Patch ``distutils.sysconfig``: ``get_python_inc`` and
|
||||
``get_python_lib`` to point to the global locations.
|
||||
* Install ``distutils.cfg`` before Setuptools, so that system
|
||||
customizations of ``distutils.cfg`` won't effect the installation.
|
||||
* Add ``bin/pythonX.Y`` to the virtualenv (in addition to
|
||||
``bin/python``).
|
||||
* Fixed an issue with Mac Framework Python builds, and absolute paths
|
||||
(from Ronald Oussoren).
|
||||
|
||||
0.9.1
|
||||
~~~~~
|
||||
|
||||
* Improve ability to create a virtualenv from inside a virtualenv.
|
||||
* Fix a little bug in ``bin/activate``.
|
||||
* Actually get ``distutils.cfg`` to work reliably.
|
||||
|
||||
0.9
|
||||
~~~
|
||||
|
||||
* Added ``lib-dynload`` and ``config`` to things that need to be
|
||||
copied over in an environment.
|
||||
* Copy over or symlink the ``include`` directory, so that you can
|
||||
build packages that need the C headers.
|
||||
* Include a ``distutils`` package, so you can locally update
|
||||
``distutils.cfg`` (in ``lib/pythonX.Y/distutils/distutils.cfg``).
|
||||
* Better avoid downloading Setuptools, and hitting PyPI on environment
|
||||
creation.
|
||||
* Fix a problem creating a ``lib64/`` directory.
|
||||
* Should work on MacOSX Framework builds (the default Python
|
||||
installations on Mac). Thanks to Ronald Oussoren.
|
||||
|
||||
0.8.4
|
||||
~~~~~
|
||||
|
||||
* Windows installs would sometimes give errors about ``sys.prefix`` that
|
||||
were inaccurate.
|
||||
* Slightly prettier output.
|
||||
|
||||
0.8.3
|
||||
~~~~~
|
||||
|
||||
* Added support for Windows.
|
||||
|
||||
0.8.2
|
||||
~~~~~
|
||||
|
||||
* Give a better warning if you are on an unsupported platform (Mac
|
||||
Framework Pythons, and Windows).
|
||||
* Give error about running while inside a workingenv.
|
||||
* Give better error message about Python 2.3.
|
||||
|
||||
0.8.1
|
||||
~~~~~
|
||||
|
||||
Fixed packaging of the library.
|
||||
|
||||
0.8
|
||||
~~~
|
||||
|
||||
Initial release. Everything is changed and new!
|
||||
|
||||
Keywords: setuptools deployment installation distutils
|
||||
Platform: UNKNOWN
|
||||
Classifier: Development Status :: 4 - Beta
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: License :: OSI Approved :: MIT License
|
||||
Classifier: Programming Language :: Python :: 2
|
||||
Classifier: Programming Language :: Python :: 2.4
|
||||
Classifier: Programming Language :: Python :: 2.5
|
||||
Classifier: Programming Language :: Python :: 2.6
|
||||
Classifier: Programming Language :: Python :: 2.7
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 3.1
|
||||
Classifier: Programming Language :: Python :: 3.2
|
||||
@@ -1,422 +0,0 @@
|
||||
virtualenv
|
||||
==========
|
||||
|
||||
* `Discussion list <http://groups.google.com/group/python-virtualenv/>`_
|
||||
* `Bugs <https://github.com/pypa/virtualenv/issues/>`_
|
||||
|
||||
.. contents::
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
news
|
||||
|
||||
.. comment: split here
|
||||
|
||||
Status and License
|
||||
------------------
|
||||
|
||||
``virtualenv`` is a successor to `workingenv
|
||||
<http://cheeseshop.python.org/pypi/workingenv.py>`_, and an extension
|
||||
of `virtual-python
|
||||
<http://peak.telecommunity.com/DevCenter/EasyInstall#creating-a-virtual-python>`_.
|
||||
|
||||
It was written by Ian Bicking, sponsored by the `Open Planning
|
||||
Project <http://openplans.org>`_ and is now maintained by a
|
||||
`group of developers <https://github.com/pypa/virtualenv/raw/master/AUTHORS.txt>`_.
|
||||
It is licensed under an
|
||||
`MIT-style permissive license <https://github.com/pypa/virtualenv/raw/master/LICENSE.txt>`_.
|
||||
|
||||
You can install it with ``easy_install virtualenv``, or the `latest
|
||||
development version <https://github.com/pypa/virtualenv/tarball/develop#egg=virtualenv-dev>`_
|
||||
with ``easy_install virtualenv==dev``.
|
||||
|
||||
What It Does
|
||||
------------
|
||||
|
||||
``virtualenv`` is a tool to create isolated Python environments.
|
||||
|
||||
The basic problem being addressed is one of dependencies and versions,
|
||||
and indirectly permissions. Imagine you have an application that
|
||||
needs version 1 of LibFoo, but another application requires version
|
||||
2. How can you use both these applications? If you install
|
||||
everything into ``/usr/lib/python2.7/site-packages`` (or whatever your
|
||||
platform's standard location is), it's easy to end up in a situation
|
||||
where you unintentionally upgrade an application that shouldn't be
|
||||
upgraded.
|
||||
|
||||
Or more generally, what if you want to install an application *and
|
||||
leave it be*? If an application works, any change in its libraries or
|
||||
the versions of those libraries can break the application.
|
||||
|
||||
Also, what if you can't install packages into the global
|
||||
``site-packages`` directory? For instance, on a shared host.
|
||||
|
||||
In all these cases, ``virtualenv`` can help you. It creates an
|
||||
environment that has its own installation directories, that doesn't
|
||||
share libraries with other virtualenv environments (and optionally
|
||||
doesn't access the globally installed libraries either).
|
||||
|
||||
The basic usage is::
|
||||
|
||||
$ python virtualenv.py ENV
|
||||
|
||||
If you install it you can also just do ``virtualenv ENV``.
|
||||
|
||||
This creates ``ENV/lib/pythonX.X/site-packages``, where any libraries you
|
||||
install will go. It also creates ``ENV/bin/python``, which is a Python
|
||||
interpreter that uses this environment. Anytime you use that interpreter
|
||||
(including when a script has ``#!/path/to/ENV/bin/python`` in it) the libraries
|
||||
in that environment will be used.
|
||||
|
||||
It also installs either `Setuptools
|
||||
<http://peak.telecommunity.com/DevCenter/setuptools>`_ or `distribute
|
||||
<http://pypi.python.org/pypi/distribute>`_ into the environment. To use
|
||||
Distribute instead of setuptools, just call virtualenv like this::
|
||||
|
||||
$ python virtualenv.py --distribute ENV
|
||||
|
||||
You can also set the environment variable VIRTUALENV_USE_DISTRIBUTE.
|
||||
|
||||
A new virtualenv also includes the `pip <http://pypy.python.org/pypi/pip>`_
|
||||
installer, so you can use `ENV/bin/pip`` to install additional packages into
|
||||
the environment.
|
||||
|
||||
Windows Notes
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
Some paths within the virtualenv are slightly different on Windows: scripts and
|
||||
executables on Windows go in ``ENV\Scripts\`` instead of ``ENV/bin/`` and
|
||||
libraries go in ``ENV\Lib\`` rather than ``ENV/lib/``.
|
||||
|
||||
To create a virtualenv under a path with spaces in it on Windows, you'll need
|
||||
the `win32api <http://sourceforge.net/projects/pywin32/>`_ library installed.
|
||||
|
||||
PyPy Support
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Beginning with virtualenv version 1.5 `PyPy <http://pypy.org>`_ is
|
||||
supported. To use PyPy 1.4 or 1.4.1, you need a version of virtualenv >= 1.5.
|
||||
To use PyPy 1.5, you need a version of virtualenv >= 1.6.1.
|
||||
|
||||
Creating Your Own Bootstrap Scripts
|
||||
-----------------------------------
|
||||
|
||||
While this creates an environment, it doesn't put anything into the
|
||||
environment. Developers may find it useful to distribute a script
|
||||
that sets up a particular environment, for example a script that
|
||||
installs a particular web application.
|
||||
|
||||
To create a script like this, call
|
||||
``virtualenv.create_bootstrap_script(extra_text)``, and write the
|
||||
result to your new bootstrapping script. Here's the documentation
|
||||
from the docstring:
|
||||
|
||||
Creates a bootstrap script, which is like this script but with
|
||||
extend_parser, adjust_options, and after_install hooks.
|
||||
|
||||
This returns a string that (written to disk of course) can be used
|
||||
as a bootstrap script with your own customizations. The script
|
||||
will be the standard virtualenv.py script, with your extra text
|
||||
added (your extra text should be Python code).
|
||||
|
||||
If you include these functions, they will be called:
|
||||
|
||||
``extend_parser(optparse_parser)``:
|
||||
You can add or remove options from the parser here.
|
||||
|
||||
``adjust_options(options, args)``:
|
||||
You can change options here, or change the args (if you accept
|
||||
different kinds of arguments, be sure you modify ``args`` so it is
|
||||
only ``[DEST_DIR]``).
|
||||
|
||||
``after_install(options, home_dir)``:
|
||||
|
||||
After everything is installed, this function is called. This
|
||||
is probably the function you are most likely to use. An
|
||||
example would be::
|
||||
|
||||
def after_install(options, home_dir):
|
||||
if sys.platform == 'win32':
|
||||
bin = 'Scripts'
|
||||
else:
|
||||
bin = 'bin'
|
||||
subprocess.call([join(home_dir, bin, 'easy_install'),
|
||||
'MyPackage'])
|
||||
subprocess.call([join(home_dir, bin, 'my-package-script'),
|
||||
'setup', home_dir])
|
||||
|
||||
This example immediately installs a package, and runs a setup
|
||||
script from that package.
|
||||
|
||||
Bootstrap Example
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
Here's a more concrete example of how you could use this::
|
||||
|
||||
import virtualenv, textwrap
|
||||
output = virtualenv.create_bootstrap_script(textwrap.dedent("""
|
||||
import os, subprocess
|
||||
def after_install(options, home_dir):
|
||||
etc = join(home_dir, 'etc')
|
||||
if not os.path.exists(etc):
|
||||
os.makedirs(etc)
|
||||
subprocess.call([join(home_dir, 'bin', 'easy_install'),
|
||||
'BlogApplication'])
|
||||
subprocess.call([join(home_dir, 'bin', 'paster'),
|
||||
'make-config', 'BlogApplication',
|
||||
join(etc, 'blog.ini')])
|
||||
subprocess.call([join(home_dir, 'bin', 'paster'),
|
||||
'setup-app', join(etc, 'blog.ini')])
|
||||
"""))
|
||||
f = open('blog-bootstrap.py', 'w').write(output)
|
||||
|
||||
Another example is available `here
|
||||
<https://svn.openplans.org/svn/fassembler/trunk/fassembler/create-venv-script.py>`_.
|
||||
|
||||
activate script
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
In a newly created virtualenv there will be a ``bin/activate`` shell
|
||||
script, or a ``Scripts/activate.bat`` batch file on Windows.
|
||||
|
||||
On Posix systems you can do::
|
||||
|
||||
$ source bin/activate
|
||||
|
||||
This will change your ``$PATH`` to point to the virtualenv's ``bin/``
|
||||
directory. (You have to use ``source`` because it changes your shell
|
||||
environment in-place.) This is all it does; it's purely a convenience. If
|
||||
you directly run a script or the python interpreter from the virtualenv's
|
||||
``bin/`` directory (e.g. ``path/to/env/bin/pip`` or
|
||||
``/path/to/env/bin/python script.py``) there's no need for activation.
|
||||
|
||||
After activating an environment you can use the function ``deactivate`` to
|
||||
undo the changes to your ``$PATH``.
|
||||
|
||||
The ``activate`` script will also modify your shell prompt to indicate
|
||||
which environment is currently active. You can disable this behavior,
|
||||
which can be useful if you have your own custom prompt that already
|
||||
displays the active environment name. To do so, set the
|
||||
``VIRTUAL_ENV_DISABLE_PROMPT`` environment variable to any non-empty
|
||||
value before running the ``activate`` script.
|
||||
|
||||
On Windows you just do::
|
||||
|
||||
> \path\to\env\Scripts\activate.bat
|
||||
|
||||
And use ``deactivate.bat`` to undo the changes.
|
||||
|
||||
The ``--no-site-packages`` Option
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If you build with ``virtualenv --no-site-packages ENV`` it will *not*
|
||||
inherit any packages from ``/usr/lib/python2.5/site-packages`` (or
|
||||
wherever your global site-packages directory is). This can be used if
|
||||
you don't have control over site-packages and don't want to depend on
|
||||
the packages there, or you just want more isolation from the global
|
||||
system.
|
||||
|
||||
Using Virtualenv without ``bin/python``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Sometimes you can't or don't want to use the Python interpreter
|
||||
created by the virtualenv. For instance, in a `mod_python
|
||||
<http://www.modpython.org/>`_ or `mod_wsgi <http://www.modwsgi.org/>`_
|
||||
environment, there is only one interpreter.
|
||||
|
||||
Luckily, it's easy. You must use the custom Python interpreter to
|
||||
*install* libraries. But to *use* libraries, you just have to be sure
|
||||
the path is correct. A script is available to correct the path. You
|
||||
can setup the environment like::
|
||||
|
||||
activate_this = '/path/to/env/bin/activate_this.py'
|
||||
execfile(activate_this, dict(__file__=activate_this))
|
||||
|
||||
This will change ``sys.path`` and even change ``sys.prefix``, but also allow
|
||||
you to use an existing interpreter. Items in your environment will show up
|
||||
first on ``sys.path``, before global items. However, global items will
|
||||
always be accessible -- this technique does not support the
|
||||
``--no-site-packages`` flag. Also, this cannot undo the activation of other
|
||||
environments, or modules that have been imported. You shouldn't try to, for
|
||||
instance, activate an environment before a web request; you should activate
|
||||
*one* environment as early as possible, and not do it again in that process.
|
||||
|
||||
Making Environments Relocatable
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Note: this option is somewhat experimental, and there are probably
|
||||
caveats that have not yet been identified. Also this does not
|
||||
currently work on Windows.
|
||||
|
||||
Normally environments are tied to a specific path. That means that
|
||||
you cannot move an environment around or copy it to another computer.
|
||||
You can fix up an environment to make it relocatable with the
|
||||
command::
|
||||
|
||||
$ virtualenv --relocatable ENV
|
||||
|
||||
This will make some of the files created by setuptools or distribute
|
||||
use relative paths, and will change all the scripts to use ``activate_this.py``
|
||||
instead of using the location of the Python interpreter to select the
|
||||
environment.
|
||||
|
||||
**Note:** you must run this after you've installed *any* packages into
|
||||
the environment. If you make an environment relocatable, then
|
||||
install a new package, you must run ``virtualenv --relocatable``
|
||||
again.
|
||||
|
||||
Also, this **does not make your packages cross-platform**. You can
|
||||
move the directory around, but it can only be used on other similar
|
||||
computers. Some known environmental differences that can cause
|
||||
incompatibilities: a different version of Python, when one platform
|
||||
uses UCS2 for its internal unicode representation and another uses
|
||||
UCS4 (a compile-time option), obvious platform changes like Windows
|
||||
vs. Linux, or Intel vs. ARM, and if you have libraries that bind to C
|
||||
libraries on the system, if those C libraries are located somewhere
|
||||
different (either different versions, or a different filesystem
|
||||
layout).
|
||||
|
||||
Currently the ``--no-site-packages`` option will not be honored if you
|
||||
use this on an environment.
|
||||
|
||||
The ``--extra-search-dir`` Option
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
When it creates a new environment, virtualenv installs either
|
||||
setuptools or distribute, and pip. In normal operation, the latest
|
||||
releases of these packages are fetched from the `Python Package Index
|
||||
<http://pypi.python.org>`_ (PyPI). In some circumstances, this
|
||||
behavior may not be wanted, for example if you are using virtualenv
|
||||
during a deployment and do not want to depend on Internet access and
|
||||
PyPI availability.
|
||||
|
||||
As an alternative, you can provide your own versions of setuptools,
|
||||
distribute and/or pip on the filesystem, and tell virtualenv to use
|
||||
those distributions instead of downloading them from the Internet. To
|
||||
use this feature, pass one or more ``--extra-search-dir`` options to
|
||||
virtualenv like this::
|
||||
|
||||
$ virtualenv --extra-search-dir=/path/to/distributions ENV
|
||||
|
||||
The ``/path/to/distributions`` path should point to a directory that
|
||||
contains setuptools, distribute and/or pip distributions. Setuptools
|
||||
distributions must be ``.egg`` files; distribute and pip distributions
|
||||
should be `.tar.gz` source distributions.
|
||||
|
||||
Virtualenv will still download these packages if no satisfactory local
|
||||
distributions are found.
|
||||
|
||||
If you are really concerned about virtualenv fetching these packages
|
||||
from the Internet and want to ensure that it never will, you can also
|
||||
provide an option ``--never-download`` like so::
|
||||
|
||||
$ virtualenv --extra-search-dir=/path/to/distributions --never-download ENV
|
||||
|
||||
If this option is provided, virtualenv will never try to download
|
||||
setuptools/distribute or pip. Instead, it will exit with status code 1
|
||||
if it fails to find local distributions for any of these required
|
||||
packages.
|
||||
|
||||
Compare & Contrast with Alternatives
|
||||
------------------------------------
|
||||
|
||||
There are several alternatives that create isolated environments:
|
||||
|
||||
* ``workingenv`` (which I do not suggest you use anymore) is the
|
||||
predecessor to this library. It used the main Python interpreter,
|
||||
but relied on setting ``$PYTHONPATH`` to activate the environment.
|
||||
This causes problems when running Python scripts that aren't part of
|
||||
the environment (e.g., a globally installed ``hg`` or ``bzr``). It
|
||||
also conflicted a lot with Setuptools.
|
||||
|
||||
* `virtual-python
|
||||
<http://peak.telecommunity.com/DevCenter/EasyInstall#creating-a-virtual-python>`_
|
||||
is also a predecessor to this library. It uses only symlinks, so it
|
||||
couldn't work on Windows. It also symlinks over the *entire*
|
||||
standard library and global ``site-packages``. As a result, it
|
||||
won't see new additions to the global ``site-packages``.
|
||||
|
||||
This script only symlinks a small portion of the standard library
|
||||
into the environment, and so on Windows it is feasible to simply
|
||||
copy these files over. Also, it creates a new/empty
|
||||
``site-packages`` and also adds the global ``site-packages`` to the
|
||||
path, so updates are tracked separately. This script also installs
|
||||
Setuptools automatically, saving a step and avoiding the need for
|
||||
network access.
|
||||
|
||||
* `zc.buildout <http://pypi.python.org/pypi/zc.buildout>`_ doesn't
|
||||
create an isolated Python environment in the same style, but
|
||||
achieves similar results through a declarative config file that sets
|
||||
up scripts with very particular packages. As a declarative system,
|
||||
it is somewhat easier to repeat and manage, but more difficult to
|
||||
experiment with. ``zc.buildout`` includes the ability to setup
|
||||
non-Python systems (e.g., a database server or an Apache instance).
|
||||
|
||||
I *strongly* recommend anyone doing application development or
|
||||
deployment use one of these tools.
|
||||
|
||||
Contributing
|
||||
------------
|
||||
|
||||
Refer to the `contributing to pip`_ documentation - it applies equally to
|
||||
virtualenv.
|
||||
|
||||
Virtualenv's release schedule is tied to pip's -- each time there's a new pip
|
||||
release, there will be a new virtualenv release that bundles the new version of
|
||||
pip.
|
||||
|
||||
.. _contributing to pip: http://www.pip-installer.org/en/latest/how-to-contribute.html
|
||||
|
||||
Running the tests
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
Virtualenv's test suite is small and not yet at all comprehensive, but we aim
|
||||
to grow it.
|
||||
|
||||
The easy way to run tests (handles test dependencies automatically)::
|
||||
|
||||
$ python setup.py test
|
||||
|
||||
If you want to run only a selection of the tests, you'll need to run them
|
||||
directly with nose instead. Create a virtualenv, and install required
|
||||
packages::
|
||||
|
||||
$ pip install nose mock
|
||||
|
||||
Run nosetests::
|
||||
|
||||
$ nosetests
|
||||
|
||||
Or select just a single test file to run::
|
||||
|
||||
$ nosetests tests.test_virtualenv
|
||||
|
||||
|
||||
Other Documentation and Links
|
||||
-----------------------------
|
||||
|
||||
* James Gardner has written a tutorial on using `virtualenv with
|
||||
Pylons
|
||||
<http://wiki.pylonshq.com/display/pylonscookbook/Using+a+Virtualenv+Sandbox>`_.
|
||||
|
||||
* `Blog announcement
|
||||
<http://blog.ianbicking.org/2007/10/10/workingenv-is-dead-long-live-virtualenv/>`_.
|
||||
|
||||
* Doug Hellmann wrote a description of his `command-line work flow
|
||||
using virtualenv (virtualenvwrapper)
|
||||
<http://www.doughellmann.com/articles/CompletelyDifferent-2008-05-virtualenvwrapper/index.html>`_
|
||||
including some handy scripts to make working with multiple
|
||||
environments easier. He also wrote `an example of using virtualenv
|
||||
to try IPython
|
||||
<http://www.doughellmann.com/articles/CompletelyDifferent-2008-02-ipython-and-virtualenv/index.html>`_.
|
||||
|
||||
* Chris Perkins created a `showmedo video including virtualenv
|
||||
<http://showmedo.com/videos/video?name=2910000&fromSeriesID=291>`_.
|
||||
|
||||
* `Using virtualenv with mod_wsgi
|
||||
<http://code.google.com/p/modwsgi/wiki/VirtualEnvironments>`_.
|
||||
|
||||
* `virtualenv commands
|
||||
<http://thisismedium.com/tech/extending-virtualenv/>`_ for some more
|
||||
workflow-related tools around virtualenv.
|
||||
@@ -1,395 +0,0 @@
|
||||
Changes & News
|
||||
--------------
|
||||
|
||||
Next release (1.7) schedule
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Beta release mid-July 2011, final release early August.
|
||||
|
||||
1.6.4 (2011-07-21)
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Restored ability to run on Python 2.4, too.
|
||||
|
||||
1.6.3 (2011-07-16)
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Restored ability to run on Python < 2.7.
|
||||
|
||||
1.6.2 (2011-07-16)
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Updated embedded distribute release to 0.6.19.
|
||||
|
||||
* Updated embedded pip release to 1.0.2.
|
||||
|
||||
* Fixed #141 - Be smarter about finding pkg_resources when using the
|
||||
non-default Python intepreter (by using the ``-p`` option).
|
||||
|
||||
* Fixed #112 - Fixed path in docs.
|
||||
|
||||
* Fixed #109 - Corrected doctests of a Logger method.
|
||||
|
||||
* Fixed #118 - Fixed creating virtualenvs on platforms that use the
|
||||
"posix_local" install scheme, such as Ubuntu with Python 2.7.
|
||||
|
||||
* Add missing library to Python 3 virtualenvs (``_dummy_thread``).
|
||||
|
||||
|
||||
1.6.1 (2011-04-30)
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Start to use git-flow.
|
||||
|
||||
* Added support for PyPy 1.5
|
||||
|
||||
* Fixed #121 -- added sanity-checking of the -p argument. Thanks Paul Nasrat.
|
||||
|
||||
* Added progress meter for pip installation as well as setuptools. Thanks Ethan
|
||||
Jucovy.
|
||||
|
||||
* Added --never-download and --search-dir options. Thanks Ethan Jucovy.
|
||||
|
||||
1.6
|
||||
~~~
|
||||
|
||||
* Added Python 3 support! Huge thanks to Vinay Sajip and Vitaly Babiy.
|
||||
|
||||
* Fixed creation of virtualenvs on Mac OS X when standard library modules
|
||||
(readline) are installed outside the standard library.
|
||||
|
||||
* Updated bundled pip to 1.0.
|
||||
|
||||
1.5.2
|
||||
~~~~~
|
||||
|
||||
* Moved main repository to Github: https://github.com/pypa/virtualenv
|
||||
|
||||
* Transferred primary maintenance from Ian to Jannis Leidel, Carl Meyer and Brian Rosner
|
||||
|
||||
* Fixed a few more pypy related bugs.
|
||||
|
||||
* Updated bundled pip to 0.8.2.
|
||||
|
||||
* Handed project over to new team of maintainers.
|
||||
|
||||
* Moved virtualenv to Github at https://github.com/pypa/virtualenv
|
||||
|
||||
1.5.1
|
||||
~~~~~
|
||||
|
||||
* Added ``_weakrefset`` requirement for Python 2.7.1.
|
||||
|
||||
* Fixed Windows regression in 1.5
|
||||
|
||||
1.5
|
||||
~~~
|
||||
|
||||
* Include pip 0.8.1.
|
||||
|
||||
* Add support for PyPy.
|
||||
|
||||
* Uses a proper temporary dir when installing environment requirements.
|
||||
|
||||
* Add ``--prompt`` option to be able to override the default prompt prefix.
|
||||
|
||||
* Fix an issue with ``--relocatable`` on Windows.
|
||||
|
||||
* Fix issue with installing the wrong version of distribute.
|
||||
|
||||
* Add fish and csh activate scripts.
|
||||
|
||||
1.4.9
|
||||
~~~~~
|
||||
|
||||
* Include pip 0.7.2
|
||||
|
||||
1.4.8
|
||||
~~~~~
|
||||
|
||||
* Fix for Mac OS X Framework builds that use
|
||||
``--universal-archs=intel``
|
||||
|
||||
* Fix ``activate_this.py`` on Windows.
|
||||
|
||||
* Allow ``$PYTHONHOME`` to be set, so long as you use ``source
|
||||
bin/activate`` it will get unset; if you leave it set and do not
|
||||
activate the environment it will still break the environment.
|
||||
|
||||
* Include pip 0.7.1
|
||||
|
||||
1.4.7
|
||||
~~~~~
|
||||
|
||||
* Include pip 0.7
|
||||
|
||||
1.4.6
|
||||
~~~~~
|
||||
|
||||
* Allow ``activate.sh`` to skip updating the prompt (by setting
|
||||
``$VIRTUAL_ENV_DISABLE_PROMPT``).
|
||||
|
||||
1.4.5
|
||||
~~~~~
|
||||
|
||||
* Include pip 0.6.3
|
||||
|
||||
* Fix ``activate.bat`` and ``deactivate.bat`` under Windows when
|
||||
``PATH`` contained a parenthesis
|
||||
|
||||
1.4.4
|
||||
~~~~~
|
||||
|
||||
* Include pip 0.6.2 and Distribute 0.6.10
|
||||
|
||||
* Create the ``virtualenv`` script even when Setuptools isn't
|
||||
installed
|
||||
|
||||
* Fix problem with ``virtualenv --relocate`` when ``bin/`` has
|
||||
subdirectories (e.g., ``bin/.svn/``); from Alan Franzoni.
|
||||
|
||||
* If you set ``$VIRTUALENV_USE_DISTRIBUTE`` then virtualenv will use
|
||||
Distribute by default (so you don't have to remember to use
|
||||
``--distribute``).
|
||||
|
||||
1.4.3
|
||||
~~~~~
|
||||
|
||||
* Include pip 0.6.1
|
||||
|
||||
1.4.2
|
||||
~~~~~
|
||||
|
||||
* Fix pip installation on Windows
|
||||
|
||||
* Fix use of stand-alone ``virtualenv.py`` (and boot scripts)
|
||||
|
||||
* Exclude ~/.local (user site-packages) from environments when using
|
||||
``--no-site-packages``
|
||||
|
||||
1.4.1
|
||||
~~~~~
|
||||
|
||||
* Include pip 0.6
|
||||
|
||||
1.4
|
||||
~~~
|
||||
|
||||
* Updated setuptools to 0.6c11
|
||||
|
||||
* Added the --distribute option
|
||||
|
||||
* Fixed packaging problem of support-files
|
||||
|
||||
1.3.4
|
||||
~~~~~
|
||||
|
||||
* Virtualenv now copies the actual embedded Python binary on
|
||||
Mac OS X to fix a hang on Snow Leopard (10.6).
|
||||
|
||||
* Fail more gracefully on Windows when ``win32api`` is not installed.
|
||||
|
||||
* Fix site-packages taking precedent over Jython's ``__classpath__``
|
||||
and also specially handle the new ``__pyclasspath__`` entry in
|
||||
``sys.path``.
|
||||
|
||||
* Now copies Jython's ``registry`` file to the virtualenv if it exists.
|
||||
|
||||
* Better find libraries when compiling extensions on Windows.
|
||||
|
||||
* Create ``Scripts\pythonw.exe`` on Windows.
|
||||
|
||||
* Added support for the Debian/Ubuntu
|
||||
``/usr/lib/pythonX.Y/dist-packages`` directory.
|
||||
|
||||
* Set ``distutils.sysconfig.get_config_vars()['LIBDIR']`` (based on
|
||||
``sys.real_prefix``) which is reported to help building on Windows.
|
||||
|
||||
* Make ``deactivate`` work on ksh
|
||||
|
||||
* Fixes for ``--python``: make it work with ``--relocatable`` and the
|
||||
symlink created to the exact Python version.
|
||||
|
||||
1.3.3
|
||||
~~~~~
|
||||
|
||||
* Use Windows newlines in ``activate.bat``, which has been reported to help
|
||||
when using non-ASCII directory names.
|
||||
|
||||
* Fixed compatibility with Jython 2.5b1.
|
||||
|
||||
* Added a function ``virtualenv.install_python`` for more fine-grained
|
||||
access to what ``virtualenv.create_environment`` does.
|
||||
|
||||
* Fix `a problem <https://bugs.launchpad.net/virtualenv/+bug/241581>`_
|
||||
with Windows and paths that contain spaces.
|
||||
|
||||
* If ``/path/to/env/.pydistutils.cfg`` exists (or
|
||||
``/path/to/env/pydistutils.cfg`` on Windows systems) then ignore
|
||||
``~/.pydistutils.cfg`` and use that other file instead.
|
||||
|
||||
* Fix ` a problem
|
||||
<https://bugs.launchpad.net/virtualenv/+bug/340050>`_ picking up
|
||||
some ``.so`` libraries in ``/usr/local``.
|
||||
|
||||
1.3.2
|
||||
~~~~~
|
||||
|
||||
* Remove the ``[install] prefix = ...`` setting from the virtualenv
|
||||
``distutils.cfg`` -- this has been causing problems for a lot of
|
||||
people, in rather obscure ways.
|
||||
|
||||
* If you use a `boot script <./index.html#boot-script>`_ it will attempt to import ``virtualenv``
|
||||
and find a pre-downloaded Setuptools egg using that.
|
||||
|
||||
* Added platform-specific paths, like ``/usr/lib/pythonX.Y/plat-linux2``
|
||||
|
||||
1.3.1
|
||||
~~~~~
|
||||
|
||||
* Real Python 2.6 compatibility. Backported the Python 2.6 updates to
|
||||
``site.py``, including `user directories
|
||||
<http://docs.python.org/dev/whatsnew/2.6.html#pep-370-per-user-site-packages-directory>`_
|
||||
(this means older versions of Python will support user directories,
|
||||
whether intended or not).
|
||||
|
||||
* Always set ``[install] prefix`` in ``distutils.cfg`` -- previously
|
||||
on some platforms where a system-wide ``distutils.cfg`` was present
|
||||
with a ``prefix`` setting, packages would be installed globally
|
||||
(usually in ``/usr/local/lib/pythonX.Y/site-packages``).
|
||||
|
||||
* Sometimes Cygwin seems to leave ``.exe`` off ``sys.executable``; a
|
||||
workaround is added.
|
||||
|
||||
* Fix ``--python`` option.
|
||||
|
||||
* Fixed handling of Jython environments that use a
|
||||
jython-complete.jar.
|
||||
|
||||
1.3
|
||||
~~~
|
||||
|
||||
* Update to Setuptools 0.6c9
|
||||
* Added an option ``virtualenv --relocatable EXISTING_ENV``, which
|
||||
will make an existing environment "relocatable" -- the paths will
|
||||
not be absolute in scripts, ``.egg-info`` and ``.pth`` files. This
|
||||
may assist in building environments that can be moved and copied.
|
||||
You have to run this *after* any new packages installed.
|
||||
* Added ``bin/activate_this.py``, a file you can use like
|
||||
``execfile("path_to/activate_this.py",
|
||||
dict(__file__="path_to/activate_this.py"))`` -- this will activate
|
||||
the environment in place, similar to what `the mod_wsgi example
|
||||
does <http://code.google.com/p/modwsgi/wiki/VirtualEnvironments>`_.
|
||||
* For Mac framework builds of Python, the site-packages directory
|
||||
``/Library/Python/X.Y/site-packages`` is added to ``sys.path``, from
|
||||
Andrea Rech.
|
||||
* Some platform-specific modules in Macs are added to the path now
|
||||
(``plat-darwin/``, ``plat-mac/``, ``plat-mac/lib-scriptpackages``),
|
||||
from Andrea Rech.
|
||||
* Fixed a small Bashism in the ``bin/activate`` shell script.
|
||||
* Added ``__future__`` to the list of required modules, for Python
|
||||
2.3. You'll still need to backport your own ``subprocess`` module.
|
||||
* Fixed the ``__classpath__`` entry in Jython's ``sys.path`` taking
|
||||
precedent over virtualenv's libs.
|
||||
|
||||
1.2
|
||||
~~~
|
||||
|
||||
* Added a ``--python`` option to select the Python interpreter.
|
||||
* Add ``warnings`` to the modules copied over, for Python 2.6 support.
|
||||
* Add ``sets`` to the module copied over for Python 2.3 (though Python
|
||||
2.3 still probably doesn't work).
|
||||
|
||||
1.1.1
|
||||
~~~~~
|
||||
|
||||
* Added support for Jython 2.5.
|
||||
|
||||
1.1
|
||||
~~~
|
||||
|
||||
* Added support for Python 2.6.
|
||||
* Fix a problem with missing ``DLLs/zlib.pyd`` on Windows. Create
|
||||
* ``bin/python`` (or ``bin/python.exe``) even when you run virtualenv
|
||||
with an interpreter named, e.g., ``python2.4``
|
||||
* Fix MacPorts Python
|
||||
* Added --unzip-setuptools option
|
||||
* Update to Setuptools 0.6c8
|
||||
* If the current directory is not writable, run ez_setup.py in ``/tmp``
|
||||
* Copy or symlink over the ``include`` directory so that packages will
|
||||
more consistently compile.
|
||||
|
||||
1.0
|
||||
~~~
|
||||
|
||||
* Fix build on systems that use ``/usr/lib64``, distinct from
|
||||
``/usr/lib`` (specifically CentOS x64).
|
||||
* Fixed bug in ``--clear``.
|
||||
* Fixed typos in ``deactivate.bat``.
|
||||
* Preserve ``$PYTHONPATH`` when calling subprocesses.
|
||||
|
||||
0.9.2
|
||||
~~~~~
|
||||
|
||||
* Fix include dir copying on Windows (makes compiling possible).
|
||||
* Include the main ``lib-tk`` in the path.
|
||||
* Patch ``distutils.sysconfig``: ``get_python_inc`` and
|
||||
``get_python_lib`` to point to the global locations.
|
||||
* Install ``distutils.cfg`` before Setuptools, so that system
|
||||
customizations of ``distutils.cfg`` won't effect the installation.
|
||||
* Add ``bin/pythonX.Y`` to the virtualenv (in addition to
|
||||
``bin/python``).
|
||||
* Fixed an issue with Mac Framework Python builds, and absolute paths
|
||||
(from Ronald Oussoren).
|
||||
|
||||
0.9.1
|
||||
~~~~~
|
||||
|
||||
* Improve ability to create a virtualenv from inside a virtualenv.
|
||||
* Fix a little bug in ``bin/activate``.
|
||||
* Actually get ``distutils.cfg`` to work reliably.
|
||||
|
||||
0.9
|
||||
~~~
|
||||
|
||||
* Added ``lib-dynload`` and ``config`` to things that need to be
|
||||
copied over in an environment.
|
||||
* Copy over or symlink the ``include`` directory, so that you can
|
||||
build packages that need the C headers.
|
||||
* Include a ``distutils`` package, so you can locally update
|
||||
``distutils.cfg`` (in ``lib/pythonX.Y/distutils/distutils.cfg``).
|
||||
* Better avoid downloading Setuptools, and hitting PyPI on environment
|
||||
creation.
|
||||
* Fix a problem creating a ``lib64/`` directory.
|
||||
* Should work on MacOSX Framework builds (the default Python
|
||||
installations on Mac). Thanks to Ronald Oussoren.
|
||||
|
||||
0.8.4
|
||||
~~~~~
|
||||
|
||||
* Windows installs would sometimes give errors about ``sys.prefix`` that
|
||||
were inaccurate.
|
||||
* Slightly prettier output.
|
||||
|
||||
0.8.3
|
||||
~~~~~
|
||||
|
||||
* Added support for Windows.
|
||||
|
||||
0.8.2
|
||||
~~~~~
|
||||
|
||||
* Give a better warning if you are on an unsupported platform (Mac
|
||||
Framework Pythons, and Windows).
|
||||
* Give error about running while inside a workingenv.
|
||||
* Give better error message about Python 2.3.
|
||||
|
||||
0.8.1
|
||||
~~~~~
|
||||
|
||||
Fixed packaging of the library.
|
||||
|
||||
0.8
|
||||
~~~
|
||||
|
||||
Initial release. Everything is changed and new!
|
||||
@@ -1,3 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
import virtualenv
|
||||
virtualenv.main()
|
||||
@@ -1,5 +0,0 @@
|
||||
[egg_info]
|
||||
tag_build =
|
||||
tag_date = 0
|
||||
tag_svn_revision = 0
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
import sys, os
|
||||
try:
|
||||
from setuptools import setup
|
||||
kw = {'entry_points':
|
||||
"""[console_scripts]\nvirtualenv = virtualenv:main\n""",
|
||||
'zip_safe': False}
|
||||
except ImportError:
|
||||
from distutils.core import setup
|
||||
if sys.platform == 'win32':
|
||||
print('Note: without Setuptools installed you will have to use "python -m virtualenv ENV"')
|
||||
kw = {}
|
||||
else:
|
||||
kw = {'scripts': ['scripts/virtualenv']}
|
||||
|
||||
here = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
## Get long_description from index.txt:
|
||||
f = open(os.path.join(here, 'docs', 'index.txt'))
|
||||
long_description = f.read().strip()
|
||||
long_description = long_description.split('split here', 1)[1]
|
||||
f.close()
|
||||
f = open(os.path.join(here, 'docs', 'news.txt'))
|
||||
long_description += "\n\n" + f.read()
|
||||
f.close()
|
||||
|
||||
setup(name='virtualenv',
|
||||
# If you change the version here, change it in virtualenv.py and
|
||||
# docs/conf.py as well
|
||||
version="1.6.4",
|
||||
description="Virtual Python Environment builder",
|
||||
long_description=long_description,
|
||||
classifiers=[
|
||||
'Development Status :: 4 - Beta',
|
||||
'Intended Audience :: Developers',
|
||||
'License :: OSI Approved :: MIT License',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 2.4',
|
||||
'Programming Language :: Python :: 2.5',
|
||||
'Programming Language :: Python :: 2.6',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.1',
|
||||
'Programming Language :: Python :: 3.2',
|
||||
],
|
||||
keywords='setuptools deployment installation distutils',
|
||||
author='Ian Bicking',
|
||||
author_email='ianb@colorstudy.com',
|
||||
maintainer='Jannis Leidel, Carl Meyer and Brian Rosner',
|
||||
maintainer_email='python-virtualenv@groups.google.com',
|
||||
url='http://www.virtualenv.org',
|
||||
license='MIT',
|
||||
py_modules=['virtualenv'],
|
||||
packages=['virtualenv_support'],
|
||||
package_data={'virtualenv_support': ['*-py%s.egg' % sys.version[:3], '*.tar.gz']},
|
||||
test_suite='nose.collector',
|
||||
tests_require=['nose', 'Mock'],
|
||||
**kw
|
||||
)
|
||||
@@ -1,827 +0,0 @@
|
||||
Metadata-Version: 1.0
|
||||
Name: virtualenv
|
||||
Version: 1.6.4
|
||||
Summary: Virtual Python Environment builder
|
||||
Home-page: http://www.virtualenv.org
|
||||
Author: Jannis Leidel, Carl Meyer and Brian Rosner
|
||||
Author-email: python-virtualenv@groups.google.com
|
||||
License: MIT
|
||||
Description:
|
||||
|
||||
Status and License
|
||||
------------------
|
||||
|
||||
``virtualenv`` is a successor to `workingenv
|
||||
<http://cheeseshop.python.org/pypi/workingenv.py>`_, and an extension
|
||||
of `virtual-python
|
||||
<http://peak.telecommunity.com/DevCenter/EasyInstall#creating-a-virtual-python>`_.
|
||||
|
||||
It was written by Ian Bicking, sponsored by the `Open Planning
|
||||
Project <http://openplans.org>`_ and is now maintained by a
|
||||
`group of developers <https://github.com/pypa/virtualenv/raw/master/AUTHORS.txt>`_.
|
||||
It is licensed under an
|
||||
`MIT-style permissive license <https://github.com/pypa/virtualenv/raw/master/LICENSE.txt>`_.
|
||||
|
||||
You can install it with ``easy_install virtualenv``, or the `latest
|
||||
development version <https://github.com/pypa/virtualenv/tarball/develop#egg=virtualenv-dev>`_
|
||||
with ``easy_install virtualenv==dev``.
|
||||
|
||||
What It Does
|
||||
------------
|
||||
|
||||
``virtualenv`` is a tool to create isolated Python environments.
|
||||
|
||||
The basic problem being addressed is one of dependencies and versions,
|
||||
and indirectly permissions. Imagine you have an application that
|
||||
needs version 1 of LibFoo, but another application requires version
|
||||
2. How can you use both these applications? If you install
|
||||
everything into ``/usr/lib/python2.7/site-packages`` (or whatever your
|
||||
platform's standard location is), it's easy to end up in a situation
|
||||
where you unintentionally upgrade an application that shouldn't be
|
||||
upgraded.
|
||||
|
||||
Or more generally, what if you want to install an application *and
|
||||
leave it be*? If an application works, any change in its libraries or
|
||||
the versions of those libraries can break the application.
|
||||
|
||||
Also, what if you can't install packages into the global
|
||||
``site-packages`` directory? For instance, on a shared host.
|
||||
|
||||
In all these cases, ``virtualenv`` can help you. It creates an
|
||||
environment that has its own installation directories, that doesn't
|
||||
share libraries with other virtualenv environments (and optionally
|
||||
doesn't access the globally installed libraries either).
|
||||
|
||||
The basic usage is::
|
||||
|
||||
$ python virtualenv.py ENV
|
||||
|
||||
If you install it you can also just do ``virtualenv ENV``.
|
||||
|
||||
This creates ``ENV/lib/pythonX.X/site-packages``, where any libraries you
|
||||
install will go. It also creates ``ENV/bin/python``, which is a Python
|
||||
interpreter that uses this environment. Anytime you use that interpreter
|
||||
(including when a script has ``#!/path/to/ENV/bin/python`` in it) the libraries
|
||||
in that environment will be used.
|
||||
|
||||
It also installs either `Setuptools
|
||||
<http://peak.telecommunity.com/DevCenter/setuptools>`_ or `distribute
|
||||
<http://pypi.python.org/pypi/distribute>`_ into the environment. To use
|
||||
Distribute instead of setuptools, just call virtualenv like this::
|
||||
|
||||
$ python virtualenv.py --distribute ENV
|
||||
|
||||
You can also set the environment variable VIRTUALENV_USE_DISTRIBUTE.
|
||||
|
||||
A new virtualenv also includes the `pip <http://pypy.python.org/pypi/pip>`_
|
||||
installer, so you can use `ENV/bin/pip`` to install additional packages into
|
||||
the environment.
|
||||
|
||||
Windows Notes
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
Some paths within the virtualenv are slightly different on Windows: scripts and
|
||||
executables on Windows go in ``ENV\Scripts\`` instead of ``ENV/bin/`` and
|
||||
libraries go in ``ENV\Lib\`` rather than ``ENV/lib/``.
|
||||
|
||||
To create a virtualenv under a path with spaces in it on Windows, you'll need
|
||||
the `win32api <http://sourceforge.net/projects/pywin32/>`_ library installed.
|
||||
|
||||
PyPy Support
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Beginning with virtualenv version 1.5 `PyPy <http://pypy.org>`_ is
|
||||
supported. To use PyPy 1.4 or 1.4.1, you need a version of virtualenv >= 1.5.
|
||||
To use PyPy 1.5, you need a version of virtualenv >= 1.6.1.
|
||||
|
||||
Creating Your Own Bootstrap Scripts
|
||||
-----------------------------------
|
||||
|
||||
While this creates an environment, it doesn't put anything into the
|
||||
environment. Developers may find it useful to distribute a script
|
||||
that sets up a particular environment, for example a script that
|
||||
installs a particular web application.
|
||||
|
||||
To create a script like this, call
|
||||
``virtualenv.create_bootstrap_script(extra_text)``, and write the
|
||||
result to your new bootstrapping script. Here's the documentation
|
||||
from the docstring:
|
||||
|
||||
Creates a bootstrap script, which is like this script but with
|
||||
extend_parser, adjust_options, and after_install hooks.
|
||||
|
||||
This returns a string that (written to disk of course) can be used
|
||||
as a bootstrap script with your own customizations. The script
|
||||
will be the standard virtualenv.py script, with your extra text
|
||||
added (your extra text should be Python code).
|
||||
|
||||
If you include these functions, they will be called:
|
||||
|
||||
``extend_parser(optparse_parser)``:
|
||||
You can add or remove options from the parser here.
|
||||
|
||||
``adjust_options(options, args)``:
|
||||
You can change options here, or change the args (if you accept
|
||||
different kinds of arguments, be sure you modify ``args`` so it is
|
||||
only ``[DEST_DIR]``).
|
||||
|
||||
``after_install(options, home_dir)``:
|
||||
|
||||
After everything is installed, this function is called. This
|
||||
is probably the function you are most likely to use. An
|
||||
example would be::
|
||||
|
||||
def after_install(options, home_dir):
|
||||
if sys.platform == 'win32':
|
||||
bin = 'Scripts'
|
||||
else:
|
||||
bin = 'bin'
|
||||
subprocess.call([join(home_dir, bin, 'easy_install'),
|
||||
'MyPackage'])
|
||||
subprocess.call([join(home_dir, bin, 'my-package-script'),
|
||||
'setup', home_dir])
|
||||
|
||||
This example immediately installs a package, and runs a setup
|
||||
script from that package.
|
||||
|
||||
Bootstrap Example
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
Here's a more concrete example of how you could use this::
|
||||
|
||||
import virtualenv, textwrap
|
||||
output = virtualenv.create_bootstrap_script(textwrap.dedent("""
|
||||
import os, subprocess
|
||||
def after_install(options, home_dir):
|
||||
etc = join(home_dir, 'etc')
|
||||
if not os.path.exists(etc):
|
||||
os.makedirs(etc)
|
||||
subprocess.call([join(home_dir, 'bin', 'easy_install'),
|
||||
'BlogApplication'])
|
||||
subprocess.call([join(home_dir, 'bin', 'paster'),
|
||||
'make-config', 'BlogApplication',
|
||||
join(etc, 'blog.ini')])
|
||||
subprocess.call([join(home_dir, 'bin', 'paster'),
|
||||
'setup-app', join(etc, 'blog.ini')])
|
||||
"""))
|
||||
f = open('blog-bootstrap.py', 'w').write(output)
|
||||
|
||||
Another example is available `here
|
||||
<https://svn.openplans.org/svn/fassembler/trunk/fassembler/create-venv-script.py>`_.
|
||||
|
||||
activate script
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
In a newly created virtualenv there will be a ``bin/activate`` shell
|
||||
script, or a ``Scripts/activate.bat`` batch file on Windows.
|
||||
|
||||
On Posix systems you can do::
|
||||
|
||||
$ source bin/activate
|
||||
|
||||
This will change your ``$PATH`` to point to the virtualenv's ``bin/``
|
||||
directory. (You have to use ``source`` because it changes your shell
|
||||
environment in-place.) This is all it does; it's purely a convenience. If
|
||||
you directly run a script or the python interpreter from the virtualenv's
|
||||
``bin/`` directory (e.g. ``path/to/env/bin/pip`` or
|
||||
``/path/to/env/bin/python script.py``) there's no need for activation.
|
||||
|
||||
After activating an environment you can use the function ``deactivate`` to
|
||||
undo the changes to your ``$PATH``.
|
||||
|
||||
The ``activate`` script will also modify your shell prompt to indicate
|
||||
which environment is currently active. You can disable this behavior,
|
||||
which can be useful if you have your own custom prompt that already
|
||||
displays the active environment name. To do so, set the
|
||||
``VIRTUAL_ENV_DISABLE_PROMPT`` environment variable to any non-empty
|
||||
value before running the ``activate`` script.
|
||||
|
||||
On Windows you just do::
|
||||
|
||||
> \path\to\env\Scripts\activate.bat
|
||||
|
||||
And use ``deactivate.bat`` to undo the changes.
|
||||
|
||||
The ``--no-site-packages`` Option
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If you build with ``virtualenv --no-site-packages ENV`` it will *not*
|
||||
inherit any packages from ``/usr/lib/python2.5/site-packages`` (or
|
||||
wherever your global site-packages directory is). This can be used if
|
||||
you don't have control over site-packages and don't want to depend on
|
||||
the packages there, or you just want more isolation from the global
|
||||
system.
|
||||
|
||||
Using Virtualenv without ``bin/python``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Sometimes you can't or don't want to use the Python interpreter
|
||||
created by the virtualenv. For instance, in a `mod_python
|
||||
<http://www.modpython.org/>`_ or `mod_wsgi <http://www.modwsgi.org/>`_
|
||||
environment, there is only one interpreter.
|
||||
|
||||
Luckily, it's easy. You must use the custom Python interpreter to
|
||||
*install* libraries. But to *use* libraries, you just have to be sure
|
||||
the path is correct. A script is available to correct the path. You
|
||||
can setup the environment like::
|
||||
|
||||
activate_this = '/path/to/env/bin/activate_this.py'
|
||||
execfile(activate_this, dict(__file__=activate_this))
|
||||
|
||||
This will change ``sys.path`` and even change ``sys.prefix``, but also allow
|
||||
you to use an existing interpreter. Items in your environment will show up
|
||||
first on ``sys.path``, before global items. However, global items will
|
||||
always be accessible -- this technique does not support the
|
||||
``--no-site-packages`` flag. Also, this cannot undo the activation of other
|
||||
environments, or modules that have been imported. You shouldn't try to, for
|
||||
instance, activate an environment before a web request; you should activate
|
||||
*one* environment as early as possible, and not do it again in that process.
|
||||
|
||||
Making Environments Relocatable
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Note: this option is somewhat experimental, and there are probably
|
||||
caveats that have not yet been identified. Also this does not
|
||||
currently work on Windows.
|
||||
|
||||
Normally environments are tied to a specific path. That means that
|
||||
you cannot move an environment around or copy it to another computer.
|
||||
You can fix up an environment to make it relocatable with the
|
||||
command::
|
||||
|
||||
$ virtualenv --relocatable ENV
|
||||
|
||||
This will make some of the files created by setuptools or distribute
|
||||
use relative paths, and will change all the scripts to use ``activate_this.py``
|
||||
instead of using the location of the Python interpreter to select the
|
||||
environment.
|
||||
|
||||
**Note:** you must run this after you've installed *any* packages into
|
||||
the environment. If you make an environment relocatable, then
|
||||
install a new package, you must run ``virtualenv --relocatable``
|
||||
again.
|
||||
|
||||
Also, this **does not make your packages cross-platform**. You can
|
||||
move the directory around, but it can only be used on other similar
|
||||
computers. Some known environmental differences that can cause
|
||||
incompatibilities: a different version of Python, when one platform
|
||||
uses UCS2 for its internal unicode representation and another uses
|
||||
UCS4 (a compile-time option), obvious platform changes like Windows
|
||||
vs. Linux, or Intel vs. ARM, and if you have libraries that bind to C
|
||||
libraries on the system, if those C libraries are located somewhere
|
||||
different (either different versions, or a different filesystem
|
||||
layout).
|
||||
|
||||
Currently the ``--no-site-packages`` option will not be honored if you
|
||||
use this on an environment.
|
||||
|
||||
The ``--extra-search-dir`` Option
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
When it creates a new environment, virtualenv installs either
|
||||
setuptools or distribute, and pip. In normal operation, the latest
|
||||
releases of these packages are fetched from the `Python Package Index
|
||||
<http://pypi.python.org>`_ (PyPI). In some circumstances, this
|
||||
behavior may not be wanted, for example if you are using virtualenv
|
||||
during a deployment and do not want to depend on Internet access and
|
||||
PyPI availability.
|
||||
|
||||
As an alternative, you can provide your own versions of setuptools,
|
||||
distribute and/or pip on the filesystem, and tell virtualenv to use
|
||||
those distributions instead of downloading them from the Internet. To
|
||||
use this feature, pass one or more ``--extra-search-dir`` options to
|
||||
virtualenv like this::
|
||||
|
||||
$ virtualenv --extra-search-dir=/path/to/distributions ENV
|
||||
|
||||
The ``/path/to/distributions`` path should point to a directory that
|
||||
contains setuptools, distribute and/or pip distributions. Setuptools
|
||||
distributions must be ``.egg`` files; distribute and pip distributions
|
||||
should be `.tar.gz` source distributions.
|
||||
|
||||
Virtualenv will still download these packages if no satisfactory local
|
||||
distributions are found.
|
||||
|
||||
If you are really concerned about virtualenv fetching these packages
|
||||
from the Internet and want to ensure that it never will, you can also
|
||||
provide an option ``--never-download`` like so::
|
||||
|
||||
$ virtualenv --extra-search-dir=/path/to/distributions --never-download ENV
|
||||
|
||||
If this option is provided, virtualenv will never try to download
|
||||
setuptools/distribute or pip. Instead, it will exit with status code 1
|
||||
if it fails to find local distributions for any of these required
|
||||
packages.
|
||||
|
||||
Compare & Contrast with Alternatives
|
||||
------------------------------------
|
||||
|
||||
There are several alternatives that create isolated environments:
|
||||
|
||||
* ``workingenv`` (which I do not suggest you use anymore) is the
|
||||
predecessor to this library. It used the main Python interpreter,
|
||||
but relied on setting ``$PYTHONPATH`` to activate the environment.
|
||||
This causes problems when running Python scripts that aren't part of
|
||||
the environment (e.g., a globally installed ``hg`` or ``bzr``). It
|
||||
also conflicted a lot with Setuptools.
|
||||
|
||||
* `virtual-python
|
||||
<http://peak.telecommunity.com/DevCenter/EasyInstall#creating-a-virtual-python>`_
|
||||
is also a predecessor to this library. It uses only symlinks, so it
|
||||
couldn't work on Windows. It also symlinks over the *entire*
|
||||
standard library and global ``site-packages``. As a result, it
|
||||
won't see new additions to the global ``site-packages``.
|
||||
|
||||
This script only symlinks a small portion of the standard library
|
||||
into the environment, and so on Windows it is feasible to simply
|
||||
copy these files over. Also, it creates a new/empty
|
||||
``site-packages`` and also adds the global ``site-packages`` to the
|
||||
path, so updates are tracked separately. This script also installs
|
||||
Setuptools automatically, saving a step and avoiding the need for
|
||||
network access.
|
||||
|
||||
* `zc.buildout <http://pypi.python.org/pypi/zc.buildout>`_ doesn't
|
||||
create an isolated Python environment in the same style, but
|
||||
achieves similar results through a declarative config file that sets
|
||||
up scripts with very particular packages. As a declarative system,
|
||||
it is somewhat easier to repeat and manage, but more difficult to
|
||||
experiment with. ``zc.buildout`` includes the ability to setup
|
||||
non-Python systems (e.g., a database server or an Apache instance).
|
||||
|
||||
I *strongly* recommend anyone doing application development or
|
||||
deployment use one of these tools.
|
||||
|
||||
Contributing
|
||||
------------
|
||||
|
||||
Refer to the `contributing to pip`_ documentation - it applies equally to
|
||||
virtualenv.
|
||||
|
||||
Virtualenv's release schedule is tied to pip's -- each time there's a new pip
|
||||
release, there will be a new virtualenv release that bundles the new version of
|
||||
pip.
|
||||
|
||||
.. _contributing to pip: http://www.pip-installer.org/en/latest/how-to-contribute.html
|
||||
|
||||
Running the tests
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
Virtualenv's test suite is small and not yet at all comprehensive, but we aim
|
||||
to grow it.
|
||||
|
||||
The easy way to run tests (handles test dependencies automatically)::
|
||||
|
||||
$ python setup.py test
|
||||
|
||||
If you want to run only a selection of the tests, you'll need to run them
|
||||
directly with nose instead. Create a virtualenv, and install required
|
||||
packages::
|
||||
|
||||
$ pip install nose mock
|
||||
|
||||
Run nosetests::
|
||||
|
||||
$ nosetests
|
||||
|
||||
Or select just a single test file to run::
|
||||
|
||||
$ nosetests tests.test_virtualenv
|
||||
|
||||
|
||||
Other Documentation and Links
|
||||
-----------------------------
|
||||
|
||||
* James Gardner has written a tutorial on using `virtualenv with
|
||||
Pylons
|
||||
<http://wiki.pylonshq.com/display/pylonscookbook/Using+a+Virtualenv+Sandbox>`_.
|
||||
|
||||
* `Blog announcement
|
||||
<http://blog.ianbicking.org/2007/10/10/workingenv-is-dead-long-live-virtualenv/>`_.
|
||||
|
||||
* Doug Hellmann wrote a description of his `command-line work flow
|
||||
using virtualenv (virtualenvwrapper)
|
||||
<http://www.doughellmann.com/articles/CompletelyDifferent-2008-05-virtualenvwrapper/index.html>`_
|
||||
including some handy scripts to make working with multiple
|
||||
environments easier. He also wrote `an example of using virtualenv
|
||||
to try IPython
|
||||
<http://www.doughellmann.com/articles/CompletelyDifferent-2008-02-ipython-and-virtualenv/index.html>`_.
|
||||
|
||||
* Chris Perkins created a `showmedo video including virtualenv
|
||||
<http://showmedo.com/videos/video?name=2910000&fromSeriesID=291>`_.
|
||||
|
||||
* `Using virtualenv with mod_wsgi
|
||||
<http://code.google.com/p/modwsgi/wiki/VirtualEnvironments>`_.
|
||||
|
||||
* `virtualenv commands
|
||||
<http://thisismedium.com/tech/extending-virtualenv/>`_ for some more
|
||||
workflow-related tools around virtualenv.
|
||||
|
||||
Changes & News
|
||||
--------------
|
||||
|
||||
Next release (1.7) schedule
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Beta release mid-July 2011, final release early August.
|
||||
|
||||
1.6.4 (2011-07-21)
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Restored ability to run on Python 2.4, too.
|
||||
|
||||
1.6.3 (2011-07-16)
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Restored ability to run on Python < 2.7.
|
||||
|
||||
1.6.2 (2011-07-16)
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Updated embedded distribute release to 0.6.19.
|
||||
|
||||
* Updated embedded pip release to 1.0.2.
|
||||
|
||||
* Fixed #141 - Be smarter about finding pkg_resources when using the
|
||||
non-default Python intepreter (by using the ``-p`` option).
|
||||
|
||||
* Fixed #112 - Fixed path in docs.
|
||||
|
||||
* Fixed #109 - Corrected doctests of a Logger method.
|
||||
|
||||
* Fixed #118 - Fixed creating virtualenvs on platforms that use the
|
||||
"posix_local" install scheme, such as Ubuntu with Python 2.7.
|
||||
|
||||
* Add missing library to Python 3 virtualenvs (``_dummy_thread``).
|
||||
|
||||
|
||||
1.6.1 (2011-04-30)
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Start to use git-flow.
|
||||
|
||||
* Added support for PyPy 1.5
|
||||
|
||||
* Fixed #121 -- added sanity-checking of the -p argument. Thanks Paul Nasrat.
|
||||
|
||||
* Added progress meter for pip installation as well as setuptools. Thanks Ethan
|
||||
Jucovy.
|
||||
|
||||
* Added --never-download and --search-dir options. Thanks Ethan Jucovy.
|
||||
|
||||
1.6
|
||||
~~~
|
||||
|
||||
* Added Python 3 support! Huge thanks to Vinay Sajip and Vitaly Babiy.
|
||||
|
||||
* Fixed creation of virtualenvs on Mac OS X when standard library modules
|
||||
(readline) are installed outside the standard library.
|
||||
|
||||
* Updated bundled pip to 1.0.
|
||||
|
||||
1.5.2
|
||||
~~~~~
|
||||
|
||||
* Moved main repository to Github: https://github.com/pypa/virtualenv
|
||||
|
||||
* Transferred primary maintenance from Ian to Jannis Leidel, Carl Meyer and Brian Rosner
|
||||
|
||||
* Fixed a few more pypy related bugs.
|
||||
|
||||
* Updated bundled pip to 0.8.2.
|
||||
|
||||
* Handed project over to new team of maintainers.
|
||||
|
||||
* Moved virtualenv to Github at https://github.com/pypa/virtualenv
|
||||
|
||||
1.5.1
|
||||
~~~~~
|
||||
|
||||
* Added ``_weakrefset`` requirement for Python 2.7.1.
|
||||
|
||||
* Fixed Windows regression in 1.5
|
||||
|
||||
1.5
|
||||
~~~
|
||||
|
||||
* Include pip 0.8.1.
|
||||
|
||||
* Add support for PyPy.
|
||||
|
||||
* Uses a proper temporary dir when installing environment requirements.
|
||||
|
||||
* Add ``--prompt`` option to be able to override the default prompt prefix.
|
||||
|
||||
* Fix an issue with ``--relocatable`` on Windows.
|
||||
|
||||
* Fix issue with installing the wrong version of distribute.
|
||||
|
||||
* Add fish and csh activate scripts.
|
||||
|
||||
1.4.9
|
||||
~~~~~
|
||||
|
||||
* Include pip 0.7.2
|
||||
|
||||
1.4.8
|
||||
~~~~~
|
||||
|
||||
* Fix for Mac OS X Framework builds that use
|
||||
``--universal-archs=intel``
|
||||
|
||||
* Fix ``activate_this.py`` on Windows.
|
||||
|
||||
* Allow ``$PYTHONHOME`` to be set, so long as you use ``source
|
||||
bin/activate`` it will get unset; if you leave it set and do not
|
||||
activate the environment it will still break the environment.
|
||||
|
||||
* Include pip 0.7.1
|
||||
|
||||
1.4.7
|
||||
~~~~~
|
||||
|
||||
* Include pip 0.7
|
||||
|
||||
1.4.6
|
||||
~~~~~
|
||||
|
||||
* Allow ``activate.sh`` to skip updating the prompt (by setting
|
||||
``$VIRTUAL_ENV_DISABLE_PROMPT``).
|
||||
|
||||
1.4.5
|
||||
~~~~~
|
||||
|
||||
* Include pip 0.6.3
|
||||
|
||||
* Fix ``activate.bat`` and ``deactivate.bat`` under Windows when
|
||||
``PATH`` contained a parenthesis
|
||||
|
||||
1.4.4
|
||||
~~~~~
|
||||
|
||||
* Include pip 0.6.2 and Distribute 0.6.10
|
||||
|
||||
* Create the ``virtualenv`` script even when Setuptools isn't
|
||||
installed
|
||||
|
||||
* Fix problem with ``virtualenv --relocate`` when ``bin/`` has
|
||||
subdirectories (e.g., ``bin/.svn/``); from Alan Franzoni.
|
||||
|
||||
* If you set ``$VIRTUALENV_USE_DISTRIBUTE`` then virtualenv will use
|
||||
Distribute by default (so you don't have to remember to use
|
||||
``--distribute``).
|
||||
|
||||
1.4.3
|
||||
~~~~~
|
||||
|
||||
* Include pip 0.6.1
|
||||
|
||||
1.4.2
|
||||
~~~~~
|
||||
|
||||
* Fix pip installation on Windows
|
||||
|
||||
* Fix use of stand-alone ``virtualenv.py`` (and boot scripts)
|
||||
|
||||
* Exclude ~/.local (user site-packages) from environments when using
|
||||
``--no-site-packages``
|
||||
|
||||
1.4.1
|
||||
~~~~~
|
||||
|
||||
* Include pip 0.6
|
||||
|
||||
1.4
|
||||
~~~
|
||||
|
||||
* Updated setuptools to 0.6c11
|
||||
|
||||
* Added the --distribute option
|
||||
|
||||
* Fixed packaging problem of support-files
|
||||
|
||||
1.3.4
|
||||
~~~~~
|
||||
|
||||
* Virtualenv now copies the actual embedded Python binary on
|
||||
Mac OS X to fix a hang on Snow Leopard (10.6).
|
||||
|
||||
* Fail more gracefully on Windows when ``win32api`` is not installed.
|
||||
|
||||
* Fix site-packages taking precedent over Jython's ``__classpath__``
|
||||
and also specially handle the new ``__pyclasspath__`` entry in
|
||||
``sys.path``.
|
||||
|
||||
* Now copies Jython's ``registry`` file to the virtualenv if it exists.
|
||||
|
||||
* Better find libraries when compiling extensions on Windows.
|
||||
|
||||
* Create ``Scripts\pythonw.exe`` on Windows.
|
||||
|
||||
* Added support for the Debian/Ubuntu
|
||||
``/usr/lib/pythonX.Y/dist-packages`` directory.
|
||||
|
||||
* Set ``distutils.sysconfig.get_config_vars()['LIBDIR']`` (based on
|
||||
``sys.real_prefix``) which is reported to help building on Windows.
|
||||
|
||||
* Make ``deactivate`` work on ksh
|
||||
|
||||
* Fixes for ``--python``: make it work with ``--relocatable`` and the
|
||||
symlink created to the exact Python version.
|
||||
|
||||
1.3.3
|
||||
~~~~~
|
||||
|
||||
* Use Windows newlines in ``activate.bat``, which has been reported to help
|
||||
when using non-ASCII directory names.
|
||||
|
||||
* Fixed compatibility with Jython 2.5b1.
|
||||
|
||||
* Added a function ``virtualenv.install_python`` for more fine-grained
|
||||
access to what ``virtualenv.create_environment`` does.
|
||||
|
||||
* Fix `a problem <https://bugs.launchpad.net/virtualenv/+bug/241581>`_
|
||||
with Windows and paths that contain spaces.
|
||||
|
||||
* If ``/path/to/env/.pydistutils.cfg`` exists (or
|
||||
``/path/to/env/pydistutils.cfg`` on Windows systems) then ignore
|
||||
``~/.pydistutils.cfg`` and use that other file instead.
|
||||
|
||||
* Fix ` a problem
|
||||
<https://bugs.launchpad.net/virtualenv/+bug/340050>`_ picking up
|
||||
some ``.so`` libraries in ``/usr/local``.
|
||||
|
||||
1.3.2
|
||||
~~~~~
|
||||
|
||||
* Remove the ``[install] prefix = ...`` setting from the virtualenv
|
||||
``distutils.cfg`` -- this has been causing problems for a lot of
|
||||
people, in rather obscure ways.
|
||||
|
||||
* If you use a `boot script <./index.html#boot-script>`_ it will attempt to import ``virtualenv``
|
||||
and find a pre-downloaded Setuptools egg using that.
|
||||
|
||||
* Added platform-specific paths, like ``/usr/lib/pythonX.Y/plat-linux2``
|
||||
|
||||
1.3.1
|
||||
~~~~~
|
||||
|
||||
* Real Python 2.6 compatibility. Backported the Python 2.6 updates to
|
||||
``site.py``, including `user directories
|
||||
<http://docs.python.org/dev/whatsnew/2.6.html#pep-370-per-user-site-packages-directory>`_
|
||||
(this means older versions of Python will support user directories,
|
||||
whether intended or not).
|
||||
|
||||
* Always set ``[install] prefix`` in ``distutils.cfg`` -- previously
|
||||
on some platforms where a system-wide ``distutils.cfg`` was present
|
||||
with a ``prefix`` setting, packages would be installed globally
|
||||
(usually in ``/usr/local/lib/pythonX.Y/site-packages``).
|
||||
|
||||
* Sometimes Cygwin seems to leave ``.exe`` off ``sys.executable``; a
|
||||
workaround is added.
|
||||
|
||||
* Fix ``--python`` option.
|
||||
|
||||
* Fixed handling of Jython environments that use a
|
||||
jython-complete.jar.
|
||||
|
||||
1.3
|
||||
~~~
|
||||
|
||||
* Update to Setuptools 0.6c9
|
||||
* Added an option ``virtualenv --relocatable EXISTING_ENV``, which
|
||||
will make an existing environment "relocatable" -- the paths will
|
||||
not be absolute in scripts, ``.egg-info`` and ``.pth`` files. This
|
||||
may assist in building environments that can be moved and copied.
|
||||
You have to run this *after* any new packages installed.
|
||||
* Added ``bin/activate_this.py``, a file you can use like
|
||||
``execfile("path_to/activate_this.py",
|
||||
dict(__file__="path_to/activate_this.py"))`` -- this will activate
|
||||
the environment in place, similar to what `the mod_wsgi example
|
||||
does <http://code.google.com/p/modwsgi/wiki/VirtualEnvironments>`_.
|
||||
* For Mac framework builds of Python, the site-packages directory
|
||||
``/Library/Python/X.Y/site-packages`` is added to ``sys.path``, from
|
||||
Andrea Rech.
|
||||
* Some platform-specific modules in Macs are added to the path now
|
||||
(``plat-darwin/``, ``plat-mac/``, ``plat-mac/lib-scriptpackages``),
|
||||
from Andrea Rech.
|
||||
* Fixed a small Bashism in the ``bin/activate`` shell script.
|
||||
* Added ``__future__`` to the list of required modules, for Python
|
||||
2.3. You'll still need to backport your own ``subprocess`` module.
|
||||
* Fixed the ``__classpath__`` entry in Jython's ``sys.path`` taking
|
||||
precedent over virtualenv's libs.
|
||||
|
||||
1.2
|
||||
~~~
|
||||
|
||||
* Added a ``--python`` option to select the Python interpreter.
|
||||
* Add ``warnings`` to the modules copied over, for Python 2.6 support.
|
||||
* Add ``sets`` to the module copied over for Python 2.3 (though Python
|
||||
2.3 still probably doesn't work).
|
||||
|
||||
1.1.1
|
||||
~~~~~
|
||||
|
||||
* Added support for Jython 2.5.
|
||||
|
||||
1.1
|
||||
~~~
|
||||
|
||||
* Added support for Python 2.6.
|
||||
* Fix a problem with missing ``DLLs/zlib.pyd`` on Windows. Create
|
||||
* ``bin/python`` (or ``bin/python.exe``) even when you run virtualenv
|
||||
with an interpreter named, e.g., ``python2.4``
|
||||
* Fix MacPorts Python
|
||||
* Added --unzip-setuptools option
|
||||
* Update to Setuptools 0.6c8
|
||||
* If the current directory is not writable, run ez_setup.py in ``/tmp``
|
||||
* Copy or symlink over the ``include`` directory so that packages will
|
||||
more consistently compile.
|
||||
|
||||
1.0
|
||||
~~~
|
||||
|
||||
* Fix build on systems that use ``/usr/lib64``, distinct from
|
||||
``/usr/lib`` (specifically CentOS x64).
|
||||
* Fixed bug in ``--clear``.
|
||||
* Fixed typos in ``deactivate.bat``.
|
||||
* Preserve ``$PYTHONPATH`` when calling subprocesses.
|
||||
|
||||
0.9.2
|
||||
~~~~~
|
||||
|
||||
* Fix include dir copying on Windows (makes compiling possible).
|
||||
* Include the main ``lib-tk`` in the path.
|
||||
* Patch ``distutils.sysconfig``: ``get_python_inc`` and
|
||||
``get_python_lib`` to point to the global locations.
|
||||
* Install ``distutils.cfg`` before Setuptools, so that system
|
||||
customizations of ``distutils.cfg`` won't effect the installation.
|
||||
* Add ``bin/pythonX.Y`` to the virtualenv (in addition to
|
||||
``bin/python``).
|
||||
* Fixed an issue with Mac Framework Python builds, and absolute paths
|
||||
(from Ronald Oussoren).
|
||||
|
||||
0.9.1
|
||||
~~~~~
|
||||
|
||||
* Improve ability to create a virtualenv from inside a virtualenv.
|
||||
* Fix a little bug in ``bin/activate``.
|
||||
* Actually get ``distutils.cfg`` to work reliably.
|
||||
|
||||
0.9
|
||||
~~~
|
||||
|
||||
* Added ``lib-dynload`` and ``config`` to things that need to be
|
||||
copied over in an environment.
|
||||
* Copy over or symlink the ``include`` directory, so that you can
|
||||
build packages that need the C headers.
|
||||
* Include a ``distutils`` package, so you can locally update
|
||||
``distutils.cfg`` (in ``lib/pythonX.Y/distutils/distutils.cfg``).
|
||||
* Better avoid downloading Setuptools, and hitting PyPI on environment
|
||||
creation.
|
||||
* Fix a problem creating a ``lib64/`` directory.
|
||||
* Should work on MacOSX Framework builds (the default Python
|
||||
installations on Mac). Thanks to Ronald Oussoren.
|
||||
|
||||
0.8.4
|
||||
~~~~~
|
||||
|
||||
* Windows installs would sometimes give errors about ``sys.prefix`` that
|
||||
were inaccurate.
|
||||
* Slightly prettier output.
|
||||
|
||||
0.8.3
|
||||
~~~~~
|
||||
|
||||
* Added support for Windows.
|
||||
|
||||
0.8.2
|
||||
~~~~~
|
||||
|
||||
* Give a better warning if you are on an unsupported platform (Mac
|
||||
Framework Pythons, and Windows).
|
||||
* Give error about running while inside a workingenv.
|
||||
* Give better error message about Python 2.3.
|
||||
|
||||
0.8.1
|
||||
~~~~~
|
||||
|
||||
Fixed packaging of the library.
|
||||
|
||||
0.8
|
||||
~~~
|
||||
|
||||
Initial release. Everything is changed and new!
|
||||
|
||||
Keywords: setuptools deployment installation distutils
|
||||
Platform: UNKNOWN
|
||||
Classifier: Development Status :: 4 - Beta
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: License :: OSI Approved :: MIT License
|
||||
Classifier: Programming Language :: Python :: 2
|
||||
Classifier: Programming Language :: Python :: 2.4
|
||||
Classifier: Programming Language :: Python :: 2.5
|
||||
Classifier: Programming Language :: Python :: 2.6
|
||||
Classifier: Programming Language :: Python :: 2.7
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 3.1
|
||||
Classifier: Programming Language :: Python :: 3.2
|
||||
@@ -1,21 +0,0 @@
|
||||
AUTHORS.txt
|
||||
LICENSE.txt
|
||||
MANIFEST.in
|
||||
setup.py
|
||||
virtualenv.py
|
||||
docs/index.txt
|
||||
docs/news.txt
|
||||
scripts/virtualenv
|
||||
virtualenv.egg-info/PKG-INFO
|
||||
virtualenv.egg-info/SOURCES.txt
|
||||
virtualenv.egg-info/dependency_links.txt
|
||||
virtualenv.egg-info/entry_points.txt
|
||||
virtualenv.egg-info/not-zip-safe
|
||||
virtualenv.egg-info/top_level.txt
|
||||
virtualenv_support/__init__.py
|
||||
virtualenv_support/distribute-0.6.19.tar.gz
|
||||
virtualenv_support/pip-1.0.2.tar.gz
|
||||
virtualenv_support/setuptools-0.6c11-py2.4.egg
|
||||
virtualenv_support/setuptools-0.6c11-py2.5.egg
|
||||
virtualenv_support/setuptools-0.6c11-py2.6.egg
|
||||
virtualenv_support/setuptools-0.6c11-py2.7.egg
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
[console_scripts]
|
||||
virtualenv = virtualenv:main
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
virtualenv_support
|
||||
virtualenv
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1
@@ -0,0 +1 @@
|
||||
psycopg2
|
||||
+1
@@ -0,0 +1 @@
|
||||
requests
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
python-2.7.13
|
||||
+1
@@ -0,0 +1 @@
|
||||
requests
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
python-3.6.0
|
||||
@@ -0,0 +1 @@
|
||||
requests
|
||||
Vendored
+114
@@ -0,0 +1,114 @@
|
||||
Maya: Datetime for Humans™
|
||||
==========================
|
||||
|
||||
.. image:: https://img.shields.io/pypi/v/maya.svg
|
||||
:target: https://pypi.python.org/pypi/maya
|
||||
|
||||
.. image:: https://travis-ci.org/kennethreitz/maya.svg?branch=master
|
||||
:target: https://travis-ci.org/kennethreitz/maya
|
||||
|
||||
.. image:: https://img.shields.io/badge/SayThanks.io-☼-1EAEDB.svg
|
||||
:target: https://saythanks.io/to/kennethreitz
|
||||
|
||||
|
||||
Datetimes are very frustrating to work with in Python, especially when dealing
|
||||
with different locales on different systems. This library exists to make the
|
||||
simple things **much** easier, while admitting that time is an illusion
|
||||
(timezones doubly so).
|
||||
|
||||
Datetimes should be interacted with via an API written for humans.
|
||||
|
||||
Maya is mostly built around the headaches and use-cases around parsing datetime data from websites.
|
||||
|
||||
|
||||
☤ Basic Usage of Maya
|
||||
---------------------
|
||||
|
||||
Behold, datetimes for humans!
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> now = maya.now()
|
||||
<MayaDT epoch=1481850660.9>
|
||||
|
||||
>>> tomorrow = maya.when('tomorrow')
|
||||
<MayaDT epoch=1481919067.23>
|
||||
|
||||
>>> tomorrow.slang_date()
|
||||
'tomorrow'
|
||||
|
||||
>>> tomorrow.slang_time()
|
||||
'23 hours from now'
|
||||
|
||||
>>> tomorrow.iso8601()
|
||||
'2016-12-16T15:11:30.263350Z'
|
||||
|
||||
>>> tomorrow.rfc2822()
|
||||
'Fri, 16 Dec 2016 20:11:30 -0000'
|
||||
|
||||
>>> tomorrow.datetime()
|
||||
datetime.datetime(2016, 12, 16, 15, 11, 30, 263350, tzinfo=<UTC>)
|
||||
|
||||
# Automatically parse datetime strings and generate naive datetimes.
|
||||
>>> scraped = '2016-12-16 18:23:45.423992+00:00'
|
||||
>>> maya.parse(scraped).datetime(to_timezone='US/Eastern', naive=True)
|
||||
datetime.datetime(2016, 12, 16, 13, 23, 45, 423992)
|
||||
|
||||
>>> rand_day = maya.when('2011-02-07', timezone='US/Eastern')
|
||||
<MayaDT epoch=1297036800.0>
|
||||
|
||||
# Note how this is the 6th, not the 7th.
|
||||
>>> rand_day.day
|
||||
6
|
||||
|
||||
# Always.
|
||||
>>> rand_day.timezone
|
||||
UTC
|
||||
|
||||
☤ Why is this useful?
|
||||
---------------------
|
||||
|
||||
- All timezone algebra will behave identically on all machines, regardless of system locale.
|
||||
- Complete symmetric import and export of both ISO 8601 and RFC 2822 datetime stamps.
|
||||
- Fantastic parsing of both dates written for/by humans and machines (``maya.when()`` vs ``maya.parse()``).
|
||||
- Support for human slang, both import and export (e.g. `an hour ago`).
|
||||
- Datetimes can very easily be generated, with or without tzinfo attached.
|
||||
- This library is based around epoch time, but dates before Jan 1 1970 are indeed supported, via negative integers.
|
||||
- Maya never panics, and always carries a towel.
|
||||
|
||||
|
||||
☤ What about Delorean, Arrow, & Pendulum?
|
||||
-----------------------------------------
|
||||
|
||||
Arrow, for example, is a fantastic library, but isn't what I wanted in a datetime library. In many ways, it's better than Maya for certain things. In some ways, in my opinion, it's not.
|
||||
|
||||
I simply desire a sane API for datetimes that made sense to me for all the things I'd ever want to do—especially when dealing with timezone algebra. Arrow doesn't do all of the things I need (but it does a lot more!). Maya does do exactly what I need.
|
||||
|
||||
I think these projects complement each-other, personally. Maya is great for parsing websites. For example- Arrow supports floors and ceilings and spans of dates, which Maya does not at all.
|
||||
|
||||
|
||||
☤ Installing Maya
|
||||
-----------------
|
||||
|
||||
Installation is easy, with pip::
|
||||
|
||||
$ pip install maya
|
||||
|
||||
✨🍰✨
|
||||
|
||||
☤ Like it?
|
||||
----------
|
||||
|
||||
`Say Thanks <https://saythanks.io/to/kennethreitz>`_!
|
||||
|
||||
|
||||
How to Contribute
|
||||
-----------------
|
||||
|
||||
#. Check for open issues or open a fresh issue to start a discussion around a feature idea or a bug.
|
||||
#. Fork `the repository`_ on GitHub to start making your changes to the **master** branch (or branch off of it).
|
||||
#. Write a test which shows that the bug was fixed or that the feature works as expected.
|
||||
#. Send a pull request and bug the maintainer until it gets merged and published. :) Make sure to add yourself to AUTHORS_.
|
||||
|
||||
.. _`the repository`: http://github.com/kennethreitz/maya
|
||||
.. _AUTHORS: https://github.com/kennethreitz/maya/blob/master/AUTHORS.rst
|
||||
Vendored
+273
@@ -0,0 +1,273 @@
|
||||
|
||||
# ___ __ ___ _ _ ___
|
||||
# || \/ | ||=|| \\// ||=||
|
||||
# || | || || // || ||
|
||||
|
||||
# Ignore warnings for yaml usage.
|
||||
import warnings
|
||||
import ruamel.yaml
|
||||
warnings.simplefilter('ignore', ruamel.yaml.error.UnsafeLoaderWarning)
|
||||
|
||||
|
||||
import email.utils
|
||||
import time
|
||||
from datetime import datetime as Datetime
|
||||
|
||||
import pytz
|
||||
import humanize
|
||||
import dateparser
|
||||
import iso8601
|
||||
import dateutil.parser
|
||||
from tzlocal import get_localzone
|
||||
|
||||
_EPOCH_START = (1970, 1, 1)
|
||||
|
||||
|
||||
def validate_class_type_arguments(operator):
|
||||
"""
|
||||
Decorator to validate all the arguments to function
|
||||
are of the type of calling class
|
||||
"""
|
||||
|
||||
def inner(function):
|
||||
def wrapper(self, *args, **kwargs):
|
||||
for arg in args + tuple(kwargs.values()):
|
||||
if not isinstance(arg, self.__class__):
|
||||
raise TypeError('unorderable types: {}() {} {}()'.format(
|
||||
type(self).__name__, operator, type(arg).__name__))
|
||||
return function(self, *args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
||||
return inner
|
||||
|
||||
|
||||
|
||||
class MayaDT(object):
|
||||
"""The Maya Datetime object."""
|
||||
|
||||
def __init__(self, epoch):
|
||||
super(MayaDT, self).__init__()
|
||||
self._epoch = epoch
|
||||
|
||||
def __repr__(self):
|
||||
return '<MayaDT epoch={}>'.format(self._epoch)
|
||||
|
||||
def __str__(self):
|
||||
return self.rfc2822()
|
||||
|
||||
def __format__(self, *args, **kwargs):
|
||||
"""Return's the datetime's format"""
|
||||
return format(self.datetime(), *args, **kwargs)
|
||||
|
||||
|
||||
@validate_class_type_arguments('==')
|
||||
def __eq__(self, maya_dt):
|
||||
return self._epoch == maya_dt._epoch
|
||||
|
||||
@validate_class_type_arguments('!=')
|
||||
def __ne__(self, maya_dt):
|
||||
return self._epoch != maya_dt._epoch
|
||||
|
||||
@validate_class_type_arguments('<')
|
||||
def __lt__(self, maya_dt):
|
||||
return self._epoch < maya_dt._epoch
|
||||
|
||||
@validate_class_type_arguments('<=')
|
||||
def __le__(self, maya_dt):
|
||||
return self._epoch <= maya_dt._epoch
|
||||
|
||||
@validate_class_type_arguments('>')
|
||||
def __gt__(self, maya_dt):
|
||||
return self._epoch > maya_dt._epoch
|
||||
|
||||
@validate_class_type_arguments('>=')
|
||||
def __ge__(self, maya_dt):
|
||||
return self._epoch >= maya_dt._epoch
|
||||
|
||||
|
||||
# Timezone Crap
|
||||
# -------------
|
||||
|
||||
@property
|
||||
def timezone(self):
|
||||
"""Returns the UTC tzinfo name. It's always UTC. Always."""
|
||||
return 'UTC'
|
||||
|
||||
@property
|
||||
def _tz(self):
|
||||
"""Returns the UTC tzinfo object."""
|
||||
return pytz.timezone(self.timezone)
|
||||
|
||||
@property
|
||||
def local_timezone(self):
|
||||
"""Returns the name of the local timezone, for informational purposes."""
|
||||
return self._local_tz.zone
|
||||
|
||||
@property
|
||||
def _local_tz(self):
|
||||
"""Returns the local timezone."""
|
||||
return get_localzone()
|
||||
|
||||
@staticmethod
|
||||
def __dt_to_epoch(dt):
|
||||
"""Converts a datetime into an epoch."""
|
||||
|
||||
# Assume UTC if no datetime is provided.
|
||||
if dt.tzinfo is None:
|
||||
dt = dt.replace(tzinfo=pytz.utc)
|
||||
|
||||
epoch_start = Datetime(*_EPOCH_START, tzinfo=pytz.timezone('UTC'))
|
||||
return (dt - epoch_start).total_seconds()
|
||||
|
||||
# Importers
|
||||
# ---------
|
||||
|
||||
@classmethod
|
||||
def from_datetime(klass, dt):
|
||||
"""Returns MayaDT instance from datetime."""
|
||||
return klass(klass.__dt_to_epoch(dt))
|
||||
|
||||
@classmethod
|
||||
def from_iso8601(klass, string):
|
||||
"""Returns MayaDT instance from iso8601 string."""
|
||||
dt = iso8601.parse_date(string)
|
||||
return klass.from_datetime(dt)
|
||||
|
||||
@staticmethod
|
||||
def from_rfc2822(string):
|
||||
"""Returns MayaDT instance from rfc2822 string."""
|
||||
return parse(string)
|
||||
|
||||
# Exporters
|
||||
# ---------
|
||||
|
||||
def datetime(self, to_timezone=None, naive=False):
|
||||
"""Returns a timezone-aware datetime...
|
||||
Defaulting to UTC (as it should).
|
||||
|
||||
Keyword Arguments:
|
||||
to_timezone {string} -- timezone to convert to (default: None/UTC)
|
||||
naive {boolean} -- if True, the tzinfo is simply dropped (default: False)
|
||||
"""
|
||||
if to_timezone:
|
||||
dt = self.datetime().astimezone(pytz.timezone(to_timezone))
|
||||
else:
|
||||
dt = Datetime.utcfromtimestamp(self._epoch)
|
||||
dt.replace(tzinfo=self._tz)
|
||||
|
||||
# Strip the timezone info if requested to do so.
|
||||
if naive:
|
||||
return dt.replace(tzinfo=None)
|
||||
else:
|
||||
if dt.tzinfo is None:
|
||||
dt = dt.replace(tzinfo=self._tz)
|
||||
|
||||
return dt
|
||||
|
||||
def iso8601(self):
|
||||
"""Returns an ISO 8601 representation of the MayaDT."""
|
||||
# Get a timezone-naive datetime.
|
||||
dt = self.datetime(naive=True)
|
||||
return '{}Z'.format(dt.isoformat())
|
||||
|
||||
def rfc2822(self):
|
||||
"""Returns an RFC 2822 representation of the MayaDT."""
|
||||
return email.utils.formatdate(self.epoch, usegmt=True)
|
||||
|
||||
# Properties
|
||||
# ----------
|
||||
|
||||
@property
|
||||
def year(self):
|
||||
return self.datetime().year
|
||||
|
||||
@property
|
||||
def month(self):
|
||||
return self.datetime().month
|
||||
|
||||
@property
|
||||
def day(self):
|
||||
return self.datetime().day
|
||||
|
||||
@property
|
||||
def week(self):
|
||||
return self.datetime().isocalendar()[1]
|
||||
|
||||
@property
|
||||
def weekday(self):
|
||||
"""Return the day of the week as an integer. Monday is 1 and Sunday is 7"""
|
||||
return self.datetime().isoweekday()
|
||||
|
||||
@property
|
||||
def hour(self):
|
||||
return self.datetime().hour
|
||||
|
||||
@property
|
||||
def minute(self):
|
||||
return self.datetime().minute
|
||||
|
||||
@property
|
||||
def second(self):
|
||||
return self.datetime().second
|
||||
|
||||
@property
|
||||
def microsecond(self):
|
||||
return self.datetime().microsecond
|
||||
|
||||
@property
|
||||
def epoch(self):
|
||||
return self._epoch
|
||||
|
||||
# Human Slang Extras
|
||||
# ------------------
|
||||
|
||||
def slang_date(self):
|
||||
""""Returns human slang representation of date."""
|
||||
dt = self.datetime(naive=True, to_timezone=self.local_timezone)
|
||||
return humanize.naturaldate(dt)
|
||||
|
||||
def slang_time(self):
|
||||
""""Returns human slang representation of time."""
|
||||
dt = self.datetime(naive=True, to_timezone=self.local_timezone)
|
||||
return humanize.naturaltime(dt)
|
||||
|
||||
|
||||
|
||||
|
||||
def now():
|
||||
"""Returns a MayaDT instance for this exact moment."""
|
||||
epoch = time.time()
|
||||
return MayaDT(epoch=epoch)
|
||||
|
||||
def when(string, timezone='UTC'):
|
||||
""""Returns a MayaDT instance for the human moment specified.
|
||||
|
||||
Powered by dateparser. Useful for scraping websites.
|
||||
|
||||
Examples:
|
||||
'next week', 'now', 'tomorrow', '300 years ago', 'August 14, 2015'
|
||||
|
||||
Keyword Arguments:
|
||||
string -- string to be parsed
|
||||
timezone -- timezone referenced from (default: 'UTC')
|
||||
|
||||
"""
|
||||
dt = dateparser.parse(string, settings={'TIMEZONE': timezone, 'RETURN_AS_TIMEZONE_AWARE': True, 'TO_TIMEZONE': 'UTC'})
|
||||
|
||||
if dt is None:
|
||||
raise ValueError('invalid datetime input specified.')
|
||||
|
||||
return MayaDT.from_datetime(dt)
|
||||
|
||||
def parse(string, day_first=False):
|
||||
""""Returns a MayaDT instance for the machine-produced moment specified.
|
||||
|
||||
Powered by dateutil. Accepts most known formats. Useful for working with data.
|
||||
|
||||
Keyword Arguments:
|
||||
string -- string to be parsed
|
||||
day_first -- if true, the first value (e.g. 01/05/2016) is parsed as day (default: False)
|
||||
"""
|
||||
dt = dateutil.parser.parse(string, dayfirst=day_first)
|
||||
return MayaDT.from_datetime(dt)
|
||||
Vendored
+51
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import sys
|
||||
import codecs
|
||||
|
||||
from setuptools import setup
|
||||
|
||||
try:
|
||||
# Python 3
|
||||
from os import dirname
|
||||
except ImportError:
|
||||
# Python 2
|
||||
from os.path import dirname
|
||||
|
||||
here = os.path.abspath(dirname(__file__))
|
||||
|
||||
with codecs.open(os.path.join(here, 'README.rst'), encoding='utf-8') as f:
|
||||
long_description = '\n' + f.read()
|
||||
|
||||
|
||||
if sys.argv[-1] == "publish":
|
||||
os.system("python setup.py sdist bdist_wheel upload")
|
||||
sys.exit()
|
||||
|
||||
required = [
|
||||
'humanize',
|
||||
'pytz',
|
||||
'dateparser',
|
||||
'iso8601',
|
||||
'python-dateutil',
|
||||
'ruamel.yaml',
|
||||
'tzlocal'
|
||||
]
|
||||
|
||||
setup(
|
||||
name='maya',
|
||||
version='0.1.6',
|
||||
description='Datetimes for Humans.',
|
||||
long_description=long_description,
|
||||
author='Kenneth Reitz',
|
||||
author_email='me@kennethreitz.com',
|
||||
url='https://github.com/kennethreitz/maya',
|
||||
py_modules=['maya'],
|
||||
install_requires=required,
|
||||
license='MIT',
|
||||
classifiers=(
|
||||
|
||||
),
|
||||
)
|
||||
@@ -0,0 +1,99 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
testNoRequirements() {
|
||||
compile "no-requirements"
|
||||
assertCapturedError
|
||||
}
|
||||
|
||||
|
||||
testSetupPy() {
|
||||
compile "setup-py"
|
||||
assertCaptured "maya"
|
||||
assertCapturedSuccess
|
||||
}
|
||||
|
||||
|
||||
testStandardRequirements() {
|
||||
compile "requirements-standard"
|
||||
assertCaptured "requests"
|
||||
assertCapturedSuccess
|
||||
}
|
||||
|
||||
testPsycopg2() {
|
||||
compile "psycopg2"
|
||||
assertCaptured "psycopg2"
|
||||
assertCapturedSuccess
|
||||
}
|
||||
|
||||
testPython2() {
|
||||
compile "python2"
|
||||
assertCaptured "python-2.7.13"
|
||||
assertCapturedSuccess
|
||||
}
|
||||
|
||||
testPython3() {
|
||||
compile "python3"
|
||||
assertCaptured "python-3.6.0"
|
||||
assertCapturedSuccess
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
pushd $(dirname 0) >/dev/null
|
||||
popd >/dev/null
|
||||
|
||||
source $(pwd)/test/utils
|
||||
|
||||
mktmpdir() {
|
||||
dir=$(mktemp -t testXXXXX)
|
||||
rm -rf $dir
|
||||
mkdir $dir
|
||||
echo $dir
|
||||
}
|
||||
|
||||
detect() {
|
||||
capture $(pwd)/bin/detect $(pwd)/test/fixtures/$1
|
||||
}
|
||||
|
||||
compile_dir=""
|
||||
|
||||
default_process_types_cleanup() {
|
||||
file="/tmp/default_process_types"
|
||||
if [ -f "$file" ]; then
|
||||
rm "$file"
|
||||
fi
|
||||
}
|
||||
|
||||
compile() {
|
||||
default_process_types_cleanup
|
||||
bp_dir=$(mktmpdir)
|
||||
compile_dir=$(mktmpdir)
|
||||
cp -a $(pwd)/* ${bp_dir}
|
||||
cp -a ${bp_dir}/test/fixtures/$1/. ${compile_dir}
|
||||
capture ${bp_dir}/bin/compile ${compile_dir} ${2:-$(mktmpdir)} $3
|
||||
}
|
||||
|
||||
compileDir() {
|
||||
default_process_types_cleanup
|
||||
|
||||
local bp_dir=$(mktmpdir)
|
||||
local compile_dir=${1:-$(mktmpdir)}
|
||||
local cache_dir=${2:-$(mktmpdir)}
|
||||
local env_dir=$3
|
||||
|
||||
cp -a $(pwd)/* ${bp_dir}
|
||||
capture ${bp_dir}/bin/compile ${compile_dir} ${cache_dir} ${env_dir}
|
||||
}
|
||||
|
||||
release() {
|
||||
bp_dir=$(mktmpdir)
|
||||
cp -a $(pwd)/* ${bp_dir}
|
||||
capture ${bp_dir}/bin/release ${bp_dir}/test/fixtures/$1
|
||||
}
|
||||
|
||||
assertFile() {
|
||||
assertEquals "$1" "$(cat ${compile_dir}/$2)"
|
||||
}
|
||||
|
||||
source $(pwd)/test/shunit2
|
||||
Executable
+1048
File diff suppressed because it is too large
Load Diff
+195
@@ -0,0 +1,195 @@
|
||||
#!/bin/sh
|
||||
|
||||
# taken from
|
||||
# https://github.com/ryanbrainard/heroku-buildpack-testrunner/blob/master/lib/test_utils.sh
|
||||
|
||||
oneTimeSetUp()
|
||||
{
|
||||
TEST_SUITE_CACHE="$(mktemp -d ${SHUNIT_TMPDIR}/test_suite_cache.XXXX)"
|
||||
}
|
||||
|
||||
oneTimeTearDown()
|
||||
{
|
||||
rm -rf ${TEST_SUITE_CACHE}
|
||||
}
|
||||
|
||||
setUp()
|
||||
{
|
||||
OUTPUT_DIR="$(mktemp -d ${SHUNIT_TMPDIR}/output.XXXX)"
|
||||
STD_OUT="${OUTPUT_DIR}/stdout"
|
||||
STD_ERR="${OUTPUT_DIR}/stderr"
|
||||
BUILD_DIR="${OUTPUT_DIR}/build"
|
||||
CACHE_DIR="${OUTPUT_DIR}/cache"
|
||||
mkdir -p ${OUTPUT_DIR}
|
||||
mkdir -p ${BUILD_DIR}
|
||||
mkdir -p ${CACHE_DIR}
|
||||
}
|
||||
|
||||
tearDown()
|
||||
{
|
||||
rm -rf ${OUTPUT_DIR}
|
||||
}
|
||||
|
||||
capture()
|
||||
{
|
||||
resetCapture
|
||||
|
||||
LAST_COMMAND="$@"
|
||||
|
||||
$@ >${STD_OUT} 2>${STD_ERR}
|
||||
RETURN=$?
|
||||
rtrn=${RETURN} # deprecated
|
||||
}
|
||||
|
||||
resetCapture()
|
||||
{
|
||||
if [ -f ${STD_OUT} ]; then
|
||||
rm ${STD_OUT}
|
||||
fi
|
||||
|
||||
if [ -f ${STD_ERR} ]; then
|
||||
rm ${STD_ERR}
|
||||
fi
|
||||
|
||||
unset LAST_COMMAND
|
||||
unset RETURN
|
||||
unset rtrn # deprecated
|
||||
}
|
||||
|
||||
detect()
|
||||
{
|
||||
capture ${BUILDPACK_HOME}/bin/detect ${BUILD_DIR}
|
||||
}
|
||||
|
||||
compile()
|
||||
{
|
||||
capture ${BUILDPACK_HOME}/bin/compile ${BUILD_DIR} ${CACHE_DIR}
|
||||
}
|
||||
|
||||
release()
|
||||
{
|
||||
capture ${BUILDPACK_HOME}/bin/release ${BUILD_DIR}
|
||||
}
|
||||
|
||||
assertCapturedEquals()
|
||||
{
|
||||
assertEquals "$@" "$(cat ${STD_OUT})"
|
||||
}
|
||||
|
||||
assertCapturedNotEquals()
|
||||
{
|
||||
assertNotEquals "$@" "$(cat ${STD_OUT})"
|
||||
}
|
||||
|
||||
assertCaptured()
|
||||
{
|
||||
assertFileContains "$@" "${STD_OUT}"
|
||||
}
|
||||
|
||||
assertNotCaptured()
|
||||
{
|
||||
assertFileNotContains "$@" "${STD_OUT}"
|
||||
}
|
||||
|
||||
assertCapturedSuccess()
|
||||
{
|
||||
assertEquals "Expected captured exit code to be 0; was <${RETURN}>" "0" "${RETURN}"
|
||||
assertEquals "Expected STD_ERR to be empty; was <$(cat ${STD_ERR})>" "" "$(cat ${STD_ERR})"
|
||||
}
|
||||
|
||||
# assertCapturedError [[expectedErrorCode] expectedErrorMsg]
|
||||
assertCapturedError()
|
||||
{
|
||||
if [ $# -gt 1 ]; then
|
||||
local expectedErrorCode=${1}
|
||||
shift
|
||||
fi
|
||||
|
||||
local expectedErrorMsg=${1:-""}
|
||||
|
||||
if [ -z ${expectedErrorCode} ]; then
|
||||
assertTrue "Expected captured exit code to be greater than 0; was <${RETURN}>" "[ ${RETURN} -gt 0 ]"
|
||||
else
|
||||
assertTrue "Expected captured exit code to be <${expectedErrorCode}>; was <${RETURN}>" "[ ${RETURN} -eq ${expectedErrorCode} ]"
|
||||
fi
|
||||
|
||||
if [ "${expectedErrorMsg}" != "" ]; then
|
||||
assertFileContains "Expected STD_ERR to contain error <${expectedErrorMsg}>" "${expectedErrorMsg}" "${STD_ERR}"
|
||||
fi
|
||||
}
|
||||
|
||||
_assertContains()
|
||||
{
|
||||
if [ 5 -eq $# ]; then
|
||||
local msg=$1
|
||||
shift
|
||||
elif [ ! 4 -eq $# ]; then
|
||||
fail "Expected 4 or 5 parameters; Receieved $# parameters"
|
||||
fi
|
||||
|
||||
local needle=$1
|
||||
local haystack=$2
|
||||
local expectation=$3
|
||||
local haystack_type=$4
|
||||
|
||||
case "${haystack_type}" in
|
||||
"file") grep -q -F -e "${needle}" ${haystack} ;;
|
||||
"text") echo "${haystack}" | grep -q -F -e "${needle}" ;;
|
||||
esac
|
||||
|
||||
if [ "${expectation}" != "$?" ]; then
|
||||
case "${expectation}" in
|
||||
0) default_msg="Expected <${haystack}> to contain <${needle}>" ;;
|
||||
1) default_msg="Did not expect <${haystack}> to contain <${needle}>" ;;
|
||||
esac
|
||||
|
||||
fail "${msg:-${default_msg}}"
|
||||
fi
|
||||
}
|
||||
|
||||
debug()
|
||||
{
|
||||
cat $STD_OUT
|
||||
}
|
||||
|
||||
assertContains()
|
||||
{
|
||||
_assertContains "$@" 0 "text"
|
||||
}
|
||||
|
||||
assertNotContains()
|
||||
{
|
||||
_assertContains "$@" 1 "text"
|
||||
}
|
||||
|
||||
assertFileContains()
|
||||
{
|
||||
_assertContains "$@" 0 "file"
|
||||
}
|
||||
|
||||
assertFileNotContains()
|
||||
{
|
||||
_assertContains "$@" 1 "file"
|
||||
}
|
||||
|
||||
command_exists () {
|
||||
type "$1" > /dev/null 2>&1 ;
|
||||
}
|
||||
|
||||
assertFileMD5()
|
||||
{
|
||||
expectedHash=$1
|
||||
filename=$2
|
||||
|
||||
if command_exists "md5sum"; then
|
||||
md5_cmd="md5sum ${filename}"
|
||||
expected_md5_cmd_output="${expectedHash} ${filename}"
|
||||
elif command_exists "md5"; then
|
||||
md5_cmd="md5 ${filename}"
|
||||
expected_md5_cmd_output="MD5 (${filename}) = ${expectedHash}"
|
||||
else
|
||||
fail "no suitable MD5 hashing command found on this system"
|
||||
fi
|
||||
|
||||
assertEquals "${expected_md5_cmd_output}" "`${md5_cmd}`"
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
DEFAULT_PATH = '{0}.zip'.format(os.path.abspath(__file__))
|
||||
BPWATCH_DISTRO_PATH = os.environ.get('BPWATCH_DISTRO_PATH', DEFAULT_PATH)
|
||||
|
||||
sys.path.insert(0, BPWATCH_DISTRO_PATH)
|
||||
|
||||
import bp_cli
|
||||
bp_cli.main()
|
||||
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
+581
@@ -0,0 +1,581 @@
|
||||
"""Pythonic command-line interface parser that will make you smile.
|
||||
|
||||
* http://docopt.org
|
||||
* Repository and issue-tracker: https://github.com/docopt/docopt
|
||||
* Licensed under terms of MIT license (see LICENSE-MIT)
|
||||
* Copyright (c) 2013 Vladimir Keleshev, vladimir@keleshev.com
|
||||
|
||||
"""
|
||||
import sys
|
||||
import re
|
||||
|
||||
|
||||
__all__ = ['docopt']
|
||||
__version__ = '0.6.1'
|
||||
|
||||
|
||||
class DocoptLanguageError(Exception):
|
||||
|
||||
"""Error in construction of usage-message by developer."""
|
||||
|
||||
|
||||
class DocoptExit(SystemExit):
|
||||
|
||||
"""Exit in case user invoked program with incorrect arguments."""
|
||||
|
||||
usage = ''
|
||||
|
||||
def __init__(self, message=''):
|
||||
SystemExit.__init__(self, (message + '\n' + self.usage).strip())
|
||||
|
||||
|
||||
class Pattern(object):
|
||||
|
||||
def __eq__(self, other):
|
||||
return repr(self) == repr(other)
|
||||
|
||||
def __hash__(self):
|
||||
return hash(repr(self))
|
||||
|
||||
def fix(self):
|
||||
self.fix_identities()
|
||||
self.fix_repeating_arguments()
|
||||
return self
|
||||
|
||||
def fix_identities(self, uniq=None):
|
||||
"""Make pattern-tree tips point to same object if they are equal."""
|
||||
if not hasattr(self, 'children'):
|
||||
return self
|
||||
uniq = list(set(self.flat())) if uniq is None else uniq
|
||||
for i, child in enumerate(self.children):
|
||||
if not hasattr(child, 'children'):
|
||||
assert child in uniq
|
||||
self.children[i] = uniq[uniq.index(child)]
|
||||
else:
|
||||
child.fix_identities(uniq)
|
||||
|
||||
def fix_repeating_arguments(self):
|
||||
"""Fix elements that should accumulate/increment values."""
|
||||
either = [list(child.children) for child in transform(self).children]
|
||||
for case in either:
|
||||
for e in [child for child in case if case.count(child) > 1]:
|
||||
if type(e) is Argument or type(e) is Option and e.argcount:
|
||||
if e.value is None:
|
||||
e.value = []
|
||||
elif type(e.value) is not list:
|
||||
e.value = e.value.split()
|
||||
if type(e) is Command or type(e) is Option and e.argcount == 0:
|
||||
e.value = 0
|
||||
return self
|
||||
|
||||
|
||||
def transform(pattern):
|
||||
"""Expand pattern into an (almost) equivalent one, but with single Either.
|
||||
|
||||
Example: ((-a | -b) (-c | -d)) => (-a -c | -a -d | -b -c | -b -d)
|
||||
Quirks: [-a] => (-a), (-a...) => (-a -a)
|
||||
|
||||
"""
|
||||
result = []
|
||||
groups = [[pattern]]
|
||||
while groups:
|
||||
children = groups.pop(0)
|
||||
parents = [Required, Optional, OptionsShortcut, Either, OneOrMore]
|
||||
if any(t in map(type, children) for t in parents):
|
||||
child = [c for c in children if type(c) in parents][0]
|
||||
children.remove(child)
|
||||
if type(child) is Either:
|
||||
for c in child.children:
|
||||
groups.append([c] + children)
|
||||
elif type(child) is OneOrMore:
|
||||
groups.append(child.children * 2 + children)
|
||||
else:
|
||||
groups.append(child.children + children)
|
||||
else:
|
||||
result.append(children)
|
||||
return Either(*[Required(*e) for e in result])
|
||||
|
||||
|
||||
class LeafPattern(Pattern):
|
||||
|
||||
"""Leaf/terminal node of a pattern tree."""
|
||||
|
||||
def __init__(self, name, value=None):
|
||||
self.name, self.value = name, value
|
||||
|
||||
def __repr__(self):
|
||||
return '%s(%r, %r)' % (self.__class__.__name__, self.name, self.value)
|
||||
|
||||
def flat(self, *types):
|
||||
return [self] if not types or type(self) in types else []
|
||||
|
||||
def match(self, left, collected=None):
|
||||
collected = [] if collected is None else collected
|
||||
pos, match = self.single_match(left)
|
||||
if match is None:
|
||||
return False, left, collected
|
||||
left_ = left[:pos] + left[pos + 1:]
|
||||
same_name = [a for a in collected if a.name == self.name]
|
||||
if type(self.value) in (int, list):
|
||||
if type(self.value) is int:
|
||||
increment = 1
|
||||
else:
|
||||
increment = ([match.value] if type(match.value) is str
|
||||
else match.value)
|
||||
if not same_name:
|
||||
match.value = increment
|
||||
return True, left_, collected + [match]
|
||||
same_name[0].value += increment
|
||||
return True, left_, collected
|
||||
return True, left_, collected + [match]
|
||||
|
||||
|
||||
class BranchPattern(Pattern):
|
||||
|
||||
"""Branch/inner node of a pattern tree."""
|
||||
|
||||
def __init__(self, *children):
|
||||
self.children = list(children)
|
||||
|
||||
def __repr__(self):
|
||||
return '%s(%s)' % (self.__class__.__name__,
|
||||
', '.join(repr(a) for a in self.children))
|
||||
|
||||
def flat(self, *types):
|
||||
if type(self) in types:
|
||||
return [self]
|
||||
return sum([child.flat(*types) for child in self.children], [])
|
||||
|
||||
|
||||
class Argument(LeafPattern):
|
||||
|
||||
def single_match(self, left):
|
||||
for n, pattern in enumerate(left):
|
||||
if type(pattern) is Argument:
|
||||
return n, Argument(self.name, pattern.value)
|
||||
return None, None
|
||||
|
||||
@classmethod
|
||||
def parse(class_, source):
|
||||
name = re.findall('(<\S*?>)', source)[0]
|
||||
value = re.findall('\[default: (.*)\]', source, flags=re.I)
|
||||
return class_(name, value[0] if value else None)
|
||||
|
||||
|
||||
class Command(Argument):
|
||||
|
||||
def __init__(self, name, value=False):
|
||||
self.name, self.value = name, value
|
||||
|
||||
def single_match(self, left):
|
||||
for n, pattern in enumerate(left):
|
||||
if type(pattern) is Argument:
|
||||
if pattern.value == self.name:
|
||||
return n, Command(self.name, True)
|
||||
else:
|
||||
break
|
||||
return None, None
|
||||
|
||||
|
||||
class Option(LeafPattern):
|
||||
|
||||
def __init__(self, short=None, long=None, argcount=0, value=False):
|
||||
assert argcount in (0, 1)
|
||||
self.short, self.long, self.argcount = short, long, argcount
|
||||
self.value = None if value is False and argcount else value
|
||||
|
||||
@classmethod
|
||||
def parse(class_, option_description):
|
||||
short, long, argcount, value = None, None, 0, False
|
||||
options, _, description = option_description.strip().partition(' ')
|
||||
options = options.replace(',', ' ').replace('=', ' ')
|
||||
for s in options.split():
|
||||
if s.startswith('--'):
|
||||
long = s
|
||||
elif s.startswith('-'):
|
||||
short = s
|
||||
else:
|
||||
argcount = 1
|
||||
if argcount:
|
||||
matched = re.findall('\[default: (.*)\]', description, flags=re.I)
|
||||
value = matched[0] if matched else None
|
||||
return class_(short, long, argcount, value)
|
||||
|
||||
def single_match(self, left):
|
||||
for n, pattern in enumerate(left):
|
||||
if self.name == pattern.name:
|
||||
return n, pattern
|
||||
return None, None
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self.long or self.short
|
||||
|
||||
def __repr__(self):
|
||||
return 'Option(%r, %r, %r, %r)' % (self.short, self.long,
|
||||
self.argcount, self.value)
|
||||
|
||||
|
||||
class Required(BranchPattern):
|
||||
|
||||
def match(self, left, collected=None):
|
||||
collected = [] if collected is None else collected
|
||||
l = left
|
||||
c = collected
|
||||
for pattern in self.children:
|
||||
matched, l, c = pattern.match(l, c)
|
||||
if not matched:
|
||||
return False, left, collected
|
||||
return True, l, c
|
||||
|
||||
|
||||
class Optional(BranchPattern):
|
||||
|
||||
def match(self, left, collected=None):
|
||||
collected = [] if collected is None else collected
|
||||
for pattern in self.children:
|
||||
m, left, collected = pattern.match(left, collected)
|
||||
return True, left, collected
|
||||
|
||||
|
||||
class OptionsShortcut(Optional):
|
||||
|
||||
"""Marker/placeholder for [options] shortcut."""
|
||||
|
||||
|
||||
class OneOrMore(BranchPattern):
|
||||
|
||||
def match(self, left, collected=None):
|
||||
assert len(self.children) == 1
|
||||
collected = [] if collected is None else collected
|
||||
l = left
|
||||
c = collected
|
||||
l_ = None
|
||||
matched = True
|
||||
times = 0
|
||||
while matched:
|
||||
# could it be that something didn't match but changed l or c?
|
||||
matched, l, c = self.children[0].match(l, c)
|
||||
times += 1 if matched else 0
|
||||
if l_ == l:
|
||||
break
|
||||
l_ = l
|
||||
if times >= 1:
|
||||
return True, l, c
|
||||
return False, left, collected
|
||||
|
||||
|
||||
class Either(BranchPattern):
|
||||
|
||||
def match(self, left, collected=None):
|
||||
collected = [] if collected is None else collected
|
||||
outcomes = []
|
||||
for pattern in self.children:
|
||||
matched, _, _ = outcome = pattern.match(left, collected)
|
||||
if matched:
|
||||
outcomes.append(outcome)
|
||||
if outcomes:
|
||||
return min(outcomes, key=lambda outcome: len(outcome[1]))
|
||||
return False, left, collected
|
||||
|
||||
|
||||
class Tokens(list):
|
||||
|
||||
def __init__(self, source, error=DocoptExit):
|
||||
self += source.split() if hasattr(source, 'split') else source
|
||||
self.error = error
|
||||
|
||||
@staticmethod
|
||||
def from_pattern(source):
|
||||
source = re.sub(r'([\[\]\(\)\|]|\.\.\.)', r' \1 ', source)
|
||||
source = [s for s in re.split('\s+|(\S*<.*?>)', source) if s]
|
||||
return Tokens(source, error=DocoptLanguageError)
|
||||
|
||||
def move(self):
|
||||
return self.pop(0) if len(self) else None
|
||||
|
||||
def current(self):
|
||||
return self[0] if len(self) else None
|
||||
|
||||
|
||||
def parse_long(tokens, options):
|
||||
"""long ::= '--' chars [ ( ' ' | '=' ) chars ] ;"""
|
||||
long, eq, value = tokens.move().partition('=')
|
||||
assert long.startswith('--')
|
||||
value = None if eq == value == '' else value
|
||||
similar = [o for o in options if o.long == long]
|
||||
if tokens.error is DocoptExit and similar == []: # if no exact match
|
||||
similar = [o for o in options if o.long and o.long.startswith(long)]
|
||||
if len(similar) > 1: # might be simply specified ambiguously 2+ times?
|
||||
raise tokens.error('%s is not a unique prefix: %s?' %
|
||||
(long, ', '.join(o.long for o in similar)))
|
||||
elif len(similar) < 1:
|
||||
argcount = 1 if eq == '=' else 0
|
||||
o = Option(None, long, argcount)
|
||||
options.append(o)
|
||||
if tokens.error is DocoptExit:
|
||||
o = Option(None, long, argcount, value if argcount else True)
|
||||
else:
|
||||
o = Option(similar[0].short, similar[0].long,
|
||||
similar[0].argcount, similar[0].value)
|
||||
if o.argcount == 0:
|
||||
if value is not None:
|
||||
raise tokens.error('%s must not have an argument' % o.long)
|
||||
else:
|
||||
if value is None:
|
||||
if tokens.current() in [None, '--']:
|
||||
raise tokens.error('%s requires argument' % o.long)
|
||||
value = tokens.move()
|
||||
if tokens.error is DocoptExit:
|
||||
o.value = value if value is not None else True
|
||||
return [o]
|
||||
|
||||
|
||||
def parse_shorts(tokens, options):
|
||||
"""shorts ::= '-' ( chars )* [ [ ' ' ] chars ] ;"""
|
||||
token = tokens.move()
|
||||
assert token.startswith('-') and not token.startswith('--')
|
||||
left = token.lstrip('-')
|
||||
parsed = []
|
||||
while left != '':
|
||||
short, left = '-' + left[0], left[1:]
|
||||
similar = [o for o in options if o.short == short]
|
||||
if len(similar) > 1:
|
||||
raise tokens.error('%s is specified ambiguously %d times' %
|
||||
(short, len(similar)))
|
||||
elif len(similar) < 1:
|
||||
o = Option(short, None, 0)
|
||||
options.append(o)
|
||||
if tokens.error is DocoptExit:
|
||||
o = Option(short, None, 0, True)
|
||||
else: # why copying is necessary here?
|
||||
o = Option(short, similar[0].long,
|
||||
similar[0].argcount, similar[0].value)
|
||||
value = None
|
||||
if o.argcount != 0:
|
||||
if left == '':
|
||||
if tokens.current() in [None, '--']:
|
||||
raise tokens.error('%s requires argument' % short)
|
||||
value = tokens.move()
|
||||
else:
|
||||
value = left
|
||||
left = ''
|
||||
if tokens.error is DocoptExit:
|
||||
o.value = value if value is not None else True
|
||||
parsed.append(o)
|
||||
return parsed
|
||||
|
||||
|
||||
def parse_pattern(source, options):
|
||||
tokens = Tokens.from_pattern(source)
|
||||
result = parse_expr(tokens, options)
|
||||
if tokens.current() is not None:
|
||||
raise tokens.error('unexpected ending: %r' % ' '.join(tokens))
|
||||
return Required(*result)
|
||||
|
||||
|
||||
def parse_expr(tokens, options):
|
||||
"""expr ::= seq ( '|' seq )* ;"""
|
||||
seq = parse_seq(tokens, options)
|
||||
if tokens.current() != '|':
|
||||
return seq
|
||||
result = [Required(*seq)] if len(seq) > 1 else seq
|
||||
while tokens.current() == '|':
|
||||
tokens.move()
|
||||
seq = parse_seq(tokens, options)
|
||||
result += [Required(*seq)] if len(seq) > 1 else seq
|
||||
return [Either(*result)] if len(result) > 1 else result
|
||||
|
||||
|
||||
def parse_seq(tokens, options):
|
||||
"""seq ::= ( atom [ '...' ] )* ;"""
|
||||
result = []
|
||||
while tokens.current() not in [None, ']', ')', '|']:
|
||||
atom = parse_atom(tokens, options)
|
||||
if tokens.current() == '...':
|
||||
atom = [OneOrMore(*atom)]
|
||||
tokens.move()
|
||||
result += atom
|
||||
return result
|
||||
|
||||
|
||||
def parse_atom(tokens, options):
|
||||
"""atom ::= '(' expr ')' | '[' expr ']' | 'options'
|
||||
| long | shorts | argument | command ;
|
||||
"""
|
||||
token = tokens.current()
|
||||
result = []
|
||||
if token in '([':
|
||||
tokens.move()
|
||||
matching, pattern = {'(': [')', Required], '[': [']', Optional]}[token]
|
||||
result = pattern(*parse_expr(tokens, options))
|
||||
if tokens.move() != matching:
|
||||
raise tokens.error("unmatched '%s'" % token)
|
||||
return [result]
|
||||
elif token == 'options':
|
||||
tokens.move()
|
||||
return [OptionsShortcut()]
|
||||
elif token.startswith('--') and token != '--':
|
||||
return parse_long(tokens, options)
|
||||
elif token.startswith('-') and token not in ('-', '--'):
|
||||
return parse_shorts(tokens, options)
|
||||
elif token.startswith('<') and token.endswith('>') or token.isupper():
|
||||
return [Argument(tokens.move())]
|
||||
else:
|
||||
return [Command(tokens.move())]
|
||||
|
||||
|
||||
def parse_argv(tokens, options, options_first=False):
|
||||
"""Parse command-line argument vector.
|
||||
|
||||
If options_first:
|
||||
argv ::= [ long | shorts ]* [ argument ]* [ '--' [ argument ]* ] ;
|
||||
else:
|
||||
argv ::= [ long | shorts | argument ]* [ '--' [ argument ]* ] ;
|
||||
|
||||
"""
|
||||
parsed = []
|
||||
while tokens.current() is not None:
|
||||
if tokens.current() == '--':
|
||||
return parsed + [Argument(None, v) for v in tokens]
|
||||
elif tokens.current().startswith('--'):
|
||||
parsed += parse_long(tokens, options)
|
||||
elif tokens.current().startswith('-') and tokens.current() != '-':
|
||||
parsed += parse_shorts(tokens, options)
|
||||
elif options_first:
|
||||
return parsed + [Argument(None, v) for v in tokens]
|
||||
else:
|
||||
parsed.append(Argument(None, tokens.move()))
|
||||
return parsed
|
||||
|
||||
|
||||
def parse_defaults(doc):
|
||||
defaults = []
|
||||
for s in parse_section('options:', doc):
|
||||
# FIXME corner case "bla: options: --foo"
|
||||
_, _, s = s.partition(':') # get rid of "options:"
|
||||
split = re.split('\n[ \t]*(-\S+?)', '\n' + s)[1:]
|
||||
split = [s1 + s2 for s1, s2 in zip(split[::2], split[1::2])]
|
||||
options = [Option.parse(s) for s in split if s.startswith('-')]
|
||||
defaults += options
|
||||
return defaults
|
||||
|
||||
|
||||
def parse_section(name, source):
|
||||
pattern = re.compile('^([^\n]*' + name + '[^\n]*\n?(?:[ \t].*?(?:\n|$))*)',
|
||||
re.IGNORECASE | re.MULTILINE)
|
||||
return [s.strip() for s in pattern.findall(source)]
|
||||
|
||||
|
||||
def formal_usage(section):
|
||||
_, _, section = section.partition(':') # drop "usage:"
|
||||
pu = section.split()
|
||||
return '( ' + ' '.join(') | (' if s == pu[0] else s for s in pu[1:]) + ' )'
|
||||
|
||||
|
||||
def extras(help, version, options, doc):
|
||||
if help and any((o.name in ('-h', '--help')) and o.value for o in options):
|
||||
print(doc.strip("\n"))
|
||||
sys.exit()
|
||||
if version and any(o.name == '--version' and o.value for o in options):
|
||||
print(version)
|
||||
sys.exit()
|
||||
|
||||
|
||||
class Dict(dict):
|
||||
def __repr__(self):
|
||||
return '{%s}' % ',\n '.join('%r: %r' % i for i in sorted(self.items()))
|
||||
|
||||
|
||||
def docopt(doc, argv=None, help=True, version=None, options_first=False):
|
||||
"""Parse `argv` based on command-line interface described in `doc`.
|
||||
|
||||
`docopt` creates your command-line interface based on its
|
||||
description that you pass as `doc`. Such description can contain
|
||||
--options, <positional-argument>, commands, which could be
|
||||
[optional], (required), (mutually | exclusive) or repeated...
|
||||
|
||||
Parameters
|
||||
----------
|
||||
doc : str
|
||||
Description of your command-line interface.
|
||||
argv : list of str, optional
|
||||
Argument vector to be parsed. sys.argv[1:] is used if not
|
||||
provided.
|
||||
help : bool (default: True)
|
||||
Set to False to disable automatic help on -h or --help
|
||||
options.
|
||||
version : any object
|
||||
If passed, the object will be printed if --version is in
|
||||
`argv`.
|
||||
options_first : bool (default: False)
|
||||
Set to True to require options precede positional arguments,
|
||||
i.e. to forbid options and positional arguments intermix.
|
||||
|
||||
Returns
|
||||
-------
|
||||
args : dict
|
||||
A dictionary, where keys are names of command-line elements
|
||||
such as e.g. "--verbose" and "<path>", and values are the
|
||||
parsed values of those elements.
|
||||
|
||||
Example
|
||||
-------
|
||||
>>> from docopt import docopt
|
||||
>>> doc = '''
|
||||
... Usage:
|
||||
... my_program tcp <host> <port> [--timeout=<seconds>]
|
||||
... my_program serial <port> [--baud=<n>] [--timeout=<seconds>]
|
||||
... my_program (-h | --help | --version)
|
||||
...
|
||||
... Options:
|
||||
... -h, --help Show this screen and exit.
|
||||
... --baud=<n> Baudrate [default: 9600]
|
||||
... '''
|
||||
>>> argv = ['tcp', '127.0.0.1', '80', '--timeout', '30']
|
||||
>>> docopt(doc, argv)
|
||||
{'--baud': '9600',
|
||||
'--help': False,
|
||||
'--timeout': '30',
|
||||
'--version': False,
|
||||
'<host>': '127.0.0.1',
|
||||
'<port>': '80',
|
||||
'serial': False,
|
||||
'tcp': True}
|
||||
|
||||
See also
|
||||
--------
|
||||
* For video introduction see http://docopt.org
|
||||
* Full documentation is available in README.rst as well as online
|
||||
at https://github.com/docopt/docopt#readme
|
||||
|
||||
"""
|
||||
argv = sys.argv[1:] if argv is None else argv
|
||||
|
||||
usage_sections = parse_section('usage:', doc)
|
||||
if len(usage_sections) == 0:
|
||||
raise DocoptLanguageError('"usage:" (case-insensitive) not found.')
|
||||
if len(usage_sections) > 1:
|
||||
raise DocoptLanguageError('More than one "usage:" (case-insensitive).')
|
||||
DocoptExit.usage = usage_sections[0]
|
||||
|
||||
options = parse_defaults(doc)
|
||||
pattern = parse_pattern(formal_usage(DocoptExit.usage), options)
|
||||
# [default] syntax for argument is disabled
|
||||
#for a in pattern.flat(Argument):
|
||||
# same_name = [d for d in arguments if d.name == a.name]
|
||||
# if same_name:
|
||||
# a.value = same_name[0].value
|
||||
argv = parse_argv(Tokens(argv), list(options), options_first)
|
||||
pattern_options = set(pattern.flat(Option))
|
||||
for options_shortcut in pattern.flat(OptionsShortcut):
|
||||
doc_options = parse_defaults(doc)
|
||||
options_shortcut.children = list(set(doc_options) - pattern_options)
|
||||
#if any_options:
|
||||
# options_shortcut.children += [Option(o.short, o.long, o.argcount)
|
||||
# for o in argv if type(o) is Option]
|
||||
extras(help, version, argv, doc)
|
||||
matched, left, collected = pattern.fix().match(argv)
|
||||
if matched and left == []: # better error message if left?
|
||||
return Dict((a.name, a.value) for a in (pattern.flat() + collected))
|
||||
raise DocoptExit()
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""Usage:
|
||||
pip-diff (--fresh | --stale) <reqfile1> <reqfile2> [--exclude <package>...]
|
||||
pip-diff (-h | --help)
|
||||
|
||||
Options:
|
||||
-h --help Show this screen.
|
||||
--fresh List newly added packages.
|
||||
--stale List removed packages.
|
||||
"""
|
||||
import os
|
||||
from docopt import docopt
|
||||
from pip.req import parse_requirements
|
||||
from pip.index import PackageFinder
|
||||
from pip._vendor.requests import session
|
||||
|
||||
requests = session()
|
||||
|
||||
|
||||
class Requirements(object):
|
||||
def __init__(self, reqfile=None):
|
||||
super(Requirements, self).__init__()
|
||||
self.path = reqfile
|
||||
self.requirements = []
|
||||
|
||||
if reqfile:
|
||||
self.load(reqfile)
|
||||
|
||||
def __repr__(self):
|
||||
return '<Requirements \'{}\'>'.format(self.path)
|
||||
|
||||
def load(self, reqfile):
|
||||
if not os.path.exists(reqfile):
|
||||
raise ValueError('The given requirements file does not exist.')
|
||||
|
||||
finder = PackageFinder([], [], session=requests)
|
||||
for requirement in parse_requirements(reqfile, finder=finder, session=requests):
|
||||
if requirement.req:
|
||||
if not getattr(requirement.req, 'name', None):
|
||||
# Prior to pip 8.1.2 the attribute `name` did not exist.
|
||||
requirement.req.name = requirement.req.project_name
|
||||
self.requirements.append(requirement.req)
|
||||
|
||||
|
||||
def diff(self, requirements, ignore_versions=False, excludes=None):
|
||||
r1 = self
|
||||
r2 = requirements
|
||||
results = {'fresh': [], 'stale': []}
|
||||
|
||||
# Generate fresh packages.
|
||||
other_reqs = (
|
||||
[r.name for r in r1.requirements]
|
||||
if ignore_versions else r1.requirements
|
||||
)
|
||||
|
||||
for req in r2.requirements:
|
||||
r = req.name if ignore_versions else req
|
||||
|
||||
if r not in other_reqs and r not in excludes:
|
||||
results['fresh'].append(req)
|
||||
|
||||
# Generate stale packages.
|
||||
other_reqs = (
|
||||
[r.name for r in r2.requirements]
|
||||
if ignore_versions else r2.requirements
|
||||
)
|
||||
|
||||
for req in r1.requirements:
|
||||
r = req.name if ignore_versions else req
|
||||
|
||||
if r not in other_reqs and r not in excludes:
|
||||
results['stale'].append(req)
|
||||
|
||||
return results
|
||||
|
||||
|
||||
def diff(r1, r2, include_fresh=False, include_stale=False, excludes=None):
|
||||
include_versions = True if include_stale else False
|
||||
excludes = excludes if len(excludes) else []
|
||||
|
||||
try:
|
||||
r1 = Requirements(r1)
|
||||
r2 = Requirements(r2)
|
||||
except ValueError:
|
||||
print('There was a problem loading the given requirements files.')
|
||||
exit(os.EX_NOINPUT)
|
||||
|
||||
results = r1.diff(r2, ignore_versions=True, excludes=excludes)
|
||||
|
||||
if include_fresh:
|
||||
for line in results['fresh']:
|
||||
print(line.name if include_versions else line)
|
||||
|
||||
if include_stale:
|
||||
for line in results['stale']:
|
||||
print(line.name if include_versions else line)
|
||||
|
||||
|
||||
def main():
|
||||
args = docopt(__doc__, version='pip-diff')
|
||||
|
||||
kwargs = {
|
||||
'r1': args['<reqfile1>'],
|
||||
'r2': args['<reqfile2>'],
|
||||
'include_fresh': args['--fresh'],
|
||||
'include_stale': args['--stale'],
|
||||
'excludes': args['<package>']
|
||||
}
|
||||
|
||||
diff(**kwargs)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""Usage:
|
||||
pip-grep [-s] <reqfile> <package>...
|
||||
|
||||
Options:
|
||||
-h --help Show this screen.
|
||||
"""
|
||||
import os
|
||||
from docopt import docopt
|
||||
from pip.req import parse_requirements
|
||||
from pip.index import PackageFinder
|
||||
from pip._vendor.requests import session
|
||||
|
||||
requests = session()
|
||||
|
||||
|
||||
class Requirements(object):
|
||||
def __init__(self, reqfile=None):
|
||||
super(Requirements, self).__init__()
|
||||
self.path = reqfile
|
||||
self.requirements = []
|
||||
|
||||
if reqfile:
|
||||
self.load(reqfile)
|
||||
|
||||
def __repr__(self):
|
||||
return '<Requirements \'{}\'>'.format(self.path)
|
||||
|
||||
def load(self, reqfile):
|
||||
if not os.path.exists(reqfile):
|
||||
raise ValueError('The given requirements file does not exist.')
|
||||
|
||||
finder = PackageFinder([], [], session=requests)
|
||||
for requirement in parse_requirements(reqfile, finder=finder, session=requests):
|
||||
if requirement.req:
|
||||
if not getattr(requirement.req, 'name', None):
|
||||
# Prior to pip 8.1.2 the attribute `name` did not exist.
|
||||
requirement.req.name = requirement.req.project_name
|
||||
self.requirements.append(requirement.req)
|
||||
|
||||
|
||||
def grep(reqfile, packages, silent=False):
|
||||
try:
|
||||
r = Requirements(reqfile)
|
||||
except ValueError:
|
||||
if not silent:
|
||||
print('There was a problem loading the given requirement file.')
|
||||
exit(os.EX_NOINPUT)
|
||||
|
||||
for req in r.requirements:
|
||||
if req.name in packages:
|
||||
if not silent:
|
||||
print('Package {} found!'.format(req.name))
|
||||
exit(0)
|
||||
|
||||
if not silent:
|
||||
print('Not found.')
|
||||
|
||||
exit(1)
|
||||
|
||||
|
||||
def main():
|
||||
args = docopt(__doc__, version='pip-grep')
|
||||
|
||||
kwargs = {'reqfile': args['<reqfile>'], 'packages': args['<package>'], 'silent': args['-s']}
|
||||
|
||||
grep(**kwargs)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
if [[ "${WEB_CONCURRENCY:-}" == 0* ]]; then
|
||||
# another buildpack set a default value, with leading zero
|
||||
unset WEB_CONCURRENCY
|
||||
fi
|
||||
|
||||
case $(ulimit -u) in
|
||||
|
||||
# Automatic configuration for Gunicorn's Workers setting.
|
||||
# Leading zero padding so a subsequent buildpack can figure out that we set a value, and not the user
|
||||
|
||||
# Standard-1X (+Free, +Hobby) Dyno
|
||||
256)
|
||||
export DYNO_RAM=512
|
||||
export WEB_CONCURRENCY=${WEB_CONCURRENCY:-02}
|
||||
;;
|
||||
|
||||
# Standard-2X Dyno
|
||||
512)
|
||||
export DYNO_RAM=1024
|
||||
export WEB_CONCURRENCY=${WEB_CONCURRENCY:-04}
|
||||
;;
|
||||
|
||||
# Performance-M Dyno
|
||||
16384)
|
||||
export DYNO_RAM=2560
|
||||
export WEB_CONCURRENCY=${WEB_CONCURRENCY:-08}
|
||||
;;
|
||||
|
||||
# Performance-L Dyno
|
||||
32768)
|
||||
export DYNO_RAM=6656
|
||||
export WEB_CONCURRENCY=${WEB_CONCURRENCY:-011}
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
# Automatic configuration for Gunicorn's ForwardedAllowIPS setting.
|
||||
export FORWARDED_ALLOW_IPS='*'
|
||||
Vendored
BIN
Binary file not shown.
+1048
File diff suppressed because it is too large
Load Diff
Vendored
+204
@@ -0,0 +1,204 @@
|
||||
#!/bin/sh
|
||||
|
||||
# taken from
|
||||
# https://github.com/ryanbrainard/heroku-buildpack-testrunner/blob/master/lib/test_utils.sh
|
||||
|
||||
oneTimeSetUp()
|
||||
{
|
||||
TEST_SUITE_CACHE="$(mktemp -d ${SHUNIT_TMPDIR}/test_suite_cache.XXXX)"
|
||||
}
|
||||
|
||||
oneTimeTearDown()
|
||||
{
|
||||
rm -rf ${TEST_SUITE_CACHE}
|
||||
}
|
||||
|
||||
setUp()
|
||||
{
|
||||
OUTPUT_DIR="$(mktemp -d ${SHUNIT_TMPDIR}/output.XXXX)"
|
||||
STD_OUT="${OUTPUT_DIR}/stdout"
|
||||
STD_ERR="${OUTPUT_DIR}/stderr"
|
||||
BUILD_DIR="${OUTPUT_DIR}/build"
|
||||
CACHE_DIR="${OUTPUT_DIR}/cache"
|
||||
mkdir -p ${OUTPUT_DIR}
|
||||
mkdir -p ${BUILD_DIR}
|
||||
mkdir -p ${CACHE_DIR}
|
||||
}
|
||||
|
||||
tearDown()
|
||||
{
|
||||
rm -rf ${OUTPUT_DIR}
|
||||
}
|
||||
|
||||
capture()
|
||||
{
|
||||
resetCapture
|
||||
|
||||
LAST_COMMAND="$@"
|
||||
|
||||
$@ >${STD_OUT} 2>${STD_ERR}
|
||||
RETURN=$?
|
||||
rtrn=${RETURN} # deprecated
|
||||
}
|
||||
|
||||
resetCapture()
|
||||
{
|
||||
if [ -f ${STD_OUT} ]; then
|
||||
rm ${STD_OUT}
|
||||
fi
|
||||
|
||||
if [ -f ${STD_ERR} ]; then
|
||||
rm ${STD_ERR}
|
||||
fi
|
||||
|
||||
unset LAST_COMMAND
|
||||
unset RETURN
|
||||
unset rtrn # deprecated
|
||||
}
|
||||
|
||||
detect()
|
||||
{
|
||||
capture ${BUILDPACK_HOME}/bin/detect ${BUILD_DIR}
|
||||
}
|
||||
|
||||
compile()
|
||||
{
|
||||
capture ${BUILDPACK_HOME}/bin/compile ${BUILD_DIR} ${CACHE_DIR}
|
||||
}
|
||||
|
||||
release()
|
||||
{
|
||||
capture ${BUILDPACK_HOME}/bin/release ${BUILD_DIR}
|
||||
}
|
||||
|
||||
assertCapturedEquals()
|
||||
{
|
||||
assertEquals "$@" "$(cat ${STD_OUT})"
|
||||
}
|
||||
|
||||
assertCapturedNotEquals()
|
||||
{
|
||||
assertNotEquals "$@" "$(cat ${STD_OUT})"
|
||||
}
|
||||
|
||||
assertCaptured()
|
||||
{
|
||||
assertFileContains "$@" "${STD_OUT}"
|
||||
}
|
||||
|
||||
assertNotCaptured()
|
||||
{
|
||||
assertFileNotContains "$@" "${STD_OUT}"
|
||||
}
|
||||
|
||||
assertCapturedSuccess()
|
||||
{
|
||||
assertEquals "Expected captured exit code to be 0; was <${RETURN}>" "0" "${RETURN}"
|
||||
assertEquals "Expected STD_ERR to be empty; was <$(cat ${STD_ERR})>" "" "$(cat ${STD_ERR})"
|
||||
}
|
||||
|
||||
# assertCapturedError [[expectedErrorCode] expectedErrorMsg]
|
||||
assertCapturedError()
|
||||
{
|
||||
if [ $# -gt 1 ]; then
|
||||
expectedErrorCode=${1}
|
||||
shift
|
||||
fi
|
||||
|
||||
expectedErrorMsg=${1:-""}
|
||||
|
||||
if [ -z ${expectedErrorCode} ]; then
|
||||
assertTrue "Expected captured exit code to be greater than 0; was <${RETURN}>" "[ ${RETURN} -gt 0 ]"
|
||||
else
|
||||
assertTrue "Expected captured exit code to be <${expectedErrorCode}>; was <${RETURN}>" "[ ${RETURN} -eq ${expectedErrorCode} ]"
|
||||
fi
|
||||
|
||||
assertFileContains "Expected STD_OUT to contain error <${expectedErrorMsg}>" "${expectedErrorMsg}" "${STD_OUT}"
|
||||
assertEquals "STD_ERR should always be empty" "" "$(cat ${STD_ERR})"
|
||||
}
|
||||
|
||||
assertAppDetected()
|
||||
{
|
||||
expectedAppType=${1?"Must provide app type"}
|
||||
|
||||
assertCapturedSuccess
|
||||
assertEquals "${expectedAppType}" "$(cat ${STD_OUT})"
|
||||
}
|
||||
|
||||
assertNoAppDetected()
|
||||
{
|
||||
assertEquals "1" "${RETURN}"
|
||||
assertEquals "no" "$(cat ${STD_OUT})"
|
||||
assertEquals "" "$(cat ${STD_ERR})"
|
||||
}
|
||||
|
||||
_assertContains()
|
||||
{
|
||||
if [ 5 -eq $# ]; then
|
||||
msg=$1
|
||||
shift
|
||||
elif [ ! 4 -eq $# ]; then
|
||||
fail "Expected 4 or 5 parameters; Receieved $# parameters"
|
||||
fi
|
||||
|
||||
needle=$1
|
||||
haystack=$2
|
||||
expectation=$3
|
||||
haystack_type=$4
|
||||
|
||||
case "${haystack_type}" in
|
||||
"file") grep -q -F -e "${needle}" ${haystack} ;;
|
||||
"text") echo "${haystack}" | grep -q -F -e "${needle}" ;;
|
||||
esac
|
||||
|
||||
if [ "${expectation}" != "$?" ]; then
|
||||
case "${expectation}" in
|
||||
0) default_msg="Expected <${haystack}> to contain <${needle}>" ;;
|
||||
1) default_msg="Did not expect <${haystack}> to contain <${needle}>" ;;
|
||||
esac
|
||||
|
||||
fail "${msg:-${default_msg}}"
|
||||
fi
|
||||
}
|
||||
|
||||
assertContains()
|
||||
{
|
||||
_assertContains "$@" 0 "text"
|
||||
}
|
||||
|
||||
assertNotContains()
|
||||
{
|
||||
_assertContains "$@" 1 "text"
|
||||
}
|
||||
|
||||
assertFileContains()
|
||||
{
|
||||
_assertContains "$@" 0 "file"
|
||||
}
|
||||
|
||||
assertFileNotContains()
|
||||
{
|
||||
_assertContains "$@" 1 "file"
|
||||
}
|
||||
|
||||
command_exists () {
|
||||
type "$1" > /dev/null 2>&1 ;
|
||||
}
|
||||
|
||||
assertFileMD5()
|
||||
{
|
||||
expectedHash=$1
|
||||
filename=$2
|
||||
|
||||
if command_exists "md5sum"; then
|
||||
md5_cmd="md5sum ${filename}"
|
||||
expected_md5_cmd_output="${expectedHash} ${filename}"
|
||||
elif command_exists "md5"; then
|
||||
md5_cmd="md5 ${filename}"
|
||||
expected_md5_cmd_output="MD5 (${filename}) = ${expectedHash}"
|
||||
else
|
||||
fail "no suitable MD5 hashing command found on this system"
|
||||
fi
|
||||
|
||||
assertEquals "${expected_md5_cmd_output}" "`${md5_cmd}`"
|
||||
}
|
||||
Reference in New Issue
Block a user