-
Notifications
You must be signed in to change notification settings - Fork 0
/
plugin.html
654 lines (614 loc) · 42.7 KB
/
plugin.html
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
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Plugins — HappyPanda X 0.13.3#170 documentation</title>
<link rel="stylesheet" href="_static/bootstrap-sphinx.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="_static/style.css" type="text/css" />
<script id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
<script src="_static/jquery.js"></script>
<script src="_static/underscore.js"></script>
<script src="_static/doctools.js"></script>
<script src="_static/language_data.js"></script>
<script src="https://platform.twitter.com/widgets.js"></script>
<script src="_static/script.js"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="next" title="TODO" href="todo.html" />
<link rel="prev" title="Creating frontends" href="client.html" />
<meta charset='utf-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge,chrome=1'>
<meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1'>
<meta name="apple-mobile-web-app-capable" content="yes">
<script type="text/javascript" src="_static/js/jquery-1.11.0.min.js "></script>
<script type="text/javascript" src="_static/js/jquery-fix.js "></script>
<script type="text/javascript" src="_static/bootstrap-3.3.7/js/bootstrap.min.js "></script>
<script type="text/javascript" src="_static/bootstrap-sphinx.js "></script>
</head><body>
<div id="navbar" class="navbar navbar-default navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<!-- .btn-navbar is used as the toggle for collapsed navbar content -->
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="index.html"><span><img src="_static/hpx_logo.svg"></span>
HappyPanda X</a>
<span class="navbar-text navbar-version pull-left"><b>0.13.3#170</b></span>
</div>
<div class="collapse navbar-collapse nav-collapse">
<ul class="nav navbar-nav">
<li class="dropdown globaltoc-container">
<a role="button"
id="dLabelGlobalToc"
data-toggle="dropdown"
data-target="#"
href="index.html">Contents <b class="caret"></b></a>
<ul class="dropdown-menu globaltoc"
role="menu"
aria-labelledby="dLabelGlobalToc"><ul>
<li class="toctree-l1"><a class="reference internal" href="install.html">Installing</a></li>
<li class="toctree-l1"><a class="reference internal" href="usage.html">Using HappyPanda X</a></li>
<li class="toctree-l1"><a class="reference internal" href="usage.html#installing-plugins">Installing plugins</a></li>
<li class="toctree-l1"><a class="reference internal" href="usage.html#securing-happypanda-x">Securing HappyPanda X</a></li>
<li class="toctree-l1"><a class="reference internal" href="usage.html#exposing-happypanda-x">Exposing HappyPanda X</a></li>
<li class="toctree-l1"><a class="reference internal" href="translation.html">Translations</a></li>
<li class="toctree-l1"><a class="reference internal" href="settings.html">Settings</a></li>
<li class="toctree-l1"><a class="reference internal" href="switches.html">Command-Line Arguments</a></li>
<li class="toctree-l1"><a class="reference internal" href="faq.html">FAQ</a></li>
</ul>
<ul class="current">
<li class="toctree-l1"><a class="reference internal" href="env.html">Contributing</a></li>
<li class="toctree-l1"><a class="reference internal" href="env.html#editing-the-documentation">Editing the documentation</a></li>
<li class="toctree-l1"><a class="reference internal" href="client.html">Creating frontends</a></li>
<li class="toctree-l1 current"><a class="current reference internal" href="#">Plugins</a></li>
<li class="toctree-l1"><a class="reference internal" href="todo.html">TODO</a></li>
</ul>
<ul>
<li class="toctree-l1"><a class="reference internal" href="api_general.html">General</a></li>
<li class="toctree-l1"><a class="reference internal" href="api.html">Server API</a></li>
<li class="toctree-l1"><a class="reference internal" href="api_plugin.html">Plugin API</a></li>
</ul>
</ul>
</li>
<li>
<a href="client.html" title="Previous Chapter: Creating frontends"><span class="glyphicon glyphicon-chevron-left visible-sm"></span><span class="hidden-sm hidden-tablet">« Creating frontends</span>
</a>
</li>
<li>
<a href="todo.html" title="Next Chapter: TODO"><span class="glyphicon glyphicon-chevron-right visible-sm"></span><span class="hidden-sm hidden-tablet">TODO »</span>
</a>
</li>
</ul>
<form class="navbar-form navbar-right" action="search.html" method="get">
<div class="form-group">
<input type="text" name="q" class="form-control" placeholder="Search" />
</div>
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div>
</div>
<ul class="quick-links">
<li>
<strong>Quick links</strong>
</li>
<li class="quick-link">
<a class="github-button" href="https://github.com/twiddli" aria-label="Follow @twiddli on GitHub">Follow @twiddli</a>
</li>
<li class="quick-link">
<a class="github-button" href="https://github.com/happypandax/happypandax/issues" data-icon="octicon-issue-opened" data-show-count="true" aria-label="Issue happypandax/happypandax on GitHub">Issue</a>
</li>
<li class="divider">·</li>
<li class="quick-link">
<a class="github-button" href="https://github.com/happypandax/happypandax" data-icon="octicon-star" data-show-count="true" aria-label="Star happypandax/happypandax on GitHub">Star</a>
</li>
<li class="quick-link">
<a class="github-button" href="https://github.com/happypandax/happypandax/fork" data-icon="octicon-repo-forked" data-show-count="true" aria-label="Fork happypandax/happypandax on GitHub">Fork</a>
</li>
<li class="divider">·</li>
<li class="quick-link">
<a href="https://twitter.com/twiddly_"
class="twitter-follow-button" data-width="145px"
data-link-color="#0069D6" data-show-count="false">
Follow
@twiddly_
</a>
</li>
<li class="quick-link">
<a href="https://twitter.com/share" class="twitter-share-button"
data-url="" data-count="horizontal"
data-via="twbootstrap"
data-related="twiddly_:Creator of HappyPanda X">Tweet</a>
</li>
</ul>
<div class="container">
<div class="row">
<div class="col-md-3">
<div id="sidebar" class="bs-sidenav" role="complementary"><ul>
<li><a class="reference internal" href="#">Plugins</a><ul>
<li><a class="reference internal" href="#terminology">Terminology</a></li>
<li><a class="reference internal" href="#defining-a-plugin">Defining a plugin</a></li>
<li><a class="reference internal" href="#writing-a-plugin">Writing a plugin</a><ul>
<li><a class="reference internal" href="#interfacing-with-hpx">Interfacing with HPX</a></li>
<li><a class="reference internal" href="#logging-and-errors">Logging and errors</a></li>
<li><a class="reference internal" href="#debugging">Debugging</a></li>
<li><a class="reference internal" href="#testing">Testing</a></li>
<li><a class="reference internal" href="#about-thread-safety">About thread safety</a></li>
<li><a class="reference internal" href="#how-to-not-break-stuff">How to not break stuff</a></li>
<li><a class="reference internal" href="#importing-modules-and-packages">Importing modules and packages</a><ul>
<li><a class="reference internal" href="#importing-external-packages">Importing external packages</a></li>
</ul>
</li>
</ul>
</li>
<li><a class="reference internal" href="#available-packages">Available packages</a></li>
</ul>
</li>
</ul>
</div>
</div>
<div class="col-md-9 content">
<div class="section" id="plugins">
<h1>Plugins<a class="headerlink" href="#plugins" title="Permalink to this headline">¶</a></h1>
<p>HPX is built in a way that makes it possible to step in and modify the way a functionality works or even add new ones with ease through plugins.</p>
<p>Plugins are written in <code class="docutils literal notranslate"><span class="pre">Python</span> <span class="pre">3.6</span></code>.</p>
<p>Here you will learn how to create a HPX plugin and use it to extend HPX.
Before that though, here are some new terminologies to learn before diving in to help us better understand how everything is screwed together.</p>
<div class="section" id="terminology">
<h2>Terminology<a class="headerlink" href="#terminology" title="Permalink to this headline">¶</a></h2>
<p><strong>Command</strong>:</p>
<blockquote>
<div><p>Besides some core features that makes everything play nice together, a <strong>command</strong> is essentially what <em>a feature</em> in HPX is.
An example of a command in HPX would be <code class="docutils literal notranslate"><span class="pre">AddGallery</span></code>. This command, like its name implies, adds a gallery into HPX.
<strong>Commands</strong> are self-contained and can act as a building-block for other commands (used by another command).
Many of the functionalities provided by HPX are built up by using many different <strong>commands</strong>. These commands can range from being very simple doing just one small job
to being complex and doing something big.</p>
</div></blockquote>
<p><strong>Command entry</strong>:</p>
<blockquote>
<div><p>This is what allows <strong>commands</strong> to be extensible. An <strong>entry</strong> allows other code to step in and run.
In plugin terms, it’s what allows a plugin handler to step in and run its code to either modify the process or do something else entirely.
<strong>Command entries</strong> are defined by <strong>commands</strong> and it’s up to a command when and how an <strong>entry</strong> is used.</p>
</div></blockquote>
<p><strong>Command event</strong>:</p>
<blockquote>
<div><p>A <strong>command event</strong> is almost like an <strong>entry</strong> with the difference that instead of modifying a process, a handler <em>reacts</em> to a process.
Like an <strong>entry</strong>, it’s up to a command when and to what an <strong>event</strong> is emitted.</p>
</div></blockquote>
</div>
<div class="section" id="defining-a-plugin">
<h2>Defining a plugin<a class="headerlink" href="#defining-a-plugin" title="Permalink to this headline">¶</a></h2>
<p>Now that we understand some basic concepts it’s time to create a plugin.</p>
<p>HPX makes it very easy to create and write a plugin.</p>
<p>Plugins are contained in their own folder, so we start by creating one for our plugin:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">-/..</span>
<span class="o">-</span><span class="n">MyPlugin</span><span class="o">/</span>
</pre></div>
</div>
<p>In this folder a manifest file named <code class="docutils literal notranslate"><span class="pre">hplugin.json</span></code> (case sensitive) is required:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">-/..</span>
<span class="o">-</span><span class="n">MyPlugin</span><span class="o">/</span>
<span class="o">-</span> <span class="n">hplugin</span><span class="o">.</span><span class="n">json</span>
</pre></div>
</div>
<p>A manifest file is a file describing a plugin. Inside <code class="docutils literal notranslate"><span class="pre">hplugin.json</span></code> is:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">{</span>
<span class="s2">"id"</span><span class="p">:</span> <span class="s2">"5c17829a-eca3-46fc-9d5e-da5804fdcbf5"</span><span class="p">,</span>
<span class="s2">"entry"</span><span class="p">:</span> <span class="s2">"main.py"</span><span class="p">,</span>
<span class="s2">"shortname"</span><span class="p">:</span> <span class="s2">"myplugin"</span><span class="p">,</span>
<span class="s2">"name"</span><span class="p">:</span> <span class="s2">"My Plugin"</span><span class="p">,</span>
<span class="s2">"author"</span><span class="p">:</span> <span class="s2">"Twiddly"</span><span class="p">,</span>
<span class="s2">"version"</span><span class="p">:</span> <span class="s2">"1.0.2b"</span><span class="p">,</span>
<span class="s2">"description"</span><span class="p">:</span> <span class="s2">"A hpx plugin"</span><span class="p">,</span>
<span class="s2">"test"</span><span class="p">:</span> <span class="s2">"test.py"</span><span class="p">,</span>
<span class="s2">"website"</span><span class="p">:</span> <span class="s2">"www.twiddly.moe"</span><span class="p">,</span>
<span class="s2">"require"</span><span class="p">:</span> <span class="p">[</span>
<span class="s2">"happypandax >= 0.0.0"</span>
<span class="p">]</span>
<span class="p">}</span>
</pre></div>
</div>
<ul>
<li><p><code class="docutils literal notranslate"><span class="pre">id</span></code>: A UUID4 string. Unique across all plugins. This attribute is required to be present.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">entry</span></code>: Path to the entry python file. Path is relative to this folder and must exist. This attribute is required to be present.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">shortname</span></code>: Your plugin name in short form. Must be all lowercase and cannot exceed <code class="docutils literal notranslate"><span class="pre">20</span></code> characters nor contain any whitespace. This attribute is required to be present.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">name</span></code>: Name of your plugin. This attribute is required to be present.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">author</span></code>: Name of plugin author. This attribute is required to be present.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">version</span></code>: A string of the version of your plugin. Must conform <span class="target" id="index-0"></span><a class="pep reference external" href="https://www.python.org/dev/peps/pep-0440"><strong>PEP 440</strong></a>. This attribute is required to be present.</p>
<blockquote>
<div><p>Examples of versioning that conforms <span class="target" id="index-1"></span><a class="pep reference external" href="https://www.python.org/dev/peps/pep-0440"><strong>PEP 440</strong></a>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="mf">1.0</span><span class="o">.</span><span class="n">dev456</span><span class="p">,</span> <span class="mf">1.0</span><span class="n">a1</span><span class="p">,</span> <span class="mf">1.0</span><span class="n">a2</span><span class="o">.</span><span class="n">dev1</span><span class="p">,</span> <span class="mf">1.0</span><span class="n">b1</span><span class="o">.</span><span class="n">dev4</span><span class="p">,</span> <span class="mf">1.0</span><span class="n">rc1</span><span class="p">,</span> <span class="mf">1.1</span><span class="o">.</span><span class="mi">0</span><span class="n">b2</span><span class="p">,</span> <span class="mf">1.1</span><span class="p">,</span> <span class="mf">1.1</span><span class="o">.</span><span class="mi">2</span>
</pre></div>
</div>
</div></blockquote>
</li>
<li><p><code class="docutils literal notranslate"><span class="pre">description</span></code>: A description of your plugin. This attribute is required to be present.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">test</span></code>: Path to the entry file for tests. Path is relative to this folder and must exist. This attribute is optional.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">website</span></code>: A url to a website for the plugin, author, etc. This attribute is optional.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">require</span></code>: A list of strings defining other plugins as dependencies. This attribute is optional.</p>
<blockquote>
<div><p>A requirement must conform <span class="target" id="index-2"></span><a class="pep reference external" href="https://www.python.org/dev/peps/pep-0508"><strong>PEP 508</strong></a> with a few exceptions.</p>
<p>Other plugins can be referred to by their id or shortname.</p>
<p>Examples of requirements that conforms <span class="target" id="index-3"></span><a class="pep reference external" href="https://www.python.org/dev/peps/pep-0508"><strong>PEP 508</strong></a>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="s2">"otherplugin"</span><span class="p">,</span>
<span class="s2">"5c17829a-eca3-46fc-9d5e-da5804fdcbf5 == 3"</span><span class="p">,</span>
<span class="s2">"otherplugin <= 1.2"</span><span class="p">,</span>
<span class="s2">"5c17829a-eca3-46fc-9d5e-da5804fdcbf5 >= 3"</span><span class="p">,</span>
<span class="s2">"otherplugin >= 3.6,<2"</span><span class="p">,</span>
<span class="s2">"otherplugin >= 3; os_name=='posix'"</span>
</pre></div>
</div>
<p>Notice the marker <code class="docutils literal notranslate"><span class="pre">os_name=='posix'</span></code> in the last example. In addition to the default markers defined in <span class="target" id="index-4"></span><a class="pep reference external" href="https://www.python.org/dev/peps/pep-0508"><strong>PEP 508</strong></a>, HPX defines <code class="docutils literal notranslate"><span class="pre">happypandax</span></code> or <code class="docutils literal notranslate"><span class="pre">hpx</span></code> to check against the running HPX version.
Markers can also be used freely like so:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="s2">"happypandax >= 1.5.3"</span><span class="p">,</span> <span class="c1"># indicates that this plugin requires this hpx version</span>
<span class="s2">"platform_system == 'Windows'"</span><span class="p">,</span> <span class="c1"># indicates that this plugin requires the windows platform</span>
<span class="s2">"otherplugin < 2; platform_system=='Windows'"</span><span class="p">,</span> <span class="c1"># indicates that otherplugin is only required on windows</span>
<span class="s2">"otherplugin > 2; platform_system=='Linux'"</span><span class="p">,</span> <span class="c1"># indicates that otherplugin is only required on linux</span>
<span class="s2">"otherplugin == 2; happypandax==1.2"</span> <span class="c1"># indicates that otherplugin is only required on hpx version 1.2</span>
</pre></div>
</div>
</div></blockquote>
</li>
</ul>
<p>After creating and defining a manifest file and create the entry files our final plugin folder looks like this:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">-/..</span>
<span class="o">-</span><span class="n">MyPlugin</span><span class="o">/</span>
<span class="o">-</span> <span class="n">hplugin</span><span class="o">.</span><span class="n">json</span>
<span class="o">-</span> <span class="n">main</span><span class="o">.</span><span class="n">py</span>
<span class="o">-</span> <span class="n">test</span><span class="o">.</span><span class="n">py</span>
</pre></div>
</div>
<p>And that’s it! We can now have HPX load our plugin. To do that, place the plugin folder into one of the locations where HPX looks for plugins.
The default location is the <code class="docutils literal notranslate"><span class="pre">plugins</span></code> folder that exists inside the HPX root folder. It is also possible to define an additional location where to also look for plugins
through the setting <code class="docutils literal notranslate"><span class="pre">plugin.plugin_dir</span></code>.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>On a MacOS HPX installation, the root HPX folder is inside the bundle at <code class="docutils literal notranslate"><span class="pre">HappyPanda</span> <span class="pre">X.app/Contents/MacOS/</span></code>.</p>
</div>
<p>After placing it in one of the locations, HPX should detect it and try to register it automatically either on startup or while running.
You can see if the plugin has been registered successfully if it appears on the plugin listing in a HPX client or if HPX doesn’t print any warnings.</p>
<div class="admonition tip">
<p class="admonition-title">Tip</p>
<p>It is recommended that you run HPX with the <code class="docutils literal notranslate"><span class="pre">--debug</span></code> and <code class="docutils literal notranslate"><span class="pre">--dev</span></code> commandline switches so that you can see what’s going on when your plugin is being loaded and in use.
See <a class="reference internal" href="switches.html#command-line-arguments"><span class="std std-ref">Command-Line Arguments</span></a>.
You can also disable all loggers except the plugin logger by adding them to the setting <code class="docutils literal notranslate"><span class="pre">advanced.disabled_loggers</span></code> to filter out all noise.</p>
</div>
</div>
<div class="section" id="writing-a-plugin">
<h2>Writing a plugin<a class="headerlink" href="#writing-a-plugin" title="Permalink to this headline">¶</a></h2>
<p>Now that we’ve defined our plugin, we can now write the code for our plugin.</p>
<p>Please note that no code will be run <em>before</em> the plugin has been installed. A registered plugin is not the same as an installed plugin.
These are the different kind of states a plugin can be in: <a class="reference internal" href="api_general.html#happypanda.interface.enums.PluginState" title="happypanda.interface.enums.PluginState"><code class="xref py py-class docutils literal notranslate"><span class="pre">PluginState</span></code></a>.</p>
<div class="section" id="interfacing-with-hpx">
<h3>Interfacing with HPX<a class="headerlink" href="#interfacing-with-hpx" title="Permalink to this headline">¶</a></h3>
<p>HPX plugins run in a special environment with a special module named <code class="docutils literal notranslate"><span class="pre">__hpx__</span></code> to interface with HPX.</p>
<p>After a plugin has been registered, it can be installed. Installation has to be manually done by the user unless either of the two settings <code class="docutils literal notranslate"><span class="pre">plugin.auto_install_plugin</span></code> and <code class="docutils literal notranslate"><span class="pre">plugin.auto_install_plugin_dependency</span></code>
are true.</p>
<p>When a plugin has been installed, it will be initialized. The entry file the plugin has provided in its manifest will be run upon initialization.
The entry file will be run in a special plugin environment and will be run just like any other Python code.</p>
<p>There are a couple of notable things about the plugin environment:</p>
<ul class="simple">
<li><p>The entry file’s <code class="docutils literal notranslate"><span class="pre">__name__</span></code> will be set to <code class="docutils literal notranslate"><span class="pre">__main__</span></code> just like how Python does with its entry file.</p></li>
</ul>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>The <code class="docutils literal notranslate"><span class="pre">__file__</span></code> attribute in the entry file is correctly set to be the path of the entry file.</p>
</div>
<ul class="simple">
<li><p>The plugin environment has been provided the special HPX interface module <a class="reference internal" href="api_plugin.html#module-happypanda.core.plugin_interface" title="happypanda.core.plugin_interface"><code class="xref py py-mod docutils literal notranslate"><span class="pre">__hpx__</span></code></a>.</p></li>
<li><p>You can import any module and packages except <code class="docutils literal notranslate"><span class="pre">happypanda</span></code>.</p></li>
</ul>
<p>With all this in mind, we can now write code to interface with HPX. In the <code class="docutils literal notranslate"><span class="pre">main.py</span></code>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">__hpx__</span> <span class="k">as</span> <span class="nn">hpx</span>
<span class="n">logger</span> <span class="o">=</span> <span class="n">hpx</span><span class="o">.</span><span class="n">get_logger</span><span class="p">(</span><span class="vm">__name__</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
<span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">"Emilia is best girl"</span><span class="p">)</span>
<span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="vm">__file__</span><span class="p">)</span>
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">'__main__'</span><span class="p">:</span>
<span class="n">main</span><span class="p">()</span>
</pre></div>
</div>
<p>As you can see, we can write our code just like how we would write any regular Python program.
HPX gives this flexibility and freedom to its plugins.</p>
<p>The contents of the <code class="docutils literal notranslate"><span class="pre">__hpx__</span></code> module can be found at <a class="reference internal" href="api_plugin.html#plugin-api"><span class="std std-ref">Plugin API</span></a>, however, the most important methods from the module which we will cover here are
<a class="reference internal" href="api_plugin.html#happypanda.core.plugin_interface.attach" title="happypanda.core.plugin_interface.attach"><code class="xref py py-meth docutils literal notranslate"><span class="pre">attach</span></code></a> and <a class="reference internal" href="api_plugin.html#happypanda.core.plugin_interface.subscribe" title="happypanda.core.plugin_interface.subscribe"><code class="xref py py-meth docutils literal notranslate"><span class="pre">subscribe</span></code></a>.</p>
<p>The main point of a HPX plugin is to use these methods to extend what HPX is capable of.
Just like previously mentioned, HPX provides many <strong>commands</strong> that defines different entrypoints and events that we can use.</p>
<p>The method <a class="reference internal" href="api_plugin.html#happypanda.core.plugin_interface.subscribe" title="happypanda.core.plugin_interface.subscribe"><code class="xref py py-meth docutils literal notranslate"><span class="pre">subscribe</span></code></a> subscribes a handler function that we define to a command event.
HPX defines the plugin events <code class="docutils literal notranslate"><span class="pre">init</span></code> and <code class="docutils literal notranslate"><span class="pre">disable</span></code> that we can listen to.
We can use these events to initialize/terminate our stuff:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">__hpx__</span> <span class="k">as</span> <span class="nn">hpx</span>
<span class="n">logger</span> <span class="o">=</span> <span class="n">hpx</span><span class="o">.</span><span class="n">get_logger</span><span class="p">(</span><span class="vm">__name__</span><span class="p">)</span>
<span class="nd">@hpx</span><span class="o">.</span><span class="n">subscribe</span><span class="p">(</span><span class="s2">"init"</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">init</span><span class="p">():</span>
<span class="n">log</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">"Initialized"</span><span class="p">)</span>
<span class="nd">@hpx</span><span class="o">.</span><span class="n">subscribe</span><span class="p">(</span><span class="s2">"disable"</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">init</span><span class="p">():</span>
<span class="n">log</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">"disabled"</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
<span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">"Emilia is best girl"</span><span class="p">)</span>
<span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="vm">__file__</span><span class="p">)</span>
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">'__main__'</span><span class="p">:</span>
<span class="n">main</span><span class="p">()</span>
</pre></div>
</div>
<p>While it is true that we could also initialize on the module level, it is safer to do it on the <code class="docutils literal notranslate"><span class="pre">init</span></code> event reasons explained at <a class="reference internal" href="api_plugin.html#module-happypanda.core.commands.meta_cmd"><span class="std std-ref">Commands</span></a>.</p>
<div class="admonition-todo admonition" id="id1">
<p class="admonition-title">Todo</p>
<p>commands and capture tokens</p>
</div>
</div>
<div class="section" id="logging-and-errors">
<h3>Logging and errors<a class="headerlink" href="#logging-and-errors" title="Permalink to this headline">¶</a></h3>
<p>HPX provides a logging facility for its plugins.</p>
<p>When a plugin has been registered, a folder called <code class="docutils literal notranslate"><span class="pre">logs</span></code> is created in the plugin’s folder. In this folder will reside <code class="docutils literal notranslate"><span class="pre">plugin.log</span></code> and <code class="docutils literal notranslate"><span class="pre">plugin_debug.log</span></code>.</p>
<p>It is <strong>strongly</strong> recommended that you use this logging facility instead of rolling your own or using the <code class="docutils literal notranslate"><span class="pre">logging</span></code> module directly.
The HPX logging facility has been set up very intricately to make sense of the logs produced.
Failing to use it will mess up how things are logged unless set up properly.
This can produce logs that are very confusing and useless to others.</p>
<p><code class="docutils literal notranslate"><span class="pre">plugin.log</span></code> is the normal log produced with a log level of <code class="docutils literal notranslate"><span class="pre">INFO</span></code>.
<code class="docutils literal notranslate"><span class="pre">plugin_debug.log</span></code> is a debug log produced only when the setting <a class="reference internal" href="settings.html#settings"><span class="std std-ref">debug</span></a> has been set to true. The log level is <code class="docutils literal notranslate"><span class="pre">DEBUG</span></code> (basically captures everything).
The <code class="docutils literal notranslate"><span class="pre">plugin_debug.log</span></code> is also special in that its contents will be reset on every run.</p>
<p>These two files contain logs pertaining to the plugin in question.
HPX also has its own <code class="docutils literal notranslate"><span class="pre">plugin.log</span></code> found at <code class="docutils literal notranslate"><span class="pre">[HPX]/logs/plugin.log</span></code> that contain logs produced by all plugins (basically a combination of every plugin’s exclusive log).</p>
</div>
<div class="section" id="debugging">
<h3>Debugging<a class="headerlink" href="#debugging" title="Permalink to this headline">¶</a></h3>
<div class="admonition-todo admonition" id="id2">
<p class="admonition-title">Todo</p>
<p>debugging plugins</p>
</div>
</div>
<div class="section" id="testing">
<h3>Testing<a class="headerlink" href="#testing" title="Permalink to this headline">¶</a></h3>
<div class="admonition-todo admonition" id="id3">
<p class="admonition-title">Todo</p>
<p>testing plugins</p>
</div>
</div>
<div class="section" id="about-thread-safety">
<h3>About thread safety<a class="headerlink" href="#about-thread-safety" title="Permalink to this headline">¶</a></h3>
<div class="admonition-todo admonition" id="id4">
<p class="admonition-title">Todo</p>
<p>gevent and etc.</p>
</div>
</div>
<div class="section" id="how-to-not-break-stuff">
<h3>How to not break stuff<a class="headerlink" href="#how-to-not-break-stuff" title="Permalink to this headline">¶</a></h3>
<p>While HPX provides plugins lots of freedom, this can sometimes lead to plugins being able to disrupt the flow of the program and/or create inexplicable bugs,
and generally make it so things are not working as intended.
Which is why care must be taken when writing plugins.</p>
<p>Here are some <strong>DO</strong>’s and <strong>DON’T</strong>’s that should ensure that everything plays nicely together.</p>
<ul class="simple">
<li><p><strong>DON’T</strong> ever change the current working directory. Especially because of the issues explained in <a class="reference internal" href="#about-thread-safety"><span class="std std-ref">thread safety</span></a>.</p></li>
<li><p><strong>DO</strong> always prefer the <a class="reference internal" href="api_plugin.html#plugin-api"><span class="std std-ref">Plugin API</span></a> instead of rolling your own thing. If you think the API is limited and doesn’t allow doing what you want to, consider opening a PR on Github instead.</p></li>
<li><p><strong>DO</strong> always prefer using the <strong>commands</strong> that HPX provides, especially because it allows other things that are beyond your control a chance to run.</p></li>
<li><p><strong>DO</strong> keep everything you produce in the plugin’s own folder when possible. Use <code class="docutils literal notranslate"><span class="pre">__hpx__.constants.current_dir</span></code> to retrieve the path to the plugin’s folder.</p></li>
</ul>
</div>
<div class="section" id="importing-modules-and-packages">
<h3>Importing modules and packages<a class="headerlink" href="#importing-modules-and-packages" title="Permalink to this headline">¶</a></h3>
<p>Importing modules works as expected and, other than <code class="docutils literal notranslate"><span class="pre">happypanda</span></code>, all available modules can be imported normally:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">modulename</span>
<span class="c1"># .. code</span>
</pre></div>
</div>
<p>It is also possible to import modules that you create yourself. Just put the file/folder in your plugin directory alongside your entry file and import it normally.</p>
<p>See <a class="reference internal" href="#available-packages"><span class="std std-ref">Available packages</span></a> for a list of all available modules in an HPX installation.</p>
<div class="section" id="importing-external-packages">
<h4>Importing external packages<a class="headerlink" href="#importing-external-packages" title="Permalink to this headline">¶</a></h4>
<p>If you need an external package that is not listed in <a class="reference internal" href="#available-packages"><span class="std std-ref">Available packages</span></a> then here’s what you can do.</p>
<div class="admonition-todo admonition" id="id5">
<p class="admonition-title">Todo</p>
<p>external packages</p>
</div>
</div>
</div>
</div>
<div class="section" id="available-packages">
<h2>Available packages<a class="headerlink" href="#available-packages" title="Permalink to this headline">¶</a></h2>
<p>Aside from the python standard library, these are the available packages HPX provides that can be imported in the plugin environment.</p>
<p><em>aiohttp==3.2.1</em></p>
<p><em>alabaster==0.7.12</em></p>
<p><em>alembic==1.4.2</em></p>
<p><em>altgraph==0.17</em></p>
<p><em>apipkg==1.5</em></p>
<p><em>appdirs==1.4.4</em></p>
<p><em>APScheduler==3.6.1</em></p>
<p><em>argh==0.26.2</em></p>
<p><em>arrow==0.15.6</em></p>
<p><em>art==4.7</em></p>
<p><em>asn1crypto==1.4.0</em></p>
<p><em>async-timeout==3.0.1</em></p>
<p><em>atomicwrites==1.3.0</em></p>
<p><em>attrs==19.3.0</em></p>
<p><em>autopep8==1.5.2</em></p>
<p><em>Babel==2.8.0</em></p>
<p><em>bcrypt==3.1.3</em></p>
<p><em>beautifulsoup4==4.8.0</em></p>
<p><em>bencodepy==0.9.5</em></p>
<p><em>biplist==1.0.3</em></p>
<p><em>bitarray==1.5.3</em></p>
<p><em>blinker==1.4</em></p>
<p><em>CacheControl==0.12.4</em></p>
<p><em>cachetools==4.1.0</em></p>
<p><em>certifi==2020.6.20</em></p>
<p><em>cffi==1.14.2</em></p>
<p><em>chardet==3.0.4</em></p>
<p><em>click==7.1.2</em></p>
<p><em>colorlog==4.0.2</em></p>
<p><em>cookies==2.2.1</em></p>
<p><em>coverage==5.2.1</em></p>
<p><em>cryptography==2.3</em></p>
<p><em>dateparser==0.7.4</em></p>
<p><em>decorator==4.4.0</em></p>
<p><em>dill==0.3.2</em></p>
<p><em>diskcache==4.1.0</em></p>
<p><em>distlib==0.3.1</em></p>
<p><em>dmgbuild==1.3.2</em></p>
<p><em>docutils==0.16</em></p>
<p><em>dogpile.cache==1.0.2</em></p>
<p><em>ds-store==1.1.2</em></p>
<p><em>elasticsearch==7.9.1</em></p>
<p><em>elasticsearch-dsl==7.2.0</em></p>
<p><em>entrypoints==0.3</em></p>
<p><em>execnet==1.7.1</em></p>
<p><em>fakeredis==1.0.5</em></p>
<p><em>filelock==3.0.12</em></p>
<p><em>flake8==3.7.8</em></p>
<p><em>Flask==1.1.2</em></p>
<p><em>Flask-Caching==1.9.0</em></p>
<p><em>Flask-Cors==3.0.8</em></p>
<p><em>Flask-SocketIO==4.3.1</em></p>
<p><em>furl==2.1.0</em></p>
<p><em>gevent==20.6.2</em></p>
<p><em>gevent-websocket==0.10.1</em></p>
<p><em>gprof2dot==2019.11.30</em></p>
<p><em>greenlet==0.4.16</em></p>
<p><em>happy-bittorrent</em></p>
<p><em>@</em></p>
<p><em>https://github.com/Pewpews/happy-bittorrent/archive/master/1.0.0.zip</em></p>
<p><em>happypandax-i18n</em></p>
<p><em>@</em></p>
<p><em>https://github.com/happypandax/i18n/archive/master.zip</em></p>
<p><em>idna==2.10</em></p>
<p><em>imagesize==1.2.0</em></p>
<p><em>importlib-metadata==1.7.0</em></p>
<p><em>iniconfig==1.0.1</em></p>
<p><em>itsdangerous==1.1.0</em></p>
<p><em>Jinja2==2.11.2</em></p>
<p><em>langcodes==2.0.0</em></p>
<p><em>mac-alias==2.0.7</em></p>
<p><em>Mako==1.1.3</em></p>
<p><em>marisa-trie==0.7.5</em></p>
<p><em>MarkupSafe==1.1.1</em></p>
<p><em>mccabe==0.6.1</em></p>
<p><em>mock==4.0.2</em></p>
<p><em>more-itertools==7.2.0</em></p>
<p><em>msgpack-python==0.5.6</em></p>
<p><em>multidict==4.3.1</em></p>
<p><em>mypy==0.782</em></p>
<p><em>mypy-extensions==0.4.3</em></p>
<p><em>natsort==7.0.1</em></p>
<p><em>nose==1.3.7</em></p>
<p><em>nplusone==1.0.0</em></p>
<p><em>numpy==1.19.1</em></p>
<p><em>ordered-set==4.0.2</em></p>
<p><em>orderedmultidict==1.0.1</em></p>
<p><em>packaging==17.1</em></p>
<p><em>pathtools==0.1.2</em></p>
<p><em>pbr==5.4.5</em></p>
<p><em>Pillow==7.2.0</em></p>
<p><em>pipenv==2020.8.13</em></p>
<p><em>pluggy==0.13.1</em></p>
<p><em>pprintpp==0.4.0</em></p>
<p><em>psutil==5.7.2</em></p>
<p><em>psycopg2-binary==2.8.3</em></p>
<p><em>py==1.9.0</em></p>
<p><em>pycodestyle==2.6.0</em></p>
<p><em>pycparser==2.20</em></p>
<p><em>pyflakes==2.1.1</em></p>
<p><em>Pygments==2.6.1</em></p>
<p><em>pyinstaller==4.0</em></p>
<p><em>pyinstaller-hooks-contrib==2020.7</em></p>
<p><em>pyOpenSSL==18.0.0</em></p>
<p><em>pyparsing==2.4.7</em></p>
<p><em>PySide2==5.15.0</em></p>
<p><em>pytest==5.1.1</em></p>
<p><em>pytest-cov==2.7.1</em></p>
<p><em>pytest-forked==1.3.0</em></p>
<p><em>pytest-profiling==1.7.0</em></p>
<p><em>pytest-xdist==1.29.0</em></p>
<p><em>python-dateutil==2.8.1</em></p>
<p><em>python-editor==1.0.4</em></p>
<p><em>python-engineio==3.13.2</em></p>
<p><em>python-socketio==4.6.0</em></p>
<p><em>pytz==2020.1</em></p>
<p><em>PyYAML==5.3.1</em></p>
<p><em>QtAwesome</em></p>
<p><em>@</em></p>
<p><em>https://github.com/spyder-ide/qtawesome/archive/master.zip</em></p>
<p><em>QtPy==1.9.0</em></p>
<p><em>rarfile==4.0</em></p>
<p><em>redis==3.2.1</em></p>
<p><em>regex==2020.7.14</em></p>
<p><em>requests==2.20.1</em></p>
<p><em>responses==0.9.0</em></p>
<p><em>Rx==3.1.1</em></p>
<p><em>sadisplay==0.4.8</em></p>
<p><em>Send2Trash==1.5.0</em></p>
<p><em>sentry-sdk==0.16.5</em></p>
<p><em>shiboken2==5.15.0</em></p>
<p><em>six==1.12.0</em></p>
<p><em>snowballstemmer==2.0.0</em></p>
<p><em>sortedcontainers==2.2.0</em></p>
<p><em>soupsieve==2.0.1</em></p>
<p><em>Sphinx==3.2.1</em></p>
<p><em>sphinx-autodoc-typehints==1.11.0</em></p>
<p><em>sphinx-bootstrap-theme==0.7.1</em></p>
<p><em>sphinxcontrib-applehelp==1.0.2</em></p>
<p><em>sphinxcontrib-autoprogram==0.1.5</em></p>
<p><em>sphinxcontrib-devhelp==1.0.2</em></p>
<p><em>sphinxcontrib-documentedlist==0.6</em></p>
<p><em>sphinxcontrib-htmlhelp==1.0.3</em></p>
<p><em>sphinxcontrib-jsmath==1.0.1</em></p>
<p><em>sphinxcontrib-qthelp==1.0.3</em></p>
<p><em>sphinxcontrib-serializinghtml==1.1.4</em></p>
<p><em>SQLAlchemy==1.3.19</em></p>
<p><em>sqlalchemy-json==0.4.0</em></p>
<p><em>SQLAlchemy-Utils==0.36.8</em></p>
<p><em>sqlparse==0.3.1</em></p>
<p><em>sqltap==0.3.11</em></p>
<p><em>stevedore==3.2.0</em></p>
<p><em>toml==0.10.1</em></p>
<p><em>Transcrypt==3.7.16</em></p>
<p><em>treelib==1.5.1</em></p>
<p><em>typed-ast==1.4.1</em></p>
<p><em>typing-extensions==3.7.4.3</em></p>
<p><em>tzlocal==2.1</em></p>
<p><em>urllib3==1.24.3</em></p>
<p><em>virtualenv==20.0.31</em></p>
<p><em>virtualenv-clone==0.5.4</em></p>
<p><em>watchdog==0.9.0</em></p>
<p><em>wcwidth==0.2.5</em></p>
<p><em>Werkzeug==1.0.1</em></p>
<p><em>yarl==1.5.1</em></p>
<p><em>zipp==3.1.0</em></p>
<p><em>zope.event==4.4</em></p>
<p><em>zope.interface==5.1.0</em></p>
</div>
</div>
</div>
</div>
<div class="row">
<script src="https://utteranc.es/client.js"
repo="happypandax/happypandax.github.io"
issue-term="pathname"
label="💬 docs"
theme="github-light"
crossorigin="anonymous"
async>
</script>
</div>
</div>
<script async defer src="https://buttons.github.io/buttons.js"></script>
<footer class="footer">
<div class="container">
<p class="pull-right">
<a href="#">Back to top</a>
<br/>
</p>
<p>
© Copyright Twiddly.<br/>
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 3.2.1.<br/>
</p>
</div>
</footer>
</body>
</html>