Intermake
=========
* ___APPLICATION FRONTEND VIA REFLECTION___

Iɴᴛᴇʀᴍᴀᴋᴇ is a library that provides a simple method of quickly adding a front-end to your Python functions.
The following frontends are supported:

* `ARG`: Call from **command line arguments**
* `CLI`: Interactive terminal-like shell (**CLI**)
* `PYI`: Interactive **Python shell** (PYI)
* `GUI`: Graphical user interface (**GUI**)
* `PYS`: Call from any **Python script** or application
* `XXX`: **Custom** front-ends are also supported

Rationale
---------

Unlike other utilities, Iɴᴛᴇʀᴍᴀᴋᴇ:
* requires minimal setup
    * (really just a `@command` decorators!)
* isn't intrusive
* generates help and documentation _automatically_,
    * uses [PEP-257](https://www.python.org/dev/peps/pep-0257/) documentation
* generates an _appropriate_ UI _automatically_:
    * uses [PEP-484](https://www.python.org/dev/peps/pep-0484/) annotations
    * converts types for you
        * your function, requiring an `int`, really gets an `int`, not the `str` the user typed
        * your function, requiring a `MyOwnClass`, really gets a `MyOwnClass`
    * annotation hints control the UI:
        * supports function defaults
        * supports the `typing` library: `List[T]`, `Union[T, U]`, `Optional[T]`, etc.
        * also includes custom-annotations: `Filename[extension]`, `Dirname`, `Nonzero[T]`
* includes optional helpers:
    * scroll bars, feedback to user, etc. 

[](toc)

Usage Tutorial
--------------
This tutorial covers **_using_** an Iɴᴛᴇʀᴍᴀᴋᴇ application. See [the other tutorial](#development-tutorial) for **_developing_** an Iɴᴛᴇʀᴍᴀᴋᴇ application

### Getting started ###

An Iɴᴛᴇʀᴍᴀᴋᴇ application can be launched in several ways, where `sample` is the name of your application, use the following commands to launch it:

| Mode                           | Command                                          |
|--------------------------------|--------------------------------------------------|
| Command-line arguments         | `sample "<commands>"`                            |
| Command line interface         | `sample` <br/> ...or... <br/> `bio42 "ui cli"`   |
| Graphical user interface       | `sample "ui gui"`                                |
| Pʏᴛʜᴏɴ interactive shell       | `sample "ui pyi"`                                |
| Interface for Pʏᴛʜᴏɴ scripting | `python3` <br/> ...then... <br/> `import sample` |

Iɴᴛᴇʀᴍᴀᴋᴇ provides an ***extensive, context-dependent, in-line help*** system.

Let's explore the basic help. First, launch your application from the command line in the default (CLI) mode.

```
$   sample
```

The `help` command can then be accessed just by typing `help`.

```
$   help
    ECO help
    INF   _help____________________________________________
          Aliases: basic_help
    
                        You are in command-line mode.
    
... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
```
 

Development Tutorial
--------------------

This tutorial covers **_developing_** an Iɴᴛᴇʀᴍᴀᴋᴇ application. See [the other tutorial](#usage-tutorial) for **_using_** an Iɴᴛᴇʀᴍᴀᴋᴇ application!

### Implementation ###

Get right in there with the full implementation of a simple Iɴᴛᴇʀᴍᴀᴋᴇ application, called Sᴀᴍᴩʟᴇ! It has two amazing functions "`say_hello`" and "`do_some_work`".
Paste the following contents into the appropriate files:

[`sample/sample/__init__.py`]
```python
from intermake import MCMD, MENV, command

@command()
def say_hello():
    """
    Says hello
    """
    MCMD.print( "hello" )

@command()
def do_some_work( count : int ):
    """
    Does nothing.
    
    :param count: The number of times to do nothing.
    """
    with MCMD.action( "Doing some work for you!", count ) as action:
        for n in range( count ):
            action.increment()

MENV.name = "sample"
```

[`sample/sample/__main__.py`]:
```python
import sample
import intermake
intermake.start( __name__ )
```

**_That's all there is!_** The next section describes what we actually did!

### Explanation ###

1. We used the `@command()` decorator to expose our function through Iɴᴛᴇʀᴍᴀᴋᴇ.
2. We properly documented our functions using PEP-287 doc comments.
3. We properly annotated our functions using PEP-484.
4. We used the `MCMD` field to obtain the abstraction to the current UI.
    * We called `MCMD.print` to print a message.
    * We called `MCMD.action` to show a progress bar.
5. We set the application name `MENV.name`.
    * (Iɴᴛᴇʀᴍᴀᴋᴇ doesn't impose any branding, so if we don't do this our application just gets called "`Untitled`".)
6. Finally, we called `intermake.start` to start Iɴᴛᴇʀᴍᴀᴋᴇ with the appropriate UI.

### Running our application ###

This is Python boilerplate stuff, but if you don't already know:
* Do a quick-and-dirty registration with Python by running:

```bash
export PYTHONPATH=$PYTHONPATH:/path/to/sample`.
alias sample="python3 -m sample"
```

Now you can try out the various modes as follows. They all do the same thing, in different ways.

#### CLI mode ####

```bash
BASH   <<< sample
SAMPLE <<< say_hello
       <<< do_some_work count=10000
       <<< exit
```

#### ARG mode ####

```bash
BASH   <<< sample "say_hello : do_some_work count=10000"
```

#### GUI mode ####

```bash
BASH   <<< sample "ui gui"
SAMPLE <<< *click say_hello*
       <<< *click run*
       <<< *click do_some_work*
       <<< *set count to 10000*
       <<< *click run*
       <<< *close the window*
```

#### PYI mode ####

```bash
BASH   <<< sample "ui pyi"
PYTHON <<< say_hello()
       <<< do_some_work(10000)
```

#### PYS mode ####

```python
PYTHON <<< import sample
       <<< sample.say_hello()
       <<< sample.do_some_work(10000)
```

Adding support for new types
----------------------------

* Iɴᴛᴇʀᴍᴀᴋᴇ uses Eᴅɪᴛᴏʀɪᴜᴍ to supply the Qᴛ GUI editor. To add GUI support for new types, call `editorium.register` (see the `editorium` module itself for details).
* Iɴᴛᴇʀᴍᴀᴋᴇ uses SᴛʀɪɴɢCᴏᴇʀᴄɪᴏɴ to supply translation from typed arguments. To add support for translation from text to new types, call `stringcoercion.register` (see the `stringcoercion` module itself for details).  
    
Advanced plugins
----------------

In our example we provided a _plugin_ through the `@command` decorator.
`@command` also allows us to register *classes*, if those classes are subclasses of the `Plugin` type.
The `plugins` directory of `intermake` contains the set of in-built plugins, which may be used as a reference-point for creating your own.

***Please see the doc-comments on `@command` and `Plugin` for full details.***

Customising
-----------

The example above set only the application title, more customisations are available via the `MENV` field, notably the `root` field, that exposes an application hierarchy derived from `IVisualisable`:

```python
MENV.root = my_root
```

The `MENV` field is a `__Environment` object defined in `environment.py`.

***Please see the doc-comments on `__Environment` and `IVisualisable` for full details.***

System requirements
-------------------

* Windows
* Ubuntu
* MacOS
* Others:
    * `CLI`/`ARG`/`PYI`
        * requires a terminal environment supporting ANSI colours and UTF8.
            * Both Ubuntu and MacOS support these by default.
            * _intermake_ provides automated an ANSI-to-WinAPI wrapper for Windows, via _colorama_, and instructs the user on how to enable UTF-8.
    * `PYS`:
        * No special requirements, but UTF-8 is not supported, Python should still be notified via the `PYTHONIOENCODING` environment variable (this will permit `CLI`/`ARG`/`PYI` to work also, albeit with strange characters). E.g. `export PYTHONIOENCODING=ascii:replace`.
    * `CLI`:
        * Command history is supported via _readline_, which only works under Unix.
            * Support on Windows _may_ be supported via _Cygwin_ or _ANSI.sys_.
    * `GUI`:
        * Requires _PyQt5_.
            * Note that, at the time of writing, some versions of Ubuntu ship with a broken _Qt_/_PyQt5_/_Sip_ install, giving a `killed 9` or `segfault` error on GUI startup. This will require re-installation of _Qt_/_PyQt_/_Sip_ by the user.
    * Note that UI components are isolated, hence `CLI` can be used without satisfying the `GUI` requirements, and vice-versa.
    
Troubleshooting
---------------

### Generally weird errors ###

User errors:

* Iɴᴛᴇʀᴍᴀᴋᴇ requires at least Pʏᴛʜᴏɴ3.6.
    * (This is especially problematic on Mac, which for some reason ships with an out-of-date Pʏᴛʜᴏɴ2) 

### Unicode errors ###

User errors:

* You're using Pʏᴛʜᴏɴ2, Iɴᴛᴇʀᴍᴀᴋᴇ requires at least Pʏᴛʜᴏɴ3.6.
* You've changed the terminal encoding. Check the solutions for Ubuntu and Windows below, regardless of your platform.

On Ubuntu:

* Problem: The terminal is using an implicit encoding `LC_ALL=C`? Pʏᴛʜᴏɴ can't handle this.
    * Solution - Use UTF8. Call `export LC_ALL="en_GB.utf8"` from the command line.
        * Replace the `en_GB` with your own locale, e.g. `es.utf8` or `zh_CN.utf8`.

On Windows:

* Problem: `cmd.exe` or _PowerShell_ with an `ASCII`-only font.
    * Solution - Change your font to a Unicode one.
    * Quick workaround - call `set PYTHONIOENCODING=ascii:replace` from the command line
    
On Mac:

* No known problems


### Segmentation fault, killed 9, or GUI fails to run ###

On Ubuntu:

* Problem: At the time of writing, some Linux systems have a corrupt installation of PyQt and/or Qt.
    * Solution: Build PyQt and/or Qt properly from source yourself, see: 
        * [riverbankcomputing.com](https://riverbankcomputing.com/software/pyqt/intro)
        * [qt.io](https://www.qt.io/)
    * Workaround: Just use your Iɴᴛᴇʀᴍᴀᴋᴇ application from one of the CLI modes.
    
On Windows or Mac:

* No known problems

On other systems (e.g. Android):

* Problem: Qt is not installed.
    * Solution: See if you can find a Qt installation for your system.
    * Workaround: Use your Iɴᴛᴇʀᴍᴀᴋᴇ application from one of the CLI modes.
    
### An Iɴᴛᴇʀᴍᴀᴋᴇ application doesn't start for some other reason ###

User errors:

* Problem: Requisite libraries not installed
    * Solution: Please follow the installation instructions included with the application.
    
### General errors ###

Coding errors:

* Problem: A Iɴᴛᴇʀᴍᴀᴋᴇ error occurs.
    * Solution: Report it so it can be fixed. Please include the debug information in your bug report. 
        * GUI: Iɴᴛᴇʀᴍᴀᴋᴇ writes debugging information to the console (`stderr`) whenever it encounters an error in the GUI.
          Launch the GUI from the command line (e.g. `./xxxx "ui gui"`) to see this information.
        * CLI: If an error occurs in the CLI version, details can be retrieved using the `error` command.
            * You can instruct all errors to be dumped by default via the `set` command.
    * Solution: Fix it yourself! All Iɴᴛᴇʀᴍᴀᴋᴇ code is heavily documented in-line using standard Python documentation. 
    
### Hard to read text in CLI mode ###

Iɴᴛᴇʀᴍᴀᴋᴇ does its best to use colours to distinguish on-screen items, and expects standard ANSI/DOS colours.
If you're getting unreadable items, such as yellow text on a white background, the colours should be changed in your terminal preferences (not the Iɴᴛᴇʀᴍᴀᴋᴇ application itself). Modify your terminal profile/theme or simply turn off ANSI colour support.

Meta
----

```ini
type= library
author= Martin Rusilowicz
language= python3
created= 2017
host= bitbucket,pypi
```
