### <a id="onepw"></a>The `onepw` Python module for 1Password integration

Documentation on how [to install and use the module](https://pypi.org/project/onepw/#install) is available at [PyPi](https://pypi.org/project/onepw/).

[1Password](https://1password.com) is a popular password manager used by individuals and organisations. It has a [desktop app](https://1password.com/downloads) for many platforms and a [support community](https://1password.community) where ideas are shared and questions are asked and answered.

For developers, it also provides [SDKs, tools and support](https://developer.1password.com). The `onepw` module uses [1Password CLI](https://developer.1password.com/docs/cli) command line tool to implement its features. For more advanced 1Password integration the [SDKs from 1Password](https://developer.1password.com/docs/sdks/) should be considered.

**Update warning:** Version 1.22 of `onepw` introduces a *non-backwards compatible* change. Since version 1.22 of `onepw`, the return value format of the method `get` has changed when the `field` argument has the value `"all"` (or `True`). In this case, the returned dictionary only includes the fields (and not other information about the 1Password entry). To get more data about the 1Password entry, you now have to use the new `info` argument of the `get` method. See the updated [documentation of the `get` method](https://pypi.org/project/onepw/#get) for more details. In version 1.22, the console script command `onepw get` also has some argument changes. The `--title` argument is replaced by the positional argument `TITLE-OR-ID` and the `--field` and `--info` arguements are updated to match the changes of the `get` method. The old usage of `--title` instead of `TITLE-OR-ID` will still work but is not documented in newer versions. See the [documentation of the `onepw get` command](https://pypi.org/project/onepw/#cli-onepw-get) for more details.


**Table of contents**

 - <a href="#install">To install and use the module</a>

     - <a href="#class-OnePW">Class `OnePW`</a>

     - <a href="#get">Method `OnePW.get`</a>

     - <a href="#list">Method `OnePW.list`</a>

     - <a href="#add">Method `OnePW.add`</a>

     - <a href="#delete">Method `OnePW.delete`</a>

 - <a href="#cli">To use the module as a console script</a>

     - <a href="#cli-onepw">Command `onepw`</a>

     - <a href="#cli-onepw-get">Command `onepw get`</a>

     - <a href="#cli-onepw-list">Command `onepw list`</a>

     - <a href="#cli-onepw-add">Command `onepw add`</a>

     - <a href="#cli-onepw-delete">Command `onepw delete`</a>

### <a id="install"></a>To install and use the module

The `onepw` Python module implements a limited *1Password* integration
using *1Password CLI*:

 - https://developer.1password.com/docs/cli

To use the module, install the *1Password CLI* tool `op`:

 - https://1password.com/downloads/command-line/

(or install it with a package tool, e.g., *HomeBrew* on a Mac).

The `onepw` module is available from my software repository and from
PyPi:

 - https://www.pg12.org/software

 - https://pypi.org/project/onepw/

It is best to install the module and the companion console script
`onepw` with `pip`:

```bash
pip install onepw
```

It is recommended to integrated the *1Password CLI* tool with the
*1Password* desktop app (to use the desktop app to sign in to
*1Password*).  See Step 2 here for details:

 - https://developer.1password.com/docs/cli/get-started/

Other similar Python modules, with more or different functionality,
are available. The obvious first choice is the SDKs from *1Password*:

 - https://developer.1password.com/docs/sdks/

Their Python SDK is in active development and should be considered
when integrating *1Password* with Python:

 - https://github.com/1Password/onepassword-sdk-python

Another option is to use the `keyring` module with the third-party
backend *OnePassword Keyring*:

 - https://pypi.org/project/keyring/

 - https://pypi.org/project/onepassword-keyring/

One downside of this approach is that when *OnePassword Keyring* is
installed, it replaces the default backend of the `keyring` module.  I
prefer that the default behavior of `keyring` is unchanged (using the
system keychain/keyring) and use a specific module (like `onepw`) for
*1Password* integration in Python.

#### Class <a id="class-OnePW"></a>`OnePW`

OnePW(account: str | None = None, pw: str | None = None)

*A Python class for 1Password sessions*

When an instance of this class is created, a *1Password* session
is started.  With this session you can perform *1Password CLI*
commands. The following methods for such commands are available:

 - `get`: get a field from a 1Password entry

 - `list`: list all entries from 1Password

 - `add`: add an entry to 1Password

 - `delete`: delete an entry from 1Password

In the following example, a *1Password* session is created and the
password from the `"Google"` entry in 1Password is fetched:

```python
op = OnePW()
pw = op.get("Google", field="password")
```

When a *1Password* session is instantiated you are signed in
to *1Password*. If the *1Password CLI* tool is integrated with
the *1Password* desktop app, the desktop app is used to sign
in to *1Password*. Otherwise, the password has to be provided,
either as the argument `pw` (usually not recommended) or
prompted for.

**Arguments:**

 - `account`: The account to sign in to (usually, not needed;
default `None`)

 - `pw`: The password used to sign in (usually, not needed;
default `None`)

#### Method <a id="get"></a>`OnePW.get`

```python
get(title: str, field: bool | str = False, info: bool | str = False, return_format: str | None = None) -> str | dict
```

*Get a field from a 1Password entry*

Get the value of a field or other information from the
1Password entry with the title or id `title`.  When using the
method you should either use the `field` or the `info`
argument (and not both at the same time). If `field` or `info`
is not given, the value of the `"password"` field of the
1Password entry is returned.

When a specific field is specified, like `"username"`,
`"password"` or `"email"`, the value of that specific field is
returned (a text string). If `field` is set to `"all"` or
`True`, a dictionary with all fields are returned. If `field`
is `True` or `"all"`, and `return_format` *is not* set, the
returned dictionary will have a format like this (numbers of
items in the dictionary will vary):

```python
{
  "username": "an@email.address",
  "password": "a s3cret p4ssw0rd"
}
```

It is possible to get a 1Password reference to the field(s)
instead of the value(s). Set the `return_format` argument to
`"reference"` to achieve this. This will work both when
`field` is `True` or `"all"`, and when `field` spcecifies a
specific field in the 1Password entry.

If `field` is `False` and `info` is not `False`, information
about the 1Password entry (and not the fields) is returned. If
`info` is `True` or `"all"`, a dictionary with information
about the entry, including id, title and more, is returned. If
`info` is a text string, the specific information identified
by this text string (key) is returned. If `field` is `False`
and `info` is `True` or `"all"`, and `return_format` *is not*
not set, the returned dictionary will have a format like this
(numbers of items in the `"urls"` section will vary):

```python
{
  "id": "auniqu4idfrom1p4ssw0rdapp1",
  "title": "An example",
  "vault": "Personal",
  "category": "LOGIN",
  "urls": {
    "website": "https://a.web.page/"
  }
}
```

If the `info` argument is `True` or `"all"` and the
`return_format` argument is `"raw-dict"`, the raw dictionary
containing all the details about the entry is returned
(including all the fields and a much more).

The `get` method raises a `OnePWError` exception if an entry
with the given title and/or field/info is not found.

**Arguments/return value:**

 - `title`: The title of the entry (can also be the id of the
entry)

 - `field`: The field to get from the entry, where `True` or
`"all"` will return all fields as a dictionary (default
`False`, meaning that the `"password"` field of the entry is
returned if `info` is `False`, too)

 - `info`: Get information about the entry, where `True` or
`"all"` will return all information as a dictionary (default
`False`)

 - `return_format`: Specifies an alternative format to the
returned field/data from the entry (default `None`)

 - `return`: The value of field(s) in the entry or information
about the entry

#### Method <a id="list"></a>`OnePW.list`

```python
list(categories: str | None = None, favorite: bool = False, tags: str | None = None, vault: str | None = None, return_format: str = 'title') -> list | dict
```

*List all entries in 1Password*

 List all the entries in 1Password with their titles, ids or as
 a dictionary representation.  By default, the method returns a
 list of all entry titles.

 If `return_format` is set to `"id"`, it returns a list of all
 entry ids. If `return_format` is set to `"title-id"`, it
 returns a list of all entries where each entry in the list is
 a title-id tuple. If `return_format` is set to `"id-title"`,
 it returns a list of all entries where each entry in the list
 is a id-title tuple.

 If `return_format` is set to `"dict"` or `"id-dict"`, it
 returns a dictionary of all entries and some data, where the
 key for each entry is the title (if `return_format` is
 `"dict"`) or the id (if `return_format` is `"id-dict"`) of the
 entry.

 If `return_format` is set to `"raw-dict"` or `"id-raw-dict"`,
 it returns a dictionary of all entries and all the details
 about each entry, where the key for each entry is the title
 (if `return_format` is `"raw-dict"`) or the id (if
 `return_format` is `"id-raw-dict"`) of the entry.

 Be aware that in the case where the argument `return_format`
 is `"dict"` or `"raw-dict"` and two or more entries have the
 same title, only one of them will be in the returned
 dictionary.

 Arguments/return value:

 - `categories`: only list items in these comma-separated
 categories (default `None`, meaning all entries)

 -  `favorite`: only list favorite items (default `False`,
 meaning all entries)

 -  `tags`: only list items with these comma-separated tags
 (default `None`, meaning all entries)

 -  `vault`: only list items in this vault (default `None`,
 meaning all vaults)

 -  `return_format`: the return format of the returned list or
 dictionary (default `"title"`, meaning a list of entry titles)

 -  `return`: returns a list or a dictionary with all the
 entries

#### Method <a id="add"></a>`OnePW.add`

```python
add(title: str, username: str, password: str, email: str | None = None, url: str | None = None)
```

*Add a new entry to 1Password*

Add a new entry to 1Password with the provided values. A
title, username and password are required. The method raises a
`OnePWError` exception if adding the entry fails.

**Arguments:**

 - `title`: The title of the entry

 - `username`: The username added to the entry

 - `password`: The password added to the entry

 - `email`: The email address added to the entry (default `None`)

 - `url`: The URL added to the entry (default `None`)

#### Method <a id="delete"></a>`OnePW.delete`

```python
delete(title: str, no_archive: bool = False)
```

*Delete an entry from 1Password*

Delete an entry from 1Password with the given title. 

**Arguments:**

 - `title`: The title of the entry to delete

 - `no_archive`: Do not archive entry when deleted (default
`False`)

### <a id="cli"></a>To use the module as a console script

#### Command <a id="cli-onepw"></a>`onepw`

*Perform 1Password CLI commands*

**Usage:**

```bash
onepw [-h] [-V] [--doc [{get,list,add,delete}]] [--account ACCOUNT] [--pw PASSWORD] {get,list,add,delete} ...
```

**Positional arguments:**

Name | Description
---- | -----------
`{get,list,add,delete}` | the command to perform

**Options:**

Name | Description
---- | -----------
`-h, --help` | show this help message and exit
`-V, --version` | show program's version number and exit
`--doc [{get,list,add,delete}]` | print documentation of module or specific method
`--account ACCOUNT` | the 1Password account (usually, not necessary)
`--pw PASSWORD` | the 1Password secret password (be careful using this)

Use `onepw {get,list,add,delete} -h` to show help message for a specific
Command

#### Command <a id="cli-onepw-get"></a>`onepw get`

*Get the value of a field from an entry in 1Password*

**Usage:**

```bash
onepw get [-h] [--field [FIELD]] [--info [{id,title,vault,category,urls}]] [--reference] TITLE-OR-ID
```

**Positional arguments:**

Name | Description
---- | -----------
`TITLE-OR-ID` | the title or id of the entry to get the value from

**Options:**

Name | Description
---- | -----------
`-h, --help` | show this help message and exit
`--field [FIELD]` | the field of the entry to get the value from, or if `all`, return all fields in a JSON string (default `password`)
`--info [{id,title,vault,category,urls}]` | get information about the entry, instead of the value of a field (it is possible to specify what info: id, title, vault, category, urls)
`--reference` | get reference to field, not value

#### Command <a id="cli-onepw-list"></a>`onepw list`

*List all entries in 1Password*

**Usage:**

```bash
onepw list [-h] [--categories CATEGORIES] [--favorite] [--tags TAGS] [--vault VAULT]
```

**Options:**

Name | Description
---- | -----------
`-h, --help` | show this help message and exit
`--categories CATEGORIES` | only list items in these categories (comma-separated)
`--favorite` | only list favorite items
`--tags TAGS` | only list items with these tags (comma-separated)
`--vault VAULT` | only list items in this vault

#### Command <a id="cli-onepw-add"></a>`onepw add`

*Add an entry to 1Password*

**Usage:**

```bash
onepw add [-h] --title TITLE --username USERNAME [--password PASSWORD] [--email EMAIL] [--url URL]
```

**Options:**

Name | Description
---- | -----------
`-h, --help` | show this help message and exit
`--title TITLE` | the title of the new entry
`--username USERNAME` | the user name in the new entry
`--password PASSWORD` | the password in the new entry (`onepw add` will ask for the password if it is not provided)
`--email EMAIL` | the email address in the new entry (optional)
`--url URL` | the URL in the new entry (optional)

#### Command <a id="cli-onepw-delete"></a>`onepw delete`

*Delete an entry from 1Password*

**Usage:**

```bash
onepw delete [-h] --title TITLE [--no-confirm] [--no-archive]
```

**Options:**

Name | Description
---- | -----------
`-h, --help` | show this help message and exit
`--title TITLE` | the title of the entry to delete
`--no-confirm` | do not confirm before deleting entry (default `False`)
`--no-archive` | do not archive deleted entry (default `False`)

