forked from mattmakai/fullstackpython.com
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathall.atom.xml
More file actions
1840 lines (1612 loc) · 156 KB
/
all.atom.xml
File metadata and controls
1840 lines (1612 loc) · 156 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Full Stack Python</title><link href="https://www.fullstackpython.com/" rel="alternate"></link><link href="https://www.fullstackpython.com/feeds/all.atom.xml" rel="self"></link><id>https://www.fullstackpython.com/</id><updated>2016-06-19T00:00:00-04:00</updated><entry><title>Configuring Python 3, Pyramid and Gunicorn on Ubuntu 16.04</title><link href="https://www.fullstackpython.com/python-3-pyramid-gunicorn-ubuntu-1604-xenial-xerus.html" rel="alternate"></link><updated>2016-06-19T00:00:00-04:00</updated><author><name>Matt Makai</name></author><id>tag:www.fullstackpython.com,2016-06-19:python-3-pyramid-gunicorn-ubuntu-1604-xenial-xerus.html</id><summary type="html"><p><a href="/ubuntu.html">Canonical's Ubuntu 16.04 Long Term Support (LTS)</a> Linux
<a href="/operating-systems.html">operating system</a>, also known as "Xenial Xerus",
was released in April 2016. It is the first Ubuntu release to include
<a href="/python-2-or-3.html">Python 3</a> instead of Python 2 as its default Python
installation.</p>
<p>The <a href="/pyramid.html">Pyramid</a> web framework has long supported Python 3.
With just a few short steps we can start a new <a href="/pyramid.html">Pyramid</a>
project and run it with
<a href="/green-unicorn-gunicorn.html">Green Unicorn (Gunicorn)</a> on Ubuntu 16.04.</p>
<h2>Required Tools</h2>
<p>Our project requires Ubuntu 16.04 plus several code libraries. You do not
need to install these tools yet - we will get to them in turn as the
walkthrough progresses. Our requirements and their current versions are:</p>
<ul>
<li><a href="http://releases.ubuntu.com/16.04/">Ubuntu 16.04 LTS (Xenial Xerus)</a></li>
<li><a href="/why-use-python.html">Python version 3.5</a> (default in Ubuntu 16.04)</li>
<li><a href="/pyramid.html">Pyramid web framework</a> version
<a href="http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/">1.7</a></li>
<li><a href="/green-unicorn-gunicorn.html">Gunicorn</a> version
<a href="http://docs.gunicorn.org/en/stable/news.html">19.6</a></li>
<li><a href="http://docs.pylonsproject.org/projects/waitress/en/latest/">Waitress</a>
version 0.9.0</li>
</ul>
<p>If you are developing on Mac OS X or Windows, you can use
virtualization software such
as <a href="https://www.parallels.com/products/desktop/">Parallels</a> or
<a href="https://www.virtualbox.org/wiki/Downloads">VirtualBox</a> with the
<a href="http://releases.ubuntu.com/16.04/">Ubuntu .iso file</a>. Either the amd64 or
i386 version of 16.04 is fine. While creating this I used the amd64 version. </p>
<p>A desktop screen like this one appears when you boot up Ubuntu.</p>
<p><img src="/source/static/img/160619-ubuntu-pyramid-gunicorn/ubuntu-desktop.jpg" width="100%" class="technical-diagram img-rounded"></p>
<p>Open a new terminal window so we can be ready to install required system
packages.</p>
<h2>Install System Packages</h2>
<p>The precise Python version can be shown using the <code>python</code> command with the
<code>--version</code> argument.</p>
<div class="highlight"><pre>python3 --version
</pre></div>
<p>We can also view where the <code>python3</code> program is installed on Ubuntu using the
<code>which</code> command.</p>
<div class="highlight"><pre>which python3
</pre></div>
<p><img src="/source/static/img/160619-ubuntu-pyramid-gunicorn/which-python.png" width="100%" class="technical-diagram img-rounded"></p>
<p>Ubuntu requires a few system packages before we can properly install Pyramid
and Gunicorn. When we run the <code>apt</code> command to install system packages we
will be prompted for the superuser password. Restricted system access is
necessary to modify files within the system folders.</p>
<div class="highlight"><pre>sudo apt-get install virtualenv python-pip python3-dev
</pre></div>
<p><img src="/source/static/img/160619-ubuntu-pyramid-gunicorn/install-packages.png" width="100%" class="technical-diagram img-rounded"></p>
<p>Press <code>y</code> then return to let the system package installation run.</p>
<p><img src="/source/static/img/160619-ubuntu-pyramid-gunicorn/packages-installed.png" width="100%" class="technical-diagram img-rounded"></p>
<p>The required system packages are installed. We can now install the
Python-specific dependencies.</p>
<h2>Set up Virtualenv</h2>
<p>In the previous section, <a href="https://virtualenv.pypa.io/en/latest/">virtualenv</a>
and <a href="https://pypi.python.org/pypi/pip">pip</a> were installed to handle our
<a href="/application-dependencies.html">application dependencies</a>.</p>
<p>Create a directory for the virtualenvs. Then create a new virtualenv.</p>
<div class="highlight"><pre># the tilde &quot;~&quot; specifies the user&#39;s home directory, like /home/matt
cd ~
mkdir venvs
# specify the system python3 installation
virtualenv --python=/usr/bin/python3 venvs/pyramidproj
</pre></div>
<p>Activate the virtualenv.</p>
<div class="highlight"><pre>source ~/venvs/pyramidproj/bin/activate
</pre></div>
<p>Our prompt will change after we properly activate the virtualenv to
something like <code>(pyramidproj) matt@ubuntu:~$</code>.</p>
<p><img src="/source/static/img/160619-ubuntu-pyramid-gunicorn/venv-activated.png" width="100%" class="technical-diagram img-rounded"></p>
<p>Our virtualenv is activated with Python 3. We can install whatever
dependencies we want, in our case Pyramid and Gunicorn. </p>
<h2>Install Python Packages</h2>
<p>We can install Pyramid, Gunicorn and Waitress into our virtualenv using
the <code>pip</code> command.</p>
<div class="highlight"><pre>pip install pyramid gunicorn waitress
</pre></div>
<p>No errors like we see in the following screenshot is a good sign.</p>
<p><img src="/source/static/img/160619-ubuntu-pyramid-gunicorn/good-sign.png" width="100%" class="technical-diagram img-rounded"></p>
<p>Pyramid comes with a project starter template creation tool named <code>pcreate</code>.
Run <code>pcreate</code> to generate the boilerplate for a new Pyramid project named
"pyramidproj".</p>
<div class="highlight"><pre>pcreate -s starter pyramidproj
</pre></div>
<p>Use the <code>cd</code> (change directory) command to move into the new folder.</p>
<div class="highlight"><pre>cd ~/pyramidproj
</pre></div>
<p>A slew of new files have been created within the "pyramidproj" directory.
These are the basic files you can customize for the web application you want
to build. A good resource for understanding and modifying these files is
to follow the
<a href="http://pyramid-stevepiercy.readthedocs.io/en/stable/quick_tutorial/index.html">quick tutorial for Pyramid</a>.</p>
<p>For now, we just want to use Gunicorn to run our starter pyramidproj app.
Install pyramidproj into your virtualenv using the <code>python</code> command on
<code>setup.py</code>.</p>
<div class="highlight"><pre>python setup.py develop
</pre></div>
<p>Now we can run our app with Gunicorn. Pyramid is a
<a href="http://docs.pylonsproject.org/projects/pyramid/en/latest/api/paster.html">paste</a>-compatible
framework, so we use the <code>--paste</code> argument to run the WSGI server with
the "development.ini" configuration file. In addition, the <code>-b</code> argument
tells Gunicorn which port number to bind on when the server starts.</p>
<div class="highlight"><pre>gunicorn --paste development.ini -b :8080
</pre></div>
<p><img src="/source/static/img/160619-ubuntu-pyramid-gunicorn/gunicorn-run.png" width="100%" class="technical-diagram img-rounded"></p>
<p>Cool, we can bring up our starter Pyramid project up in the web browser at
the <code>localhost:8000</code> or <code>127.0.0.1:8000</code> address.</p>
<p><img src="/source/static/img/160619-ubuntu-pyramid-gunicorn/it-works.png" width="100%" class="technical-diagram img-rounded"></p>
<p>Time to develop a full-fledged web application with <a href="/pyramid.html">Pyramid</a>!</p>
<h2>Ready to Develop with Pyramid</h2>
<p>Now you have a simple setup to develop Pyramid web apps using Gunicorn as
the <a href="/wsgi-servers.html">WSGI server</a> on Ubuntu 16.04. If you need a
full step-by-step tutorial to deploy your Python web application to a
production environment, check out the
<a href="http://www.deploypython.com/">Full Stack Python Guide to Deployments book</a>.</p>
<p>To decide what to do next with your Python project, check out the
<a href="/table-of-contents.html">Full Stack Python table of contents</a> page.</p>
<p>See something wrong in this post? Fork
<a href="https://github.com/makaimc/fullstackpython.com/blob/gh-pages/source/content/posts/160619-pyramid-gunicorn-ubuntu-1604.markdown">this page's source on GitHub</a>
and submit a pull request.</p></summary></entry><entry><title>Replying to SMS Text Messages with Python and Bottle</title><link href="https://www.fullstackpython.com/reply-sms-text-messages-python-bottle.html" rel="alternate"></link><updated>2016-06-05T00:00:00-04:00</updated><author><name>Matt Makai</name></author><id>tag:www.fullstackpython.com,2016-06-05:reply-sms-text-messages-python-bottle.html</id><summary type="html"><p>Python applications can
<a href="/blog/send-sms-text-messages-python.html">easily send SMS</a>
by using a <a href="/application-programming-interfaces.html">web API</a>.
Web apps built with the <a href="/bottle.html">Bottle</a> framework can also reply
to incoming text messages by handling inbound HTTP POST webhooks. In
this post we'll quickly walk through how to set up a Bottle web app to
handle SMS data in the form of HTTP POST requests.</p>
<h2>Tools We'll Need</h2>
<p>This tutorial works with either <a href="/python-2-or-3.html">Python 2 or 3</a>,
although Python 3 is recommended by the community for new applications.
Install one of those two Python versions on your system to use for this
walkthrough. We also need:</p>
<ul>
<li><a href="https://pip.pypa.io/en/stable/">pip</a> and
<a href="https://virtualenv.pypa.io/en/latest/">virtualenv</a> to handle
<a href="/application-dependencies.html">application dependencies</a></li>
<li><a href="/bottle.html">Bottle</a> web framework</li>
<li><a href="https://ngrok.com/">Ngrok</a> for localhost tunneling to our Bottle
application while it's running on our local development environment</li>
<li>Free <a href="https://www.twilio.com/try-twilio">Twilio account</a> to use their
<a href="https://www.twilio.com/docs/api/rest/sending-messages">SMS web API</a></li>
<li>Open source
<a href="https://pypi.python.org/pypi/twilio">Twilio Python helper library</a></li>
</ul>
<p>Check out the guide on
<a href="/blog/python-3-bottle-gunicorn-ubuntu-1604-xenial-xerus.html">how to set up Python 3, Bottle and Gunicorn on Ubuntu 16.04 LTS</a>
if you need help getting your
<a href="/development-environments.html">development environment</a>
configured.</p>
<h2>Application Dependency Installation</h2>
<p>Our application will use a helper code library to reply to inbound SMS.
Bottle and the helper library are installable from
<a href="https://pypi.python.org/pypi">PyPI</a> into a virtualenv. Open your terminal
and use the <code>virtualenv</code> command to create a new virtualenv:</p>
<div class="highlight"><pre>virtualenv replysms
</pre></div>
<p>Invoke the virtualenv's <code>activate</code> script, which makes it the "active"
Python installation. Note that you need to do this in every terminal window
that you want this virtualenv to be used.</p>
<div class="highlight"><pre>source replysms/bin/activate
</pre></div>
<p>The command prompt will change after activating the virtualenv:</p>
<p><img src="/source/static/img/160605-reply-sms-python-bottle/activate-virtualenv.png" width="100%" class="technical-diagram img-rounded"></p>
<p>Use the <code>pip</code> command to install the <a href="/bottle.html">Bottle</a> and
<a href="https://www.twilio.com/docs/libraries/python">Twilio Python</a> packages
into your virtualenv.</p>
<div class="highlight"><pre>pip install bottle twilio
</pre></div>
<p>We have installed the required dependencies so now Python code that is run
with the virtualenv activated will be able to use those packages. It's time
to build our Bottle web app and reply to incoming text messages.</p>
<h2>Coding Our Bottle App</h2>
<p>The Bottle web app will have two routes. One route will allow us to test
that the app is running. The other route will handle and respond to incoming
HTTP POST requests from Twilio. Create a new file named <code>app.py</code> in your
in the directory where you want to store this Python project.</p>
<p>Write the following code in the new <code>app.py</code> file. There is also
<a href="https://gist.github.com/makaimc/6ec3b46e40a1020a3ea9c772c601199a">a GitHub Gist</a>
with the code that you can copy and paste.</p>
<div class="highlight"><pre><span class="kn">from</span> <span class="nn">bottle</span> <span class="kn">import</span> <span class="p">(</span><span class="n">post</span><span class="p">,</span> <span class="n">request</span><span class="p">,</span> <span class="n">response</span><span class="p">,</span> <span class="n">route</span><span class="p">,</span> <span class="n">run</span><span class="p">,</span> <span class="p">)</span>
<span class="kn">from</span> <span class="nn">twilio</span> <span class="kn">import</span> <span class="n">twiml</span>
<span class="nd">@route</span><span class="p">(</span><span class="s">&#39;/&#39;</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">check_app</span><span class="p">():</span>
<span class="c"># returns a simple string stating the app is working</span>
<span class="k">return</span> <span class="s">&quot;It works!&quot;</span>
<span class="nd">@post</span><span class="p">(</span><span class="s">&#39;/twilio&#39;</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">inbound_sms</span><span class="p">():</span>
<span class="n">twiml_response</span> <span class="o">=</span> <span class="n">twiml</span><span class="o">.</span><span class="n">Response</span><span class="p">()</span>
<span class="c"># grab message from the request. could also get the &quot;To&quot; and </span>
<span class="c"># &quot;From&quot; phone numbers as well from parameters with those names</span>
<span class="n">inbound_message</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">forms</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">&quot;Body&quot;</span><span class="p">)</span>
<span class="c"># we can now use the incoming message text in our Python application</span>
<span class="k">if</span> <span class="n">inbound_message</span> <span class="o">==</span> <span class="s">&quot;Hello&quot;</span><span class="p">:</span>
<span class="n">twiml_response</span><span class="o">.</span><span class="n">message</span><span class="p">(</span><span class="s">&quot;Hello from Bottle right back at you!&quot;</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">twiml_response</span><span class="o">.</span><span class="n">message</span><span class="p">(</span><span class="s">&quot;Hi! Not quite sure what you meant, but okay.&quot;</span><span class="p">)</span>
<span class="c"># we return back the mimetype because Twilio needs an XML response</span>
<span class="n">response</span><span class="o">.</span><span class="n">content_type</span> <span class="o">=</span> <span class="s">&quot;application/xml&quot;</span>
<span class="k">return</span> <span class="nb">str</span><span class="p">(</span><span class="n">twiml_response</span><span class="p">)</span>
<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&#39;__main__&#39;</span><span class="p">:</span>
<span class="n">run</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s">&#39;127.0.0.1&#39;</span><span class="p">,</span> <span class="n">port</span><span class="o">=</span><span class="mi">5000</span><span class="p">,</span> <span class="n">debug</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">reloader</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
</pre></div>
<p>The lines starting with <code>#</code> are comments that give explanations for what
the code lines below them are doing. Bottle web apps define URL routes with
the <code>@route</code> and <code>@post</code> decorators, depending on the type of HTTP request
the route should handle. </p>
<p>Make sure your virtualenv is still active so that the application can use
the Bottle and Twilio code libraries we installed earlier. Give the
application a try by running it with <code>python app.py</code>. </p>
<p>Open a web browser and go to localhost:5000 (or 127.0.0.1:5000). We should
see "It works!" on the screen.</p>
<p><img src="/source/static/img/160605-reply-sms-python-bottle/bottle-app-local.jpg" width="100%" class="technical-diagram img-rounded" alt="Bottle application running locally on Ubuntu."></p>
<p>However, there is an issue with our web app running on our local development
environment. Twilio cannot send a the HTTP POST request to the web app
server unless a localhost tunnel is created.</p>
<h2>Ngrok Localhost Tunneling</h2>
<p><a href="https://ngrok.com">Ngrok</a> is a localhost tunneling tool that bridges
your local development environment to an external URL.
<a href="https://ngrok.com/download">Download and install</a> the Ngrok version that's
appropriate for your operating system.</p>
<p>We can run Ngrok locally and expose our Bottle app that is running on
port 5000. Run this command within the directory where the Ngrok executable is
located.</p>
<div class="highlight"><pre>./ngrok http 5000
</pre></div>
<p><img src="/source/static/img/160605-reply-sms-python-bottle/start-ngrok.jpg" width="100%" class="technical-diagram img-rounded" alt="Ngrok started and running to serve as a localhost tunnel."></p>
<p>Cool, now we can use the Forwarding URL so Twilio can send POST requests
to our application when there is an inbound SMS. Replace the URL in the
text box with your own Forwarding URL, like I did in this screenshot.</p>
<p><img src="/source/static/img/160605-reply-sms-python-bottle/access-ngrok.jpg" width="100%" class="technical-diagram img-rounded" alt="Paste the ngrok Forwarding URL into the Twilio webhook configuration text box."></p>
<p>Now we just need a Twilio phone number that will send POST request to our
application when there is an inbound SMS.</p>
<h2>Obtain a Phone Number</h2>
<p>Our Bottle web app's route can respond to incoming POST requests but we
need to use Twilio to have a phone number that will convert the inbound SMS
data into the POST request. In your web browser go to the
<a href="https://www.twilio.com/try-twilio">Twilio website and sign up for a free account</a>.
You can also sign into your existing Twilio account if you already have one.</p>
<p><img src="/source/static/img/160605-reply-sms-python-bottle/try-twilio.png" width="100%" class="technical-diagram img-rounded" alt="Twilio sign up screen."></p>
<p>The Twilio trial account allows you to send and receive text messages to
your own validated phone number. To send and reply to SMS to and from any
phone number then you need to upgrade your account. Trial accounts are
great for initial development before your application goes live.</p>
<p>When you sign up, you receive a free Twilio phone number. We can
configure that phone number to forward the SMS information to our web
application by setting up the response webhook.</p>
<p>Go to the
<a href="https://www.twilio.com/console/phone-numbers">manage phone numbers screen</a>
and click on the phone number you want to configure for replying to
text messages.</p>
<p>Scroll down and look for the "Messaging" header. Change the
"A Message Comes in" text box to input the ngrok Forwarding URL plus
the "/twilio" route, as shown in the screenshot below.</p>
<p><img src="/source/static/img/160605-reply-sms-python-bottle/webhook-ngrok.jpg" width="100%" class="technical-diagram img-rounded" alt="Paste the ngrok Forwarding URL into the Twilio webhook configuration text box."></p>
<p>Click the "Save" button so that our changes take effect.</p>
<p>Our application is ready to go - time to give our phone number a try!
Send "Hello" or whatever text you want to your phone number. Here is what
the result looks like on my iPhone.</p>
<p><img src="/source/static/img/160605-reply-sms-python-bottle/bottle-success.png" width="100%" class="technical-diagram img-rounded" alt="Example screenshot of what SMS replies look like on the iPhone."></p>
<p>The concise Bottle web app is a good start to build more complicated
programs such as
<a href="https://www.twilio.com/blog/2014/11/choose-your-own-adventure-presentations-with-reveal-js-python-and-websockets.html">Choose Your Own Adventure Presentations</a>
or
<a href="https://www.twilio.com/blog/2016/05/build-sms-slack-bot-python.html">SMS Slack bots</a>.</p>
<h2>What's next?</h2>
<p>Awesome, our Bottle application now replies to inbound SMS text
messages! </p>
<p>Questions? Contact me via Twitter
<a href="https://twitter.com/fullstackpython">@fullstackpython</a>
or <a href="https://twitter.com/mattmakai">@mattmakai</a>. I'm also on GitHub with
the username <a href="https://github.com/makaimc">makaimc</a>.</p>
<p>Something wrong with this post? Fork
<a href="https://github.com/makaimc/fullstackpython.com/blob/gh-pages/source/content/posts/160605-reply-sms-python-bottle.markdown">this page's source on GitHub</a>.</p></summary></entry><entry><title>How to Build Your First Slack Bot with Python</title><link href="https://www.fullstackpython.com/build-first-slack-bot-python.html" rel="alternate"></link><updated>2016-06-04T00:00:00-04:00</updated><author><name>Matt Makai</name></author><id>tag:www.fullstackpython.com,2016-06-04:build-first-slack-bot-python.html</id><summary type="html"><p><a href="/bots.html">Bots</a> are a useful way to interact with chat services such as
<a href="https://slack.com/">Slack</a>. If you have never built a bot before, this
post provides an easy starter tutorial for combining the
<a href="https://api.slack.com/">Slack API</a> with Python to create your first bot.</p>
<p>We will walk through setting up your development environment, obtaining a
Slack API bot token and coding our simple bot in Python.</p>
<h2>Tools We Need</h2>
<p>Our bot, which we will name "StarterBot", requires Python and the Slack API.
To run our Python code we need:</p>
<ul>
<li>Either <a href="/python-2-or-3.html">Python 2 or 3</a></li>
<li><a href="https://pip.pypa.io/en/stable/">pip</a> and
<a href="https://virtualenv.pypa.io/en/stable/">virtualenv</a> to handle Python
<a href="/application-dependencies.html">application dependencies</a></li>
<li><a href="https://slack.com/">Free Slack account</a> with a team on which you have
API access or sign up for the
<a href="http://dev4slack.xoxco.com/">Slack Developer Hangout team</a></li>
<li>Official Python
<a href="https://github.com/slackhq/python-slackclient">slackclient</a> code
library built by the Slack team</li>
<li><a href="https://api.slack.com/tokens">Slack API testing token</a></li>
</ul>
<p>It is also useful to have the <a href="https://api.slack.com/">Slack API docs</a> handy
while you're building this tutorial.</p>
<p>All the code for this tutorial is available open source under the MIT license
in the <a href="https://github.com/makaimc/slack-starterbot">slack-starterbot</a> public
repository.</p>
<h2>Establishing Our Environment</h2>
<p>We now know what tools we need for our project so let's get our development
environment set up. Go to the terminal (or Command Prompt on Windows) and
change into the directory where you want to store this project. Within
that directory, create a new virtualenv to isolate our application
dependencies from other Python projects.</p>
<div class="highlight"><pre>virtualenv starterbot
</pre></div>
<p>Activate the virtualenv:</p>
<div class="highlight"><pre>source starterbot/bin/activate
</pre></div>
<p>Your prompt should now look like the one in this screenshot.</p>
<p><img src="/source/static/img/160604-simple-python-slack-bot/virtualenv-activate.png" width="100%" class="technical-diagram img-rounded" alt="Command prompt with starterbot's virtualenv activated."></p>
<p>The official slackclient API helper library built by Slack can send and
receive messages from a Slack channel. Install the slackclient library with
the <code>pip</code> command:</p>
<div class="highlight"><pre>pip install slackclient
</pre></div>
<p>When <code>pip</code> is finished you should see output like this and you'll be
back at the prompt.</p>
<p><img src="/source/static/img/160604-simple-python-slack-bot/pip-install-slackclient.png" width="100%" class="technical-diagram img-rounded" alt="Output from using the pip install slackclient command with a virtualenv activated."></p>
<p>We also need to obtain an access token for our Slack team so our bot can
use it to connect to the Slack API.</p>
<h2>Slack Real Time Messaging (RTM) API</h2>
<p>Slack grants programmatic access to their messaging channels via a
<a href="/application-programming-interfaces.html">web API</a>. Go to the
<a href="https://api.slack.com/">Slack web API page</a> and sign up to create your own
Slack team. You can also sign into an existing account where you have
administrative privileges.</p>
<p><img src="/source/static/img/160604-simple-python-slack-bot/sign-in-slack.png" width="100%" class="technical-diagram img-rounded" alt="Use the sign in button on the top right corner of the Slack API page."></p>
<p>After you have signed in go to the
<a href="https://api.slack.com/bot-users">Bot Users page</a>.</p>
<p><img src="/source/static/img/160604-simple-python-slack-bot/custom-bot-users.png" width="100%" class="technical-diagram img-rounded" alt="Custom bot users webpage."></p>
<p>Name your bot "starterbot" then click the “Add bot integration” button.</p>
<p><img src="/source/static/img/160604-simple-python-slack-bot/starterbot.jpg" width="100%" class="technical-diagram img-rounded" alt="Add a bot integration named starterbot."></p>
<p>The page will reload and you will see a newly-generated access token. You
can also change the logo to a custom design. For example, I gave this bot
the Full Stack Python logo.</p>
<p><img src="/source/static/img/160604-simple-python-slack-bot/slack-token.png" width="100%" class="technical-diagram img-rounded" alt="Copy and paste the access token for your new Slack bot."></p>
<p>Click the "Save Integration" button at the bottom of the page. Your bot is
now ready to connect to Slack's API.</p>
<p>A common practice for Python developers is to export secret tokens as
environment variables. Export the Slack token with the name
<code>SLACK_BOT_TOKEN</code>:</p>
<div class="highlight"><pre>export SLACK_BOT_TOKEN=&#39;your slack token pasted here&#39;
</pre></div>
<p>Nice, now we are authorized to use the Slack API as a bot.</p>
<p>There is one more piece of information we need to build our bot: our bot's
ID. Next we will write a short script to obtain that ID from the Slack API.</p>
<h2>Obtaining Our Bot’s ID</h2>
<p>It is <em>finally</em> time to write some Python code! We'll get warmed up by coding
a short Python script to obtain StarterBot's ID. The ID varies based on the
Slack team. </p>
<p>We need the ID because it allows our application to determine if messages
parsed from the Slack RTM are directed at StarterBot. Our script also
tests that our <code>SLACK_BOT_TOKEN</code> environment variable is properly set. </p>
<p>Create a new file named <code>print_bot_id.py</code> and fill it with the following
code.</p>
<div class="highlight"><pre><span class="kn">import</span> <span class="nn">os</span>
<span class="kn">from</span> <span class="nn">slackclient</span> <span class="kn">import</span> <span class="n">SlackClient</span>
<span class="n">BOT_NAME</span> <span class="o">=</span> <span class="s">&#39;starterbot&#39;</span>
<span class="n">slack_client</span> <span class="o">=</span> <span class="n">SlackClient</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">&#39;SLACK_BOT_TOKEN&#39;</span><span class="p">))</span>
<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&quot;__main__&quot;</span><span class="p">:</span>
<span class="n">api_call</span> <span class="o">=</span> <span class="n">slack_client</span><span class="o">.</span><span class="n">api_call</span><span class="p">(</span><span class="s">&quot;users.list&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="n">api_call</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">&#39;ok&#39;</span><span class="p">):</span>
<span class="c"># retrieve all users so we can find our bot</span>
<span class="n">users</span> <span class="o">=</span> <span class="n">api_call</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">&#39;members&#39;</span><span class="p">)</span>
<span class="k">for</span> <span class="n">user</span> <span class="ow">in</span> <span class="n">users</span><span class="p">:</span>
<span class="k">if</span> <span class="s">&#39;name&#39;</span> <span class="ow">in</span> <span class="n">user</span> <span class="ow">and</span> <span class="n">user</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">&#39;name&#39;</span><span class="p">)</span> <span class="o">==</span> <span class="n">BOT_NAME</span><span class="p">:</span>
<span class="k">print</span><span class="p">(</span><span class="s">&quot;Bot ID for &#39;&quot;</span> <span class="o">+</span> <span class="n">user</span><span class="p">[</span><span class="s">&#39;name&#39;</span><span class="p">]</span> <span class="o">+</span> <span class="s">&quot;&#39; is &quot;</span> <span class="o">+</span> <span class="n">user</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">&#39;id&#39;</span><span class="p">))</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">print</span><span class="p">(</span><span class="s">&quot;could not find bot user with the name &quot;</span> <span class="o">+</span> <span class="n">BOT_NAME</span><span class="p">)</span>
</pre></div>
<p>Our code imports the SlackClient and instantiates it with our
<code>SLACK_BOT_TOKEN</code>, which we set as an environment variable. When the
script is executed by the <code>python</code> command we call the Slack API to list
all Slack users and get the ID for the one that matches the name "starterbot".</p>
<p>We only need to run this script once to obtain our bot’s ID.</p>
<div class="highlight"><pre>python print_bot_id.py
</pre></div>
<p>The script prints a single line of output when it is run that provides
us with our bot's ID.</p>
<p><img src="/source/static/img/160604-simple-python-slack-bot/printed-bot-id.png" width="100%" class="technical-diagram img-rounded" alt="Use the Python script to print the Slack bot's ID in your Slack team."></p>
<p>Copy the unique ID that your script prints out. Export the ID as an
environment variable named <code>BOT_ID</code>.</p>
<div class="highlight"><pre>(starterbot)$ export BOT_ID=&#39;bot id returned by script&#39;
</pre></div>
<p>The script only needs to be run once to get the bot ID. We can now use
that ID in our Python application that will run StarterBot.</p>
<h2>Coding Our StarterBot</h2>
<p>We've got everything we need to write the StarterBot code. Create a new file
named <code>starterbot.py</code> and include the following code in it.</p>
<div class="highlight"><pre><span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">time</span>
<span class="kn">from</span> <span class="nn">slackclient</span> <span class="kn">import</span> <span class="n">SlackClient</span>
</pre></div>
<p>The <code>os</code> and <code>SlackClient</code> imports will look familiar because we used them
in the <code>print_bot_id.py</code> program.</p>
<p>With our dependencies imported we can use them to obtain the environment
variable values and then instantiate the Slack client.</p>
<div class="highlight"><pre><span class="cp"># starterbot&#39;s ID as an environment variable</span>
<span class="n">BOT_ID</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">environ</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">&quot;BOT_ID&quot;</span><span class="p">)</span>
<span class="cp"># constants</span>
<span class="n">AT_BOT</span> <span class="o">=</span> <span class="s">&quot;&lt;@&quot;</span> <span class="o">+</span> <span class="n">BOT_ID</span> <span class="o">+</span> <span class="s">&quot;&gt;:&quot;</span>
<span class="n">EXAMPLE_COMMAND</span> <span class="o">=</span> <span class="s">&quot;do&quot;</span>
<span class="cp"># instantiate Slack &amp; Twilio clients</span>
<span class="n">slack_client</span> <span class="o">=</span> <span class="n">SlackClient</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">environ</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="err">&#39;</span><span class="n">SLACK_BOT_TOKEN</span><span class="err">&#39;</span><span class="p">))</span>
</pre></div>
<p>The code instantiates the <code>SlackClient</code> client with our <code>SLACK_BOT_TOKEN</code>
exported as an environment variable. </p>
<div class="highlight"><pre>if __name__ == &quot;__main__&quot;:
READ_WEBSOCKET_DELAY = 1 # 1 second delay between reading from firehose
if slack_client.rtm_connect():
print(&quot;StarterBot connected and running!&quot;)
while True:
command, channel = parse_slack_output(slack_client.rtm_read())
if command and channel:
handle_command(command, channel)
time.sleep(READ_WEBSOCKET_DELAY)
else:
print(&quot;Connection failed. Invalid Slack token or bot ID?&quot;)
</pre></div>
<p>The Slack client connects to the Slack RTM API WebSocket then constantly
loops while parsing messages from the firehose. If any of those messages are
directed at StarterBot, a function named <code>handle_command</code> determines what
to do.</p>
<p>Next add two new functions to parse Slack output and handle commands.</p>
<div class="highlight"><pre><span class="nx">def</span> <span class="nx">handle_command</span><span class="p">(</span><span class="nx">command</span><span class="p">,</span> <span class="nx">channel</span><span class="p">)</span><span class="o">:</span>
<span class="s2">&quot;&quot;&quot;</span>
<span class="s2"> Receives commands directed at the bot and determines if they</span>
<span class="s2"> are valid commands. If so, then acts on the commands. If not,</span>
<span class="s2"> returns back what it needs for clarification.</span>
<span class="s2"> &quot;&quot;&quot;</span>
<span class="nx">response</span> <span class="o">=</span> <span class="s2">&quot;Not sure what you mean. Use the *&quot;</span> <span class="o">+</span> <span class="nx">EXAMPLE_COMMAND</span> <span class="o">+</span> <span class="o">\</span>
<span class="s2">&quot;* command with numbers, delimited by spaces.&quot;</span>
<span class="k">if</span> <span class="nx">command</span><span class="p">.</span><span class="nx">startswith</span><span class="p">(</span><span class="nx">EXAMPLE_COMMAND</span><span class="p">)</span><span class="o">:</span>
<span class="nx">response</span> <span class="o">=</span> <span class="s2">&quot;Sure...write some more code then I can do that!&quot;</span>
<span class="nx">slack_client</span><span class="p">.</span><span class="nx">api_call</span><span class="p">(</span><span class="s2">&quot;chat.postMessage&quot;</span><span class="p">,</span> <span class="nx">channel</span><span class="o">=</span><span class="nx">channel</span><span class="p">,</span>
<span class="nx">text</span><span class="o">=</span><span class="nx">response</span><span class="p">,</span> <span class="nx">as_user</span><span class="o">=</span><span class="nx">True</span><span class="p">)</span>
<span class="nx">def</span> <span class="nx">parse_slack_output</span><span class="p">(</span><span class="nx">slack_rtm_output</span><span class="p">)</span><span class="o">:</span>
<span class="s2">&quot;&quot;&quot;</span>
<span class="s2"> The Slack Real Time Messaging API is an events firehose.</span>
<span class="s2"> this parsing function returns None unless a message is</span>
<span class="s2"> directed at the Bot, based on its ID.</span>
<span class="s2"> &quot;&quot;&quot;</span>
<span class="nx">output_list</span> <span class="o">=</span> <span class="nx">slack_rtm_output</span>
<span class="k">if</span> <span class="nx">output_list</span> <span class="nx">and</span> <span class="nx">len</span><span class="p">(</span><span class="nx">output_list</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="o">:</span>
<span class="k">for</span> <span class="nx">output</span> <span class="k">in</span> <span class="nx">output_list</span><span class="o">:</span>
<span class="k">if</span> <span class="nx">output</span> <span class="nx">and</span> <span class="s1">&#39;text&#39;</span> <span class="k">in</span> <span class="nx">output</span> <span class="nx">and</span> <span class="nx">AT_BOT</span> <span class="k">in</span> <span class="nx">output</span><span class="cp">[</span><span class="s1">&#39;text&#39;</span><span class="cp">]</span><span class="o">:</span>
<span class="err">#</span> <span class="k">return</span> <span class="nx">text</span> <span class="nx">after</span> <span class="nx">the</span> <span class="err">@</span> <span class="nx">mention</span><span class="p">,</span> <span class="nx">whitespace</span> <span class="nx">removed</span>
<span class="k">return</span> <span class="nx">output</span><span class="cp">[</span><span class="s1">&#39;text&#39;</span><span class="cp">]</span><span class="p">.</span><span class="nx">split</span><span class="p">(</span><span class="nx">AT_BOT</span><span class="p">)</span><span class="cp">[</span><span class="mi">1</span><span class="cp">]</span><span class="p">.</span><span class="nx">strip</span><span class="p">().</span><span class="nx">lower</span><span class="p">(),</span> <span class="o">\</span>
<span class="nx">output</span><span class="cp">[</span><span class="s1">&#39;channel&#39;</span><span class="cp">]</span>
<span class="k">return</span> <span class="nx">None</span><span class="p">,</span> <span class="nx">None</span>
</pre></div>
<p>The <code>parse_slack_output</code> function takes messages from Slack and determines
if they are directed at our StarterBot. Messages that start with a direct
command to our bot ID are then handled by our code - which is currently
just posts a message back in the Slack channel telling the user to write
some more Python code!</p>
<p>Here is how the entire program should look when it's all put together
(you can also
<a href="https://github.com/makaimc/slack-starterbot/blob/master/starterbot.py">view the file in GitHub</a>):</p>
<div class="highlight"><pre><span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">time</span>
<span class="kn">from</span> <span class="nn">slackclient</span> <span class="kn">import</span> <span class="n">SlackClient</span>
<span class="c"># starterbot&#39;s ID as an environment variable</span>
<span class="n">BOT_ID</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">&quot;BOT_ID&quot;</span><span class="p">)</span>
<span class="c"># constants</span>
<span class="n">AT_BOT</span> <span class="o">=</span> <span class="s">&quot;&lt;@&quot;</span> <span class="o">+</span> <span class="n">BOT_ID</span> <span class="o">+</span> <span class="s">&quot;&gt;:&quot;</span>
<span class="n">EXAMPLE_COMMAND</span> <span class="o">=</span> <span class="s">&quot;do&quot;</span>
<span class="c"># instantiate Slack &amp; Twilio clients</span>
<span class="n">slack_client</span> <span class="o">=</span> <span class="n">SlackClient</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">&#39;SLACK_BOT_TOKEN&#39;</span><span class="p">))</span>
<span class="k">def</span> <span class="nf">handle_command</span><span class="p">(</span><span class="n">command</span><span class="p">,</span> <span class="n">channel</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Receives commands directed at the bot and determines if they</span>
<span class="sd"> are valid commands. If so, then acts on the commands. If not,</span>
<span class="sd"> returns back what it needs for clarification.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">response</span> <span class="o">=</span> <span class="s">&quot;Not sure what you mean. Use the *&quot;</span> <span class="o">+</span> <span class="n">EXAMPLE_COMMAND</span> <span class="o">+</span> \
<span class="s">&quot;* command with numbers, delimited by spaces.&quot;</span>
<span class="k">if</span> <span class="n">command</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="n">EXAMPLE_COMMAND</span><span class="p">):</span>
<span class="n">response</span> <span class="o">=</span> <span class="s">&quot;Sure...write some more code then I can do that!&quot;</span>
<span class="n">slack_client</span><span class="o">.</span><span class="n">api_call</span><span class="p">(</span><span class="s">&quot;chat.postMessage&quot;</span><span class="p">,</span> <span class="n">channel</span><span class="o">=</span><span class="n">channel</span><span class="p">,</span>
<span class="n">text</span><span class="o">=</span><span class="n">response</span><span class="p">,</span> <span class="n">as_user</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">parse_slack_output</span><span class="p">(</span><span class="n">slack_rtm_output</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> The Slack Real Time Messaging API is an events firehose.</span>
<span class="sd"> this parsing function returns None unless a message is</span>
<span class="sd"> directed at the Bot, based on its ID.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">output_list</span> <span class="o">=</span> <span class="n">slack_rtm_output</span>
<span class="k">if</span> <span class="n">output_list</span> <span class="ow">and</span> <span class="nb">len</span><span class="p">(</span><span class="n">output_list</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
<span class="k">for</span> <span class="n">output</span> <span class="ow">in</span> <span class="n">output_list</span><span class="p">:</span>
<span class="k">if</span> <span class="n">output</span> <span class="ow">and</span> <span class="s">&#39;text&#39;</span> <span class="ow">in</span> <span class="n">output</span> <span class="ow">and</span> <span class="n">AT_BOT</span> <span class="ow">in</span> <span class="n">output</span><span class="p">[</span><span class="s">&#39;text&#39;</span><span class="p">]:</span>
<span class="c"># return text after the @ mention, whitespace removed</span>
<span class="k">return</span> <span class="n">output</span><span class="p">[</span><span class="s">&#39;text&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="n">AT_BOT</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span><span class="o">.</span><span class="n">lower</span><span class="p">(),</span> \
<span class="n">output</span><span class="p">[</span><span class="s">&#39;channel&#39;</span><span class="p">]</span>
<span class="k">return</span> <span class="bp">None</span><span class="p">,</span> <span class="bp">None</span>
<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&quot;__main__&quot;</span><span class="p">:</span>
<span class="n">READ_WEBSOCKET_DELAY</span> <span class="o">=</span> <span class="mi">1</span> <span class="c"># 1 second delay between reading from firehose</span>
<span class="k">if</span> <span class="n">slack_client</span><span class="o">.</span><span class="n">rtm_connect</span><span class="p">():</span>
<span class="k">print</span><span class="p">(</span><span class="s">&quot;StarterBot connected and running!&quot;</span><span class="p">)</span>
<span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
<span class="n">command</span><span class="p">,</span> <span class="n">channel</span> <span class="o">=</span> <span class="n">parse_slack_output</span><span class="p">(</span><span class="n">slack_client</span><span class="o">.</span><span class="n">rtm_read</span><span class="p">())</span>
<span class="k">if</span> <span class="n">command</span> <span class="ow">and</span> <span class="n">channel</span><span class="p">:</span>
<span class="n">handle_command</span><span class="p">(</span><span class="n">command</span><span class="p">,</span> <span class="n">channel</span><span class="p">)</span>
<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="n">READ_WEBSOCKET_DELAY</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">print</span><span class="p">(</span><span class="s">&quot;Connection failed. Invalid Slack token or bot ID?&quot;</span><span class="p">)</span>
</pre></div>
<p>Now that all of our code is in place we can run our StarterBot on the
command line with the <code>python starterbot.py</code> command.</p>
<p><img src="/source/static/img/160604-simple-python-slack-bot/starterbot-running.png" width="100%" class="technical-diagram img-rounded" alt="Console output when the StarterBot is running and connected to the API."></p>
<p>In Slack, create a new channel and invite StarterBot or invite it to an
existing channel.</p>
<p><img src="/source/static/img/160604-simple-python-slack-bot/create-channel.png" width="100%" class="technical-diagram img-rounded" alt="In the Slack user interface create a new channel and invite StarterBot."></p>
<p>Now start giving StarterBot commands in your channel.</p>
<p><img src="/source/static/img/160604-simple-python-slack-bot/working-starterbot.png" width="100%" class="technical-diagram img-rounded" alt="Give StarterBot commands in your Slack channel."></p>
<h2>Wrapping Up</h2>
<p>Alright, now you've got a simple StarterBot with a bunch of places in the
code you can add whatever features you want to build. </p>
<p>There is a whole lot more that could be done using the Slack RTM API and Python.
Check out these posts to learn what you could do:</p>
<ul>
<li>Attach a persistent <a href="/databases.html">relational database</a> or
<a href="/no-sql-datastore.html">NoSQL back-end</a> such as
<a href="/postgresql.html">PostgreSQL</a>, <a href="/mysql.html">MySQL</a> or <a href="/sqlite.html">SQLite</a>
to save and retrieve user data</li>
<li>Add another channel to interact with the bot
<a href="https://www.twilio.com/blog/2016/05/build-sms-slack-bot-python.html">via SMS</a>
or
<a href="https://www.twilio.com/blog/2016/05/add-phone-calling-slack-python.html">phone calls</a></li>
<li><a href="/api-integration.html">Integrate other web APIs</a> such as
<a href="https://developer.github.com/v3/">GitHub</a>,
<a href="https://www.twilio.com/docs">Twilio</a> or <a href="https://docs.api.ai/">api.ai</a></li>
</ul>
<p>Questions? Contact me via Twitter
<a href="https://twitter.com/fullstackpython">@fullstackpython</a>
or <a href="https://twitter.com/mattmakai">@mattmakai</a>. I'm also on GitHub with
the username <a href="https://github.com/makaimc">makaimc</a>.</p>
<p>Something wrong with this post? Fork
<a href="https://github.com/makaimc/fullstackpython.com/blob/gh-pages/source/content/posts/160604-build-first-slack-bot-python.markdown">this page's source on GitHub</a>.</p></summary></entry><entry><title>Responding to SMS Text Messages with Python & Flask</title><link href="https://www.fullstackpython.com/respond-sms-text-messages-python-flask.html" rel="alternate"></link><updated>2016-05-30T00:00:00-04:00</updated><author><name>Matt Makai</name></author><id>tag:www.fullstackpython.com,2016-05-30:respond-sms-text-messages-python-flask.html</id><summary type="html"><p>Short Message Service (SMS) text messages are
<a href="/blog/send-sms-text-messages-python.html">easy to send from Python applications</a>
with a
<a href="/application-programming-interfaces.html">web application programming interface (API)</a>.
Flask applications can also receive incoming text messages and respond
back to the sender with just a few lines of Python code.</p>
<h2>Tools We Need</h2>
<p>This tutorial is fine for both Python 2 and 3. Make sure you have one of
those two versions installed on your system.</p>
<ul>
<li>Either <a href="/python-2-or-3.html">Python 2 or 3</a></li>
<li><a href="https://pip.pypa.io/en/stable/">pip</a> and
<a href="https://virtualenv.pypa.io/en/latest/">virtualenv</a> to handle
<a href="/application-dependencies.html">application dependencies</a></li>
<li>The <a href="/flask.html">Flask</a> micro web framework</li>
<li>A free <a href="https://www.twilio.com/try-twilio">Twilio account</a> to use their
<a href="https://www.twilio.com/docs/api/rest/sending-messages">SMS web API</a></li>
<li>Open source
<a href="https://pypi.python.org/pypi/twilio">Twilio Python helper library</a></li>
<li><a href="https://ngrok.com/">Ngrok</a> for localhost tunneling to our Flask
application while it's running on our local development environment</li>
</ul>
<p>If you need assistance getting pip and virtualenv installed, take a look at
the first few steps in the
<a href="/blog/python-3-flask-green-unicorn-ubuntu-1604-xenial-xerus.html">how to set up Python 3, Flask and Green Unicorn on Ubuntu 16.04 LTS</a>
guide, which shows how to install system packages for those tools.</p>
<h2>Installing Our Dependencies</h2>
<p>Our code will use a helper library to make it easier to respond to text
messages from Python. The helper library dependency along with the Flask
code library can be installed from <a href="https://pypi.python.org/pypi">PyPI</a> into
a virtualenv. In your terminal use the following command to generate a new
virtualenv. </p>
<div class="highlight"><pre>virtualenv respondsms
</pre></div>
<p>Activate the virtualenv.</p>
<div class="highlight"><pre>source respondsms/bin/activate
</pre></div>
<p>The command prompt will change after we properly activate the virtualenv
to something like this:</p>
<p><img src="/source/static/img/160530-respond-sms-python-flask/activate-virtualenv.png" width="100%" class="technical-diagram img-rounded"></p>
<p>Install Flask and the Twilio Python helper library into the virtualenv with
the <code>pip</code> command. </p>
<div class="highlight"><pre>pip install flask twilio
</pre></div>
<p>The dependencies are installed so that we can use it with our Python code.
Now we can write our Python application.</p>
<h2>Building Our Flask Web App</h2>
<p>Our Flask application will have two routes: one to make sure the web app
is running and another that handles incoming HTTP POST requests. Create
a new file named <code>app.py</code> in your home directory or where you choose to
store your Python project files.</p>
<p>Within <code>app.py</code> write the following code. You can also see
<a href="https://gist.github.com/makaimc/8ab434ccb604d3ba5bde817a183e0bde">this code in a GitHub Gist</a>
if that's easier to copy and paste.</p>
<div class="highlight"><pre><span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">Flask</span><span class="p">,</span> <span class="n">Response</span><span class="p">,</span> <span class="n">request</span>
<span class="kn">from</span> <span class="nn">twilio</span> <span class="kn">import</span> <span class="n">twiml</span>
<span class="n">app</span> <span class="o">=</span> <span class="n">Flask</span><span class="p">(</span><span class="n">__name__</span><span class="p">)</span>
<span class="nd">@app.route</span><span class="p">(</span><span class="s">&quot;/&quot;</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">check_app</span><span class="p">():</span>
<span class="c"># returns a simple string stating the app is working</span>
<span class="k">return</span> <span class="n">Response</span><span class="p">(</span><span class="s">&quot;It works!&quot;</span><span class="p">),</span> <span class="mi">200</span>
<span class="nd">@app.route</span><span class="p">(</span><span class="s">&quot;/twilio&quot;</span><span class="p">,</span> <span class="n">methods</span><span class="o">=</span><span class="p">[</span><span class="s">&quot;POST&quot;</span><span class="p">])</span>
<span class="k">def</span> <span class="nf">inbound_sms</span><span class="p">():</span>
<span class="n">response</span> <span class="o">=</span> <span class="n">twiml</span><span class="o">.</span><span class="n">Response</span><span class="p">()</span>
<span class="c"># we get the SMS message from the request. we could also get the </span>
<span class="c"># &quot;To&quot; and the &quot;From&quot; phone number as well</span>
<span class="n">inbound_message</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">form</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">&quot;Body&quot;</span><span class="p">)</span>
<span class="c"># we can now use the incoming message text in our Python application</span>
<span class="k">if</span> <span class="n">inbound_message</span> <span class="o">==</span> <span class="s">&quot;Hello&quot;</span><span class="p">:</span>
<span class="n">response</span><span class="o">.</span><span class="n">message</span><span class="p">(</span><span class="s">&quot;Hello back to you!&quot;</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">response</span><span class="o">.</span><span class="n">message</span><span class="p">(</span><span class="s">&quot;Hi! Not quite sure what you meant, but okay.&quot;</span><span class="p">)</span>
<span class="c"># we return back the mimetype because Twilio needs an XML response</span>
<span class="k">return</span> <span class="n">Response</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">response</span><span class="p">),</span> <span class="n">mimetype</span><span class="o">=</span><span class="s">&quot;application/xml&quot;</span><span class="p">),</span> <span class="mi">200</span>
<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&quot;__main__&quot;</span><span class="p">:</span>
<span class="n">app</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">debug</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
</pre></div>
<p>The inline comments on the lines starting with <code>#</code> explain what the lines
below them do. Flask applications define URL routes with the <code>@app.route</code>
decorator. Our application needs two routes therefore we have two of those
decorators defined.</p>
<p>Give the application a try by running it with <code>python app.py</code>. If you have
trouble running the program, make sure your virtualenv is still active so
that the application can use the Flask and Twilio code libraries we installed
earlier.</p>
<p>Open a web browser and go to localhost:5000 (or 127.0.0.1:5000). We should
see "It works!" on the screen.</p>
<p><img src="/source/static/img/160530-respond-sms-python-flask/app-local.jpg" width="100%" class="technical-diagram img-rounded"></p>
<p>There is one problem with our application running on our local development
environment: there's no way for our server to receive HTTP POST requests
unless we use a localhost tunnel.</p>
<h2>Localhost Tunneling with Ngrok</h2>
<p><a href="https://ngrok.com">Ngrok</a> provides a localhost tunnel so that outside
services can connect to a server running in your local development
environment. Download and install Ngrok.</p>
<p>We can now run Ngrok locally and connect our Flask app running on port 5000.
Within the directory where you extracted Ngrok, run this command.</p>
<div class="highlight"><pre>./ngrok http 5000
</pre></div>
<p><img src="/source/static/img/160530-respond-sms-python-flask/start-ngrok.jpg" width="100%" class="technical-diagram img-rounded"></p>
<p>Awesome, now we can use that Ngrok Forwarding URL to access our application
from any machine that has an internet connection. Replace the URL in the
web browser with your own Forwarding URL, like I did in this screenshot.</p>
<p><img src="/source/static/img/160530-respond-sms-python-flask/access-ngrok.png" width="100%" class="technical-diagram img-rounded"></p>
<p>We just need a phone number that'll hit our application with a POST request
to respond to text messages.</p>
<h2>Obtaining Our Phone Number</h2>
<p>We can use our Flask application's route to respond to incoming web API
requests based on incoming SMS messages to a Twilio phone number. Go to the
<a href="https://www.twilio.com/try-twilio">Twilio website and sign up for a free trial account</a>
to use their API. If you already have a Twilio account then sign into your
existing account.</p>
<p><img src="/source/static/img/160530-respond-sms-python-flask/try-twilio.png" width="100%" class="technical-diagram img-rounded"></p>
<p>The Twilio trial account allows you to send and receive text messages to
your own validated phone number. To send and respond to SMS to and from any
phone number then you need to upgrade your account. Trial accounts are
great for initial development before your application goes live.</p>
<p>When you sign up, you receive a free Twilio phone number. We can
configure that phone number to forward the SMS information to our web
application by setting up the response webhook.</p>
<p>Go to the
<a href="https://www.twilio.com/console/phone-numbers">manage phone numbers screen</a>
and click on the phone number you want to configure for responding to
inbound text messages.</p>
<p>Scroll down to near the bottom of the page and look for the "Messaging"
header. Modify the "A Message Comes in" text box so that it has your
ngrok Forwarding URL plus the "/twilio" route, as shown in this screenshot.</p>
<p><img src="/source/static/img/160530-respond-sms-python-flask/number-configuration.png" width="100%" class="technical-diagram img-rounded"></p>
<p>Now press the red "Save" button at the bottom to make our changes take
effect.</p>
<p>Our application is ready to go - time to give our phone number a try!
Send "Hello" or whatever text you want to your phone number. Here is what
the result looks like on my iPhone.</p>
<p><img src="/source/static/img/160530-respond-sms-python-flask/success.jpg" width="100%" class="technical-diagram img-rounded"></p>
<p>This simple Flask application is a good start to build more complicated
responses such as
<a href="https://www.twilio.com/blog/2014/06/using-natural-language-processing-for-better-sms-interfaces-using-twilio-and-pythons-textblob.html">adding natural language processing</a>,
<a href="https://www.twilio.com/blog/2016/05/build-sms-slack-bot-python.html">building SMS Slack bots</a>
or
<a href="https://www.twilio.com/blog/2015/08/romram-hacking-building-an-sms-powered-game-genie-with-lua-and-python.html">coding SMS-powered NES Game Genies</a>.</p>
<h2>What's next?</h2>
<p>Sweet, now our Flask web app automatically responds to incoming SMS text
messages! It's pretty crazy to think that entire businesses such as
<a href="http://techcrunch.com/2016/03/07/superphone/">SuperPhone</a> and
<a href="https://www.remind.com/">Remind</a> are built off code that started out very
similar to the code we just wrote.</p>
<p>Questions? Contact me via Twitter
<a href="https://twitter.com/fullstackpython">@fullstackpython</a>
or <a href="https://twitter.com/mattmakai">@mattmakai</a>. I'm also on GitHub with
the username <a href="https://github.com/makaimc">makaimc</a>.</p>
<p>Something wrong with this post? Fork
<a href="https://github.com/makaimc/fullstackpython.com/blob/gh-pages/source/content/posts/160530-respond-sms-text-messages-python-flask.markdown">this page's source on GitHub</a>.</p></summary></entry><entry><title>How to Install and Use MySQL on Ubuntu 16.04</title><link href="https://www.fullstackpython.com/install-mysql-ubuntu-1604.html" rel="alternate"></link><updated>2016-05-28T00:00:00-04:00</updated><author><name>Matt Makai</name></author><id>tag:www.fullstackpython.com,2016-05-28:install-mysql-ubuntu-1604.html</id><summary type="html"><p><a href="/mysql.html">MySQL</a> is a common open source
<a href="/databases.html">relational database</a> for creating, reading, updating
and deleting data in <a href="/web-frameworks.html">Python web applications</a>.
Let's learn how to install MySQL on <a href="/ubuntu.html">Ubuntu 16.04</a> and then
run a few SQL queries within the command line client.</p>
<p>We will not go over connecting via Python applications using
<a href="/object-relational-mappers-orms.html">object-relational mappers (ORMs)</a>
but these steps can be used as a prerequisite to working with an ORM such
as SQLAlchemy or Peewee.</p>
<h2>Tools We Need</h2>
<p>In this tutorial we'll use the following components:</p>
<ul>
<li><a href="http://releases.ubuntu.com/16.04/">Ubuntu 16.04</a> (this tutorial
should also work on other Ubuntu versions)</li>
<li><a href="http://dev.mysql.com/doc/">MySQL</a></li>
</ul>
<h2>Install MySQL</h2>
<p>We can install MySQL by using the <code>apt</code> package manager. First make sure
your packages list are up to date. Open the terminal and run this <code>apt</code>
command.</p>
<div class="highlight"><pre>sudo apt-get update
</pre></div>
<p>We need to install the <code>mysql-server</code> package, which downloads the required
files, configures the initial database set up and handles running MySQL
as a system service. Run this <code>apt</code> command to get the process started.</p>
<div class="highlight"><pre>sudo apt-get install mysql
</pre></div>
<p>Enter 'y' when prompted with whether or not you want to install the
new package.</p>
<p><img src="/source/static/img/160528-mysql-ubuntu-1604/apt-install-prompt.png" width="100%" class="technical-diagram img-rounded"></p>
<p>An administrative screen asking for a new root password will appear in the
middle of the package installation process. Enter your chosen new password
twice and the installation will continue.</p>
<p><img src="/source/static/img/160528-mysql-ubuntu-1604/new-root-password.png" width="100%" class="technical-diagram img-rounded"></p>
<p>In a moment the installation will finish and you'll be back at the command
prompt.</p>
<p><img src="/source/static/img/160528-mysql-ubuntu-1604/apt-finished.png" width="100%" class="technical-diagram img-rounded"></p>
<p>MySQL is now installed with a root user. However, we do not want to have our
applications connect to the database with that user, so next we will
create a new non-root user.</p>
<h2>Securing MySQL</h2>
<p>MySQL is installed with a basic configuration meant for development and testing
purposes. However, the configuration is not secure for production enviroments,
therefore it comes with a utility to handle basic security. Run the
following command and answer the questions based on your environment
requirements.</p>
<div class="highlight"><pre>sudo mysql_secure_installation
</pre></div>
<p>When you finish running the script you should see the following output and
be back at the command prompt.</p>
<p><img src="/source/static/img/160528-mysql-ubuntu-1604/mysql-secure-installation.png" width="100%" class="technical-diagram img-rounded"></p>
<p>Our MySQL instance has basic security in place but we need to create a
non-root user for applications to interact with the database.</p>
<h2>Creating MySQL Users</h2>
<p>To create a non-root user, connect to the MySQL instance with the
<code>mysql</code> command line client.</p>
<div class="highlight"><pre>mysql -u root -p
</pre></div>
<p>Now use the <code>CREATE USER</code> command to generate a new user. Make sure to
change "mynewuser" and "goodPassword" with your own values.</p>
<div class="highlight"><pre>CREATE USER &#39;mynewuser&#39;@&#39;localhost&#39; IDENTIFIED BY &#39;goodPassword&#39;;
</pre></div>
<p>No output after the command is good - that means the command succeeded.</p>
<p><img src="/source/static/img/160528-mysql-ubuntu-1604/create-user.png" width="100%" class="technical-diagram img-rounded"></p>
<p>We need to apply privileges to the new user so it can handle basic database
operations. Again, make sure to replace the default username in this command
with your new username.</p>
<div class="highlight"><pre>GRANT ALL PRIVILEGES ON * . * TO &#39;mynewuser&#39;@&#39;localhost&#39;;
</pre></div>
<p><img src="/source/static/img/160528-mysql-ubuntu-1604/grant-all.png" width="100%" class="technical-diagram img-rounded"></p>
<p>It's a good idea to reload the privileges to make sure our new user's
permissions are in place.</p>
<div class="highlight"><pre>FLUSH PRIVILEGES;
</pre></div>
<p>Now that our permissions are reloaded we can connect with the new user.</p>
<h2>New User Connection</h2>
<p>We're set to connect to the database with our new user. Exit the MySQL
client with "Ctrl-d". Reconnect using a slightly different command than
we used earlier.</p>
<div class="highlight"><pre>mysql -u mynewuser -p
</pre></div>
<p><img src="/source/static/img/160528-mysql-ubuntu-1604/mysql-new-user.png" width="100%" class="technical-diagram img-rounded" alt="Connect to MySQL as the new user we just created."></p>
<p>Create a new database with the <code>CREATE DATABASE</code> command.</p>
<div class="highlight"><pre>CREATE DATABASE fullstackpython;
</pre></div>
<p><img src="/source/static/img/160528-mysql-ubuntu-1604/create-database.png" width="100%" class="technical-diagram img-rounded" alt="Create a new MySQL database with our new user."></p>
<p>Connect to the new database with the <code>USE</code> command.</p>
<div class="highlight"><pre>use fullstackpython;
</pre></div>
<p><img src="/source/static/img/160528-mysql-ubuntu-1604/use-command.png" width="100%" class="technical-diagram img-rounded" alt="Connect to the newly-created database with the USE command."></p>
<p>Create a simple new table with the <code>CREATE TABLE</code> command.</p>
<div class="highlight"><pre>CREATE TABLE pages (name VARCHAR(50), url VARCHAR(1024));
</pre></div>
<p>Our table is ready to go - we can interact with it using the
<code>SELECT</code>, <code>INSERT</code>, <code>UPDATE</code> and <code>DELETE</code> SQL commands.</p>
<h2>What's next?</h2>
<p>We now have our MySQL instance installed and ready for interaction.
Take a look at the <a href="/mysql.html">MySQL</a>,
<a href="/databases.html">relational databases</a> and
<a href="/object-relational-mappers-orms.html">object-relational mappers (ORMs)</a>
pages for more tutorials.</p>
<p>Questions? Tweet <a href="https://twitter.com/fullstackpython">@fullstackpython</a>
or post a message on the
<a href="https://www.facebook.com/fullstackpython">Full Stack Python Facebook page</a>.
Something wrong with this post? Fork
<a href="https://github.com/makaimc/fullstackpython.com/blob/gh-pages/source/content/posts/160528-install-mysql-ubuntu-1604.markdown">this page's source on GitHub</a>.</p></summary></entry><entry><title>Setting up PostgreSQL with Python 3 and psycopg on Ubuntu 16.04</title><link href="https://www.fullstackpython.com/postgresql-python-3-psycopg2-ubuntu-1604.html" rel="alternate"></link><updated>2016-05-18T00:00:00-04:00</updated><author><name>Matt Makai</name></author><id>tag:www.fullstackpython.com,2016-05-18:postgresql-python-3-psycopg2-ubuntu-1604.html</id><summary type="html"><p><a href="/postgresql.html">PostgreSQL</a> is a powerful open source
<a href="/databases.html">relational database</a> frequently used to create, read,
update and delete <a href="/web-frameworks.html">Python web application</a> data.
<a href="http://pythonhosted.org/psycopg2/">Psycopg2</a> is a PostgreSQL database
driver that serves as a Python client for access to the PostgreSQL server.
This post explains how to install PostgreSQL on <a href="/ubuntu.html">Ubuntu 16.04</a>
and run a few basic SQL queries within a Python program.</p>
<p>We won't cover
<a href="/object-relational-mappers-orms.html">object-relational mappers (ORMs)</a>
in this tutorial but these steps can be used as a prerequisite to working
with an ORM such as SQLAlchemy or Peewee.</p>
<h2>Tools We Need</h2>
<p>Our walkthrough should work with either <a href="/python-2-or-3.html">Python 2 or 3</a>
although all the steps were tested specifically with Python 3.5. Besides
the Python interpreter, here are the other components we'll use:</p>
<ul>
<li><a href="http://releases.ubuntu.com/16.04/">Ubuntu 16.04</a> (these
steps should also work fine with other Ubuntu versions)</li>
<li><a href="https://pip.pypa.io/en/stable/">pip</a> and
<a href="https://virtualenv.pypa.io/en/latest/">virtualenv</a> to handle the
<a href="https://pypi.python.org/pypi/psycopg2/2.6.1">psycopg2</a>
<a href="/application-dependencies.html">application dependency</a></li>
<li><a href="http://www.postgresql.org/">PostgreSQL</a></li>
</ul>
<p>If you aren't sure how how to install pip and virtualenv, review the
first few steps of the
<a href="/blog/python-3-bottle-gunicorn-ubuntu-1604-xenial-xerus.html">how to set up Python 3, Bottle and Green Unicorn on Ubuntu 16.04 LTS</a>
guide.</p>
<h2>Install PostgreSQL</h2>
<p>We'll install PostgreSQL via the <code>apt</code> package manager. There are a few
packages we need since we want to both run PostgreSQL and use the psycopg2
driver with our Python programs. PostgreSQL will also be installed as a
system service so we can start, stop and reload its configuration when
necessary with the <code>service</code> command. Open the terminal and run: </p>
<div class="highlight"><pre>sudo apt-get install postgresql libpq-dev postgresql-client postgresql-client-common
</pre></div>
<p>Enter your <code>sudo</code> password when prompted and enter 'yes' when <code>apt</code> asks
if you want to install the new packages.</p>
<p><img src="/source/static/img/160518-postgresql-ubuntu-1604/apt-get-postgresql.png" width="100%" class="technical-diagram img-rounded"></p>
<p>After a few moments <code>apt</code> will finish downloading, installing and
processing.</p>
<p><img src="/source/static/img/160518-postgresql-ubuntu-1604/apt-get-postgresql-done.png" width="100%" class="technical-diagram img-rounded"></p>
<p>We now have PostgreSQL installed and the PostgreSQL service is running
in the background. However, we need to create a user and a database instance
to really start using it. Use the <code>sudo</code> command to switch to the new
"postgres" account.</p>
<div class="highlight"><pre>sudo -i -u postgres
</pre></div>
<p>Within the "postgres" account, create a user from the command line with the
<code>createuser</code> command. PostgreSQL will prompt you with several questions.
Answer "n" to superuser and "y" to the other questions.</p>
<div class="highlight"><pre>createuser matt -P --interactive
</pre></div>
<p><img src="/source/static/img/160518-postgresql-ubuntu-1604/createuser.png" width="100%" class="technical-diagram img-rounded"></p>
<p>Awesome, now we have a PostgreSQL user that matches our Ubuntu login
account. Exit out of the postgres account by pressing the "Ctrl" key along
with "d" into the shell. We're back in our own user account.</p>
<p>Create a new database we can use for testing. You can name it "testpython"
or whatever you want for your application.</p>
<div class="highlight"><pre>createdb testpython
</pre></div>
<p>Now we can interact with "testpython" via the PostgreSQL command line tool.</p>
<h2>Interacting with PostgreSQL</h2>
<p>The <code>psql</code> command line client is useful for connecting directly to our
PostgreSQL server without any Python code. Try out <code>psql</code> by using this
command at the prompt: </p>
<div class="highlight"><pre>psql
</pre></div>
<p>The PostgreSQL client will connect to the localhost server. The client is
now ready for input:</p>
<p><img src="/source/static/img/160518-postgresql-ubuntu-1604/postgresql-cli.png" width="100%" class="technical-diagram img-rounded"></p>
<p>Try out PostgreSQL's command prompt a try with commands such as <code>\dt</code> and
<code>\dd</code>. We can also run SQL queries such as "SELECT * from testpython",
although that won't give us back any data yet because we have not inserted