Source

JythonBook / JythonIDE.rst

Full commit
june...@gmail.co… 28b0486 

june...@gmail.co… 604a3bc 











































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































   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
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
Chapter 11:  Using Jython in an IDE
+++++++++++++++++++++++++++++++++++

In this chapter, we will discuss developing Jython applications
using two of the most popular integrated development environments,
Eclipse and Netbeans. There are many other development environments
available for Python and Jython today; however, these two are
perhaps the most popular and contain the most Jython-specific
tools. Eclipse has had a plug-in known as PyDev for a number of
years, and this plug-in provides rich support for developing and
maintaining Python and Jython applications alike. Netbeans began to
include Python and Jython support with version 6.5 and later. The
Netbeans IDE also provides rich support for development and
maintenance of Python and Jython applications.

Please note that in this chapter we will refer to Python/Jython as
Jython. All of the IDE options discussed are available for both
Python and Jython unless otherwise noted. For readability and
consistency sake, we'll not refer to both Python and Jython
throughout this chapter unless there is some feature that is not
available for Python or Jython specifically. Also note that we will
call the plug-ins discussed by their names, so in the case of
Netbeans the plug-in is called Netbeans Python Plug-in. This
plug-in works with both Python and Jython in all cases.

Eclipse
=======

Naturally, you will need to have Eclipse installed on your machine
to use Jython with it. The latest available version when this book
is being written is Eclipse 3.5 (also known as Eclipse Galileo),
and it is the recommended version to use to follow this section.
Versions 3.2, 3.3, and 3.4 will work, too, although there will be
minor user interface differences which may confuse you while
following this section.

If you don't have Eclipse installed on your machine, go to
www.eclipse.org/downloads and download the version for Java
developers.

Installing PyDev
----------------

Eclipse doesn't include built-in Jython support. Thus, we will use
PyDev, an excellent plug-in which adds support for the Python
language and includes specialized support for Jython. PyDev's home
page is http://pydev.org, but you won't need to manually download
and install it.

To install the plug-in, start Eclipse and go to Help>Install new
Software..., and type http://pydev.org/updates into the 'Work with'
input box. Press Enter. After a short moment, you will see an entry
for PyDev in the bigger box below. Just select it, clicking on the
checkbox that appears at the left of PyDev (see Figure 11-1), and
then click the Next button.

.. image:: images/chapter11-pydev-installation-1.png
   :alt: PyDev Installation
Figure 11-1. Installing PyDev

After this, just follow the wizard, read the license agreement,
and, if you agree with the Eclipse Public License v1.0, accept it.
Then click the Finish button.

Once the plug-in has been installed by Eclipse, you will be asked
if you want to restart the IDE to enable the plug-in. As that is
the recommended option, do so. Once Eclipse restarts itself, you
will enjoy full Python support on the IDE.

Minimal Configuration
---------------------

Before starting a PyDev project you must tell PyDev which Python
interpreters are available. In this context, an interpreter is just
a particular installation of some implementation of Python. When
starting you will normally only need one interpreter, and for this
chapter we will only use Jython 2.5.1. To configure it, open the
Eclipse Preferences dialog (via Windows>Preferences in the main
menu bar). On the text box located at the top of the left panel
(called 'Filter text'), type 'Jython.' This will filter the myriad
of Eclipse (and PyDev!) options and will present us with a much
simplified view, in which you will spot the 'Interpreter – Jython'
section on the left.

Once you have selected the 'Interpreter – Jython' section, you will
be presented with an empty list of Jython interpreters at the top
of the right side. We clearly need to fix that! So, click the New
button, enter 'Jython 2.5.1' as the Interpreter Name, click Browse,
and find jython.jar inside your Jython 2.5.1 installation.

.. note::

    Even if this is the only runtime we will use in this
    chapter, we recommend you use a naming schema like the one proposed
    here, including both the implementation name (Jython) and the full
    version (2.5.1) on the interpreter name. This will avoid confusion
    and name clashing when adding new interpreters in the future.

After selecting the jython.jar file, PyDev will automatically
detect the default, global sys.path entries. PyDev always infer the
right values, so unless you have very special needs, just accept
the default selection and click OK.
   
If all has gone well, you will now see an entry on the list of
Jython interpreters, representing the information you just entered.
It will be similar to Figure 11-2 (of course, your filesystem paths
will differ).

.. image:: images/chapter11-pydev-configuration-1.png
   :alt: PyDev Configuration: Jython Interpreter
Figure 11-2. List of Jython interpreters

That's all. Click OK and you will be ready to develop with Jython
while enjoying the support provided by a modern IDE.

If you are curious, you may want to explore the other options found
on the Preferences window, below the PyDev section (after clearing
the search filter we used to quickly go to the Jython interpreter
configuration). But in our experience, it's rarely needed to change
most of the other options available.

In the next sections we will take a look to the more important
PyDev features to have a more pleasant learning experience and make
you more productive.

Hello PyDev!: Creating Projects and Executing Modules
-----------------------------------------------------

Once you see the first piece of example code on this chapter, it
may seem overly simplistic. It is, indeed, a very dumb example. The
point is to keep the focus on the basic steps you will perform for
the lifecycle of any Python-based project inside the Eclipse IDE,
which will apply to simple and complex projects. So, as you
probably guessed, our first project will be a Hello World. Let's
start it!

Go to File>New >Project. You will be presented with a potentially
long list of all the kinds of projects you can create with Eclipse.
Select PyDev Project under the PyDev group (you can also use the
filter text box at the top and type 'PyDev Project' if it's faster
for you).

The next dialog will ask you for your project properties. As the
project name, we will use LearningPyDev. In the 'Project contents'
field, check the 'Use default' checkbox, so PyDev will create a
directory with the same name as the project inside the Eclipse
workspace (which is the root path of your eclipse projects).
Because we are using Jython 2.5.1, we will change the project type
to Jython and the grammar version to 2.5. We will leave the
Interpreter alone, which will default to the Jython interpreter we
just defined on the Minimal Configuration section. We will also
leave checked the 'Create default 'src' folder and add it to the
pythonpath' option, because it's a common convention on Eclipse
projects.

After you click Finish, PyDev will create your project, which will
only contain an empty src directory and a reference to the
interpreter being used. Let's create our program now.

Right-click on the project, and select New>PyDev Module. Leave the
Package blank and enter 'main' in the Name field. PyDev offers some
templates to speed up the creation of new modules, but we won't use
them, as our needs are rather humble. So leave the Template field
empty and click Finish.

PyDev will present you an editor for the main.py file it just
created. It's time to implement our program. Write the following
code in the editor:

Listing 11-1.
::
    
    if __name__ == "__main__":
        print "Hello PyDev!"



and then press Ctrl + F11 to run this program. Select Jython Run
from the dialog presented and click OK. The program will run and
the text 'Hello PyDev!' will appear on the console, located on the
bottom area of the IDE.

.. note::
    
    When describing the hotkeys (such as Ctrl + F11 for
    'Jython Run'), we're using the PC keyboard convention. Mac
    users should press the Command key instead of Ctrl for all the
    hotkeys listed on this chapter, unless otherwise noted.

If you manually typed the program, you probably noted that the IDE
knows that in Python a line ending in ':' marks the start of a
block and will automatically put your cursor at the appropriate
level of indentation in the next line. See what happens if you
manually override this decision and put the print statement at the
same indentation level of the if statement and save the file. The
IDE will highlight the line flagging the error. If you hover at the
error mark, you will see the explanation of the error, as seen in
Figure 11-3.

.. image:: images/chapter11-pydev-editing-1.png
   :alt: PyDev Highlighting a Simple Error
Figure 11-3. Error explanation appears when you hover over the
error mark.

Expect the same kind of feedback for whatever syntax error you
made. It helps to avoid the frustration of going on edit-run loops
only to find further minor syntax errors.

Passing Command-line Arguments and Customizing Execution
--------------------------------------------------------

Command line arguments may seem old fashioned, but they are
actually a very simple and effective way to let programs interact
with the outside. Because you have learned to use Jython as a
scripting language, it won't be uncommon to write scripts that will
take their input from the command line (note that for unattended
execution, reading input from the command line is way more
convenient that obtaining data from the standard input, let alone
using a GUI).

As you have probably guessed, we will make our toy program to take
a command line argument. The argument will represent the name of
the user to greet, to build a more personalized solution. Here is
how our main.py should look:

Listing 11-2.
::
    
    import sys
    if __name__ == "__main__":
        if len(sys.argv) < 2:
            print "Sorry, I can't greet you if you don't say your name"
        else: 
            print "Hello %s!" % sys.argv[1]


If you hit Ctrl + F11 again, you will see the 'Sorry I can't greet
you...' message on the console. It makes sense, because you didn't
pass the name. Not to say that it was your fault, as you didn't
have a chance to say your name.

To specify command line arguments, go to the Run>Run Configurations
menu, and you will find an entry named 'LearningPyDev main.py' in
the Jython Run section on the left. It will probably be already
selected, but if it's not, select it manually. Then, on the main
section of the dialog, you will find ways to customize the
execution of our script. You can change aspects such as the current
directory, pass special argument to the JVM, change the interpreter
to use, set environment variables, and so on. We just need to
specify an argument, so let's type 'Bob' in the 'Program arguments'
box and click Run.

As you'd expect, the program now prints 'Hello Bob!' on the
console. Note that the value you entered is remembered; that is, if
you press Ctrl + F11 now, the program will print 'Hello Bob!'
again. Some people may point out that this behavior makes testing
this kind of program very awkward, because the Run Configurations
dialog will have to be opened each time the arguments need to be
changed. But if we really want to test our programs (which is a
good idea), we should do it in the right way. We will look into
that soon, but first let's finish our tour on basic IDE features.

Playing with the Editor
-----------------------

Let's extend our example code a bit more, providing different ways
to greet our users, in different languages. We will use the
optparse module to process the arguments this time. Refer to
Chapter 9 if you want to remember how to use optparse. We will also
use decorators (seen in Chapter 4) to make it trivial to extend our
program with new ways to greet our users. So, our little
main.py has grown a bit now.

Listing 11-3.
::
    
    # -*- coding: utf-8 -*-
    import sys
    from optparse import OptionParser
    
    greetings = dict(en=u'Hello %s!',
                     es=u'Hola %s!',
                     fr=u'Bonjour %s!',
                     pt=u'Alò %s!')
    
    uis = {}
    def register_ui(ui_name):
        def decorator(f):
            uis[ui_name] = f
            return f
        return decorator
    
    def message(ui, msg):
        if ui in uis:
            uis[ui](msg)
        else:
            raise ValueError("No greeter named %s" % ui)
        
    def list_uis():
        return uis.keys()
    
    @register_ui('console')
    def print_message(msg):
        print msg
    
    @register_ui('window')
    def show_message_as_window(msg):
        from javax.swing import JFrame, JLabel
        frame = JFrame(msg,
                       defaultCloseOperation=JFrame.EXIT_ON_CLOSE,
                       size=(100, 100),
                       visible=True)
        frame.contentPane.add(JLabel(msg))
            
    if __name__ == "__main__":
        parser = OptionParser()
        parser.add_option('--ui', dest='ui', default='console', 
                          help="Sets the UI to use to greet the user. One of: %s" %
                          ", ".join("'%s'" % ui for ui in list_uis()))
        parser.add_option('--lang', dest='lang', default='en',
                          help="Sets the language to use")
        options, args = parser.parse_args(sys.argv)
        if len(args) < 2:        
            print "Sorry, I can't greet you if you don't say your name"
            sys.exit(1)
        
        if options.lang not in greetings:
            print "Sorry, I don't speak '%s'" % options.lang
            sys.exit(1)
        
        msg = greetings[options.lang] % args[1] 
        
        try:
            message(options.ui, msg)
        except ValueError, e:
            print "Invalid UI name\n"    
            print "Valid UIs:\n\n" + "\n".join(' * ' + ui for ui in list_uis())
	    sys.exit(1)



Take a little time to play with this code in the editor. Try
pressing Ctrl + Space (don't change Ctrl with Command if you are
using Mac OS X; this hotkey is the same on every platform), which
is the shortcut for automatic code completion (also known as
Intellisense in Microsoft's parlance) on different locations. It
will provide completion for import statements (try completing that
line just after the import token, or in the middle of the
OptionParser token) and attribute or method access (like on
sys.exit or parser.add_option or even in
JFrame.EXIT_ON_CLOSE which is accessing a Java class!) It also
provides hints about the parameters in the case of methods.

In general, every time you type a dot, the automatic completion
list will pop up, if the IDE knows enough about the symbol you just
typed to provide help. But you can also call for help at any point.
For example, go to the bottom of the code and type 'message(.'
Suppose you just forgot the order of the parameters to that
function. Solution: Press Ctrl + Space and PyDev will complete the
statement, using the name of the formal parameters of the
function.

Also try Ctrl + Space on keywords like 'def.' PyDev will provide
you little templates that may save you some typing. You can
customize the templates on the PyDev>Editor>Templates section of
the Eclipse Preferences window (available on the Window>Preferences
main menu).

The other thing you may have noted now that we have a more sizable
program with some imports, functions, and global variables is that
the Outline panel on the right side of the IDE window shows a
tree-structure view of code being edited showing such features. It
also displays classes, by the way.

And don't forget to run the code! Of course, it's not really
spectacular to see that after pressing Ctrl + F11 we still get the
same boring 'Hello Bob!' text on the console. But if you edit the
command line argument (via the Run Configurations dialog) to the
following: 'Bob --lang es --ui window,' you will get a nice window
greeting Bob in Spanish. Also see what happens if you specify a non
supported UI (say, --ui speech) or an unsupported language. We even
support the --help! So we have a generic, polyglot greeter which
also happens to be reasonably robust and user friendly (for command
line program standards that is).

At this point you are probably tired of manually testing the
program editing the command line argument on that dialog. Just one
more section and we will see a better way to test our program using
the IDE. Actually, part of the next section will help us move
toward the solution.

A Bit of Structure: Packages, Modules, and Navigation
-----------------------------------------------------

If you like simplicity you may be asking (or swearing, depending on
your character) why we over-engineered the last example. There are
simpler (in the sense of a more concise and understandable code)
solutions to the same problem statement. But we needed to grow the
toy code to explore another aspect of IDEs, which for some people
are a big reason to use them: organizing complex code bases. And
you don't expect me to put a full-blown Pet Store example in this
book to get to that point, do you?

So, let's suppose that the complications we introduced (mainly the
registry of UIs exposed via decorators) are perfectly justified,
because we are working on a slightly complicated problem. In other
words: let's extrapolate.

The point is, we know that the great majority of our projects can't
be confined to just one file (one Python module). Even our very
dumb example is starting to get unpleasant to read. And, when we
realize that we need more than one module, we also realize we need
to group our modules under a common umbrella, to keep it clear that
our modules form a coherent thing together and to lower the chances
of name clashing with other projects. So, as seen in Chapter 8, the
Python solution to this problem is modules and packages.

Our plan is to organize the code as follows: everything will go
under the package 'hello.' The core logic, including the language
support, will go into the package itself (into its __init__.py
file) and each UI will go into its own module under the 'hello'
package. The main.py script will remain as the command line entry
point.

Right-click on the project and select New>PyDev Package. Enter
'hello' as the Name and click Finish. PyDev will create the package
and open an editor for its __init.py__ file. As we said, we
will move the core logic to this package, so this file will contain
the following code, extracted from our previous version of the main
code:

Listing 11-4.
::
    
    # -*- coding: utf-8 -*-
    greetings = dict(en=u'Hello %s!',
                     es=u'Hola %s!',
                     fr=u'Bonjour %s!',
                     pt=u'Alò %s!')
    
    class LanguageNotSupportedException(ValueError): 
        pass
    
    class UINotSupportedExeption(ValueError):
        pass
    
    uis = {}
    def register_ui(ui_name):
        def decorator(f):
            uis[ui_name] = f
            return f
        return decorator
    
    def message(ui, msg):
        '''
        Displays the message `msg` via the specified UI which has to be
	previously registered.
        '''
        if ui in uis:
            uis[ui](msg)
        else:
            raise UINotSupportedExeption(ui)
        
    def list_uis():
        return uis.keys()
    
    def greet(name, lang, ui):
        '''
        Greets the person called `name` using the language `lang` via the 
        specified UI which has to be previously registered.
        '''
        if lang not in greetings:
            raise LanguageNotSupportedException(lang)
        message(ui, greetings[lang] % name)



Note that we embraced the idea of modularizing our code, providing
exceptions to notify clients of problems when calling the greeter,
instead of directly printing messages on the standard output.

Now we will create the hello.console module containing the console
UI. Right-click on the project, select New>PyDev Module, Enter
'hello' as the Package and 'console' as the Name. You can avoid
typing the package name if you right-click on the package instead
of the project. Click Finish and copy the print_message
function there:

Listing 11-5.
::
    
    from hello import register_ui
    
    @register_ui('console')
    def print_message(msg):
        print msg



Likewise, create the window module inside the hello package, and
put there the code for show_message_as_window:

Listing 11-6.
::
    
    from javax.swing import JFrame, JLabel
    from hello import register_ui

    @register_ui('window')
    def show_message_as_window(msg):
        frame = JFrame(msg,
                       defaultCloseOperation=JFrame.EXIT_ON_CLOSE,
                       size=(100, 100),
                       visible=True)
        frame.contentPane.add(JLabel(msg))



Finally, the code for our old main.py is slightly reshaped into the
following:

Listing 11-7.
::
    
    import sys
    import hello, hello.console, hello.window 
    from optparse import OptionParser
            
    def main(args):
        parser = OptionParser()
        parser.add_option('--ui', dest='ui', default='console', 
                          help="Sets the UI to use to greet the user. One of: %s" %
                          ", ".join("'%s'" % ui for ui in list_uis()))
        parser.add_option('--lang', dest='lang', default='en',
                          help="Sets the language to use")
        options, args = parser.parse_args(args)
        if len(args) < 2:        
            print "Sorry, I can't greet you if you don't say your name"
            return 1    
        try:
            hello.greet(args[1], options.lang, options.ui)        
        except hello.LanguageNotSupportedException:
            print "Sorry, I don't speak '%s'" % options.lang
            return 1
        except hello.UINotSupportedExeption:
            print "Invalid UI name\n"    
            print "Valid UIs:\n\n" + "\n".join(' * ' + ui for ui in hello.list_uis())
            return 1
        return 0
        
    if __name__ == "__main__":
        main(sys.argv)

.. tip:: 

   Until now, we have used PyDev's wizards to create new modules and
   packages. But, as you saw on Chapter 7, modules are just files with the
   ``.py`` extension located on the ``sys.path`` or inside packages, and
   packages are just directories that happen to contain a ``__init__.py``
   file. So you may want to create modules using :menuselection:`New --> File`
   and packages using :menuselection:`New --> Folder` if you don't like the
   wizards.


Now we have our code split over many files. On a small project,
navigating through it using the left-side project tree (called the
PyDev Package Explorer) isn't difficult, but you can imagine that
on a project with dozens of files it would be. So we will see some
ways to ease the navigation of a code base.

First, let's suppose you are reading main.py and want to jump to
the definition of the hello.greet function, called on line 17.
Instead of manually changing to such a file and scanning until
finding the function, just press Ctrl and click greet. PyDev will
automatically move you into the definition. This also works on most
variables and modules (try it on the import statements, for
example).

Another good way to quickly jump between files without having to
resort to the Package Explorer is to use Ctrl + Shift + R, which is
the shortcut for "Open Resource". Just type (part of) the file name
you want to jump to and PyDev will search on every package and
directory of your open projects.

Now that you have many files, note that you don't need to
necessarily have the file you want to run opened and active on the
editor. For every script you run (using the procedure in which you
need to be editing the program and then press Ctrl + F11) the IDE
will remember that such script is something you are interested in
running and will add it to the "Run History". You can access the
"Run History" on the main menu under Run -> Run History, or in the
dropdown button located in the main toolbar, along the green "play"
icon. In both places you will find the latest programs you ran, and
many times using this list and selecting the script you want to
re-run will be more convenient than jumping to the script on the
editor and then pressing Ctrl + F11.

Finally, the IDE internally records a history of your "jumps"
between files, just like a web browser do for web pages you visit.
And just like a web browser you can go back and forward. To do
this, use the appropriate button on the toolbar or the default
shortcuts which are Ctrl + Left and Ctrl + Right.

Testing
-------

Okay, it's about time to explore our options to test our code,
without resorting to the cumbersome manual black box testing we
have been doing changing the command line argument and observing
the output.

PyDev supports running PyUnit tests from the IDE, so we will write
them. Let's create a module named tests on the hello package with
the following code:

Listing 11-8.
::
    
    import unittest
    import hello
    class UIMock(object):
        def __init__(self):
            self.msgs = []
        def __call__(self, msg):
            self.msgs.append(msg)
    class TestUIs(unittest.TestCase):
        def setUp(self):
            global hello
            hello = reload(hello)
            self.foo = UIMock()
            self.bar = UIMock()
            hello.register_ui('foo')(self.foo)
            hello.register_ui('bar')(self.bar)
            hello.message('foo', "message using the foo UI")
            hello.message('foo', "another message using foo")
            hello.message('bar', "message using the bar UI")
        def testBarMessages(self):
            self.assertEqual(["message using the bar UI"],
    self.bar.msgs)
        def testFooMessages(self):
            self.assertEqual(["message using the foo UI",
                              "another message using foo"],
                              self.foo.msgs)
        def testNonExistentUI(self):
            self.assertRaises(hello.UINotSupportedExeption,
                              hello.message, 'non-existent-ui', 'msg')
        def testListUIs(self):
            uis = hello.list_uis()
            self.assertEqual(2, len(uis))
            self.assert_('foo' in uis)
            self.assert_('bar' in uis)



As you can see, the test covers the functionality of the
dispatching of messages to different UIs. A nice feature of PyDev
is the automatic discovery of tests, so you don't need to code
anything else to run the previous tests. Just right-click on the
src folder on the Package Explorer and select Run As>Jython
unit-test. You will see the output of the test almost immediately
on the console:

Listing 11-9.
::
    
    Finding files...
    ['/home/lsoto/eclipse3.5/workspace-jythonbook/LearningPyDev/src/']
    ... done
    Importing test modules ... done.
    testBarMessages (hello.tests.TestUIs) ... ok
    testFooMessages (hello.tests.TestUIs) ... ok
    testListUIs (hello.tests.TestUIs) ... ok
    testNonExistentUI (hello.tests.TestUIs) ... ok
    ----------------------------------------------------------------------
    Ran 4 tests in 0.064s
    OK


Python's unittest is not the only testing option on the Python
world. A convenient way to do tests which are more black-box-like
than unit test, though equally automated is doctest.

.. note::
    
    We will cover testing tools in much greater detail in
    Chapter 18, so take a look at that chapter if you feel too
    disoriented.


The nice thing about doctests is that they look like an interactive
session with the interpreter, which makes them quite legible and
easy to create. We will test our console module using a doctest.

First, click the right-most button on the console's toolbar (you
will recognize it as the one with a plus sign on its upper
left-hand corner, which has the Open Console tip when you pass the
mouse over it). From the menu, select PyDev Console. To the next
dialog, answer Jython Console. After doing this you will get an
interactive interpreter embedded on the IDE.

Let's start exploring our own code using the interpreter:

Listing 11-10.
::
    
    >>> from hello import console
    >>> console.print_message("testing")
    testing



We highly encourage you to type those two commands yourself. You
will note how code completion also works on the interactive
interpreter!

Back to the topic, we just interactively checked that our console
module works as expected. The cool thing is that we can copy and
paste this very snippet as a doctest that will serve to
automatically check that the behavior we just tested will stay the
same in the future.

Create a module named doctests inside the 'hello' package and paste
those three lines from the interactive console, surrounding them by
triple quotes (because they are not syntactically correct Python
code after all). After adding a little of boilerplate to make this
file executable, it will look like this:

Listing 11-11.
::
    
    
    """
    >>> from hello import console
    >>> console.print_message("testing")
    testing
    """
    if __name__ == "__main__":
        import doctest
        doctest.testmod(verbose=True)



After doing this, you can run this test via the Run>Jython
run*menu* while doctests.py is the currently active file on the
editor. If all goes well, you will get the following output:

Listing 11-12.
::
    
    Trying:
        from hello import console
    Expecting nothing
    ok
    Trying:
        console.print_message("testing")
    Expecting:
        testing
    ok
    1 items passed all tests:
       2 tests in __main__
    2 tests in 1 items.
    2 passed and 0 failed.
    Test passed.


After running the doctest you will notice that your interactive
console has gone away, replaced by the output console showing the
test results. To go back to the interactive console, look for the
console button in the console tab toolbar, exactly at the left of
the button you used to spawn the console. Then on the drop-down
menu select the PyDev Console, as shown in Figure 11-4.

.. image:: images/chapter11-pydev-console-select.png
   :alt: Bringing back the interactive console.
   
Figure 11-4. Selecting PyDev Console

As you can see, you can use the interactive console to play with
your code, try ideas, and test them. And later a simple test can be
made just by copying and pasting text from the same interactive
console session. Of special interest is the fact that, because
Jython code can access Java APIs quite easily, you can also test
classes written with Java in this way.

Adding Java Libraries to the Project
------------------------------------

Finally, we will show you how to integrate Java libraries into your
project. We said some pages ago that we could add a 'speech'
interface for our greeter. It doesn't sound like a bad idea after
all, because (like with almost any aspect) the Java world has good
libraries to solve that problem.

We will use the FreeTTS library, which can be downloaded from
http://freetts.sourceforge.net/docs/index.php. (You should download
the binary version.)

After downloading FreeTTS, you will have to extract the archive on
some place on your hard disk. Then, we will import a JAR file from
FreeTTS into our PyDev project.

Right-click the project and select Import. Then choose General>File
System and browse to the directory in which you expanded FreeTTS
and select it. Finally, expand the directory on the left side panel
and check the lib subdirectory. See Figure 11-5.

.. image:: images/chapter11-pydev-importing-freetts.png
   :alt: Importing ``freetts.jar`` into the PyDev Project
   
Figure 11-5. Adding Java libraries to the project

After clicking Finish, you will see that the files are now part of
your project.

.. tip::
    
    Alternatively, and depending on your operating system, the
    same operation can be performed copying the files or folders from
    the file manager and pasting it into the project (either via menu,
    keyboard shortcuts, or drag and drop).

Now, the files are part of the project, but we need to tell PyDev
that lib/freetts.jar is a JAR file and should be added to the
sys.path of our project environment. To do this, right-click on the
project and select Properties. Then, on the left panel of the
dialog, select PyDev - PYTHONPATH. Then click the 'Add zip/jar/egg'
button and select the lib/freetts.jar file on the right side of the
dialog that will appear. Click OK on both dialogs and you are ready
to use this library from Python code.

The code for our new hello.speech module is as follows:

Listing 11-13.
::
    
    from com.sun.speech.freetts import VoiceManager
    from hello import register_ui
    @register_ui('speech')
    def speech_message(msg):
        voice = VoiceManager().getVoice("kevin16")
        voice.allocate()
        voice.speak(msg)
        voice.deallocate()



If you play with the code on the editor you will notice that PyDev
also provides completion for imports statement referencing the Java
library we are using.

Finally, we will change the second line of main.py from:

Listing 11-14.
::
    
    import hello, hello.console, hello.window

to

::
    
    import hello, hello.console, hello.window, hello.speech



in order to load the speech UI too. Feel free to power on the
speakers and use the --ui speech option to let the computer greet
yourself and your friends!

There you go, our humble greeter has finally evolved into a quite
interesting, portable program with speech synthesis abilities. It's
still a toy, but one which shows how quickly you can move with the
power of Jython, the diversity of Java, and the help of an IDE.

Debugging
=========

PyDev also offers full debugging capabilities for your Jython code.
To try it just put some breakpoints in your code by double-clicking
on the left margin of the editor, and then start your program using
the F11 shortcut instead of Ctrl + F11.


Once the debugger hits your breakpoint, the IDE will ask you to
change its perspective. This means it will change to a different
layout, better suited for debugging activities. Answer Yes and you
will find yourself on the debugging perspective, shown in Figure
11-6.

.. image:: images/chapter11-pydev-debug-session.png
   :alt: PyDev's Jython Debugger.
   
Figure 11-6. Debugging perspective

The perspective offers the typical elements of a debugger. In the
upper left area in the contents of the 'Debug' tab we have the call
stack for each running thread. Click on an item of the call to
navigate to the particular line of code which made the
corresponding call. The call stack view also has influence over
what is shown by the Variables panel on the upper right-hand area,
which lists all the current local and global variables. You can
'drill down' on every non-primitive value to see its components, as
a tree. By default the variables shown are from the point of view
of the code being currently executed. But if we select a different
element on the call stack in the left area it will show the
variables for the line of code associated with that particular
stack frame.

Also in the same upper right-hand area there is the Breakpoints
tab, which is quite useful for taking a global look at all the
breakpoints defined. Clicking on the breakpoint entry will navigate
the code editor to the associated line of code, of course. And you
can disable, enable, and remove breakpoints by right-clicking on
the entries.

The rest of the elements are already known: the central area is
filled by the main editor (using less space this time to make room
for the extra tools) and its outline, while the output console
takes the lower area.

Once you reach a breakpoint you can control the execution, by using
Step Into (F5) to go into the code of the next function call, Step
Over (F6) to run the current line and stop again, Step Return
(F7) to execute the remaining code of the current function, and
Resume Execution (F8) to let the program continue running until the
next breakpoint is reached (or the program finishes).

Once you finish your debugging session, you can go back to the
normal editing perspective by selecting PyDev on the upper
right-hand area of the main IDE Window (which will have the Debug
button pushed while staying in the debugging perspective).

Conclusion about Eclipse
------------------------

PyDev is a very mature plug-in for the Eclipse platform, which can
be an important element in your toolbox. Automatic completion and
suggestions help a lot when learning new APIs (both Python APIs and
Java APIs!) especially if paired with the interactive console. It
is also a good way to introduce a whole team into Jython or into a
specific Jython project, because the project-level configuration
can be shared via normal source control systems. Not to mention
that programmers coming from the Java world will find themselves
much more comfortable on a familiar environment.

To us, IDEs are a useful part of our toolbox, and tend to shine on
big codebases and/or complex code which we may not completely
understand yet. Powerful navigation and refactoring abilities are
key to the process of understanding such projects and are features
that should only improve in the future. Even if the refactoring
capabilities are not still as complete as the state of the art on
Java IDEs, we encourage you to try them on PyDev: 'Extract local
variable,' 'Inline local variable,' and 'Extract method' are quite
useful. Even if the alternative of doing the refactor manually
isn't as painful with Python as with Java (or any other statically
typed language without type inference), when the IDE can do the
right thing for you and avoid some mechanical work, you will be
more productive.

Finally, the debugging capabilities of PyDev are superb and will
end your days of using print as a poor man's debugger (seriously,
we did that for a while!) Even more advanced Python users who
master the art of import pdb; pdb.set_trace() should give it a
try.

Now, PyDev isn't the only IDE available for Jython. If you are
already using the Netbeans IDE or didn't like Eclipse or PyDev for
some reason, take a look at the rest of this chapter, in which we
will cover the Netbeans plug-in for Python development.

Netbeans
========

The Netbeans integrated development environment has been serving
the Java community well for over ten years now. During that time,
the tool has matured quite a bit from what began as an ordinary
Java development tool into what is today an advanced development
and testing environment for Java and other languages alike. As Java
and JavaEE application development still remain an integral part of
the tool, other languages such as JRuby, Python, Groovy, and Scala
have earned themselves a niche in the tool as well. Most of these
languages are supported as plug-ins to the core development
environment, which is what makes Netbeans such an easy IDE to
extend, as it is very easy to build additional features to
distribute. The Python support within Netbeans began as a small
plug-in known as nbPython, but it has grown into a fully featured
Python development environment and it continues to grow.

The Netbeans Python support provides developers with all of the
expected IDE features, such as code completion, color-coding, and
easy runtime development. It also includes some nice advanced
features for debugging applications and the like.

IDE Installation and Configuration
==================================

The first step for installing the Netbeans Python development
environment is to download the current release of the Netbeans IDE.
At the time of this writing, Netbeans 6.7.1 is the most recent
release, but 6.8 is right around the corner. You can find the IDE
download by going to the web site www.netbeans.org and clicking on
the download link. Once you do so, you'll be presented with plenty
of different download options. These are variations of the IDE that
are focused on providing different features for developers
depending upon what they will use the most. Nobody wants a bulky,
memory-hungry development tool that will overhaul a computer to the
extreme. By providing several different configurations of the IDE,
Netbeans gives you the option to leave off the extras and only
install those pieces that are essential to your development. The
different flavors for the IDE include Java SE, Java, Ruby, C/C++,
PHP, and All. For those developers only interested in developing
core Java applications, the Java SE download would suffice.
Likewise, someone interested in any of the other languages could
download the IDE configuration specific to that language. For the
purposes of this book and in our everyday development, we use the
All option, because as we enjoy having all of the options
available. However, there are options available for adding features
if you download only the Java SE or another low-profile build and
wish to add more later.

At the time of this writing, there is also a link near the top of
the downloads page for PythonEA distribution. If that link or a
similar Python Netbeans distribution link is available, then you
can use it to download and install just the Jython-specific
features of the Netbeans IDE. We definitely do not recommend taking
this approach unless you plan to purely code Python applications
alone. It seems to us that a large population of the Jython
developer community also codes some Java, and may even integrate
Java and Jython within their applications. If this is the case, you
will want to have the Java-specific features of Netbeans available
as well. That is why we do not recommend the Python-only
distribution for Jython developers, but the choice is there for you
to make.

Now that you've obtained the IDE, it is important to take a look at
the license. Python support for Netbeans is licensed under CDDL
version 1.0, so it may be a good idea to take a look at that as
well. It is easy to install in any environment using the intuitive
Netbeans installer. Perhaps the most daunting task when using a new
IDE is configuring it for your needs. This should not be the case
with Netbeans though because the configuration for Java and Python
alike are quite simple. For instance, if you working with the
fully-featured installation, you will already have application
servers available for use as Netbeans installs Glassfish by
default. Note that it is a smart idea to change that admin password
very soon after installation in order to avoid any potentially
embarrassing security issues.

When the IDE initially opens up, you are presented with a main
window that includes links to blogs and articles pertaining to
Netbeans features. You also have the standard menu items available
such as File, Edit, Tools, and so on. In this chapter we will
specifically cover the configuration and use of the Jython
features; however, there are very useful tutorials available online
and in book format for covering other Netbeans features. One thing
you should note at this point is that with the initial
installation, Python/Jython development tools are not yet installed
unless you chose to install the PythonEA distribution. Assuming
that you have installed the full Netbeans distribution, you will
need to add the Python plug-in via the Netbeans plug-in center. You
will need to go to the Tools menu and then open the Plug-ins
submenu. From there, you should choose the Available Plug-ins tab
and sort by category. Select all of the plug-ins in the Python
category and then install. This option will install the Python
plug-in as well as a distribution of Jython. You will need to
follow on-screen directions to complete the installation.

Once the plug-in has been successfully installed then it is time to
configure your Python and Jython homes. To do so, go to the Tools
menu and then open the Python Platforms menu as this will open the
platform manager for Python/Jython. At the time of this writing,
the default Jython version that was installed with the Python
plug-in was 2.5+. You most likely have your own Jython installation
by now that includes additional packages that you may wish to use.
As this is the case, go ahead and add your
Jython installation as a platform option and make it the default
(see Figure 11-7).

.. image:: images/chapter11-nbplatformmgr.jpg
   :alt: Netbeans Python Platform Manager.
   
Figure 11-7. Adding your Jython installation as a platform option
and making it the default

To do so, click on the New button underneath the platform listing.
You can try to select the Auto Detect option, but we did not have
luck with Netbeans finding our Jython installation using it. If you
choose the New button, then you will be presented with a file
chooser window. You should choose the Jython executable that
resides in the area <JYTHON_HOME>/bin and all of the other
necessary fields will auto-populate with the correct values. Once
completed, choose the Close button near the bottom of the Python
Platform Manager window. You are now ready to start programming
with Python and Jython in Netbeans.

Advanced Python Options
=======================

If you enter the Netbeans preferences window you will find some
more advanced options for customizing your Python plug-in. If you
go to the Editor tab, you can set up Python specific options for
formatting, code templates, and hints. In doing so, you can
completely customize the way that Netbeans displays code and offers
assistance when working with Jython. You can also choose to set up
different fonts and coloring for Python code by selecting the Fonts
and Colors tab. This is one example of just how customizable
Netbeans really is because you can set up different fonts and
colors for each language type.

If you choose the Miscellaneous tab you can add different file
types to the Netbeans IDE and associate them with different IDE
features. If you look through the pull-down menu of files, you can
see that files with the extension of py**or pyc are associated as
Python files. This ensures that files with the associated
extensions will make use of their designated Netbeans features. For
instance, if we wanted to designate**a different extension on some
Jython-related files*,* we could easily do so and associate this
extension with Python files in Netbeans. Of course, we do not
recommend doing so, as Jython will not import files with unknown
extensions! Once we've made this association then we can create
files with an extension of that we've added and use them within
Netbeans just as if they were Python files. Lastly, you can alter a
few basic options such as enabling prompting for python program
arguments, and changing debugger port and shell colors from the
Python tab in Netbeans preferences.

General Python Usage
====================

As stated previously in the chapter, there are a number of options
when using the Netbeans Python solution. There are a few different
selections that can be made when creating a new Python project. You
can either choose to create a Python Project*or*Python Project with
Existing Sources. These two project types are named quite
appropriately, as a Python Project will create an empty project;
once created it is easy to develop and maintain applications and
scripts alike. Moreover, you can debug your application via the
Python debugger as derived from Jean-Yves Mengant's jpydbg
debugger, and have Netbeans create tests if you choose to do so.
One of the first nice features you will notice right away is the
syntax coloring in the editor.

Standalone Jython Apps
======================

In this section, we will discuss how to develop a standalone Jython
application within Netbeans. We will use a variation of the
standard HockeyRoster application that we have used in other places
throughout the book. Overall, the development of a stand-alone
Jython application in Netbeans differs very little from a
stand-alone Java application. The main difference is that you will
have different project properties and other options available that
pertain to creating Jython projects. And obviously you will be
developing in Jython source files along with all of the
color-coding and code completion, and other options that the Python
plug-in has to offer.

To get started, go ahead and create a new Python Project by using
the File menu or the shortcut in the Netbeans toolbar. For the
purposes of this section, name the new project HockeyRoster.
Uncheck the option to Create Main File, as we will do this
manually. Once your project has been created, explore some of the
options you have available by right-clicking (Ctrl-click) on the
project name. The resulting menu should allow you the option to
create new files, run, debug, or test your application, build eggs,
work with code coverage, and more. At this point you can also
change the view of your Python packages within Netbeans by choosing
the 'View Python Packages as' option. This will allow you the
option to either see the application in list or tree mode, your
preference. You can search through your code using the Find option,
share it on Kenai with the integrated Netbeans Kenai support, look
at the local file history, or use your code with a version control
system.

.. note::
    
    In case you are not familiar with project Kenai, it is
    an online service started by Sun Microsystems for hosting open
    source projects and code. For more information, go to www.kenai.com
    and check it out.

Click on the Properties option and the Project Properties
window should appear. From within the Project Properties window,
there are options listed on the left-hand side including
Source*,*Python*,*Run*,*and Formatting. The Source option provides
the ability to change source location or add new source locations
to your project. The Test Root Folders section within this option
allows you to add a location where Python tests reside so that you
can use them with your project. The Python option allows you to
change your Python platform and add locations, JARs, and files to
your Python path. Changing your Python platform provides a handy
ability to test your program on Jython and Python alike, if you
want to ensure that your code works on each platform. The Run
option provides the ability to add or change the Main module, and
add application arguments. Lastly, the Formatting option allows you
to specify different formatting options in Netbeans for this
particular project. This is great, because each different project
can have different colored text, and so on, depending upon the
options chosen.

At this point, create the Main module for the HockeyRoster
application. Go to File>New and right-clicking (Cntrl-click) on the
project, or use the toolbar icon. From here you can either create
an Executable Module, Module, Empty Module, Python Package, or Unit
Test. Choose to create an Executable Module and name the main file
HockeyRoster.py*,* and keep in mind that when we created the
project we had the ability to have the IDE generate this file for
us but we chose to decline. Personally, we like to organize our
projects using the Python packaging system. Create some packages
now using the same process that you used to create a file and name
the package jythonbook. Once created, drag your HockeyRoster.py
module into the jythonbook package to move it into place. Note that
you can also create several packages at the same time by naming a
package like jythonbook.features or something of the like*,*which
will create both of the resulting packages.

The HockeyRoster**main module will be the implementation module for
our application, but we still need somewhere to store each of the
player's information. For this, we will create a module named
Player. Go ahead and create an Empty Module named Player within the
same jythonbook package. Now we will code the Player class for our
project. To do so, erase the code that was auto-generated by
Netbeans in the Player.py module and type the following. Note that
you can change the default code that is created when generating a
new file by changing the template for Python applications.

Listing 11-15.
::
    
    # Player.py
    # Container to hold player information
    class Player:
    
        def __init__(self, id, first, last, position):
            self.id = id
            self.first = first
            self.last = last
            self.position = position
           
        def add_assist(self):
            self.assists = assists + 1

The first thing to note is that Netbeans will maintain your
indentation level. It is also easy to decrease the indentation
level by using the SHIFT + TAB keyboard shortcut. Using the default
environment settings, the keywords should be in a different color
(blue by default) than the other code. Method names will be in
bold, and references to self or variables will be in a different
color as well. You should notice some code completion, mainly the
automatic self placement after you type a method name and then the
right parentheses. Other subtle code completion features also help
to make our development lives easier. If you make an error,
indentation or otherwise, you will see a red underline near the
error, and a red error badge on the line number within the
left-hand side of the editor. Netbeans will offer you some
assistance in determining the cause of the error if you hover your
mouse over the red error badge or underline.

Now that we have coded the first class in our stand-alone Jython
application, it is time to take a look at the implementation code.
The HockeyRoster.py module is the heart of our roster application,
as it controls what is done with the team. We will use the shelve
technique to store our Player objects to disk for the roster
application. As you can see from the following code, this is a very
basic application and is much the same as the implementation that
will be found in the next chapter using Hibernate persistence.

Listing 11-16.
::
    
    # HockeyRoster.py
    #
    # Implementation logic for the HockeyRoster application
    
    # Import Player class from the Player module
    from Player import Player
    
    # Import shelve for storage to disk
    import shelve
    
    class HockeyRoster:
        def __init__(self):
            self.player_data = shelve.open("players")
    
        def make_selection(self):
            '''
            Creates a selector for our application.  The function prints output to the
            command line.  It then takes a parameter as keyboard input at the command
            line in order to choose our application option.
            '''
            options_dict = {1:self.add_player,
                            2:self.print_roster,
                            3:self.search_roster,
                            4:self.remove_player}
            print "Please chose an option\\n"
    
            selection = raw_input('''Press 1 to add a player, 2 to print the roster,
                                  3 to search for a player on the team,
                                  4 to remove player, 5 to quit: ''')
            if int(selection) not in options_dict:
                if int(selection) == 5:
                    print "Thanks for using the HockeyRoster application."
                else:
                    print "Not a valid option, please try again\\n"
                    self.make_selection()
            else:
                func = options_dict[int(selection)]
                if func:
                    func()
                else:
                    print "Thanks for using the HockeyRoster application."
    
        def add_player(self):
            '''
            Accepts keyboard input to add a player object to the roster list.
            This function creates a new player object each time it is invoked
            and appends it to the list.
            '''
            add_new = 'Y'
            print "Add a player to the roster by providing the following information\\n"
    
            while add_new.upper() == 'Y':
                first = raw_input("First Name: ")
                last = raw_input("Last Name: ")
                position = raw_input("Position: ")
    
                id = self.return_player_count() + 1
                print id
                #set player and shelve
                player = Player(id, first, last, position)
                self.player_data[str(id)] = player
    
    
                print "Player successfully added to the roster\\n"
                add_new = raw_input("Add another? (Y or N)")
    
            self.make_selection()
    
        def print_roster(self):
            '''
            Prints the contents of the list to the command line as a report
            '''
            print "====================\\n"
            print "Complete Team Roster\\n"
            print "======================\\n\\n"
            player_list = self.return_player_list()
            for player in player_list:
                print "%s %s - %s" % (player_list[player].first,
                        player_list[player].last, player_list[player].position)
            print "\\n"
            print "=== End of Roster ===\\n"
            self.make_selection()
    
        def search_roster(self):
            '''
            Takes input from the command line for a player's name to search within the
            roster list.  If the player is found in the list then an affirmative message
            is printed.  If not found, then a negative message is printed.
            '''
            index = 0
            found = False
            print "Enter a player name below to search the team\\n"
            first = raw_input("First Name: ")
            last = raw_input("Last Name: ")
            position = None
            player_list = self.return_player_list()
    
            for player_key in player_list:
                player = player_list[player_key]
                if player.first.upper() == first.upper() and \\
                   player.last.upper() == last.upper():
                    position = player.position
    
            if position:
                print '%s %s is in the roster as %s' % (first, last, position)
            else:
                print '%s %s is not in the roster.' % (first, last)
            self.make_selection()
    
        def remove_player(self):
            '''
            Removes a player from the list
            '''
            index = 0
            found = False
            print "Enter a player name below to remove them from the team roster\\n"
            first = raw_input("First Name: ")
            last = raw_input("Last Name: ")
            position = None
            player_list = self.return_player_list()
            found_player = None
    
            for player_key in player_list:
                player = player_list[player_key]
                if player.first.upper() == first.upper() and \\
                   player.last.upper() == last.upper():
                    found_player = player
                    break
    
            if found_player:
                print '''%s %s is in the roster as %s,
                         are you sure you wish to remove?''' % (found_player.first,
                                                                found_player.last,
                                                                found_player.position)
                yesno = raw_input("Y or N")
                if yesno.upper() == 'Y':
                    # remove player from shelve
                    print 'The player has been removed from the roster',
                    found_player.id
                    del(self.player_data[str(found_player.id)])
                else:
                    print 'The player will not be removed'
            else:
                print '%s %s is not in the roster.' % (first, last)
            self.make_selection()
    
        def return_player_list(self):
            return self.player_data
    
        def return_player_count(self):
            return len(self.player_data)
    
    # main
    #
    # This is the application entry point.  It simply prints the applicaion title
    # to the command line and then invokes the makeSelection() function.
    if __name__ == "__main__":
        print "Hockey Roster Application\\n\\n"
        hockey = HockeyRoster()
        hockey.make_selection()

The code should be relatively easy to follow at this point in the
book. The main function initiates the process as expected, and as
you see it either creates or obtains a reference to the shelve or
dictionary where the roster is stored. Once this occurs the
processing is forwarded to the make_selection() function that
drives the program. The important thing to note here is that, when
using Netbeans, the code is laid out nicely, and that code
completion will assist with imports and completion of various code
blocks. To run your program, you can either right-click
(Ctrl+click) on the project or set the project as the main project
within Netbeans and use the toolbar or pull-down menus. If
everything has been set up correctly, you should see the program
output displaying in the Netbeans output window. You can interact
with the output window just as you would with the terminal.

Jython and Java Integrated Apps
===============================

Rather than repeat the different ways in which Jython and Java can
be intermixed within an application, this section will focus on how
to do so from within the Netbeans IDE. There are various approaches
that can be taken in order to perform integration, and this section
will not cover all of them. However, the goal is to provide you
with some guidelines and examples to use when developing integrated
Jython and Java applications within Netbeans.

Using a JAR or Java Project in Your Jython App
----------------------------------------------

Making use of Java from within a Jython application is all about
importing and ensuring that you have the necessary Java class files
and/or JAR files in your classpath. In order to achieve this
technique successfully, you can easily ensure that all of the
necessary files will be recognized by the Netbeans project.
Therefore, the focus of this section is on using the Python project
properties to set up the sys.path for your project. To follow
along, go ahead and use your HockeyRoster Jython project that was
created earlier in this section.

Let's say that we wish to add some features to the project that are
implemented in a Java project named HockeyIntegration that we are
coding in Netbeans. Furthermore, let's assume that the
HockeyIntegration Java project compiles into a JAR file. Let's set
up the HockeyIntegration project by choosing New>Project. When the
New Project window appears, select Java as the category, and Java
Application as the project and click Next. Now make sure you name
your application HockeyIntegration and click Finish. See Figure
11-8.

Your java application is now created and you are ready to begin
development. In order to use this project from within our
HockeyRoster project, you'll need to open up the project properties
by right-clicking on your Jython project and choosing the
Properties option. Once the window is open, click on the Python
menu item on the left-hand side of the window. This will give you
access to the sys.path so you can add other Python modules, eggs,
Java classes, JAR files, and so on. Click on the Add button and
then traverse to the project directory for the Java application you
are developing. Once there, go to the dist directory and select the
resulting JAR file and click OK. You can now use any of the Java
project's features from within your Jython application.


.. image:: Ch11JuneauJythonIDE_files/image016.png

Figure 11-8.

If you are interested in utilizing a Java API that exists within
the standard Java library, then you are in great shape. As you
should know by now, Jython automatically provides access to the
entire Java standard library. You merely import the Java classes
that you wish to use within your Jython application and begin
using, nothing special to set up within Netbeans. At the time of
this writing, the Netbeans Python EA did not support import
completion for the standard Java library. However, we suspect that
this feature will be added in a subsequent release.


Using Jython in Java
--------------------

If you are interested in using Jython or Python modules from within
your Java applications, Netbeans makes it easy to do. As mentioned
in Chapter 10, the most common method of utilizing Jython from Java
is to use the object factory pattern. However, there are other ways
to do this, such as using the clamp project, which is not yet
production-ready at the time of writing. For the purposes of this
section, we'll discuss how to utilize another Netbeans Jython
project as well as other Jython modules from within your Java
application using the object factory pattern.

In order to effectively demonstrate the use of the object factory
pattern from within Netbeans, we'll be making use of the PlyJy
project, which provides object factory implementations that can be
used out of the box. If you haven't done so already, go to the
Project Kenai site find the PlyJy project and download the provided
JAR. We will use the Netbeans project properties window in our Java
project to add this JAR file to our project. Doing so will
effectively diminish the requirement of coding any object factory
implementations by hand and we'll be able to directly utilize
Jython classes in our project.

Create a Java project named ObjectFactoryExample by selecting
New>Project>Java Application. Once you've done so, right-click
(Cntrl+click) on the project and choose Properties. Once the
project properties window appears, click the Libraries option on
the left-hand side. From there, add the PlyJy JAR file that you
previously downloaded to your project classpath. You will also have
to add the jython.jar file for the appropriate version of Jython
that you wish to use. In our case, we will utilize the Jython 2.5.1
release. See Figure 11-9.



.. image:: Ch11JuneauJythonIDE_files/image018.png
Figure 11-9. Adding the JAR file

The next step is to ensure that any and all Jython modules that you
wish to use are in your CLASSPATH somewhere. This can be easily
done by either adding them to your application as regular code
modules somewhere and then going into the project properties window
and including that directory in the Compile-Time Libraries list
contained the Libraries section, or by clicking the Add JAR/Folder
button. Although this step may seem unnecessary because the modules
are already part of your project, it must be done in order to place
them into your CLASSPATH. Once they've been added to the
CLASSPATH successfully, you can begin to make use of them via the
object factory pattern. Netbeans will seamlessly use the modules in
your application as if all of the code was written in the same
language. At this point your project should be set up and ready for
using object factories. To learn more about using object factories,
please refer to Chapter 10.

The Netbeans Python Debugger
============================

As mentioned previously, the Netbeans IDE also includes a Python
debugger that is derived from Jean-Yves Mengant's jpydbg debugger.
This section will discuss how to make use of the Netbeans Python
debugger along with some examples using our HockeyRoster code that
was written in the previous section. If you have used a debugger in
another IDE, or perhaps the Java debugger that is available for
Netbeans, this debugger will feel quite familiar. The Python
debugger includes many features such as breakpoints, run-time local
variable values, code stepping, and more.


Prior to using the debugger, it may be useful to take a look at the
debugger preferences by navigating to the Netbeans
Preferences>Python Options>Debugger window. From there you will see
that you have the ability to change the debugger port, code
coloring for debugging sessions, and to stop at the first line of
the script or continue until the debugger reaches the first
breakpoint. To make the debugger feel and act similar to the
Netbeans Java debugger, you may want to de-select the 'Stop at the
first line' checkbox. Otherwise the debugger will not load your
module right away, but rather stop execution at the first line of
your module and wait for you to continue. See Figure 11-10.

.. image:: Ch11JuneauJythonIDE_files/image020.png
Figure 11-10. The Netbeans Python debugger

Making use of the Python debugger included with Netbeans is much
like working from the Jython interactive interpreter from the
command-line or terminal window. If you have selected the 'Stop at
first line' checkbox in the debugger preferences, the debugger will
halt at the first line of code in your main module and you must use
the debugger Continue button to move to the first line of code that
is executed. However, if you have de-selected the checkbox, then
the module will automatically run your program until it reaches the
first breakpoint. For the purposes of this exercise, let's keep the
checkbox selected. In order to set a breakpoint, click on the
margin to the left of the line in your code where you would like
the debugger to halt program execution. In our case, let's open the
HockeyRoster.py module and set a breakpoint in the code as shown in
Figure 11-11.

.. image:: Ch11JuneauJythonIDE_files/image022.png
Figure 11-11. Setting a breakpoint in the code


Now that we've set a breakpoint, we need to start our debugger.
However, prior to debugging it is important to make sure that
Netbeans knows which module to use for starting the program. To do
so, right-click on your project and select Properties. When the
properties window opens, select Run in the left-hand side of the
window. You should now type or browse to the module that you wish
to use as a starting point for your program. See Figure 11-12.

.. image:: Ch11JuneauJythonIDE_files/image024.png

Figure 11-12. Click Browse to select the module you wish to use as
a starting point.

Note that this may already be automatically filled in for you by
Netbeans. Once you've ensured that you have set the main module,
you can begin the debugging session. To do so, you can either
select your program and use the Debug menu option, or you can
right-click on the project and select Debug. Once you've started
the debugger, you will see a series of messages appearing in the
debugging window near the bottom of the IDE window to indicate that
the debugger has been started. After a few seconds, you will see
the messages stop writing in the debugger output window, and the
editor will focus on the first line of code in your main module and
highlight it in green. See Figure 11-13.

.. image:: Ch11JuneauJythonIDE_files/image026.png
Figure 11-13. Beginning the debugging session

To continue the debugger to the first line of code that is
executed, select the green Continue button in the toolbar, or press
the F5 key. You should see the program will begin to execute within
the debugger output window and it will halt to allow us to enter a
selection. See Figure 11-14.



.. image:: Ch11JuneauJythonIDE_files/image028.png
Figure 11-14. The debugger output window

Make sure your cursor is within the debugger output window and
enter 1 to add a player. When you hit the Enter button to continue,
the program will not continue to execute, but instead it will halt
at the breakpoint that we have set up. In the editor you will see
the line which we added a breakpoint to is now highlighted in
green. The debugger has suspended state at this point in the
program, and this affords us the ability to perform tasks to see
exactly what is occurring at this point in the program. For
instance, if you select the Variables tab in the lower portion of
the Netbeans IDE, you will be able to see the values of all local
variables at this current point in the program. See Figure 11-15.

.. image:: Ch11JuneauJythonIDE_files/image030.png
Figure 11-15. The values of all local variables at this current
point in the program

You can also select the Call Stack tab to see the execution order
of your program to this point. See Figure 11-16.

.. image:: Ch11JuneauJythonIDE_files/image032.png
Figure 11-16. The execution order of your program

Once you've evaluated the program at the breakpoint, you can
continue the program execution by stepping forward through the code
using the buttons in the toolbar. You can also click the Continue
button to run the program until it reaches the next breakpoint, or
in this case because we have no more breakpoints, it will just
continue the program execution as normal. The debugger is
especially helpful if you are attempting to evaluate a specific
line of code or portion of your program by stepping through the
code and executing it line by line.


Another nice feature of the debugger is that you can set certain
conditions on breakpoints. To do so, set a breakpoint in your code
and then right-click on the breakpoint and select Breakpoint and
then Properties from the resulting window. At this point you will
see the additional breakpoint options. In this case, set up a
condition that will cause the debugger to halt only if the
*selection* variable is equal to 3, as shown in Figure 11-17.

.. image:: Ch11JuneauJythonIDE_files/image034.png

Figure 11-17. Setting a condition for halting the debugger

At this point you can run the debugger again, and if you select the
option of 3 during your program execution you will notice that the
debugger will halt.

The Netbeans Python debugger offers enough options to fill up an
entire chapter worth of reading, but hopefully the content covered
in this section will help you get started. Once you've mastered the
use of the debugger, it can save you lots of time.

Other Netbeans Python Features
==============================

There are a number of additional features in the Netbeans Python
IDE support that we haven't touched upon yet. For instance, minimal
refactoring support is available for any Python module. By
right-clicking on the module in the project navigator or within a
module, a bevy of additional options become available to you via
the right-click menu. You'll see that there is a Refactoring option
that becomes available. However at the time of this writing the
only available refactoring options were Rename, Move, Copy, and
Safely Delete. There is a Navigate feature that allows for one to
perform shortcuts such as highlighting a variable and finding its
declaration. The Navigate feature also allows you to jump to any
line in your code by simply providing a line number. If your Python
class is inheriting from some other object, you can use the
Navigate feature to quickly go to the super implementation. It is
easy to find the usages of any Python module, method, function, or
variable by using the Find Usages feature. If your code is not
formatted correctly, you can quickly have the IDE format it for you
by choosing the Format option, which is also available in the
right-click menu.

Another nice feature that is available in the right-click menu is
Insert Code. This feature allows you to choose from a number of
different templates in order to have the IDE auto-generate code for
you. Once you select the Insert Code option, another menu appears
allowing you to choose from a code templates including Property,
Constructor, Method, and Class. Once a template is chosen, the IDE
auto-generates the code to create a generic Python property,
constructor, method, or class. You can then refine the
automatically generated code to your needs. This feature allows the
developer to type less, and if used widely throughout a program it
can ensure that code is written in a consistent manner. See Figure
11-18.

.. image:: Ch11JuneauJythonIDE_files/image036.png

Figure 11-18. The very handy Insert Code option

Another nice feature is Fast Import. This allows you to highlight
an object in your code and automatically have the IDE import the
required module for using the object. You also have the ability to
Fix Imports, which will automatically clean up unused imports in
your code.

Along with all of the other features that are available with the
Netbeans IDE, these additional features are like the icing on the
cake! Keep in mind that you are not required to right-click each
time that you wish to use one of these additional features, there
are also keyboard shortcuts for each of them. The keyboard
shortcuts will differ depending upon which operating system you are
using.

Summary
=======

As with most other programming languages, you have several options
to use for an IDE when developing Jython. In this chapter we
covered two of the most widely used IDE options for developing
Jython applications, Netbeans and Eclipse. Eclipse offers a truly
complete IDE solution for developing Jython applications, both
stand alone and web-based. PyDev is under constant development and
always getting better, adding new features and streamlining
existing features.

Netbeans Jython support is in still in development at the time of
this writing. Many of the main features such as code completion and
syntax coloring are already in place. It is possible to develop
Jython applications including Jython and Java integration as well
as web-based applications. In the future, Netbeans Jython support
will develop to include many more features and they will surely be
covered in future releases of this book.

In the next chapter, we will take a look at developing some
applications utilizing databases. The zxJDBC API will be covered
and you'll learn how to develop Jython applications utilizing
standard database transactions. Object relational mapping is also
available for Jython in various forms, we'll discuss many of those
options as well.




.. |image0| image:: Ch11JuneauJythonIDE_files/image002.png
.. |image1| image:: Ch11JuneauJythonIDE_files/image004.png
.. |image2| image:: Ch11JuneauJythonIDE_files/image006.png
.. |image3| image:: Ch11JuneauJythonIDE_files/image008.png
.. |image4| image:: Ch11JuneauJythonIDE_files/image010.png
.. |image5| image:: Ch11JuneauJythonIDE_files/image012.png
.. |image6| image:: Ch11JuneauJythonIDE_files/image014.png
.. |image7| image:: Ch11JuneauJythonIDE_files/image016.png
.. |image8| image:: Ch11JuneauJythonIDE_files/image018.png
.. |image9| image:: Ch11JuneauJythonIDE_files/image020.png
.. |image10| image:: Ch11JuneauJythonIDE_files/image022.png
.. |image11| image:: Ch11JuneauJythonIDE_files/image024.png
.. |image12| image:: Ch11JuneauJythonIDE_files/image026.png
.. |image13| image:: Ch11JuneauJythonIDE_files/image028.png
.. |image14| image:: Ch11JuneauJythonIDE_files/image030.png
.. |image15| image:: Ch11JuneauJythonIDE_files/image032.png
.. |image16| image:: Ch11JuneauJythonIDE_files/image034.png
.. |image17| image:: Ch11JuneauJythonIDE_files/image036.png