Skip to main content

PyCoT: Python Cursor-on-Target toolkit (node-CoT style) with XML->CoTEvent, GeoJSON, Cesium conversion capabilities

Project description

PyCoT - Python Cursor-on-Target Toolkit

Python 3.9+ License: MIT PyPI version

PyCoT is a comprehensive and optimized Python library for working with Cursor on Target (CoT) data, the standard used in military and security applications such as ATAK (Android Team Awareness Kit) and WinTAK.

🚀 Key Features

  • ⚡ Optimized Performance: Ultra-fast XML parsing with lxml
  • 🔒 Robust Validation: Pydantic models for data validation
  • 🔄 Multiple Formats: Conversion to GeoJSON, Cesium, KML, WKT and more
  • 🌐 Async Network Transport: Support for UDP, TCP, TLS and WebSocket
  • 📊 Batch Processing: Efficient handling of multiple events
  • 🛠️ CLI Tools: Integrated command-line utilities
  • 📝 Comprehensive Logging: Configurable logging system
  • 🧪 Testing: Complete unit test coverage

📦 Installation

Basic Installation

pip install pycot

Installation with Optional Dependencies

# For better performance
pip install "pycot[speed]"

# For WebSocket support
pip install "pycot[ws]"

# For TAK Protocol support
pip install "pycot[proto]"

# For development
pip install "pycot[dev]"

# For documentation
pip install "pycot[docs]"

Installation from Source

git clone https://github.com/yourusername/pycot.git
cd pycot
pip install -e .

🎯 Quick Start

Basic Conversion

from pycot import CoT

# Create from XML
xml_data = '''
<event uid="demo-1" type="a-f-G-U-C">
    <point lat="40.4" lon="-3.7" hae="100"/>
    <detail>
        <contact callsign="ALPHA-1"/>
        <track course="45" speed="25"/>
    </detail>
</event>
'''

cot = CoT.from_xml(xml_data)

# Convert to different formats
geojson = cot.to_geojson()
cesium = cot.to_cesium()
kml = cot.to_kml()
wkt = cot.to_wkt()
json_data = cot.to_json()

print(f"Event: {cot}")
print(f"Position: {cot.get_position()}")
print(f"Accuracy: {cot.get_accuracy()}")

Batch Processing

from pycot import CoTCollection, parse_file

# Read multiple events from file
events = parse_file("events.xml")
collection = CoTCollection(events)

# Convert to GeoJSON FeatureCollection
geojson_collection = collection.to_geojson_collection()

# Convert to complete Cesium scene
cesium_scene = collection.to_cesium_scene()

# Export HTML viewer
collection.export_html_viewer("viewer.html")

Network Transport

import asyncio
from pycot import stream_events, send_event

async def receive_events():
    """Receive events from UDP server"""
    async for event in stream_events("udp://localhost:8087"):
        print(f"Event received: {event.uid}")
        # Process event...

async def send_events():
    """Send event to server"""
    event_data = '''
    <event uid="test-1" type="a-f-G-U-C">
        <point lat="40.4" lon="-3.7"/>
    </event>
    '''
    await send_event("tcp://localhost:8087", event_data)

# Execute
asyncio.run(receive_events())

📚 Complete API

Main Class: CoT

class CoT:
    # Constructors
    @classmethod
    def from_xml(cls, xml: Union[bytes, str]) -> "CoT"
    @classmethod
    def from_file(cls, file_path: str) -> "CoT"
    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "CoT"

    # Conversions
    def to_xml(self, pretty: bool = False) -> bytes
    def to_geojson(self) -> Dict[str, Any]
    def to_cesium(self, options: Optional[Dict] = None) -> Dict[str, Any]
    def to_kml(self) -> str
    def to_wkt(self) -> str
    def to_json(self, **kwargs) -> str

    # Utilities
    def get_position(self) -> Dict[str, float]
    def get_accuracy(self) -> Dict[str, float]
    def update_position(self, lat: float, lon: float, hae: Optional[float] = None)
    def add_contact(self, callsign: str, **kwargs)
    def add_track(self, course: Optional[float] = None, speed: Optional[float] = None)
    def export_all_formats(self, output_dir: str = ".", prefix: str = "") -> Dict[str, str]

Event Collection: CoTCollection

class CoTCollection:
    def __init__(self, events: Optional[List[CoTEvent]] = None)
    def add_event(self, event: CoTEvent)
    def to_geojson_collection(self) -> Dict[str, Any]
    def to_cesium_collection(self, options: Optional[Dict] = None) -> Dict[str, Any]
    def to_cesium_scene(self, options: Optional[Dict] = None) -> Dict[str, Any]
    def export_html_viewer(self, output_path: str, options: Optional[Dict] = None) -> str

Parsing Functions

# Individual parsing
parse_event(xml_input: XML) -> CoTEvent
parse_event_dict(xml_input: XML) -> Dict[str, Any]

# Batch parsing
parse_many(xml_stream: Iterable[XML]) -> Iterator[Dict[str, Any]]
parse_file(file_path: str) -> List[CoTEvent]

# Validation
validate_cot_xml(xml_input: XML) -> bool

Geographic Conversions

# Individual conversions
event_to_geojson(evt: Union[Dict, CoTEvent]) -> Dict[str, Any]
event_to_json(evt: Union[Dict, CoTEvent]) -> str
event_to_kml(evt: Union[Dict, CoTEvent]) -> str
event_to_wkt(evt: Union[Dict, CoTEvent]) -> str

# Batch conversions
events_to_geojson_collection(events: List[Union[Dict, CoTEvent]]) -> Dict[str, Any]

# Validation and reverse conversion
validate_geojson(geojson: Dict[str, Any]) -> bool
geojson_to_cot(geojson: Dict[str, Any]) -> Dict[str, Any]

Cesium Conversions

# Individual conversions
to_cesium(event: CoTEvent, options: Optional[Dict] = None) -> Dict[str, Any]

# Batch conversions
to_cesium_collection(events: List[CoTEvent], options: Optional[Dict] = None) -> Dict[str, Any]
to_cesium_scene(events: List[CoTEvent], options: Optional[Dict] = None) -> Dict[str, Any]

# HTML generation
cesium_to_html(cesium_scene: Dict[str, Any], options: Optional[Dict] = None) -> str

🛠️ CLI Tools

pycot-cat: View Events

# Show event in readable format
pycot-cat event.xml

# Convert to GeoJSON
pycot-cat event.xml --format geojson

# Convert to Cesium
pycot-cat event.xml --format cesium

# Validate XML
pycot-cat event.xml --validate

pycot-send: Send Events

# Send event to UDP server
pycot-send event.xml udp://localhost:8087

# Send to TCP server with TLS
pycot-send event.xml tls://localhost:8087 --cert client.pem --key client.key

# Send multiple events
pycot-send events/*.xml udp://localhost:8087

pycot-bridge: Network Bridge

# UDP to TCP bridge
pycot-bridge udp://localhost:8087 tcp://localhost:8088

# Bridge with filtering
pycot-bridge udp://localhost:8087 tcp://localhost:8088 --filter "type=a-f-G-U-C"

# Bridge with transformation
pycot-bridge udp://localhost:8087 tcp://localhost:8088 --transform geojson

🔧 Configuration

Logging

import logging

# Configure logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)

# PyCoT specific logging
logging.getLogger('pycot').setLevel(logging.DEBUG)

Cesium Options

# Custom Cesium options
cesium_options = {
    "pointSize": 15,
    "outlineWidth": 3,
    "labelScale": 1.0,
    "billboardScale": 1.5,
    "modelUrl": "models/aircraft.glb",
    "enableLighting": True,
    "defaultCameraPosition": [-74.0, 40.0, 1000000.0]
}

cesium_entity = cot.to_cesium(options=cesium_options)

📖 Advanced Examples

Create Event Programmatically

from pycot import CoT, CoTEvent, Point, Detail, Contact, Track

# Create event from scratch
event = CoTEvent(
    type="a-f-G-U-C",
    uid="unit-001",
    time="2024-01-01T12:00:00Z",
    stale="2024-01-01T12:05:00Z",
    how="h-g-i-g-o",
    point=Point(lat=40.4, lon=-3.7, hae=100),
    detail=Detail(
        contact=Contact(callsign="ALPHA-1"),
        track=Track(course=45, speed=25)
    )
)

cot = CoT(event)

Large File Processing

import asyncio
from pycot import parse_many

async def process_large_file(file_path: str):
    """Process large file efficiently"""

    async def read_file_chunks():
        with open(file_path, 'rb') as f:
            chunk = ""
            for line in f:
                chunk += line.decode('utf-8')
                if line.strip().endswith(b'</event>'):
                    yield chunk
                    chunk = ""

    # Process in batches
    async for event_dict in parse_many(read_file_chunks()):
        # Process each event
        print(f"Processing: {event_dict['uid']}")

# Execute
asyncio.run(process_large_file("large_events.xml"))

External System Integration

from pycot import CoT, CoTCollection
import requests

def fetch_and_process_cot_data(api_url: str):
    """Fetch and process CoT data from external API"""

    # Get data
    response = requests.get(api_url)
    cot_xml_list = response.text.split('</event>')

    # Process events
    collection = CoTCollection()
    for xml_chunk in cot_xml_list:
        if xml_chunk.strip():
            try:
                cot = CoT.from_xml(xml_chunk + '</event>')
                collection.add_event(cot.to_event())
            except Exception as e:
                print(f"Error processing event: {e}")

    # Export results
    collection.export_html_viewer("external_data_viewer.html")
    return collection

🧪 Testing

# Run all tests
pytest

# Tests with coverage
pytest --cov=pycot --cov-report=html

# Specific tests
pytest tests/test_parser.py
pytest tests/test_geo.py -v

# Integration tests
pytest -m integration

# Performance tests
pytest -m slow

📊 Benchmarks

PyCoT is optimized for performance:

  • XML Parsing: 10x faster than xml.etree
  • GeoJSON Conversion: 5x faster than standard implementations
  • Memory: 30% less memory usage
  • Validation: Real-time validation without performance impact

🤝 Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Local Development

git clone https://github.com/yourusername/pycot.git
cd pycot
pip install -e ".[dev]"

# Format code
black src/
isort src/

# Type checking
mypy src/

# Run linting
ruff check src/

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🙏 Acknowledgments

  • TAK Product Center for the CoT standard
  • Cesium for the 3D visualization platform
  • Pydantic for the data validation system
  • lxml for high-performance XML parsing

📞 Support


PyCoT - Transforming CoT data into actionable information 🎯

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pycot_tak-0.0.4.tar.gz (23.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pycot_tak-0.0.4-py3-none-any.whl (25.6 kB view details)

Uploaded Python 3

File details

Details for the file pycot_tak-0.0.4.tar.gz.

File metadata

  • Download URL: pycot_tak-0.0.4.tar.gz
  • Upload date:
  • Size: 23.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.5

File hashes

Hashes for pycot_tak-0.0.4.tar.gz
Algorithm Hash digest
SHA256 a59bf3959802ed38912c2b529ca7830a64d7e7ac33e7f9f053f8ccf53d45c511
MD5 1f977f0fcc11c8887cea3f8dc183f8d1
BLAKE2b-256 63145eb3cf250c0720de621e37699e90825dde1e9ba2faa8357f0a6e03787590

See more details on using hashes here.

File details

Details for the file pycot_tak-0.0.4-py3-none-any.whl.

File metadata

  • Download URL: pycot_tak-0.0.4-py3-none-any.whl
  • Upload date:
  • Size: 25.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.5

File hashes

Hashes for pycot_tak-0.0.4-py3-none-any.whl
Algorithm Hash digest
SHA256 51c2ee66b79f365fbaa7767c3949237e94ed2321215e79103d1a8de1b6c86d90
MD5 1b5334723a090d1b48bf48ec5b565360
BLAKE2b-256 701dc1980344105e81a803413546d35a17c2170ce934accff3eccf07ec79a9ba

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page