nficano commited on
Commit
e5fc29e
·
1 Parent(s): c052b5c

use pipenv, added contrib

Browse files
.envrc ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # TODO: This function is only necessary until
2
+ # https://github.com/direnv/direnv/pull/314 gets accepted
3
+ # -------------------- 8< ---------------------------------
4
+ layout_pipenv() {
5
+ if [[ ! -f Pipfile ]]; then
6
+ echo 'No Pipfile found. Use `pipenv` to create a Pipfile first.' >&2
7
+ exit 2
8
+ fi
9
+
10
+ local VENV=$(pipenv --bare --venv 2>/dev/null)
11
+ if [[ -z $VENV || ! -d $VENV ]]; then
12
+ pipenv install --dev
13
+ fi
14
+
15
+ export VIRTUAL_ENV=$(pipenv --venv)
16
+ export PIPENV_ACTIVE=1
17
+ PATH_add "$VIRTUAL_ENV/bin"
18
+ }
19
+ # -------------------- 8< ---------------------------------
20
+
21
+ layout pipenv
22
+
23
+ # Will add node_modules/.bin to the $PATH
24
+ layout node
Makefile CHANGED
@@ -12,6 +12,7 @@ clean-build:
12
  rm -fr .eggs/
13
  find . -name '*.egg-info' -exec rm -fr {} +
14
  find . -name '*.egg' -exec rm -f {} +
 
15
 
16
  clean-pyc:
17
  find . -name '*.pyc' -exec rm -f {} +
 
12
  rm -fr .eggs/
13
  find . -name '*.egg-info' -exec rm -fr {} +
14
  find . -name '*.egg' -exec rm -f {} +
15
+ find . -name '*.DS_Store' -exec rm -f {} +
16
 
17
  clean-pyc:
18
  find . -name '*.pyc' -exec rm -f {} +
Pipfile ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [[source]]
2
+
3
+ url = "https://pypi.python.org/simple"
4
+ verify_ssl = true
5
+ name = "pypi"
6
+
7
+
8
+ [packages]
9
+
10
+
11
+
12
+ [dev-packages]
13
+
14
+ bumpversion = "*"
15
+ coveralls = "*"
16
+ "flake8" = "*"
17
+ mock = "*"
18
+ pre-commit = "*"
19
+ pytest = "*"
20
+ pytest-cov = "*"
21
+ pytest-mock = "*"
22
+ sphinx = "*"
23
+ sphinx-rtd-theme = "*"
24
+
25
+
26
+ [requires]
27
+
28
+ python_version = "2.7"
Pipfile.lock ADDED
@@ -0,0 +1,371 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_meta": {
3
+ "hash": {
4
+ "sha256": "cfd5870db2e1ead08c85c866c3b50a92b4a08be4df3737e2f090f061389b8812"
5
+ },
6
+ "host-environment-markers": {
7
+ "implementation_name": "cpython",
8
+ "implementation_version": "0",
9
+ "os_name": "posix",
10
+ "platform_machine": "x86_64",
11
+ "platform_python_implementation": "CPython",
12
+ "platform_release": "17.4.0",
13
+ "platform_system": "Darwin",
14
+ "platform_version": "Darwin Kernel Version 17.4.0: Sun Dec 17 09:19:54 PST 2017; root:xnu-4570.41.2~1/RELEASE_X86_64",
15
+ "python_full_version": "2.7.14",
16
+ "python_version": "2.7",
17
+ "sys_platform": "darwin"
18
+ },
19
+ "pipfile-spec": 6,
20
+ "requires": {
21
+ "python_version": "2.7"
22
+ },
23
+ "sources": [
24
+ {
25
+ "name": "pypi",
26
+ "url": "https://pypi.python.org/simple",
27
+ "verify_ssl": true
28
+ }
29
+ ]
30
+ },
31
+ "default": {},
32
+ "develop": {
33
+ "alabaster": {
34
+ "hashes": [
35
+ "sha256:2eef172f44e8d301d25aff8068fddd65f767a3f04b5f15b0f4922f113aa1c732",
36
+ "sha256:37cdcb9e9954ed60912ebc1ca12a9d12178c26637abdf124e3cde2341c257fe0"
37
+ ],
38
+ "version": "==0.7.10"
39
+ },
40
+ "aspy.yaml": {
41
+ "hashes": [
42
+ "sha256:be70cc0ccd1ee1d30f589f2403792eb2ffa7546470af0a17179541b13d8374df",
43
+ "sha256:6215f44900ff65f27dbd00a36b06a7926276436ed377320cfd4febd69bbd4a94"
44
+ ],
45
+ "version": "==1.0.0"
46
+ },
47
+ "attrs": {
48
+ "hashes": [
49
+ "sha256:a17a9573a6f475c99b551c0e0a812707ddda1ec9653bed04c13841404ed6f450",
50
+ "sha256:1c7960ccfd6a005cd9f7ba884e6316b5e430a3f1a6c37c5f87d8b43f83b54ec9"
51
+ ],
52
+ "version": "==17.4.0"
53
+ },
54
+ "babel": {
55
+ "hashes": [
56
+ "sha256:ad209a68d7162c4cff4b29cdebe3dec4cef75492df501b0049a9433c96ce6f80",
57
+ "sha256:8ce4cb6fdd4393edd323227cba3a077bceb2a6ce5201c902c65e730046f41f14"
58
+ ],
59
+ "version": "==2.5.3"
60
+ },
61
+ "bumpversion": {
62
+ "hashes": [
63
+ "sha256:6753d9ff3552013e2130f7bc03c1007e24473b4835952679653fb132367bdd57",
64
+ "sha256:6744c873dd7aafc24453d8b6a1a0d6d109faf63cd0cd19cb78fd46e74932c77e"
65
+ ],
66
+ "version": "==0.5.3"
67
+ },
68
+ "cached-property": {
69
+ "hashes": [
70
+ "sha256:fe045921fe75c873064028e9fbbe06121114ccf613227f4ba284fa7d4c9ff27f",
71
+ "sha256:6562f0be134957547421dda11640e8cadfa7c23238fc4e0821ab69efdb1095f3"
72
+ ],
73
+ "version": "==1.3.1"
74
+ },
75
+ "certifi": {
76
+ "hashes": [
77
+ "sha256:14131608ad2fd56836d33a71ee60fa1c82bc9d2c8d98b7bdbc631fe1b3cd1296",
78
+ "sha256:edbc3f203427eef571f79a7692bb160a2b0f7ccaa31953e99bd17e307cf63f7d"
79
+ ],
80
+ "version": "==2018.1.18"
81
+ },
82
+ "chardet": {
83
+ "hashes": [
84
+ "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691",
85
+ "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"
86
+ ],
87
+ "version": "==3.0.4"
88
+ },
89
+ "coverage": {
90
+ "hashes": [
91
+ "sha256:464d85d6959497cc4adfa9f0d36fca809e2ca7ec5f4625f548317892cac6ed7c",
92
+ "sha256:e958ab5b6a7f3b88289a25c95d031f2b62bc73219141c09d261fd97f244c124c",
93
+ "sha256:67288f8834a0a64c1af66286b22fd325b5524ceaa153a51c3e2e30f7e8b3f826",
94
+ "sha256:cfb6b7035c6605e2a87abe7d84ea35a107e6c432014a3f1ca243ab57a558fbcd",
95
+ "sha256:c86a12b3dc004bcbe97a3849354bd1f93eb6fb69b0e4eb58831fd7adba7740ec",
96
+ "sha256:8ddcf308f894d01a1a0ae01283d19b613751815b7190113266a0b7f9d076e86d",
97
+ "sha256:adab01e4c63a01bdf036f57f0114497994aa2195d8659d12a3d69673c3f27939",
98
+ "sha256:54d73fe68a7ac9c847af69a234a7461bbaf3cad95f258317d4584d14dd53f679",
99
+ "sha256:a0d98c71d026c1757c7393a99d24c6e42091ff41e20e68238b17e145252c2d0a",
100
+ "sha256:464e0eda175c7fe2dc730d9d02acde5b8a8518d9417413dee6ca187d1f65ef89",
101
+ "sha256:2890cb40464686c0c1dccc1223664bbc34d85af053bc5dbcd71ea13959e264f2",
102
+ "sha256:0f2315c793b1360f80a9119fff76efb7b4e5ab5062651dff515e681719f29689",
103
+ "sha256:85c028e959312285225040cdac5ad3db6189e958a234f09ae6b4ba5f539c842d",
104
+ "sha256:da6585339fc8a25086003a2b2c0167438b8ab0cd0ccae468d22ed603e414bba1",
105
+ "sha256:e837865a7b20c01a8a2f904c05fba36e8406b146649ff9174cbddf32e217b777",
106
+ "sha256:b718efb33097c7651a60a03b4b38b14776f92194bc0e9e598ce05ddaef7c70e7",
107
+ "sha256:7413f078fbba267de44814584593a729f88fc37f2d938263844b7f4daf1e36ec",
108
+ "sha256:47ad00a0c025f87a7528cc13d013c54e4691ae8730430e49ec9c7ace7e0e1fba",
109
+ "sha256:95f9f5072afeb2204401401cbd0ab978a9f86ef1ebc5cd267ba431cfa581cc4d",
110
+ "sha256:ca8827a5dad1176a8da6bf5396fd07e66549d1bc842047b76cdf69e196597a80",
111
+ "sha256:c68164c4f49cfc2e66ca1ded62e4a1092a6bd4b2c65222059b867700ad19151c",
112
+ "sha256:61e0bcf15aa0385e15d1fe4a86022a6b813d08c785855e3fab56ba6d7ac3dd21",
113
+ "sha256:981a64063242a2c6c88dda33ccafe3583026847961fe56636b6a00c47674e258",
114
+ "sha256:21e47d2ff9c75e25880dd12b316db11379e9afc98b39e9516149d189c15c564b",
115
+ "sha256:f6b822c68f68f48d480d23fcfcd1d4df7d42ff03cf5d7b574d09e662c0b95b43",
116
+ "sha256:53fa7aa7643a22eeadcf8b781b97a51f37d43ba1d897a05238aa7e4d11bc0667",
117
+ "sha256:95ce1a70323d47c0f6b8d6cfd3c14c38cb30d51fd1ab4f6414734fa33a78b17e",
118
+ "sha256:b7a06a523dfeaf417da630d46ad4f4e11ca1bae6202c9312c4cb987dde5792fc",
119
+ "sha256:585e8db44b8f3af2a4152b00dd8a7a36bc1d2aba7de5e50fc17a54178428f0d6",
120
+ "sha256:102933e14b726bd4fdfafb541e122ad36c150732aee36db409d8c8766e11537e",
121
+ "sha256:15f92238487d93f7f34a3ba03be3bd4615c69cffc88388b4dd1ea99af74fc1bf",
122
+ "sha256:319190dd7fa08c23332215782b563a9ef12b76fb15e4a325915592b825eca9ed",
123
+ "sha256:af14e9628c0a3152b6a1fbba4471e6a3e5f5567ecae614f84b84ff3441c58692",
124
+ "sha256:72bc3f91a25a87fd87eb57983c8cefbb8aa5bacd50d73516ade398271d652d77",
125
+ "sha256:c3905f10786dcf386f3f6cebe0ae4a36f47e5e256471161fb944ca537e97e928",
126
+ "sha256:3344079d73a4849341aaaecd9b391141824b8c9a96732fbd6ef95ba9566895d3"
127
+ ],
128
+ "version": "==4.5"
129
+ },
130
+ "coveralls": {
131
+ "hashes": [
132
+ "sha256:84dd8c88c5754e8db70a682f537e2781366064aa3cdd6b24c2dcecbd3181187c",
133
+ "sha256:510682001517bcca1def9f6252df6ce730fcb9831c62d9fff7c7d55b6fdabdf3"
134
+ ],
135
+ "version": "==1.2.0"
136
+ },
137
+ "docopt": {
138
+ "hashes": [
139
+ "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"
140
+ ],
141
+ "version": "==0.6.2"
142
+ },
143
+ "docutils": {
144
+ "hashes": [
145
+ "sha256:7a4bd47eaf6596e1295ecb11361139febe29b084a87bf005bf899f9a42edc3c6",
146
+ "sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6",
147
+ "sha256:51e64ef2ebfb29cae1faa133b3710143496eca21c530f3f71424d77687764274"
148
+ ],
149
+ "version": "==0.14"
150
+ },
151
+ "flake8": {
152
+ "hashes": [
153
+ "sha256:c7841163e2b576d435799169b78703ad6ac1bbb0f199994fc05f700b2a90ea37",
154
+ "sha256:7253265f7abd8b313e3892944044a365e3f4ac3fcdcfb4298f55ee9ddf188ba0"
155
+ ],
156
+ "version": "==3.5.0"
157
+ },
158
+ "identify": {
159
+ "hashes": [
160
+ "sha256:804e6af41604b11e0b8e0670ae172ef254b152cb5370c7e6b6e7d0c6e9c6a95e",
161
+ "sha256:496d3cce9c4088664e4840e0e01db460820bffa13f03a3016078d99feda0cd74"
162
+ ],
163
+ "version": "==1.0.7"
164
+ },
165
+ "idna": {
166
+ "hashes": [
167
+ "sha256:8c7309c718f94b3a625cb648ace320157ad16ff131ae0af362c9f21b80ef6ec4",
168
+ "sha256:2c6a5de3089009e3da7c5dde64a141dbc8551d5b7f6cf4ed7c2568d0cc520a8f"
169
+ ],
170
+ "version": "==2.6"
171
+ },
172
+ "imagesize": {
173
+ "hashes": [
174
+ "sha256:6ebdc9e0ad188f9d1b2cdd9bc59cbe42bf931875e829e7a595e6b3abdc05cdfb",
175
+ "sha256:0ab2c62b87987e3252f89d30b7cedbec12a01af9274af9ffa48108f2c13c6062"
176
+ ],
177
+ "version": "==0.7.1"
178
+ },
179
+ "jinja2": {
180
+ "hashes": [
181
+ "sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd",
182
+ "sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4"
183
+ ],
184
+ "version": "==2.10"
185
+ },
186
+ "markupsafe": {
187
+ "hashes": [
188
+ "sha256:a6be69091dac236ea9c6bc7d012beab42010fa914c459791d627dad4910eb665"
189
+ ],
190
+ "version": "==1.0"
191
+ },
192
+ "mccabe": {
193
+ "hashes": [
194
+ "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42",
195
+ "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"
196
+ ],
197
+ "version": "==0.6.1"
198
+ },
199
+ "mock": {
200
+ "hashes": [
201
+ "sha256:5ce3c71c5545b472da17b72268978914d0252980348636840bd34a00b5cc96c1",
202
+ "sha256:b158b6df76edd239b8208d481dc46b6afd45a846b7812ff0ce58971cf5bc8bba"
203
+ ],
204
+ "version": "==2.0.0"
205
+ },
206
+ "nodeenv": {
207
+ "hashes": [
208
+ "sha256:98835dab727f94a713eacc7234e3db6777a55cafb60f391485011899e5c818df"
209
+ ],
210
+ "version": "==1.2.0"
211
+ },
212
+ "pbr": {
213
+ "hashes": [
214
+ "sha256:60c25b7dfd054ef9bb0ae327af949dd4676aa09ac3a9471cdc871d8a9213f9ac",
215
+ "sha256:05f61c71aaefc02d8e37c0a3eeb9815ff526ea28b3b76324769e6158d7f95be1"
216
+ ],
217
+ "version": "==3.1.1"
218
+ },
219
+ "pluggy": {
220
+ "hashes": [
221
+ "sha256:7f8ae7f5bdf75671a718d2daf0a64b7885f74510bcd98b1a0bb420eb9a9d0cff"
222
+ ],
223
+ "version": "==0.6.0"
224
+ },
225
+ "pre-commit": {
226
+ "hashes": [
227
+ "sha256:036ac395075609b0ee7017dd356df42e486ccb8d675493e497492795146eab46",
228
+ "sha256:6d6646f5a390677c5c9cd61d5a2613b89d93f079725047aff16fddda9a3ce77f"
229
+ ],
230
+ "version": "==1.6.0"
231
+ },
232
+ "py": {
233
+ "hashes": [
234
+ "sha256:8cca5c229d225f8c1e3085be4fcf306090b00850fefad892f9d96c7b6e2f310f",
235
+ "sha256:ca18943e28235417756316bfada6cd96b23ce60dd532642690dcfdaba988a76d"
236
+ ],
237
+ "version": "==1.5.2"
238
+ },
239
+ "pycodestyle": {
240
+ "hashes": [
241
+ "sha256:6c4245ade1edfad79c3446fadfc96b0de2759662dc29d07d80a6f27ad1ca6ba9",
242
+ "sha256:682256a5b318149ca0d2a9185d365d8864a768a28db66a84a2ea946bcc426766"
243
+ ],
244
+ "version": "==2.3.1"
245
+ },
246
+ "pyflakes": {
247
+ "hashes": [
248
+ "sha256:08bd6a50edf8cffa9fa09a463063c425ecaaf10d1eb0335a7e8b1401aef89e6f",
249
+ "sha256:8d616a382f243dbf19b54743f280b80198be0bca3a5396f1d2e1fca6223e8805"
250
+ ],
251
+ "version": "==1.6.0"
252
+ },
253
+ "pygments": {
254
+ "hashes": [
255
+ "sha256:78f3f434bcc5d6ee09020f92ba487f95ba50f1e3ef83ae96b9d5ffa1bab25c5d",
256
+ "sha256:dbae1046def0efb574852fab9e90209b23f556367b5a320c0bcb871c77c3e8cc"
257
+ ],
258
+ "version": "==2.2.0"
259
+ },
260
+ "pytest": {
261
+ "hashes": [
262
+ "sha256:95fa025cd6deb5d937e04e368a00552332b58cae23f63b76c8c540ff1733ab6d",
263
+ "sha256:6074ea3b9c999bd6d0df5fa9d12dd95ccd23550df2a582f5f5b848331d2e82ca"
264
+ ],
265
+ "version": "==3.4.0"
266
+ },
267
+ "pytest-cov": {
268
+ "hashes": [
269
+ "sha256:890fe5565400902b0c78b5357004aab1c814115894f4f21370e2433256a3eeec",
270
+ "sha256:03aa752cf11db41d281ea1d807d954c4eda35cfa1b21d6971966cc041bbf6e2d"
271
+ ],
272
+ "version": "==2.5.1"
273
+ },
274
+ "pytest-mock": {
275
+ "hashes": [
276
+ "sha256:7ed6e7e8c636fd320927c5d73aedb77ac2eeb37196c3410e6176b7c92fdf2f69",
277
+ "sha256:920d1167af5c2c2ad3fa0717d0c6c52e97e97810160c15721ac895cac53abb1c"
278
+ ],
279
+ "version": "==1.6.3"
280
+ },
281
+ "pytz": {
282
+ "hashes": [
283
+ "sha256:80af0f3008046b9975242012a985f04c5df1f01eed4ec1633d56cc47a75a6a48",
284
+ "sha256:feb2365914948b8620347784b6b6da356f31c9d03560259070b2f30cff3d469d",
285
+ "sha256:59707844a9825589878236ff2f4e0dc9958511b7ffaae94dc615da07d4a68d33",
286
+ "sha256:d0ef5ef55ed3d37854320d4926b04a4cb42a2e88f71da9ddfdacfde8e364f027",
287
+ "sha256:c41c62827ce9cafacd6f2f7018e4f83a6f1986e87bfd000b8cfbd4ab5da95f1a",
288
+ "sha256:8cc90340159b5d7ced6f2ba77694d946fc975b09f1a51d93f3ce3bb399396f94",
289
+ "sha256:dd2e4ca6ce3785c8dd342d1853dd9052b19290d5bf66060846e5dc6b8d6667f7",
290
+ "sha256:699d18a2a56f19ee5698ab1123bbcc1d269d061996aeb1eda6d89248d3542b82",
291
+ "sha256:fae4cffc040921b8a2d60c6cf0b5d662c1190fe54d718271db4eb17d44a185b7"
292
+ ],
293
+ "version": "==2017.3"
294
+ },
295
+ "pyyaml": {
296
+ "hashes": [
297
+ "sha256:3262c96a1ca437e7e4763e2843746588a965426550f3797a79fca9c6199c431f",
298
+ "sha256:16b20e970597e051997d90dc2cddc713a2876c47e3d92d59ee198700c5427736",
299
+ "sha256:e863072cdf4c72eebf179342c94e6989c67185842d9997960b3e69290b2fa269",
300
+ "sha256:bc6bced57f826ca7cb5125a10b23fd0f2fff3b7c4701d64c439a300ce665fff8",
301
+ "sha256:c01b880ec30b5a6e6aa67b09a2fe3fb30473008c85cd6a67359a1b15ed6d83a4",
302
+ "sha256:827dc04b8fa7d07c44de11fabbc888e627fa8293b695e0f99cb544fdfa1bf0d1",
303
+ "sha256:592766c6303207a20efc445587778322d7f73b161bd994f227adaa341ba212ab",
304
+ "sha256:5f84523c076ad14ff5e6c037fe1c89a7f73a3e04cf0377cb4d017014976433f3",
305
+ "sha256:0c507b7f74b3d2dd4d1322ec8a94794927305ab4cebbe89cc47fe5e81541e6e8",
306
+ "sha256:b4c423ab23291d3945ac61346feeb9a0dc4184999ede5e7c43e1ffb975130ae6",
307
+ "sha256:ca233c64c6e40eaa6c66ef97058cdc80e8d0157a443655baa1b2966e812807ca",
308
+ "sha256:4474f8ea030b5127225b8894d626bb66c01cda098d47a2b0d3429b6700af9fd8",
309
+ "sha256:326420cbb492172dec84b0f65c80942de6cedb5233c413dd824483989c000608",
310
+ "sha256:5ac82e411044fb129bae5cfbeb3ba626acb2af31a8d17d175004b70862a741a7"
311
+ ],
312
+ "version": "==3.12"
313
+ },
314
+ "requests": {
315
+ "hashes": [
316
+ "sha256:6a1b267aa90cac58ac3a765d067950e7dbbf75b1da07e895d1f594193a40a38b",
317
+ "sha256:9c443e7324ba5b85070c4a818ade28bfabedf16ea10206da1132edaa6dda237e"
318
+ ],
319
+ "version": "==2.18.4"
320
+ },
321
+ "six": {
322
+ "hashes": [
323
+ "sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb",
324
+ "sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9"
325
+ ],
326
+ "version": "==1.11.0"
327
+ },
328
+ "snowballstemmer": {
329
+ "hashes": [
330
+ "sha256:9f3bcd3c401c3e862ec0ebe6d2c069ebc012ce142cce209c098ccb5b09136e89",
331
+ "sha256:919f26a68b2c17a7634da993d91339e288964f93c274f1343e3bbbe2096e1128"
332
+ ],
333
+ "version": "==1.2.1"
334
+ },
335
+ "sphinx": {
336
+ "hashes": [
337
+ "sha256:d5b91b4dad56ffc9f19425ebaa7bc23290a0a2e9035781d5bc54822384663277",
338
+ "sha256:832bed0dc6099c2abca957d90ff55bc1a6ec4425c13fc144adbae68a970e3775"
339
+ ],
340
+ "version": "==1.6.7"
341
+ },
342
+ "sphinx-rtd-theme": {
343
+ "hashes": [
344
+ "sha256:62ee4752716e698bad7de8a18906f42d33664128eea06c46b718fc7fbd1a9f5c",
345
+ "sha256:2df74b8ff6fae6965c527e97cca6c6c944886aae474b490e17f92adfbe843417"
346
+ ],
347
+ "version": "==0.2.4"
348
+ },
349
+ "sphinxcontrib-websupport": {
350
+ "hashes": [
351
+ "sha256:f4932e95869599b89bf4f80fc3989132d83c9faa5bf633e7b5e0c25dffb75da2",
352
+ "sha256:7a85961326aa3a400cd4ad3c816d70ed6f7c740acd7ce5d78cd0a67825072eb9"
353
+ ],
354
+ "version": "==1.0.1"
355
+ },
356
+ "urllib3": {
357
+ "hashes": [
358
+ "sha256:06330f386d6e4b195fbfc736b297f58c5a892e4440e54d294d7004e3a9bbea1b",
359
+ "sha256:cc44da8e1145637334317feebd728bd869a35285b93cbb4cca2577da7e62db4f"
360
+ ],
361
+ "version": "==1.22"
362
+ },
363
+ "virtualenv": {
364
+ "hashes": [
365
+ "sha256:39d88b533b422825d644087a21e78c45cf5af0ef7a99a1fc9fbb7b481e5c85b0",
366
+ "sha256:02f8102c2436bb03b3ee6dede1919d1dac8a427541652e5ec95171ec8adbc93a"
367
+ ],
368
+ "version": "==15.1.0"
369
+ }
370
+ }
371
+ }
requirements.txt → pytube/contrib/__init__.py RENAMED
File without changes
pytube/{playlist.py → contrib/playlist.py} RENAMED
@@ -2,15 +2,17 @@
2
  """
3
  Module to download a complete playlist from a youtube channel
4
  """
5
- from __future__ import print_function
 
6
  from pytube import request
7
  from pytube.__main__ import YouTube
8
 
 
 
9
 
10
  class Playlist(object):
11
- """
12
- Handles all the task of manipulating and downloading
13
- a whole YouTube playlist
14
  """
15
 
16
  def __init__(self, url):
@@ -18,26 +20,26 @@ class Playlist(object):
18
  self.video_urls = []
19
 
20
  def construct_playlist_url(self):
21
- """
22
- There are two kinds of playlist urls in YouTube. One that
23
  contains watch?v= in URL, another one contains the "playlist?list="
24
  portion. It is preferable to work with the later one.
 
25
  :return: playlist url -> string
26
  """
27
 
28
- if "watch?v=" in self.playlist_url:
29
- base_url = "https://www.youtube.com/playlist?list="
30
- playlist_code = self.playlist_url.split("&list=")[1]
31
  return base_url + playlist_code
32
 
33
  # url is already in the desired format, so just return it
34
  return self.playlist_url
35
 
36
  def parse_links(self):
37
- """
38
- Parse the video links from the page source, extracts and
39
  returns the /watch?v= part from video link href
40
  It's an alternative for BeautifulSoup
 
41
  :return: list
42
  """
43
 
@@ -45,52 +47,42 @@ class Playlist(object):
45
  req = request.get(url)
46
 
47
  # split the page source by line and process each line
48
- content = [x for x in req.split("\n") if "pl-video-title-link" in x]
49
- link_list = [x.split('href="', 1)[1].split("&", 1)[0] for x in content]
50
 
51
  return link_list
52
 
53
  def populate_video_urls(self):
54
- """
55
- Construct complete links of all the videos in playlist and
56
  populate video_urls list
 
57
  :return: urls -> string
58
  """
59
 
60
- base_url = "https://www.youtube.com"
61
  link_list = self.parse_links()
62
 
63
  for video_id in link_list:
64
  complete_url = base_url + video_id
65
- # print complete_url
66
  self.video_urls.append(complete_url)
67
 
68
  def download_all(self):
69
- """
70
- Download all the videos in the the playlist. Initially, download
71
  resolution is 720p (or highest available), later more option
72
  should be added to download resolution of choice
73
- TODO: Add option to download resolution of user's choice
74
- :return: None
75
  """
76
 
77
  self.populate_video_urls()
78
- print("Total videos found:", len(self.video_urls))
79
- # print(self.video_urls)
80
- print("Starting download...\n")
81
 
82
  for link in self.video_urls:
83
  yt = YouTube(link)
84
 
85
- # (ISSUE #206): the try/except is done to prevent
86
- # the UnicodeEncodeError
87
- try:
88
- print("Downloading:", yt.title)
89
- except UnicodeEncodeError:
90
- print("(title cannot be shown due to unicode error)")
91
-
92
- yt.streams.filter(progressive=True,
93
- subtype="mp4").order_by(
94
- "resolution").desc().first().download()
95
 
96
- print("Download complete")
 
2
  """
3
  Module to download a complete playlist from a youtube channel
4
  """
5
+ import logging
6
+
7
  from pytube import request
8
  from pytube.__main__ import YouTube
9
 
10
+ logger = logging.getLogger(__name__)
11
+
12
 
13
  class Playlist(object):
14
+ """Handles all the task of manipulating and downloading a whole YouTube
15
+ playlist
 
16
  """
17
 
18
  def __init__(self, url):
 
20
  self.video_urls = []
21
 
22
  def construct_playlist_url(self):
23
+ """There are two kinds of playlist urls in YouTube. One that
 
24
  contains watch?v= in URL, another one contains the "playlist?list="
25
  portion. It is preferable to work with the later one.
26
+
27
  :return: playlist url -> string
28
  """
29
 
30
+ if 'watch?v=' in self.playlist_url:
31
+ base_url = 'https://www.youtube.com/playlist?list='
32
+ playlist_code = self.playlist_url.split('&list=')[1]
33
  return base_url + playlist_code
34
 
35
  # url is already in the desired format, so just return it
36
  return self.playlist_url
37
 
38
  def parse_links(self):
39
+ """Parse the video links from the page source, extracts and
 
40
  returns the /watch?v= part from video link href
41
  It's an alternative for BeautifulSoup
42
+
43
  :return: list
44
  """
45
 
 
47
  req = request.get(url)
48
 
49
  # split the page source by line and process each line
50
+ content = [x for x in req.split('\n') if 'pl-video-title-link' in x]
51
+ link_list = [x.split('href="', 1)[1].split('&', 1)[0] for x in content]
52
 
53
  return link_list
54
 
55
  def populate_video_urls(self):
56
+ """Construct complete links of all the videos in playlist and
 
57
  populate video_urls list
58
+
59
  :return: urls -> string
60
  """
61
 
62
+ base_url = 'https://www.youtube.com'
63
  link_list = self.parse_links()
64
 
65
  for video_id in link_list:
66
  complete_url = base_url + video_id
 
67
  self.video_urls.append(complete_url)
68
 
69
  def download_all(self):
70
+ """Download all the videos in the the playlist. Initially, download
 
71
  resolution is 720p (or highest available), later more option
72
  should be added to download resolution of choice
73
+
74
+ TODO(nficano): Add option to download resolution of user's choice
75
  """
76
 
77
  self.populate_video_urls()
78
+ logger.debug('total videos found: ', len(self.video_urls))
79
+ logger.debug('starting download')
 
80
 
81
  for link in self.video_urls:
82
  yt = YouTube(link)
83
 
84
+ yt.streams.filter(
85
+ progressive=True, subtype='mp4',
86
+ ).order_by('resolution').desc().first().download()
 
 
 
 
 
 
 
87
 
88
+ logger.debug('download complete')
setup.cfg CHANGED
@@ -3,7 +3,7 @@ commit = True
3
  tag = True
4
  current_version = 9.0.3
5
  parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(\-(?P<release>[a-z]+))?
6
- serialize =
7
  {major}.{minor}.{patch}
8
 
9
  [metadata]
@@ -15,6 +15,5 @@ description-file = README.md
15
 
16
  [coverage:run]
17
  source = pytube
18
- omit =
19
  pytube/compat.py
20
-
 
3
  tag = True
4
  current_version = 9.0.3
5
  parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(\-(?P<release>[a-z]+))?
6
+ serialize =
7
  {major}.{minor}.{patch}
8
 
9
  [metadata]
 
15
 
16
  [coverage:run]
17
  source = pytube
18
+ omit =
19
  pytube/compat.py
 
tests/requirements.txt DELETED
@@ -1,10 +0,0 @@
1
- bumpversion==0.5.3
2
- coveralls==1.0
3
- flake8==3.3.0
4
- mock==1.3.0
5
- pre-commit==0.15.0
6
- pytest==3.1.3
7
- pytest-cov==2.4.0
8
- pytest-mock==1.6.3
9
- sphinx==1.6.4
10
- sphinx-rtd-theme==0.2.4
 
 
 
 
 
 
 
 
 
 
 
tests/test_playlist.py CHANGED
@@ -4,33 +4,40 @@ from pytube import playlist
4
 
5
  def test_construct():
6
  ob = playlist.Playlist(
7
- "https://www.youtube.com/watch?v=m5q2GCsteQs&list="
8
- "PL525f8ds9RvsXDl44X6Wwh9t3fCzFNApw")
9
- expected = "https://www.youtube.com/" \
10
- "playlist?list=" \
11
- "PL525f8ds9RvsXDl44X6Wwh9t3fCzFNApw"
 
12
 
13
  assert ob.construct_playlist_url() == expected
14
 
15
 
16
  def test_link_parse():
17
  ob = playlist.Playlist(
18
- "https://www.youtube.com/watch?v=m5q2GCsteQs&list="
19
- "PL525f8ds9RvsXDl44X6Wwh9t3fCzFNApw")
20
-
21
- expected = ["/watch?v=m5q2GCsteQs",
22
- "/watch?v=5YK63cXyJ2Q",
23
- "/watch?v=Rzt4rUPFYD4"]
 
 
 
24
  assert ob.parse_links() == expected
25
 
26
 
27
  def test_populate():
28
  ob = playlist.Playlist(
29
- "https://www.youtube.com/watch?v=m5q2GCsteQs&list="
30
- "PL525f8ds9RvsXDl44X6Wwh9t3fCzFNApw")
31
- expected = ["https://www.youtube.com/watch?v=m5q2GCsteQs",
32
- "https://www.youtube.com/watch?v=5YK63cXyJ2Q",
33
- "https://www.youtube.com/watch?v=Rzt4rUPFYD4"]
 
 
 
34
 
35
  ob.populate_video_urls()
36
  assert ob.video_urls == expected
@@ -38,6 +45,7 @@ def test_populate():
38
 
39
  def test_download():
40
  ob = playlist.Playlist(
41
- "https://www.youtube.com/watch?v=lByG_AgKS9k&list="
42
- "PL525f8ds9RvuerPZ3bZygmNiYw2sP4BDk")
 
43
  ob.download_all()
 
4
 
5
  def test_construct():
6
  ob = playlist.Playlist(
7
+ 'https://www.youtube.com/watch?v=m5q2GCsteQs&list='
8
+ 'PL525f8ds9RvsXDl44X6Wwh9t3fCzFNApw',
9
+ )
10
+ expected = 'https://www.youtube.com/' \
11
+ 'playlist?list=' \
12
+ 'PL525f8ds9RvsXDl44X6Wwh9t3fCzFNApw'
13
 
14
  assert ob.construct_playlist_url() == expected
15
 
16
 
17
  def test_link_parse():
18
  ob = playlist.Playlist(
19
+ 'https://www.youtube.com/watch?v=m5q2GCsteQs&list='
20
+ 'PL525f8ds9RvsXDl44X6Wwh9t3fCzFNApw',
21
+ )
22
+
23
+ expected = [
24
+ '/watch?v=m5q2GCsteQs',
25
+ '/watch?v=5YK63cXyJ2Q',
26
+ '/watch?v=Rzt4rUPFYD4',
27
+ ]
28
  assert ob.parse_links() == expected
29
 
30
 
31
  def test_populate():
32
  ob = playlist.Playlist(
33
+ 'https://www.youtube.com/watch?v=m5q2GCsteQs&list='
34
+ 'PL525f8ds9RvsXDl44X6Wwh9t3fCzFNApw',
35
+ )
36
+ expected = [
37
+ 'https://www.youtube.com/watch?v=m5q2GCsteQs',
38
+ 'https://www.youtube.com/watch?v=5YK63cXyJ2Q',
39
+ 'https://www.youtube.com/watch?v=Rzt4rUPFYD4',
40
+ ]
41
 
42
  ob.populate_video_urls()
43
  assert ob.video_urls == expected
 
45
 
46
  def test_download():
47
  ob = playlist.Playlist(
48
+ 'https://www.youtube.com/watch?v=lByG_AgKS9k&list='
49
+ 'PL525f8ds9RvuerPZ3bZygmNiYw2sP4BDk',
50
+ )
51
  ob.download_all()