PyCoT: Python Cursor-on-Target toolkit (node-CoT style) with XML->CoTEvent, GeoJSON, Cesium conversion capabilities
Project description
PyCoT - Python Cursor-on-Target Toolkit
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:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - 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
- Documentation: https://pycot.readthedocs.io
- Issues: https://github.com/yourusername/pycot/issues
- Discussions: https://github.com/yourusername/pycot/discussions
PyCoT - Transforming CoT data into actionable information 🎯
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a59bf3959802ed38912c2b529ca7830a64d7e7ac33e7f9f053f8ccf53d45c511
|
|
| MD5 |
1f977f0fcc11c8887cea3f8dc183f8d1
|
|
| BLAKE2b-256 |
63145eb3cf250c0720de621e37699e90825dde1e9ba2faa8357f0a6e03787590
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
51c2ee66b79f365fbaa7767c3949237e94ed2321215e79103d1a8de1b6c86d90
|
|
| MD5 |
1b5334723a090d1b48bf48ec5b565360
|
|
| BLAKE2b-256 |
701dc1980344105e81a803413546d35a17c2170ce934accff3eccf07ec79a9ba
|