# PyAnzo Developer Readme

__Note:__ This readme is meant for developers of PyAnzo.

## Setup

```bash
pip install -U -r requirements_dev.txt
```

## Testing

### Running Tests
Run the following bash command from within the main directory of the package.
```bash
make test
```

### Setup a Local Environment for Testing

To run the tests, Anzo and AnzoGraph need to be setup and running locally.

#### Assumptions

- Running on a mac (unfortunately, windows will be different because this assumes a symbolic link between `/tmp` and `/private/tmp`
- This repository is located in `/private/tmp` (on a mac). The real requirement is that the FLDS is located as such, but it's easier if the whole repo is there
- Can run local Anzo with out persisted journal
- Docker is setup and recent image is pulled; if needed: `docker pull cambridgesemantics/anzograph`
- The Docker File Sharing preferences include `/private`.

#### Steps

1. Add the Anzo command line to the PATH, by putting something like this in `~/.bash_profile`:
```bash
export PATH=~/git/asdl/org.openanzo.client/cli/bin/anzo:$PATH
```

2. Turn on Anzo in Eclipse (not persisted)
3. Start docker
```bash
docker run -ti -d \
    -v /private/tmp/pyanzo/tests/test_assets:/private/tmp/pyanzo/tests/test_assets \
    -p 38080:8080 \
    -p 38443:8443 \
    -p 7070:7070 \
    -p 5700:5700 \
    -p 5600:5600 \
    --name=pyanzo-azg \
    cambridgesemantics/anzograph:latest
```

If you've already created a docker container on your computer, you can start it with
```bash
docker start pyanzo-azg
```

Check if it's started with
```bash
docker ps -a
```

4. Import trig: `anzo import --useModes tests/test_assets/trig/*`
5. Go to Anzograph in the Anzo UI and reload. Confirm that graphmart loaded.


#### Automating those steps after initial setup

Here's a helpful script that can be used for automating this process:

```bash
#!/bin/bash

# To be able to delete this symlink, it must *not* have a trailing slash "/"
TMP_PATH="/private/tmp/pyanzo"

CODE_PATH="~/git/pyanzo"
TRIGS="${CODE_PATH}/tests/test_assets/trig/*"

if [ -d ${TMP_PATH} ]
then
    echo "Sym link exists. Removing it."
    rm ${TMP_PATH}
fi

echo "Creating sym link to ${TMP_PATH}"
ln -s ${CODE_PATH} ${TMP_PATH}

echo "Starting docker container pyanzo-azg"
docker start pyanzo-azg

echo "Importing trig"
anzo import --useModes ${TRIGS}

echo "Everything is setup!"
```

### Running Tests on New Hires Playground

Although testing PyAnzo using a local environment is preferred, it is also possible to run the tests by targeting `new-hires-playground`.

To run tests against the new hires playground, edit `tests/test_common.py` to have the following:

```python
GRAPHMART = "http://cambridgesemantics.com/Graphmart/81f7b5b1253d4fb8bc340075ae9c8ff4"
SERVER = "10.100.0.26"
PORT = "443"
USERNAME = "sysadmin"
PASSWORD = "123"
```

__Note:__ A few things could go wrong when running the tests on `new-hires-playground`. If you are running into unexpected errors:
- Ensure `new-hires-playground` (10.100.0.26) and `new-hires-anzograph-2` (10.100.0.60) are both running
- Ensure that Anzo and AnzoGraph are connected by going to Administration/Anzograph in the Anzo web interface.
- Ensure the PyAnzo Graphmart is loaded

The steps above should fix most problems. However, it is also possible that the PyAnzo Graphmart was updated in some way, but those updates did not make it to `new-hires-playground`. If you suspect this is the case, reach out to the PyAnzo developers.

### Test Parameterization

In order to have a cleaner test suite, we use the `parameterized` python package
to create parameterized tests where possible.

`@parameterized.expand` can be used to generate test methods when the test class
is a subclass of unittest.TestCase.

```python
import unittest
from parameterized import parameterized

class AddTestCase(unittest.TestCase):
    @parameterized.expand([
        ("2 and 3", 2, 3, 5),
        ("3 and 5", 2, 3, 5),
    ])
    def test_add(self, _, a, b, expected):
        assert_equal(a + b, expected)
```

Will create the following tests:

```bash
$ python setup.py test
test_add_0_2_and_3 (example.AddTestCase) ... ok
test_add_1_3_and_5 (example.AddTestCase) ... ok

----------------------------------------------------------------------
Ran 2 tests in 0.001s

OK

```

Note that `@parameterized.expand` works by creating new methods on the test class. If the first parameter is a string, that string will be added to the end of the method name. For example, the test case above will generate the methods `test_add_0_2_and_3` and `test_add_1_3_and_5`.

The names of the test cases generated by @parameterized.expand can be customized using the name_func keyword argument. The remaining parameters are passed to the test method. Thus,
`test_add_0_2_and_3` runs the test:

```python
test_add(self, "2 and 3", 2, 3, 5)
```

For more information about `parameterized`, click [here](https://pypi.org/project/parameterized/).

### Pitfalls

 - The tests rely on the binary store being active and usable. If you are seeing failures of tests like `test_simple_service_call_with_empty_request` this could be because of an issue with the binary store. To fix the issue, go to **Advanced Configuration**. Select the **Anzo Binary Store**, click **STOP BUNDLE**, and then click **START BUNDLE**.


## Naming Conventions

For methods that are converting objects to other kinds, prefer `from_x` for a static constructor and `as_x` for converting to another object.
It's been the convention so far that `as_x` will return an object and not modify the source object.

## Documentation

All docstrings should adhere to the [Google Python Style Guide](https://google.github.io/styleguide/pyguide.html). Prior to committing and submitting pull requests, you should verify that all new classes, functions, methods, etc. have a proper docstring that adheres to these standards.

It is also good practice to verify that the documentation renders properly. This can be checked by running the following command from the main directory of the package and viewing the rendered docs (in the `docs/_build` folder).

```bash
make docs
```

## Linting

Stylistic conform is checked and enforced with flake8.

To run the linter:
```
make lint
```

## Type Annotations

Type annotations are used where possible.

To run the typ checker:
```
make type
```

## Background

This python package was configured using https://github.com/audreyr/cookiecutter-pypackage, with things modifed, removed, and added to fit the project's needs.
