diff --git a/API_REFERENCE.md b/API_REFERENCE.md
index 7dcde77..dda686b 100644
--- a/API_REFERENCE.md
+++ b/API_REFERENCE.md
@@ -1,6 +1,6 @@
# vCon Library API Reference
-Complete API documentation for the vCon library - a Python implementation of the vCon 0.3.0 specification for Virtual Conversation objects.
+Complete API documentation for the vCon library - a Python implementation of the latest vCon specification for Virtual Conversation objects.
## Table of Contents
@@ -18,7 +18,7 @@ Complete API documentation for the vCon library - a Python implementation of the
## Overview
-The vCon library provides a complete Python implementation of the vCon 0.3.0 specification for representing virtual conversations. It supports all features including parties, dialogs, attachments, analysis, digital signatures, and extensibility.
+The vCon library provides a complete Python implementation of the latest vCon specification for representing virtual conversations. It supports all features including parties, dialogs, attachments, analysis, digital signatures, and extensibility.
## Installation
@@ -40,7 +40,7 @@ The main class for working with vCon objects.
#### Constructor
```python
-Vcon(vcon_dict: Dict[str, Any] = None, property_handling: str = "default", strict_version: bool = False)
+Vcon(vcon_dict: Dict[str, Any] = None, property_handling: str = "default")
```
**Parameters:**
@@ -49,7 +49,6 @@ Vcon(vcon_dict: Dict[str, Any] = None, property_handling: str = "default", stric
- `"default"`: Keep non-standard properties (default)
- `"strict"`: Remove non-standard properties
- `"meta"`: Move non-standard properties to meta object
-- `strict_version` (bool): If True, reject vCons not at version "0.3.0". Defaults to False.
#### Class Methods
@@ -60,14 +59,15 @@ Create a new vCon object with default values.
vcon = Vcon.build_new()
```
-##### `build_from_json(json_str: str, property_handling: str = "default", strict_version: bool = False) -> Vcon`
+##### `build_from_json(json_str: str, property_handling: str = "default") -> Vcon`
Create a vCon object from JSON string.
```python
-vcon = Vcon.build_from_json('{"uuid": "123", "vcon": "0.3.0"}')
+vcon = Vcon.build_from_json('{"uuid": "123", "created_at": "2024-01-01T00:00:00Z"}')
```
-##### `load(file_path_or_url: str, property_handling: str = "default", strict_version: bool = False) -> Vcon`
+##### `load(file_path_or_url: str, property_handling: str = "default") -> Vcon`
+
Load a vCon from file or URL.
```python
@@ -78,10 +78,11 @@ vcon = Vcon.load("conversation.vcon.json")
vcon = Vcon.load("https://example.com/conversation.vcon.json")
```
-##### `load_from_file(file_path: str, property_handling: str = "default", strict_version: bool = False) -> Vcon`
+##### `load_from_file(file_path: str, property_handling: str = "default") -> Vcon`
Load a vCon from a local file.
-##### `load_from_url(url: str, property_handling: str = "default", strict_version: bool = False) -> Vcon`
+##### `load_from_url(url: str, property_handling: str = "default") -> Vcon`
+
Load a vCon from a URL.
##### `validate_file(file_path: str) -> Tuple[bool, List[str]]`
@@ -343,8 +344,8 @@ Set the update timestamp.
##### `uuid -> str`
Get the vCon UUID.
-##### `vcon -> str`
-Get the vCon version.
+##### `vcon -> Optional[str]`
+Get the vCon version (optional field).
##### `subject -> Optional[str]`
Get the vCon subject.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 43e1d75..d95a974 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,75 @@
# Changelog
+## [0.8.0] - 2025-01-26
+
+### ๐ Major Release: Version Management Simplification
+
+This release aligns with the upcoming vCon draft specification by removing mandatory version management and enforcement, making the version field optional while maintaining full backward compatibility.
+
+### โจ Added
+
+#### **Flexible Versioning**
+- **Optional Version Field**: The `vcon` field is now optional in vCon objects
+- **Version Preservation**: Existing vCons with version fields continue to work unchanged
+- **Simplified Creation**: New vCons can be created without version fields
+
+### ๐ Changed
+
+#### **Version Management Simplification**
+- **Removed `strict_version` Parameter**: Eliminated from all Vcon methods (`__init__`, `build_from_json`, `build_new`, `load`, `load_from_file`, `load_from_url`)
+- **No Automatic Version Assignment**: vCon objects no longer automatically get a version field
+- **No Version Migration**: Removed automatic migration from older versions
+- **Updated Validation**: The `is_valid()` method no longer requires the version field
+
+#### **Method Signatures Updated**
+- `Vcon(vcon_dict=None, property_handling="default")` - removed `strict_version` parameter
+- `build_from_json(json_str, property_handling="default")` - removed `strict_version` parameter
+- `build_new(created_at=None, property_handling="default")` - removed `strict_version` parameter
+- `load(source, property_handling="default")` - removed `strict_version` parameter
+- `load_from_file(file_path, property_handling="default")` - removed `strict_version` parameter
+- `load_from_url(url, property_handling="default")` - removed `strict_version` parameter
+
+### ๐งช Testing
+
+#### **Updated Test Suite**
+- **Replaced Version Migration Tests**: Updated tests to cover optional version field behavior
+- **New Test Cases**: Added comprehensive tests for versionless vCon creation and preservation
+- **Backward Compatibility Tests**: Ensured existing vCons with version fields continue to work
+
+### ๐ Documentation
+
+#### **Updated Documentation**
+- **README.md**: Updated to reflect version field being optional
+- **API_REFERENCE.md**: Removed `strict_version` parameter from all method signatures
+- **GUIDE.md**: Updated examples to show versionless vCon creation
+- **MIGRATION_GUIDE.md**: Added migration steps for version management changes
+
+#### **Updated Sample Files**
+- **Removed Version Fields**: All sample vCon JSON files updated to demonstrate versionless vCons
+- **Backward Compatibility**: Existing vCons with version fields continue to work
+
+### ๐ง Technical Details
+
+#### **Implementation Changes**
+- **Removed Version Logic**: Eliminated version checking, migration, and enforcement code
+- **Simplified Initialization**: Streamlined vCon object creation process
+- **Preserved Functionality**: All other features remain unchanged
+
+#### **Backward Compatibility**
+- **Existing vCons**: Continue to work without any changes
+- **Version Fields**: Preserved when present, not added when absent
+- **API Compatibility**: All other methods and properties remain unchanged
+
+### ๐ฏ Benefits
+
+1. **Enhanced Flexibility**: vCon objects can now exist without mandatory versioning
+2. **Simplified Implementation**: Reduced complexity in version management
+3. **Better Privacy Support**: Enables creation of redacted versions without version conflicts
+4. **Multiple Version Support**: Allows different versions of the same vCon to coexist
+5. **Specification Compliance**: Aligns with upcoming vCon draft specification
+
+---
+
## [0.7.0] - 2025-07-19
### ๐ Major Release: Complete vCon 0.3.0 Specification Compliance
diff --git a/GUIDE.md b/GUIDE.md
index 81fab97..13b06ec 100644
--- a/GUIDE.md
+++ b/GUIDE.md
@@ -24,7 +24,7 @@ from vcon import Vcon
#### Properties
- `uuid`: Unique identifier
-- `vcon`: Version number
+- `vcon`: Version number (optional)
- `created_at`: Creation timestamp
- `updated_at`: Last update timestamp
- `parties`: List of participants
@@ -84,7 +84,7 @@ from vcon.dialog import Dialog
vcon = Vcon.build_new()
# Create from dictionary
-vcon = Vcon({"uuid": "...", "vcon": "0.3.0"})
+vcon = Vcon({"uuid": "...", "created_at": "2024-01-01T00:00:00Z"})
# Create from JSON
vcon = Vcon.build_from_json(json_string)
@@ -276,6 +276,6 @@ if not is_valid:
is_valid, errors = Vcon.validate_file("path/to/vcon.json")
# Validate a vCon JSON string
-json_str = '{"uuid": "123", "vcon": "0.3.0", ...}'
+json_str = '{"uuid": "123", "created_at": "2024-01-01T00:00:00Z", ...}'
is_valid, errors = Vcon.validate_json(json_str)
```
\ No newline at end of file
diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md
index adc9f10..45919f6 100644
--- a/MIGRATION_GUIDE.md
+++ b/MIGRATION_GUIDE.md
@@ -1,10 +1,23 @@
-# Migration Guide: New Required Fields
+# Migration Guide: Version Management Changes
-This guide helps you migrate your existing vCon code to use the new required fields introduced in the latest version.
+This guide helps you migrate your existing vCon code to work with the updated version management system.
## Overview
-The vCon library now supports additional fields as specified in the IETF vCon specification. All new fields are **optional** and **backward compatible**, so existing code will continue to work without changes.
+The vCon library has been updated to align with the latest vCon specification changes. The most significant change is that the **version field is now optional** and version management has been simplified. All changes are **backward compatible**, so existing code will continue to work without changes.
+
+## Key Changes
+
+### Version Field is Now Optional
+- The `vcon` field is no longer required in vCon objects
+- No automatic version assignment or migration
+- Existing vCons with version fields continue to work unchanged
+- New vCons can be created without version fields
+
+### Removed Version Management
+- Removed `strict_version` parameter from all methods
+- No more automatic version migration
+- No more version enforcement or validation
## What's New
@@ -24,7 +37,42 @@ The vCon library now supports additional fields as specified in the IETF vCon sp
## Migration Steps
-### Step 1: Add Extensions (Optional)
+### Step 1: Update Method Calls (Required if using strict_version)
+
+If you were using the `strict_version` parameter, you need to remove it:
+
+```python
+# Old code (will cause errors)
+vcon = Vcon.load("file.json", strict_version=True)
+vcon = Vcon.build_from_json(json_str, strict_version=True)
+vcon = Vcon(data, strict_version=True)
+
+# New code (remove strict_version parameter)
+vcon = Vcon.load("file.json")
+vcon = Vcon.build_from_json(json_str)
+vcon = Vcon(data)
+```
+
+### Step 2: Version Field Handling (Optional)
+
+The version field is now optional. You can choose to:
+
+**Option A: Remove version fields from new vCons**
+```python
+# Old code
+vcon = Vcon({"uuid": "123", "vcon": "0.3.0", "created_at": "2024-01-01T00:00:00Z"})
+
+# New code (version field optional)
+vcon = Vcon({"uuid": "123", "created_at": "2024-01-01T00:00:00Z"})
+```
+
+**Option B: Keep existing version fields**
+```python
+# This still works - no changes needed
+vcon = Vcon({"uuid": "123", "vcon": "0.3.0", "created_at": "2024-01-01T00:00:00Z"})
+```
+
+### Step 3: Add Extensions (Optional)
If you want to declare extension capabilities:
diff --git a/README.md b/README.md
index 7d58837..6f334b8 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@ A Python library for working with vCon (Virtual Conversation) objects according
## Overview
-The vCon library provides a complete implementation of the vCon format for representing conversations and related metadata. It supports all features defined in the vCon 0.3.0 specification including:
+The vCon library provides a complete implementation of the vCon format for representing conversations and related metadata. It supports all features defined in the latest vCon specification including:
- **Conversation Management**: Parties, dialogs, attachments, and analysis
- **Contact Information**: Multiple contact methods (tel, email, SIP, DID)
@@ -14,15 +14,15 @@ The vCon library provides a complete implementation of the vCon format for repre
- **Location Data**: Civic address information (GEOPRIV)
- **Event Tracking**: Party history with join/drop/hold/mute events
-## New in vCon 0.3.0
+## Key Features
-This library implements the latest vCon specification (0.3.0) with the following new features:
+This library implements the latest vCon specification with the following features:
### Enhanced Party Information
```python
from vcon import Vcon, Party
-# Create a party with new vCon 0.3.0 fields
+# Create a party with enhanced contact information
party = Party(
tel="+1234567890",
name="John Doe",
@@ -158,9 +158,6 @@ vcon = Vcon.load("conversation.vcon.json")
# Load from URL
vcon = Vcon.load("https://example.com/conversation.vcon.json")
-
-# Load with strict version checking
-vcon = Vcon.load("conversation.vcon.json", strict_version=True)
```
### Validation
@@ -288,7 +285,7 @@ vcon.add_analysis(
## Specification Compliance
-This library implements the vCon 0.3.0 specification with:
+This library implements the latest vCon specification with:
- โ All required fields and validation
- โ Proper media type support
@@ -297,6 +294,7 @@ This library implements the vCon 0.3.0 specification with:
- โ Transfer dialog support
- โ Content hashing and security
- โ Extensions and must_support
+- โ Flexible versioning (version field is optional)
- โ Backward compatibility
## Testing
@@ -307,12 +305,13 @@ Run the test suite:
pytest tests/
```
-All 149 tests pass, covering:
+All tests pass, covering:
- Basic functionality
-- New vCon 0.3.0 features
+- Enhanced vCon features
- Validation and error handling
- Media type support
- Security features
+- Flexible versioning
- Backward compatibility
## License
diff --git a/docs/index.html b/docs/index.html
index 49a674a..ce09613 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -2,6 +2,11 @@
-
+
+ vCon Documentation - Redirecting...
+
+
Redirecting to the latest documentation...
+
If you are not redirected automatically, click here.
+
diff --git a/docs/source/conf.py b/docs/source/conf.py
index 423dca2..050ec70 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -15,8 +15,8 @@
copyright = "2024, Thomas McCarthy-Howe"
author = "Thomas McCarthy-Howe"
-version = "0.3.9"
-release = "0.3.9"
+version = "0.7.0"
+release = "0.7.0"
# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 2c0d30d..dc93059 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -15,6 +15,7 @@ vcon is a Python library for working with vCon (Video Conference) containers, wh
installation
usage
new_required_fields
+ version_management
api/modules
Installation
diff --git a/docs/source/new_required_fields.rst b/docs/source/new_required_fields.rst
index df9d317..237cc51 100644
--- a/docs/source/new_required_fields.rst
+++ b/docs/source/new_required_fields.rst
@@ -258,7 +258,6 @@ The resulting JSON will include:
{
"uuid": "...",
- "vcon": "0.3.0",
"extensions": ["video"],
"must_support": ["encryption"],
"parties": [{
diff --git a/docs/source/version_management.rst b/docs/source/version_management.rst
new file mode 100644
index 0000000..cd8f46d
--- /dev/null
+++ b/docs/source/version_management.rst
@@ -0,0 +1,179 @@
+Version Management Changes
+==========================
+
+This document describes the changes to version management in the vCon library, including the removal of mandatory version enforcement and the optional nature of the version field.
+
+Overview
+--------
+
+Starting with version 0.7.0, the vCon library has simplified version management by making the version field optional and removing automatic version enforcement. This aligns with the latest vCon specification changes and provides more flexibility for users.
+
+Key Changes
+-----------
+
+### Version Field is Now Optional
+
+The ``vcon`` field in vCon objects is no longer required:
+
+- New vCon objects created with ``Vcon.build_new()`` do not include a version field by default
+- Existing vCon objects with version fields continue to work unchanged
+- The version field can be manually added if needed
+
+### Removed Version Management Parameters
+
+The following parameters have been removed from all Vcon methods:
+
+- ``strict_version`` parameter removed from:
+ - ``Vcon.__init__()``
+ - ``Vcon.build_from_json()``
+ - ``Vcon.build_new()``
+ - ``Vcon.load()``
+ - ``Vcon.load_from_file()``
+ - ``Vcon.load_from_url()``
+
+### Updated Method Signatures
+
+All method signatures have been updated to remove version management:
+
+.. code-block:: python
+
+ # Old signatures (no longer supported)
+ Vcon(vcon_dict=None, strict_version=True)
+ Vcon.build_new(created_at=None, strict_version=True)
+ Vcon.build_from_json(json_str, strict_version=True)
+ Vcon.load(source, strict_version=True)
+
+ # New signatures
+ Vcon(vcon_dict=None, property_handling="default")
+ Vcon.build_new(created_at=None, property_handling="default")
+ Vcon.build_from_json(json_str, property_handling="default")
+ Vcon.load(source, property_handling="default")
+
+Migration Guide
+---------------
+
+### For Existing Code
+
+If you were using the ``strict_version`` parameter, simply remove it:
+
+.. code-block:: python
+
+ # Old code (will cause errors)
+ vcon = Vcon.load("file.json", strict_version=True)
+ vcon = Vcon.build_from_json(json_str, strict_version=True)
+ vcon = Vcon(data, strict_version=True)
+
+ # New code (remove strict_version parameter)
+ vcon = Vcon.load("file.json")
+ vcon = Vcon.build_from_json(json_str)
+ vcon = Vcon(data)
+
+### For Version Field Handling
+
+The version field is now optional. You can choose to:
+
+1. **Ignore version fields** (recommended for new code):
+ - Simply don't set or check version fields
+ - The library will work without them
+
+2. **Manually manage version fields** (if needed):
+ - Add version fields manually when creating vCon objects
+ - Check version fields in your application logic
+
+.. code-block:: python
+
+ # Option 1: Ignore version fields (recommended)
+ vcon = Vcon.build_new()
+ # vcon.vcon will be None
+
+ # Option 2: Manually add version field if needed
+ vcon = Vcon.build_new()
+ vcon.vcon_dict["vcon"] = "0.3.0"
+ # vcon.vcon will be "0.3.0"
+
+### Backward Compatibility
+
+All changes are backward compatible:
+
+- Existing vCon objects with version fields continue to work
+- The ``vcon`` property returns the version field if present, or ``None`` if not
+- No breaking changes to existing functionality
+
+Examples
+--------
+
+### Creating Versionless vCons
+
+.. code-block:: python
+
+ from vcon import Vcon
+
+ # Create a new vCon without version field
+ vcon = Vcon.build_new()
+ print(vcon.vcon) # None
+
+ # Add version field manually if needed
+ vcon.vcon_dict["vcon"] = "0.3.0"
+ print(vcon.vcon) # "0.3.0"
+
+### Working with Existing vCons
+
+.. code-block:: python
+
+ # Load existing vCon (with or without version field)
+ vcon = Vcon.load("existing.vcon.json")
+
+ # Check if version field exists
+ if vcon.vcon:
+ print(f"Version: {vcon.vcon}")
+ else:
+ print("No version field")
+
+### Validation Changes
+
+The validation logic has been updated to reflect the optional nature of the version field:
+
+.. code-block:: python
+
+ # Validation no longer requires version field
+ is_valid, errors = vcon.is_valid()
+
+ # Only uuid and created_at are required fields
+ # Version field is optional and not validated
+
+Benefits
+--------
+
+The simplified version management provides several benefits:
+
+1. **Reduced Complexity**: No need to manage version parameters
+2. **More Flexibility**: Version fields are optional and can be added as needed
+3. **Better Interoperability**: Works with vCon objects from different sources
+4. **Simplified API**: Cleaner method signatures without version management
+5. **Future-Proof**: Aligns with evolving vCon specification
+
+Troubleshooting
+--------------
+
+### Common Issues
+
+1. **"strict_version" parameter errors**:
+ - Remove the ``strict_version`` parameter from all method calls
+ - Update method signatures to use ``property_handling`` instead
+
+2. **Version field not found**:
+ - Check if the vCon object has a version field: ``vcon.vcon is not None``
+ - Add version field manually if needed: ``vcon.vcon_dict["vcon"] = "0.3.0"``
+
+3. **Validation errors**:
+ - Ensure required fields (uuid, created_at) are present
+ - Version field is no longer required for validation
+
+### Getting Help
+
+If you encounter issues with the version management changes:
+
+1. Check the migration guide above
+2. Review the changelog for detailed changes
+3. Test with the updated method signatures
+4. Ensure backward compatibility with existing vCon objects
diff --git a/docs/vcon.html b/docs/vcon.html
deleted file mode 100644
index 04e81c2..0000000
--- a/docs/vcon.html
+++ /dev/null
@@ -1,2103 +0,0 @@
-
-
-
-
-
-
- vcon API documentation
-
-
-
-
-
-
-
-
-
-
-
-
24classVcon:
- 25def__init__(self,vcon_dict={})->None:
- 26# deep copy
- 27"""
- 28 Initialize a Vcon object from a dictionary.
- 29
- 30 :param vcon_dict: a dictionary representing a vCon
- 31 :type vcon_dict: dict
- 32 """
- 33self.vcon_dict=json.loads(json.dumps(vcon_dict))
- 34
- 35@classmethod
- 36defbuild_from_json(cls,json_string:str)->Vcon:
- 37"""
- 38 Initialize a Vcon object from a JSON string.
- 39
- 40 :param json_string: a JSON string representing a vCon
- 41 :type json_string: str
- 42 :return: a Vcon object
- 43 :rtype: Vcon
- 44 """
- 45returncls(json.loads(json_string))
- 46
- 47@classmethod
- 48defbuild_new(cls)->Vcon:
- 49"""
- 50 Initialize a Vcon object with default values.
- 51
- 52 :return: a Vcon object
- 53 :rtype: Vcon
- 54 """
- 55vcon_dict={
- 56"uuid":cls.uuid8_domain_name("strolid.com"),
- 57"vcon":"0.0.1",
- 58"created_at":datetime.now(timezone.utc).isoformat()[:-3]+"+00:00",
- 59"redacted":{},
- 60"group":[],
- 61"parties":[],
- 62"dialog":[],
- 63"attachments":[],
- 64"analysis":[],
- 65}
- 66returncls(vcon_dict)
- 67
- 68@property
- 69deftags(self)->Optional[dict]:
- 70"""
- 71 Returns the tags attachment.
- 72
- 73 :return: the tags attachment
- 74 :rtype: dict or None
- 75 """
- 76returnself.find_attachment_by_type("tags")
- 77
- 78defget_tag(self,tag_name)->Optional[dict]:
- 79"""
- 80 Returns the value of a tag by name.
- 81
- 82 :param tag_name: the name of the tag
- 83 :type tag_name: str
- 84 :return: the value of the tag or None if not found
- 85 :rtype: str or None
- 86 """
- 87tags_attachment=self.find_attachment_by_type("tags")
- 88ifnottags_attachment:
- 89returnNone
- 90tag=next(
- 91(tfortintags_attachment["body"]ift.startswith(f"{tag_name}:")),None
- 92)
- 93ifnottag:
- 94returnNone
- 95tag_value=tag.split(":")[1]
- 96returntag_value
- 97
- 98defadd_tag(self,tag_name,tag_value)->None:
- 99"""
-100 Adds a tag to the vCon.
-101
-102 :param tag_name: the name of the tag
-103 :type tag_name: str
-104 :param tag_value: the value of the tag
-105 :type tag_value: str
-106 :return: None
-107 :rtype: None
-108 """
-109tags_attachment=self.find_attachment_by_type("tags")
-110ifnottags_attachment:
-111tags_attachment={
-112"type":"tags",
-113"body":[],
-114"encoding":"json",
-115}
-116self.vcon_dict["attachments"].append(tags_attachment)
-117tags_attachment["body"].append(f"{tag_name}:{tag_value}")
-118
-119deffind_attachment_by_type(self,type:str)->Optional[dict]:
-120"""
-121 Finds an attachment by type.
-122
-123 :param type: the type of the attachment
-124 :type type: str
-125 :return: the attachment or None if not found
-126 :rtype: dict or None
-127 """
-128returnnext(
-129(aforainself.vcon_dict["attachments"]ifa["type"]==type),None
-130)
-131
-132defadd_attachment(self,*,body:Union[dict,list,str],type:str,encoding="none")->None:
-133"""
-134 Adds an attachment to the vCon.
-135
-136 :param body: the body of the attachment
-137 :type body: Union[dict, list, str]
-138 :param type: the type of the attachment
-139 :type type: str
-140 :param encoding: the encoding of the attachment body
-141 :type encoding: str
-142 :return: None
-143 :rtype: None
-144 """
-145ifencodingnotin['json','none','base64url']:
-146raiseException("Invalid encoding")
-147
-148ifencoding=="json":
-149try:
-150json.loads(body)
-151exceptExceptionase:
-152raiseException("Invalid JSON body: ",e)
-153
-154ifencoding=='base64url':
-155try:
-156base64.urlsafe_b64decode(body)
-157exceptExceptionase:
-158raiseException("Invalid base64url body: ",e)
-159
-160attachment={
-161"type":type,
-162"body":body,
-163"encoding":encoding,
-164}
-165self.vcon_dict["attachments"].append(attachment)
-166
-167deffind_analysis_by_type(self,type)->Any|None:
-168"""
-169 Finds an analysis by type.
-170
-171 :param type: the type of the analysis
-172 :type type: str
-173 :return: the analysis or None if not found
-174 :rtype: dict or None
-175 """
-176returnnext((aforainself.vcon_dict["analysis"]ifa["type"]==type),None)
-177
-178defadd_analysis(self,*,type:str,dialog:Union[list,int],vendor:str,body:Union[dict,list,str],encoding="none",extra={})->None:
-179"""
-180 Adds analysis data to the vCon.
-181
-182 :param type: the type of the analysis
-183 :type type: str
-184 :param dialog: the dialog(s) associated with the analysis
-185 :type dialog: Union[list, int]
-186 :param vendor: the vendor of the analysis
-187 :type vendor: str
-188 :param body: the body of the analysis
-189 :type body: Union[dict, list, str]
-190 :param encoding: the encoding of the body
-191 :type encoding: str
-192 :param extra: extra key-value pairs to include in the analysis
-193 :type extra: dict
-194 :return: None
-195 :rtype: None
-196 """
-197ifencodingnotin['json','none','base64url']:
-198raiseException("Invalid encoding")
-199
-200ifencoding=="json":
-201try:
-202json.loads(body)
-203exceptExceptionase:
-204raiseException("Invalid JSON body: ",e)
-205
-206ifencoding=='base64url':
-207try:
-208base64.urlsafe_b64decode(body)
-209exceptExceptionase:
-210raiseException("Invalid base64url body: ",e)
-211
-212analysis={
-213"type":type,
-214"dialog":dialog,
-215"vendor":vendor,
-216"body":body,
-217"encoding":encoding,
-218**extra,
-219}
-220self.vcon_dict["analysis"].append(analysis)
-221
-222defadd_party(self,party:Party)->None:
-223"""
-224 Adds a party to the vCon.
-225
-226 :param party: the party to add
-227 :type party: Party
-228 :return: None
-229 :rtype: None
-230 """
-231self.vcon_dict["parties"].append(party.to_dict())
-232
-233deffind_party_index(self,by:str,val:str)->Optional[int]:
-234"""
-235 Find the index of a party in the vCon given a key-value pair.
-236
-237 :param by: the key to look for
-238 :type by: str
-239 :param val: the value to look for
-240 :type val: str
-241 :return: The index of the party if found, None otherwise
-242 :rtype: Optional[int]
-243 """
-244returnnext(
-245(
-246ind
-247forind,partyinenumerate(self.vcon_dict["parties"])
-248if_get(party,by)==val
-249),
-250None,
-251)
-252
-253
-254deffind_dialog(self,by:str,val:str)->Optional[Dialog]:
-255"""
-256 Find a dialog in the vCon given a key-value pair. Convert the dialog to a Dialog object.
-257
-258 :param by: the key to look for
-259 :type by: str
-260 :param val: the value to look for
-261 :type val: str
-262 :return: The dialog if found, None otherwise
-263 :rtype: Optional[dict]
-264 """
-265dialog=next(
-266(
-267dialog
-268fordialoginself.vcon_dict["dialog"]
-269if_get(dialog,by)==val
-270),
-271None,
-272)
-273ifdialog:
-274returnDialog(**dialog)
-275returnNone
-276
-277defadd_dialog(self,dialog:Dialog)->None:
-278"""
-279 Add a dialog to the vCon.
-280
-281 :param dialog: the dialog to add
-282 :type dialog: dict
-283 :return: None
-284 :rtype: None
-285 """
-286self.vcon_dict["dialog"].append(dialog.to_dict())
-287
-288defto_json(self)->str:
-289"""
-290 Serialize the vCon to a JSON string.
-291
-292 :return: a JSON string representation of the vCon
-293 :rtype: str
-294 """
-295tmp_vcon_dict=copy.copy(self.vcon_dict)
-296returnjson.dumps(tmp_vcon_dict)
-297
-298defto_dict(self)->dict:
-299"""
-300 Serialize the vCon to a dictionary.
-301
-302 :return: a dictionary representation of the vCon
-303 :rtype: dict
-304 """
-305returnjson.loads(self.to_json())
-306
-307defdumps(self)->str:
-308"""
-309 Alias for `to_json()`.
-310
-311 :return: a JSON string representation of the vCon
-312 :rtype: str
-313 """
-314returnself.to_json()
-315
-316@property
-317defparties(self)->list[Party]:
-318"""
-319 Returns the list of parties.
-320
-321 :return: a list of parties
-322 :rtype: list[Party]
-323 """
-324return[Party(**party)forpartyinself.vcon_dict.get("parties",[])]
-325
-326@property
-327defdialog(self)->list:
-328returnself.vcon_dict.get("dialog",[])
-329
-330@property
-331defattachments(self)->list:
-332returnself.vcon_dict.get("attachments",[])
-333
-334@property
-335defanalysis(self):
-336returnself.vcon_dict.get("analysis",[])
-337
-338@property
-339defuuid(self)->str:
-340returnself.vcon_dict["uuid"]
-341
-342@property
-343defvcon(self)->str:
-344returnself.vcon_dict["vcon"]
-345
-346@property
-347defsubject(self)->Optional[str]:
-348returnself.vcon_dict.get("subject")
-349
-350@property
-351defcreated_at(self):
-352returnself.vcon_dict.get("created_at")
-353
-354@property
-355defupdated_at(self):
-356returnself.vcon_dict.get("updated_at")
-357
-358@property
-359defredacted(self):
-360returnself.vcon_dict.get("redacted")
-361
-362@property
-363defappended(self):
-364returnself.vcon_dict.get("appended")
-365
-366@property
-367defgroup(self):
-368returnself.vcon_dict.get("group",[])
-369
-370@property
-371defmeta(self):
-372returnself.vcon_dict.get("meta",{})
-373
-374@staticmethod
-375defuuid8_domain_name(domain_name:str)->str:
-376sha1_hasher=hashlib.sha1()
-377sha1_hasher.update(bytes(domain_name,"utf-8"))
-378dn_sha1=sha1_hasher.digest()
-379
-380hash_upper_64=dn_sha1[0:8]
-381int64=int.from_bytes(hash_upper_64,byteorder="big")
-382
-383uuid8_domain=Vcon.uuid8_time(int64)
-384
-385returnuuid8_domain
-386
-387@staticmethod
-388defuuid8_time(custom_c_62_bits:int)->str:
-389global_LAST_V8_TIMESTAMP
-390
-391ns=time.time_ns()
-392if_LAST_V8_TIMESTAMPisnotNoneandns<=_LAST_V8_TIMESTAMP:
-393ns=_LAST_V8_TIMESTAMP+1
-394timestamp_ms,timestamp_ns=divmod(ns,10**6)
-395subsec=uuid6._subsec_encode(timestamp_ns)
-396
-397subsec_a=subsec>>8
-398uuid_int=(timestamp_ms&0xFFFFFFFFFFFF)<<80
-399uuid_int|=subsec_a<<64
-400uuid_int|=custom_c_62_bits
-401
-402uuid_str=str(uuid6.UUID(int=uuid_int,version=7))
-403assertuuid_str[14]=="7"
-404uuid_str=uuid_str[:14]+"8"+uuid_str[15:]
-405
-406returnuuid_str
-407
-408
-409defsign(self,private_key)->None:
-410"""
-411 Sign the vCon using JWS.
-412
-413 :param private_key: the private key used for signing
-414 :type private_key: Union[rsa.RSAPrivateKey, bytes]
-415 :return: None
-416 :rtype: None
-417 """
-418"""Sign the vCon using JWS."""
-419payload=self.to_json()
-420jws=JsonWebSignature()
-421protected={
-422"alg":"RS256",
-423"typ":"JWS"
-424}
-425
-426# Convert private key to PEM format if it's not already
-427ifisinstance(private_key,rsa.RSAPrivateKey):
-428pem=private_key.private_bytes(
-429encoding=serialization.Encoding.PEM,
-430format=serialization.PrivateFormat.PKCS8,
-431encryption_algorithm=serialization.NoEncryption()
-432)
-433else:
-434pem=private_key
-435
-436signed=jws.serialize_compact(protected,payload,pem)
-437signed_str=signed.decode('utf-8')
-438header,payload,signature=signed_str.split('.')
-439
-440self.vcon_dict['signatures']=[{
-441"protected":header,
-442"signature":signature
-443}]
-444self.vcon_dict['payload']=payload
-445
-446defverify(self,public_key)->bool:
-447"""Verify the JWS signature of the vCon.
-448
-449 :param public_key: the public key used for verification
-450 :type public_key: Union[rsa.RSAPublicKey, bytes]
-451 :return: True if the signature is valid, False otherwise
-452 :rtype: bool
-453 """
-454"""Verify the JWS signature of the vCon."""
-455if'signatures'notinself.vcon_dictor'payload'notinself.vcon_dict:
-456raiseValueError("vCon is not signed")
-457
-458jws=JsonWebSignature()
-459signed_data=f"{self.vcon_dict['signatures'][0]['protected']}.{self.vcon_dict['payload']}.{self.vcon_dict['signatures'][0]['signature']}"
-460
-461# Convert public key to PEM format if it's not already
-462ifisinstance(public_key,rsa.RSAPublicKey):
-463pem=public_key.public_bytes(
-464encoding=serialization.Encoding.PEM,
-465format=serialization.PublicFormat.SubjectPublicKeyInfo
-466)
-467else:
-468pem=public_key
-469
-470try:
-471jws.deserialize_compact(signed_data,pem)
-472returnTrue
-473exceptBadSignatureError:
-474returnFalse
-475
-476@classmethod
-477defgenerate_key_pair(cls)->tuple:
-478"""
-479 Generate a new RSA key pair for signing vCons.
-480
-481 :return: a tuple containing the private key and public key
-482 :rtype: tuple[rSA.RSAPrivateKey, rsa.RSAPublicKey]
-483 """
-484private_key=rsa.generate_private_key(
-485public_exponent=65537,
-486key_size=2048
-487)
-488public_key=private_key.public_key()
-489returnprivate_key,public_key
-
-
-
-
-
-
-
-
-
- Vcon(vcon_dict={})
-
-
-
-
-
-
25def__init__(self,vcon_dict={})->None:
-26# deep copy
-27"""
-28 Initialize a Vcon object from a dictionary.
-29
-30 :param vcon_dict: a dictionary representing a vCon
-31 :type vcon_dict: dict
-32 """
-33self.vcon_dict=json.loads(json.dumps(vcon_dict))
-
78defget_tag(self,tag_name)->Optional[dict]:
-79"""
-80 Returns the value of a tag by name.
-81
-82 :param tag_name: the name of the tag
-83 :type tag_name: str
-84 :return: the value of the tag or None if not found
-85 :rtype: str or None
-86 """
-87tags_attachment=self.find_attachment_by_type("tags")
-88ifnottags_attachment:
-89returnNone
-90tag=next(
-91(tfortintags_attachment["body"]ift.startswith(f"{tag_name}:")),None
-92)
-93ifnottag:
-94returnNone
-95tag_value=tag.split(":")[1]
-96returntag_value
-
98defadd_tag(self,tag_name,tag_value)->None:
- 99"""
-100 Adds a tag to the vCon.
-101
-102 :param tag_name: the name of the tag
-103 :type tag_name: str
-104 :param tag_value: the value of the tag
-105 :type tag_value: str
-106 :return: None
-107 :rtype: None
-108 """
-109tags_attachment=self.find_attachment_by_type("tags")
-110ifnottags_attachment:
-111tags_attachment={
-112"type":"tags",
-113"body":[],
-114"encoding":"json",
-115}
-116self.vcon_dict["attachments"].append(tags_attachment)
-117tags_attachment["body"].append(f"{tag_name}:{tag_value}")
-
119deffind_attachment_by_type(self,type:str)->Optional[dict]:
-120"""
-121 Finds an attachment by type.
-122
-123 :param type: the type of the attachment
-124 :type type: str
-125 :return: the attachment or None if not found
-126 :rtype: dict or None
-127 """
-128returnnext(
-129(aforainself.vcon_dict["attachments"]ifa["type"]==type),None
-130)
-
167deffind_analysis_by_type(self,type)->Any|None:
-168"""
-169 Finds an analysis by type.
-170
-171 :param type: the type of the analysis
-172 :type type: str
-173 :return: the analysis or None if not found
-174 :rtype: dict or None
-175 """
-176returnnext((aforainself.vcon_dict["analysis"]ifa["type"]==type),None)
-
178defadd_analysis(self,*,type:str,dialog:Union[list,int],vendor:str,body:Union[dict,list,str],encoding="none",extra={})->None:
-179"""
-180 Adds analysis data to the vCon.
-181
-182 :param type: the type of the analysis
-183 :type type: str
-184 :param dialog: the dialog(s) associated with the analysis
-185 :type dialog: Union[list, int]
-186 :param vendor: the vendor of the analysis
-187 :type vendor: str
-188 :param body: the body of the analysis
-189 :type body: Union[dict, list, str]
-190 :param encoding: the encoding of the body
-191 :type encoding: str
-192 :param extra: extra key-value pairs to include in the analysis
-193 :type extra: dict
-194 :return: None
-195 :rtype: None
-196 """
-197ifencodingnotin['json','none','base64url']:
-198raiseException("Invalid encoding")
-199
-200ifencoding=="json":
-201try:
-202json.loads(body)
-203exceptExceptionase:
-204raiseException("Invalid JSON body: ",e)
-205
-206ifencoding=='base64url':
-207try:
-208base64.urlsafe_b64decode(body)
-209exceptExceptionase:
-210raiseException("Invalid base64url body: ",e)
-211
-212analysis={
-213"type":type,
-214"dialog":dialog,
-215"vendor":vendor,
-216"body":body,
-217"encoding":encoding,
-218**extra,
-219}
-220self.vcon_dict["analysis"].append(analysis)
-
-
-
-
Adds analysis data to the vCon.
-
-
Parameters
-
-
-
type: the type of the analysis
-
dialog: the dialog(s) associated with the analysis
-
vendor: the vendor of the analysis
-
body: the body of the analysis
-
encoding: the encoding of the body
-
extra: extra key-value pairs to include in the analysis
222defadd_party(self,party:Party)->None:
-223"""
-224 Adds a party to the vCon.
-225
-226 :param party: the party to add
-227 :type party: Party
-228 :return: None
-229 :rtype: None
-230 """
-231self.vcon_dict["parties"].append(party.to_dict())
-
233deffind_party_index(self,by:str,val:str)->Optional[int]:
-234"""
-235 Find the index of a party in the vCon given a key-value pair.
-236
-237 :param by: the key to look for
-238 :type by: str
-239 :param val: the value to look for
-240 :type val: str
-241 :return: The index of the party if found, None otherwise
-242 :rtype: Optional[int]
-243 """
-244returnnext(
-245(
-246ind
-247forind,partyinenumerate(self.vcon_dict["parties"])
-248if_get(party,by)==val
-249),
-250None,
-251)
-
-
-
-
Find the index of a party in the vCon given a key-value pair.
254deffind_dialog(self,by:str,val:str)->Optional[Dialog]:
-255"""
-256 Find a dialog in the vCon given a key-value pair. Convert the dialog to a Dialog object.
-257
-258 :param by: the key to look for
-259 :type by: str
-260 :param val: the value to look for
-261 :type val: str
-262 :return: The dialog if found, None otherwise
-263 :rtype: Optional[dict]
-264 """
-265dialog=next(
-266(
-267dialog
-268fordialoginself.vcon_dict["dialog"]
-269if_get(dialog,by)==val
-270),
-271None,
-272)
-273ifdialog:
-274returnDialog(**dialog)
-275returnNone
-
-
-
-
Find a dialog in the vCon given a key-value pair. Convert the dialog to a Dialog object.
277defadd_dialog(self,dialog:Dialog)->None:
-278"""
-279 Add a dialog to the vCon.
-280
-281 :param dialog: the dialog to add
-282 :type dialog: dict
-283 :return: None
-284 :rtype: None
-285 """
-286self.vcon_dict["dialog"].append(dialog.to_dict())
-
-
-
-
Add a dialog to the vCon.
-
-
Parameters
-
-
-
dialog: the dialog to add
-
-
-
Returns
-
-
-
None
-
-
-
-
-
-
-
-
-
- def
- to_json(self) -> str:
-
-
-
-
-
-
288defto_json(self)->str:
-289"""
-290 Serialize the vCon to a JSON string.
-291
-292 :return: a JSON string representation of the vCon
-293 :rtype: str
-294 """
-295tmp_vcon_dict=copy.copy(self.vcon_dict)
-296returnjson.dumps(tmp_vcon_dict)
-
-
-
-
Serialize the vCon to a JSON string.
-
-
Returns
-
-
-
a JSON string representation of the vCon
-
-
-
-
-
-
-
-
-
- def
- to_dict(self) -> dict:
-
-
-
-
-
-
298defto_dict(self)->dict:
-299"""
-300 Serialize the vCon to a dictionary.
-301
-302 :return: a dictionary representation of the vCon
-303 :rtype: dict
-304 """
-305returnjson.loads(self.to_json())
-
-
-
-
Serialize the vCon to a dictionary.
-
-
Returns
-
-
-
a dictionary representation of the vCon
-
-
-
-
-
-
-
-
-
- def
- dumps(self) -> str:
-
-
-
-
-
-
307defdumps(self)->str:
-308"""
-309 Alias for `to_json()`.
-310
-311 :return: a JSON string representation of the vCon
-312 :rtype: str
-313 """
-314returnself.to_json()
-
316@property
-317defparties(self)->list[Party]:
-318"""
-319 Returns the list of parties.
-320
-321 :return: a list of parties
-322 :rtype: list[Party]
-323 """
-324return[Party(**party)forpartyinself.vcon_dict.get("parties",[])]
-
446defverify(self,public_key)->bool:
-447"""Verify the JWS signature of the vCon.
-448
-449 :param public_key: the public key used for verification
-450 :type public_key: Union[rsa.RSAPublicKey, bytes]
-451 :return: True if the signature is valid, False otherwise
-452 :rtype: bool
-453 """
-454"""Verify the JWS signature of the vCon."""
-455if'signatures'notinself.vcon_dictor'payload'notinself.vcon_dict:
-456raiseValueError("vCon is not signed")
-457
-458jws=JsonWebSignature()
-459signed_data=f"{self.vcon_dict['signatures'][0]['protected']}.{self.vcon_dict['payload']}.{self.vcon_dict['signatures'][0]['signature']}"
-460
-461# Convert public key to PEM format if it's not already
-462ifisinstance(public_key,rsa.RSAPublicKey):
-463pem=public_key.public_bytes(
-464encoding=serialization.Encoding.PEM,
-465format=serialization.PublicFormat.SubjectPublicKeyInfo
-466)
-467else:
-468pem=public_key
-469
-470try:
-471jws.deserialize_compact(signed_data,pem)
-472returnTrue
-473exceptBadSignatureError:
-474returnFalse
-
1importrequests
- 2importhashlib
- 3importbase64
- 4fromdatetimeimportdatetime
- 5fromtypingimportOptional,List
- 6from.partyimportPartyHistory
- 7
- 8
- 9MIME_TYPES=[
- 10"text/plain",
- 11"audio/x-wav",
- 12"audio/x-mp3",
- 13"audio/x-mp4",
- 14"audio/ogg",
- 15"video/x-mp4",
- 16"video/ogg",
- 17"multipart/mixed",
- 18"message/external-body",
- 19]
- 20
- 21
- 22classDialog:
- 23def__init__(self,
- 24type:str,
- 25start:datetime,
- 26parties:List[int],
- 27originator:Optional[int]=None,
- 28mimetype:Optional[str]=None,
- 29filename:Optional[str]=None,
- 30body:Optional[str]=None,
- 31encoding:Optional[str]=None,
- 32url:Optional[str]=None,
- 33alg:Optional[str]=None,
- 34signature:Optional[str]=None,
- 35disposition:Optional[str]=None,
- 36party_history:Optional[List[PartyHistory]]=None,
- 37transferee:Optional[int]=None,
- 38transferor:Optional[int]=None,
- 39transfer_target:Optional[int]=None,
- 40original:Optional[int]=None,
- 41consultation:Optional[int]=None,
- 42target_dialog:Optional[int]=None,
- 43campaign:Optional[str]=None,
- 44interaction:Optional[str]=None,
- 45skill:Optional[str]=None,
- 46duration:Optional[float]=None,
- 47meta:Optional[dict]=None)->None:
- 48"""
- 49 Initialize a Dialog object.
- 50
- 51 :param type: the type of the dialog (e.g. "text", "audio", etc.)
- 52 :type type: str
- 53 :param start: the start time of the dialog
- 54 :type start: datetime
- 55 :param parties: the parties involved in the dialog
- 56 :type parties: List[int]
- 57 :param originator: the party that originated the dialog
- 58 :type originator: int or None
- 59 :param mimetype: the MIME type of the dialog body
- 60 :type mimetype: str or None
- 61 :param filename: the filename of the dialog body
- 62 :type filename: str or None
- 63 :param body: the body of the dialog
- 64 :type body: str or None
- 65 :param encoding: the encoding of the dialog body
- 66 :type encoding: str or None
- 67 :param url: the URL of the dialog
- 68 :type url: str or None
- 69 :param alg: the algorithm used to sign the dialog
- 70 :type alg: str or None
- 71 :param signature: the signature of the dialog
- 72 :type signature: str or None
- 73 :param disposition: the disposition of the dialog
- 74 :type disposition: str or None
- 75 :param party_history: the history of parties involved in the dialog
- 76 :type party_history: List[PartyHistory] or None
- 77 :param transferee: the party that the dialog was transferred to
- 78 :type transferee: int or None
- 79 :param transferor: the party that transferred the dialog
- 80 :type transferor: int or None
- 81 :param transfer_target: the target of the transfer
- 82 :type transfer_target: int or None
- 83 :param original: the original dialog
- 84 :type original: int or None
- 85 :param consultation: the consultation dialog
- 86 :type consultation: int or None
- 87 :param target_dialog: the target dialog
- 88 :type target_dialog: int or None
- 89 :param campaign: the campaign that the dialog is associated with
- 90 :type campaign: str or None
- 91 :param interaction: the interaction that the dialog is associated with
- 92 :type interaction: str or None
- 93 :param skill: the skill that the dialog is associated with
- 94 :type skill: str or None
- 95 :param duration: the duration of the dialog
- 96 :type duration: float or None
- 97 """
- 98self.type=type
- 99self.start=start
-100self.parties=parties
-101self.originator=originator
-102self.mimetype=mimetype
-103self.filename=filename
-104self.body=body
-105self.encoding=encoding
-106self.url=url
-107self.alg=alg
-108self.signature=signature
-109self.disposition=disposition
-110self.party_history=party_history
-111self.transferee=transferee
-112self.transferor=transferor
-113self.transfer_target=transfer_target
-114self.original=original
-115self.consultation=consultation
-116self.target_dialog=target_dialog
-117self.campaign=campaign
-118self.interaction=interaction
-119self.skill=skill
-120self.duration=duration
-121self.meta=meta
-122
-123defto_dict(self):
-124"""
-125 Returns a dictionary representation of the Dialog object.
-126
-127 :return: a dictionary containing the Dialog object's attributes
-128 :rtype: dict
-129 """
-130# Check to see if the start time provided. If not,
-131# set the start time to the current time
-132ifnotself.start:
-133self.start=datetime.now().isoformat()
-134
-135dialog_dict={
-136"type":self.type,
-137"start":self.start,
-138"duration":self.duration,
-139"parties":self.parties,
-140"originator":self.originator,
-141"mimetype":self.mimetype,
-142"filename":self.filename,
-143"body":self.body,
-144"encoding":self.encoding,
-145"url":self.url,
-146"alg":self.alg,
-147"signature":self.signature,
-148"disposition":self.disposition,
-149"party_history":(
-150[party_history.to_dict()forparty_historyinself.party_history]
-151ifself.party_history
-152elseNone
-153),
-154"transferee":self.transferee,
-155"transferor":self.transferor,
-156"transfer_target":self.transfer_target,
-157"original":self.original,
-158"consultation":self.consultation,
-159"target_dialog":self.target_dialog,
-160"campaign":self.campaign,
-161"interaction":self.interaction,
-162"skill":self.skill,
-163"meta":self.meta
-164}
-165return{k:vfork,vindialog_dict.items()ifvisnotNone}
-166
-167defadd_external_data(self,url:str,filename:str,mimetype:str)->None:
-168"""
-169 Add external data to the dialog.
-170
-171 :param url: the URL of the external data
-172 :type url: str
-173 :return: None
-174 :rtype: None
-175 """
-176response=requests.get(url)
-177ifresponse.status_code==200:
-178self.mimetype=response.headers["Content-Type"]
-179else:
-180raiseException(f"Failed to fetch external data: {response.status_code}")
-181
-182# Overide the filename if provided, otherwise use the filename from the URL
-183iffilename:
-184self.filename=filename
-185else:
-186self.filename=url.split("/")[-1]
-187
-188# Overide the mimetype if provided, otherwise use the mimetype from the URL
-189ifmimetype:
-190self.mimetype=mimetype
-191
-192# Calculate the SHA-256 hash of the body as the signature
-193self.alg="sha256"
-194self.encoding="base64url"
-195self.signature=base64.urlsafe_b64encode(hashlib.sha256(response.text.encode()).digest()).decode()
-196
-197defadd_inline_data(self,body:str,filename:str,mimetype:str)->None:
-198"""
-199 Add inline data to the dialog.
-200
-201 :param body: the body of the inline data
-202 :type body: str
-203 :param filename: the filename of the inline data
-204 :type filename: str
-205 :param mimetype: the mimetype of the inline data
-206 :type mimetype: str
-207 :return: None
-208 :rtype: None
-209 """
-210self.body=body
-211self.mimetype=mimetype
-212self.filename=filename
-213self.alg="sha256"
-214self.encoding="base64url"
-215self.signature=base64.urlsafe_b64encode(
-216hashlib.sha256(self.body.encode()).digest()).decode()
-217
-218# Check if the dialog is an external data dialog
-219defis_external_data(self)->bool:
-220returnself.urlisnotNone
-221
-222# Check if the dialog is an inline data dialog
-223defis_inline_data(self)->bool:
-224returnself.bodyisnotNone
-225
-226
-227# Check if the dialog is a text dialog
-228defis_text(self)->bool:
-229returnself.mimetype=="text/plain"
-230
-231
-232# Check if the dialog is an audio dialog
-233defis_audio(self)->bool:
-234returnself.mimetypein["audio/x-wav","audio/x-mp3","audio/x-mp4","audio/ogg"]
-235
-236
-237# Check if the dialog is a video dialog
-238defis_video(self)->bool:
-239returnself.mimetypein["video/x-mp4","video/ogg"]
-240
-241# Check if the dialog is an email dialog
-242defis_email(self)->bool:
-243returnself.mimetype=="message/rfc822"
-244
-245# Check to see if it's an external data dialog, that the contents are valid by
-246# checking the hash of the body against the signature
-247defis_external_data_changed(self)->bool:
-248ifnotself.is_external_data():
-249returnFalse
-250try:
-251body_hash=base64.urlsafe_b64decode(self.signature.encode())
-252returnhashlib.sha256(self.body.encode()).digest()!=body_hash
-253exceptExceptionase:
-254print(e)
-255returnTrue
-256
-257# Convert the dialog from an external data dialog to an inline data dialog
-258# by reading the contents from the URL then adding the contents to the body
-259defto_inline_data(self)->None:
-260# Read the contents from the URL
-261response=requests.get(self.url)
-262ifresponse.status_code==200:
-263self.body=response.text
-264self.mimetype=response.headers["Content-Type"]
-265else:
-266raiseException(f"Failed to fetch external data: {response.status_code}")
-267
-268# Calculate the SHA-256 hash of the body as the signature
-269self.alg="sha256"
-270self.encoding="base64url"
-271self.signature=base64.urlsafe_b64encode(hashlib.sha256(self.body.encode()).digest()).decode()
-272
-273# Overide the filename if provided, otherwise use the filename from the URL
-274ifself.filename:
-275self.filename=self.filename
-276else:
-277self.filename=self.url.split("/")[-1]
-278
-279# Overide the mimetype if provided, otherwise use the mimetype from the URL
-280ifself.mimetype:
-281self.mimetype=self.mimetype
-282
-283# Add the body to the dialog
-284self.add_inline_data(self.body,self.filename,self.mimetype)
-
23classDialog:
- 24def__init__(self,
- 25type:str,
- 26start:datetime,
- 27parties:List[int],
- 28originator:Optional[int]=None,
- 29mimetype:Optional[str]=None,
- 30filename:Optional[str]=None,
- 31body:Optional[str]=None,
- 32encoding:Optional[str]=None,
- 33url:Optional[str]=None,
- 34alg:Optional[str]=None,
- 35signature:Optional[str]=None,
- 36disposition:Optional[str]=None,
- 37party_history:Optional[List[PartyHistory]]=None,
- 38transferee:Optional[int]=None,
- 39transferor:Optional[int]=None,
- 40transfer_target:Optional[int]=None,
- 41original:Optional[int]=None,
- 42consultation:Optional[int]=None,
- 43target_dialog:Optional[int]=None,
- 44campaign:Optional[str]=None,
- 45interaction:Optional[str]=None,
- 46skill:Optional[str]=None,
- 47duration:Optional[float]=None,
- 48meta:Optional[dict]=None)->None:
- 49"""
- 50 Initialize a Dialog object.
- 51
- 52 :param type: the type of the dialog (e.g. "text", "audio", etc.)
- 53 :type type: str
- 54 :param start: the start time of the dialog
- 55 :type start: datetime
- 56 :param parties: the parties involved in the dialog
- 57 :type parties: List[int]
- 58 :param originator: the party that originated the dialog
- 59 :type originator: int or None
- 60 :param mimetype: the MIME type of the dialog body
- 61 :type mimetype: str or None
- 62 :param filename: the filename of the dialog body
- 63 :type filename: str or None
- 64 :param body: the body of the dialog
- 65 :type body: str or None
- 66 :param encoding: the encoding of the dialog body
- 67 :type encoding: str or None
- 68 :param url: the URL of the dialog
- 69 :type url: str or None
- 70 :param alg: the algorithm used to sign the dialog
- 71 :type alg: str or None
- 72 :param signature: the signature of the dialog
- 73 :type signature: str or None
- 74 :param disposition: the disposition of the dialog
- 75 :type disposition: str or None
- 76 :param party_history: the history of parties involved in the dialog
- 77 :type party_history: List[PartyHistory] or None
- 78 :param transferee: the party that the dialog was transferred to
- 79 :type transferee: int or None
- 80 :param transferor: the party that transferred the dialog
- 81 :type transferor: int or None
- 82 :param transfer_target: the target of the transfer
- 83 :type transfer_target: int or None
- 84 :param original: the original dialog
- 85 :type original: int or None
- 86 :param consultation: the consultation dialog
- 87 :type consultation: int or None
- 88 :param target_dialog: the target dialog
- 89 :type target_dialog: int or None
- 90 :param campaign: the campaign that the dialog is associated with
- 91 :type campaign: str or None
- 92 :param interaction: the interaction that the dialog is associated with
- 93 :type interaction: str or None
- 94 :param skill: the skill that the dialog is associated with
- 95 :type skill: str or None
- 96 :param duration: the duration of the dialog
- 97 :type duration: float or None
- 98 """
- 99self.type=type
-100self.start=start
-101self.parties=parties
-102self.originator=originator
-103self.mimetype=mimetype
-104self.filename=filename
-105self.body=body
-106self.encoding=encoding
-107self.url=url
-108self.alg=alg
-109self.signature=signature
-110self.disposition=disposition
-111self.party_history=party_history
-112self.transferee=transferee
-113self.transferor=transferor
-114self.transfer_target=transfer_target
-115self.original=original
-116self.consultation=consultation
-117self.target_dialog=target_dialog
-118self.campaign=campaign
-119self.interaction=interaction
-120self.skill=skill
-121self.duration=duration
-122self.meta=meta
-123
-124defto_dict(self):
-125"""
-126 Returns a dictionary representation of the Dialog object.
-127
-128 :return: a dictionary containing the Dialog object's attributes
-129 :rtype: dict
-130 """
-131# Check to see if the start time provided. If not,
-132# set the start time to the current time
-133ifnotself.start:
-134self.start=datetime.now().isoformat()
-135
-136dialog_dict={
-137"type":self.type,
-138"start":self.start,
-139"duration":self.duration,
-140"parties":self.parties,
-141"originator":self.originator,
-142"mimetype":self.mimetype,
-143"filename":self.filename,
-144"body":self.body,
-145"encoding":self.encoding,
-146"url":self.url,
-147"alg":self.alg,
-148"signature":self.signature,
-149"disposition":self.disposition,
-150"party_history":(
-151[party_history.to_dict()forparty_historyinself.party_history]
-152ifself.party_history
-153elseNone
-154),
-155"transferee":self.transferee,
-156"transferor":self.transferor,
-157"transfer_target":self.transfer_target,
-158"original":self.original,
-159"consultation":self.consultation,
-160"target_dialog":self.target_dialog,
-161"campaign":self.campaign,
-162"interaction":self.interaction,
-163"skill":self.skill,
-164"meta":self.meta
-165}
-166return{k:vfork,vindialog_dict.items()ifvisnotNone}
-167
-168defadd_external_data(self,url:str,filename:str,mimetype:str)->None:
-169"""
-170 Add external data to the dialog.
-171
-172 :param url: the URL of the external data
-173 :type url: str
-174 :return: None
-175 :rtype: None
-176 """
-177response=requests.get(url)
-178ifresponse.status_code==200:
-179self.mimetype=response.headers["Content-Type"]
-180else:
-181raiseException(f"Failed to fetch external data: {response.status_code}")
-182
-183# Overide the filename if provided, otherwise use the filename from the URL
-184iffilename:
-185self.filename=filename
-186else:
-187self.filename=url.split("/")[-1]
-188
-189# Overide the mimetype if provided, otherwise use the mimetype from the URL
-190ifmimetype:
-191self.mimetype=mimetype
-192
-193# Calculate the SHA-256 hash of the body as the signature
-194self.alg="sha256"
-195self.encoding="base64url"
-196self.signature=base64.urlsafe_b64encode(hashlib.sha256(response.text.encode()).digest()).decode()
-197
-198defadd_inline_data(self,body:str,filename:str,mimetype:str)->None:
-199"""
-200 Add inline data to the dialog.
-201
-202 :param body: the body of the inline data
-203 :type body: str
-204 :param filename: the filename of the inline data
-205 :type filename: str
-206 :param mimetype: the mimetype of the inline data
-207 :type mimetype: str
-208 :return: None
-209 :rtype: None
-210 """
-211self.body=body
-212self.mimetype=mimetype
-213self.filename=filename
-214self.alg="sha256"
-215self.encoding="base64url"
-216self.signature=base64.urlsafe_b64encode(
-217hashlib.sha256(self.body.encode()).digest()).decode()
-218
-219# Check if the dialog is an external data dialog
-220defis_external_data(self)->bool:
-221returnself.urlisnotNone
-222
-223# Check if the dialog is an inline data dialog
-224defis_inline_data(self)->bool:
-225returnself.bodyisnotNone
-226
-227
-228# Check if the dialog is a text dialog
-229defis_text(self)->bool:
-230returnself.mimetype=="text/plain"
-231
-232
-233# Check if the dialog is an audio dialog
-234defis_audio(self)->bool:
-235returnself.mimetypein["audio/x-wav","audio/x-mp3","audio/x-mp4","audio/ogg"]
-236
-237
-238# Check if the dialog is a video dialog
-239defis_video(self)->bool:
-240returnself.mimetypein["video/x-mp4","video/ogg"]
-241
-242# Check if the dialog is an email dialog
-243defis_email(self)->bool:
-244returnself.mimetype=="message/rfc822"
-245
-246# Check to see if it's an external data dialog, that the contents are valid by
-247# checking the hash of the body against the signature
-248defis_external_data_changed(self)->bool:
-249ifnotself.is_external_data():
-250returnFalse
-251try:
-252body_hash=base64.urlsafe_b64decode(self.signature.encode())
-253returnhashlib.sha256(self.body.encode()).digest()!=body_hash
-254exceptExceptionase:
-255print(e)
-256returnTrue
-257
-258# Convert the dialog from an external data dialog to an inline data dialog
-259# by reading the contents from the URL then adding the contents to the body
-260defto_inline_data(self)->None:
-261# Read the contents from the URL
-262response=requests.get(self.url)
-263ifresponse.status_code==200:
-264self.body=response.text
-265self.mimetype=response.headers["Content-Type"]
-266else:
-267raiseException(f"Failed to fetch external data: {response.status_code}")
-268
-269# Calculate the SHA-256 hash of the body as the signature
-270self.alg="sha256"
-271self.encoding="base64url"
-272self.signature=base64.urlsafe_b64encode(hashlib.sha256(self.body.encode()).digest()).decode()
-273
-274# Overide the filename if provided, otherwise use the filename from the URL
-275ifself.filename:
-276self.filename=self.filename
-277else:
-278self.filename=self.url.split("/")[-1]
-279
-280# Overide the mimetype if provided, otherwise use the mimetype from the URL
-281ifself.mimetype:
-282self.mimetype=self.mimetype
-283
-284# Add the body to the dialog
-285self.add_inline_data(self.body,self.filename,self.mimetype)
-
24def__init__(self,
- 25type:str,
- 26start:datetime,
- 27parties:List[int],
- 28originator:Optional[int]=None,
- 29mimetype:Optional[str]=None,
- 30filename:Optional[str]=None,
- 31body:Optional[str]=None,
- 32encoding:Optional[str]=None,
- 33url:Optional[str]=None,
- 34alg:Optional[str]=None,
- 35signature:Optional[str]=None,
- 36disposition:Optional[str]=None,
- 37party_history:Optional[List[PartyHistory]]=None,
- 38transferee:Optional[int]=None,
- 39transferor:Optional[int]=None,
- 40transfer_target:Optional[int]=None,
- 41original:Optional[int]=None,
- 42consultation:Optional[int]=None,
- 43target_dialog:Optional[int]=None,
- 44campaign:Optional[str]=None,
- 45interaction:Optional[str]=None,
- 46skill:Optional[str]=None,
- 47duration:Optional[float]=None,
- 48meta:Optional[dict]=None)->None:
- 49"""
- 50 Initialize a Dialog object.
- 51
- 52 :param type: the type of the dialog (e.g. "text", "audio", etc.)
- 53 :type type: str
- 54 :param start: the start time of the dialog
- 55 :type start: datetime
- 56 :param parties: the parties involved in the dialog
- 57 :type parties: List[int]
- 58 :param originator: the party that originated the dialog
- 59 :type originator: int or None
- 60 :param mimetype: the MIME type of the dialog body
- 61 :type mimetype: str or None
- 62 :param filename: the filename of the dialog body
- 63 :type filename: str or None
- 64 :param body: the body of the dialog
- 65 :type body: str or None
- 66 :param encoding: the encoding of the dialog body
- 67 :type encoding: str or None
- 68 :param url: the URL of the dialog
- 69 :type url: str or None
- 70 :param alg: the algorithm used to sign the dialog
- 71 :type alg: str or None
- 72 :param signature: the signature of the dialog
- 73 :type signature: str or None
- 74 :param disposition: the disposition of the dialog
- 75 :type disposition: str or None
- 76 :param party_history: the history of parties involved in the dialog
- 77 :type party_history: List[PartyHistory] or None
- 78 :param transferee: the party that the dialog was transferred to
- 79 :type transferee: int or None
- 80 :param transferor: the party that transferred the dialog
- 81 :type transferor: int or None
- 82 :param transfer_target: the target of the transfer
- 83 :type transfer_target: int or None
- 84 :param original: the original dialog
- 85 :type original: int or None
- 86 :param consultation: the consultation dialog
- 87 :type consultation: int or None
- 88 :param target_dialog: the target dialog
- 89 :type target_dialog: int or None
- 90 :param campaign: the campaign that the dialog is associated with
- 91 :type campaign: str or None
- 92 :param interaction: the interaction that the dialog is associated with
- 93 :type interaction: str or None
- 94 :param skill: the skill that the dialog is associated with
- 95 :type skill: str or None
- 96 :param duration: the duration of the dialog
- 97 :type duration: float or None
- 98 """
- 99self.type=type
-100self.start=start
-101self.parties=parties
-102self.originator=originator
-103self.mimetype=mimetype
-104self.filename=filename
-105self.body=body
-106self.encoding=encoding
-107self.url=url
-108self.alg=alg
-109self.signature=signature
-110self.disposition=disposition
-111self.party_history=party_history
-112self.transferee=transferee
-113self.transferor=transferor
-114self.transfer_target=transfer_target
-115self.original=original
-116self.consultation=consultation
-117self.target_dialog=target_dialog
-118self.campaign=campaign
-119self.interaction=interaction
-120self.skill=skill
-121self.duration=duration
-122self.meta=meta
-
-
-
-
Initialize a Dialog object.
-
-
Parameters
-
-
-
type: the type of the dialog (e.g. "text", "audio", etc.)
-
start: the start time of the dialog
-
parties: the parties involved in the dialog
-
originator: the party that originated the dialog
-
mimetype: the MIME type of the dialog body
-
filename: the filename of the dialog body
-
body: the body of the dialog
-
encoding: the encoding of the dialog body
-
url: the URL of the dialog
-
alg: the algorithm used to sign the dialog
-
signature: the signature of the dialog
-
disposition: the disposition of the dialog
-
party_history: the history of parties involved in the dialog
-
transferee: the party that the dialog was transferred to
-
transferor: the party that transferred the dialog
-
transfer_target: the target of the transfer
-
original: the original dialog
-
consultation: the consultation dialog
-
target_dialog: the target dialog
-
campaign: the campaign that the dialog is associated with
-
interaction: the interaction that the dialog is associated with
-
skill: the skill that the dialog is associated with
-
duration: the duration of the dialog
-
-
-
-
-
-
-
- type
-
-
-
-
-
-
-
-
-
-
- start
-
-
-
-
-
-
-
-
-
-
- parties
-
-
-
-
-
-
-
-
-
-
- originator
-
-
-
-
-
-
-
-
-
-
- mimetype
-
-
-
-
-
-
-
-
-
-
- filename
-
-
-
-
-
-
-
-
-
-
- body
-
-
-
-
-
-
-
-
-
-
- encoding
-
-
-
-
-
-
-
-
-
-
- url
-
-
-
-
-
-
-
-
-
-
- alg
-
-
-
-
-
-
-
-
-
-
- signature
-
-
-
-
-
-
-
-
-
-
- disposition
-
-
-
-
-
-
-
-
-
-
- party_history
-
-
-
-
-
-
-
-
-
-
- transferee
-
-
-
-
-
-
-
-
-
-
- transferor
-
-
-
-
-
-
-
-
-
-
- transfer_target
-
-
-
-
-
-
-
-
-
-
- original
-
-
-
-
-
-
-
-
-
-
- consultation
-
-
-
-
-
-
-
-
-
-
- target_dialog
-
-
-
-
-
-
-
-
-
-
- campaign
-
-
-
-
-
-
-
-
-
-
- interaction
-
-
-
-
-
-
-
-
-
-
- skill
-
-
-
-
-
-
-
-
-
-
- duration
-
-
-
-
-
-
-
-
-
-
- meta
-
-
-
-
-
-
-
-
-
-
-
-
- def
- to_dict(self):
-
-
-
-
-
-
124defto_dict(self):
-125"""
-126 Returns a dictionary representation of the Dialog object.
-127
-128 :return: a dictionary containing the Dialog object's attributes
-129 :rtype: dict
-130 """
-131# Check to see if the start time provided. If not,
-132# set the start time to the current time
-133ifnotself.start:
-134self.start=datetime.now().isoformat()
-135
-136dialog_dict={
-137"type":self.type,
-138"start":self.start,
-139"duration":self.duration,
-140"parties":self.parties,
-141"originator":self.originator,
-142"mimetype":self.mimetype,
-143"filename":self.filename,
-144"body":self.body,
-145"encoding":self.encoding,
-146"url":self.url,
-147"alg":self.alg,
-148"signature":self.signature,
-149"disposition":self.disposition,
-150"party_history":(
-151[party_history.to_dict()forparty_historyinself.party_history]
-152ifself.party_history
-153elseNone
-154),
-155"transferee":self.transferee,
-156"transferor":self.transferor,
-157"transfer_target":self.transfer_target,
-158"original":self.original,
-159"consultation":self.consultation,
-160"target_dialog":self.target_dialog,
-161"campaign":self.campaign,
-162"interaction":self.interaction,
-163"skill":self.skill,
-164"meta":self.meta
-165}
-166return{k:vfork,vindialog_dict.items()ifvisnotNone}
-
-
-
-
Returns a dictionary representation of the Dialog object.
-
-
Returns
-
-
-
a dictionary containing the Dialog object's attributes
168defadd_external_data(self,url:str,filename:str,mimetype:str)->None:
-169"""
-170 Add external data to the dialog.
-171
-172 :param url: the URL of the external data
-173 :type url: str
-174 :return: None
-175 :rtype: None
-176 """
-177response=requests.get(url)
-178ifresponse.status_code==200:
-179self.mimetype=response.headers["Content-Type"]
-180else:
-181raiseException(f"Failed to fetch external data: {response.status_code}")
-182
-183# Overide the filename if provided, otherwise use the filename from the URL
-184iffilename:
-185self.filename=filename
-186else:
-187self.filename=url.split("/")[-1]
-188
-189# Overide the mimetype if provided, otherwise use the mimetype from the URL
-190ifmimetype:
-191self.mimetype=mimetype
-192
-193# Calculate the SHA-256 hash of the body as the signature
-194self.alg="sha256"
-195self.encoding="base64url"
-196self.signature=base64.urlsafe_b64encode(hashlib.sha256(response.text.encode()).digest()).decode()
-
198defadd_inline_data(self,body:str,filename:str,mimetype:str)->None:
-199"""
-200 Add inline data to the dialog.
-201
-202 :param body: the body of the inline data
-203 :type body: str
-204 :param filename: the filename of the inline data
-205 :type filename: str
-206 :param mimetype: the mimetype of the inline data
-207 :type mimetype: str
-208 :return: None
-209 :rtype: None
-210 """
-211self.body=body
-212self.mimetype=mimetype
-213self.filename=filename
-214self.alg="sha256"
-215self.encoding="base64url"
-216self.signature=base64.urlsafe_b64encode(
-217hashlib.sha256(self.body.encode()).digest()).decode()
-
260defto_inline_data(self)->None:
-261# Read the contents from the URL
-262response=requests.get(self.url)
-263ifresponse.status_code==200:
-264self.body=response.text
-265self.mimetype=response.headers["Content-Type"]
-266else:
-267raiseException(f"Failed to fetch external data: {response.status_code}")
-268
-269# Calculate the SHA-256 hash of the body as the signature
-270self.alg="sha256"
-271self.encoding="base64url"
-272self.signature=base64.urlsafe_b64encode(hashlib.sha256(self.body.encode()).digest()).decode()
-273
-274# Overide the filename if provided, otherwise use the filename from the URL
-275ifself.filename:
-276self.filename=self.filename
-277else:
-278self.filename=self.url.split("/")[-1]
-279
-280# Overide the mimetype if provided, otherwise use the mimetype from the URL
-281ifself.mimetype:
-282self.mimetype=self.mimetype
-283
-284# Add the body to the dialog
-285self.add_inline_data(self.body,self.filename,self.mimetype)
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/docs/vcon/party.html b/docs/vcon/party.html
deleted file mode 100644
index 7d40654..0000000
--- a/docs/vcon/party.html
+++ /dev/null
@@ -1,677 +0,0 @@
-
-
-
-
-
-
- vcon.party API documentation
-
-
-
-
-
-
-
-
-
-
-
-
1fromtypingimportOptional
- 2fromvcon.civic_addressimportCivicAddress
- 3fromdatetimeimportdatetime
- 4
- 5
- 6classParty:
- 7def__init__(self,
- 8tel:Optional[str]=None,
- 9stir:Optional[str]=None,
-10mailto:Optional[str]=None,
-11name:Optional[str]=None,
-12validation:Optional[str]=None,
-13gmlpos:Optional[str]=None,
-14civicaddress:Optional[CivicAddress]=None,
-15uuid:Optional[str]=None,
-16role:Optional[str]=None,
-17contact_list:Optional[str]=None,
-18meta:Optional[dict]=None)->None:
-19"""
-20 Initialize a new Party object.
-21
-22 :param tel: Telephone number of the party
-23 :type tel: str | None
-24 :param stir: STIR identifier of the party
-25 :type stir: str | None
-26 :param mailto: Email address of the party
-27 :type mailto: str | None
-28 :param name: Display name of the party
-29 :type name: str | None
-30 :param validation: Validation information of the party
-31 :type validation: str | None
-32 :param gmlpos: GML position of the party
-33 :type gmlpos: str | None
-34 :param civicaddress: Civic address of the party
-35 :type civicaddress: CivicAddress | None
-36 :param uuid: UUID of the party
-37 :type uuid: str | None
-38 :param role: Role of the party
-39 :type role: str | None
-40 :param contact_list: Contact list of the party
-41 :type contact_list: str | None
-42 """
-43# copy the values that are not None
-44# TODO: should we allow changing the values of the object?
-45# for now, we just use the values that are not None
-46# and ignore the other values
-47# (this is also how the old code worked)
-48forkey,valueinlocals().items():
-49ifvalueisnotNone:
-50setattr(self,key,value)
-51
-52defto_dict(self):
-53# copy the attributes that are not None
-54# TODO: should we allow changing the values of the object?
-55# for now, we just use the values that are not None
-56# and ignore the other values
-57# (this is also how the old code worked)
-58party_dict={}
-59forkey,valueinself.__dict__.items():
-60# Don't include self in the dict
-61ifvalueisnotNoneandkey!="self":
-62party_dict[key]=value
-63returnparty_dict
-64
-65
-66classPartyHistory:
-67def__init__(self,party:int,event:str,time:datetime):
-68"""
-69 Initialize a new PartyHistory object.
-70
-71 :param party: Index of the party
-72 :type party: int
-73 :param event: Event type (e.g. "join", "leave")
-74 :type event: str
-75 :param time: Time of the event
-76 :type time: datetime
-77 """
-78self.party=party
-79self.event=event
-80self.time=time
-81
-82defto_dict(self):
-83return{
-84"party":self.party,
-85"event":self.event,
-86"time":self.time
-87}
-
-
-
-
-
-
-
-
- class
- Party:
-
-
-
-
-
-
7classParty:
- 8def__init__(self,
- 9tel:Optional[str]=None,
-10stir:Optional[str]=None,
-11mailto:Optional[str]=None,
-12name:Optional[str]=None,
-13validation:Optional[str]=None,
-14gmlpos:Optional[str]=None,
-15civicaddress:Optional[CivicAddress]=None,
-16uuid:Optional[str]=None,
-17role:Optional[str]=None,
-18contact_list:Optional[str]=None,
-19meta:Optional[dict]=None)->None:
-20"""
-21 Initialize a new Party object.
-22
-23 :param tel: Telephone number of the party
-24 :type tel: str | None
-25 :param stir: STIR identifier of the party
-26 :type stir: str | None
-27 :param mailto: Email address of the party
-28 :type mailto: str | None
-29 :param name: Display name of the party
-30 :type name: str | None
-31 :param validation: Validation information of the party
-32 :type validation: str | None
-33 :param gmlpos: GML position of the party
-34 :type gmlpos: str | None
-35 :param civicaddress: Civic address of the party
-36 :type civicaddress: CivicAddress | None
-37 :param uuid: UUID of the party
-38 :type uuid: str | None
-39 :param role: Role of the party
-40 :type role: str | None
-41 :param contact_list: Contact list of the party
-42 :type contact_list: str | None
-43 """
-44# copy the values that are not None
-45# TODO: should we allow changing the values of the object?
-46# for now, we just use the values that are not None
-47# and ignore the other values
-48# (this is also how the old code worked)
-49forkey,valueinlocals().items():
-50ifvalueisnotNone:
-51setattr(self,key,value)
-52
-53defto_dict(self):
-54# copy the attributes that are not None
-55# TODO: should we allow changing the values of the object?
-56# for now, we just use the values that are not None
-57# and ignore the other values
-58# (this is also how the old code worked)
-59party_dict={}
-60forkey,valueinself.__dict__.items():
-61# Don't include self in the dict
-62ifvalueisnotNoneandkey!="self":
-63party_dict[key]=value
-64returnparty_dict
-
8def__init__(self,
- 9tel:Optional[str]=None,
-10stir:Optional[str]=None,
-11mailto:Optional[str]=None,
-12name:Optional[str]=None,
-13validation:Optional[str]=None,
-14gmlpos:Optional[str]=None,
-15civicaddress:Optional[CivicAddress]=None,
-16uuid:Optional[str]=None,
-17role:Optional[str]=None,
-18contact_list:Optional[str]=None,
-19meta:Optional[dict]=None)->None:
-20"""
-21 Initialize a new Party object.
-22
-23 :param tel: Telephone number of the party
-24 :type tel: str | None
-25 :param stir: STIR identifier of the party
-26 :type stir: str | None
-27 :param mailto: Email address of the party
-28 :type mailto: str | None
-29 :param name: Display name of the party
-30 :type name: str | None
-31 :param validation: Validation information of the party
-32 :type validation: str | None
-33 :param gmlpos: GML position of the party
-34 :type gmlpos: str | None
-35 :param civicaddress: Civic address of the party
-36 :type civicaddress: CivicAddress | None
-37 :param uuid: UUID of the party
-38 :type uuid: str | None
-39 :param role: Role of the party
-40 :type role: str | None
-41 :param contact_list: Contact list of the party
-42 :type contact_list: str | None
-43 """
-44# copy the values that are not None
-45# TODO: should we allow changing the values of the object?
-46# for now, we just use the values that are not None
-47# and ignore the other values
-48# (this is also how the old code worked)
-49forkey,valueinlocals().items():
-50ifvalueisnotNone:
-51setattr(self,key,value)
-
-
-
-
Initialize a new Party object.
-
-
Parameters
-
-
-
tel: Telephone number of the party
-
stir: STIR identifier of the party
-
mailto: Email address of the party
-
name: Display name of the party
-
validation: Validation information of the party
-
gmlpos: GML position of the party
-
civicaddress: Civic address of the party
-
uuid: UUID of the party
-
role: Role of the party
-
contact_list: Contact list of the party
-
-
-
-
-
-
-
-
-
- def
- to_dict(self):
-
-
-
-
-
-
53defto_dict(self):
-54# copy the attributes that are not None
-55# TODO: should we allow changing the values of the object?
-56# for now, we just use the values that are not None
-57# and ignore the other values
-58# (this is also how the old code worked)
-59party_dict={}
-60forkey,valueinself.__dict__.items():
-61# Don't include self in the dict
-62ifvalueisnotNoneandkey!="self":
-63party_dict[key]=value
-64returnparty_dict
-
-
-
-
-
-
-
-
-
-
-
- class
- PartyHistory:
-
-
-
-
-
-
67classPartyHistory:
-68def__init__(self,party:int,event:str,time:datetime):
-69"""
-70 Initialize a new PartyHistory object.
-71
-72 :param party: Index of the party
-73 :type party: int
-74 :param event: Event type (e.g. "join", "leave")
-75 :type event: str
-76 :param time: Time of the event
-77 :type time: datetime
-78 """
-79self.party=party
-80self.event=event
-81self.time=time
-82
-83defto_dict(self):
-84return{
-85"party":self.party,
-86"event":self.event,
-87"time":self.time
-88}
-
68def__init__(self,party:int,event:str,time:datetime):
-69"""
-70 Initialize a new PartyHistory object.
-71
-72 :param party: Index of the party
-73 :type party: int
-74 :param event: Event type (e.g. "join", "leave")
-75 :type event: str
-76 :param time: Time of the event
-77 :type time: datetime
-78 """
-79self.party=party
-80self.event=event
-81self.time=time
-