From 95ff0f8e9cea358697fb8bc1115536a8276d6ea7 Mon Sep 17 00:00:00 2001 From: Octavian Ionescu Date: Thu, 9 Apr 2026 14:26:30 +0300 Subject: [PATCH 1/5] first iteration --- AGENTS.md | 410 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 410 insertions(+) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..3bb1ab5b --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,410 @@ +# ftrack Python API - Agent Specifications + +## Project Overview + +**ftrack-python-api** is the official Python client library for interacting with ftrack, a project management and media review platform. This API provides a high-level, Pythonic interface for creating, querying, updating, and managing entities in ftrack. + +- **Repository**: https://github.com/ftrackhq/ftrack-python +- **Documentation**: https://developer.ftrack.com/api-clients/python/ +- **API Reference**: https://ftrack-python-api.readthedocs.io/en/stable/api_reference/index.html +- **Package**: ftrack-python-api (distributed via PyPI) +- **License**: Apache-2.0 +- **Python Support**: 3.8 - 3.13 + +## Architecture + +### Core Components + +1. **Session** (`session.py`) - Main entry point + - Manages connection to ftrack server + - Handles authentication (API key + user) + - Provides entity querying, creation, and updates + - Manages event hub for real-time updates + - Implements caching layer + - Thread-safe operations + +2. **Entity System** (`entity/`) + - Factory pattern for creating entity types + - Base entity classes with attribute management + - Location system for file storage + - Dynamic entity type construction from schema + +3. **Event System** (`event/`) + - Event hub for publish/subscribe pattern + - WebSocket-based real-time event streaming + - Event handlers and listeners + +4. **Storage System** (`accessor/`, `structure/`) + - **Accessors**: Abstract file I/O (disk, server) + - **Structures**: Define file organization patterns + - Centralized storage scenario support + +5. **Query System** (`query.py`) + - Query language parser (uses pyparsing) + - Expression building and filtering + - Projection and selection + +6. **Cache System** (`cache.py`) + - In-memory entity caching + - Cache key generation + - Layered cache support + +### Module Structure + +``` +source/ftrack_api/ +├── __init__.py # Main package exports (Session, mixin) +├── session.py # Core session implementation (2,700+ lines) +├── entity/ # Entity type system +│ ├── factory.py # Entity creation +│ ├── base.py # Base entity class +│ └── location.py # Location management +├── event/ # Event system +│ ├── hub.py # Event hub +│ └── base.py # Event classes +├── accessor/ # Storage accessors +│ ├── disk.py # Local disk I/O +│ └── server.py # Server-based storage +├── structure/ # File structure patterns +│ ├── origin.py +│ └── entity_id.py +├── resource_identifier_transformer/ +├── attribute.py # Entity attributes +├── cache.py # Caching layer +├── collection.py # Entity collections +├── query.py # Query language +├── exception.py # Custom exceptions +├── plugin.py # Plugin system +├── operation.py # Operation tracking +└── _centralized_storage_scenario.py +``` + +## Development Setup + +### Prerequisites +- Python 3.8+ +- Poetry for dependency management +- Git + +### Installation + +```bash +# Install dependencies +poetry install + +# Install with dev dependencies +poetry install --with dev + +# Install with test dependencies +poetry install --with test +``` + +### Environment Variables + +Required for API access: +- `FTRACK_SERVER` - ftrack server URL (e.g., https://mycompany.ftrackapp.com) +- `FTRACK_API_USER` - API username +- `FTRACK_API_KEY` - API key for authentication + +### Key Dependencies + +**Runtime:** +- `requests>=2,<3` - HTTP client +- `arrow>=0.4.4,<1` - Date/time handling +- `pyparsing>=2.0,<3` - Query language parser +- `clique==1.6.1` - Sequence management +- `websocket-client>=0.40.0,<1` - Event hub WebSocket +- `platformdirs>=4.0.0,<5` - Platform-specific directories + +**Development:** +- `black` - Code formatting +- `pre-commit` - Git hooks +- `sphinx` + `sphinx_rtd_theme` - Documentation + +**Testing:** +- `pytest` - Test framework +- `pytest-mock` - Mocking support +- `mock` - Mock objects +- `flaky` - Retry flaky tests + +## Testing + +### Running Tests + +```bash +# Run all tests +poetry run pytest + +# Run with coverage +poetry run pytest --cov=ftrack_api + +# Run specific test file +poetry run pytest test/unit/test_session.py + +# Disable warnings (CI mode) +poetry run pytest --disable-pytest-warnings +``` + +### Test Structure + +``` +test/ +├── fixture/ +│ └── plugin/ # Test plugins +├── unit/ +│ ├── accessor/ # Accessor tests +│ ├── entity/ # Entity tests +│ ├── conftest.py # Test configuration +│ └── test_*.py # Unit tests +└── integration/ # Integration tests (require live server) +``` + +### Test Configuration + +- **pytest.ini**: Test discovery patterns, JUnit XML output +- Tests write reports to `test-reports/junit.xml` +- Mock mode available via `mock_use_standalone_module = true` + +### Important Test Notes + +- Integration tests require live ftrack server credentials +- Use `@pytest.mark.flaky` for tests that may be unreliable +- Tests should clean up entities they create +- Mock external dependencies (network, filesystem) in unit tests + +## Build & Release + +### Version Management + +Uses **poetry-dynamic-versioning** for automatic versioning: +- Version extracted from git tags +- Format: `v{major}.{minor}.{patch}` (e.g., v2.5.1) +- Written to `source/ftrack_api/_version.py` + +### Building + +```bash +# Build wheel +poetry build --format=wheel + +# Validate distribution +poetry run twine check dist/* +``` + +### CI/CD Pipeline + +**GitHub Actions** (`.github/workflows/cicd.yml`): + +1. **check-formatting**: Black formatting validation +2. **run-tests**: Matrix testing across Python 3.8-3.13 +3. **build**: Package distribution build +4. **publish-test**: Deploy to test.pypi.org (on tag push) +5. **publish-prod**: Deploy to pypi.org (on tag push, production env) + +**Branch Strategy:** +- `main` - Primary development branch +- Tags trigger PyPI releases: `v*` +- PRs run full test suite + +**Publishing Process:** +1. Create and push version tag: `git tag v2.5.1 && git push origin v2.5.1` +2. CI builds and tests across all Python versions +3. Publishes to test PyPI (staging environment) +4. Publishes to production PyPI (production environment) + +## Key Concepts & Patterns + +### Session Management + +```python +import ftrack_api + +# Basic session +session = ftrack_api.Session( + server_url='https://mycompany.ftrackapp.com', + api_key='your-api-key', + api_user='user@email.com' +) + +# With event hub +session = ftrack_api.Session(auto_connect_event_hub=True) + +# With custom cache +session = ftrack_api.Session(cache=custom_cache) +``` + +### Entity Operations + +- **Query**: `session.query('Task where project.name is "MyProject"')` +- **Create**: `session.create('Task', {...})` +- **Update**: `entity['name'] = 'New Name'; session.commit()` +- **Delete**: `session.delete(entity); session.commit()` + +### Plugin System + +- Plugins in `resource/plugin/` +- Loaded via `plugin_paths` argument +- Hooks for session lifecycle events +- Can extend entity types and behaviors + +### Mixin Pattern + +The `mixin()` function dynamically adds functionality to entity instances: + +```python +ftrack_api.mixin(entity, CustomMixin, name='CustomEntity') +``` + +### Thread Safety + +- Sessions should not be shared across threads +- Use `threading.Lock` for shared resources +- Event hub manages its own thread for WebSocket + +## Important Files & Locations + +### Configuration +- `pyproject.toml` - Poetry project config, dependencies +- `pytest.ini` - Test configuration +- `.pre-commit-config.yaml` - Pre-commit hooks +- `setup.cfg` - Legacy setuptools config +- `readthedocs.yaml` - ReadTheDocs build config + +### Documentation +- `doc/` - Sphinx documentation source +- `doc/api_reference/` - API reference docs +- `README.rst` - Package overview + +### Code Quality +- `.git-blame-ignore-revs` - Git blame configuration +- `CODEOWNERS` - GitHub code ownership + +### Build Artifacts +- `dist/` - Built distributions +- `test-reports/` - JUnit test results +- `.pytest_cache/` - Pytest cache + +## Common Development Tasks + +### Adding New Features + +1. Understand the entity schema from ftrack server +2. Implement in appropriate module (`entity/`, `accessor/`, etc.) +3. Add unit tests in `test/unit/` +4. Update type stubs in `stubs/` if applicable +5. Document in `doc/` + +### Fixing Bugs + +1. Write failing test that reproduces the bug +2. Implement fix +3. Ensure test passes +4. Check for similar issues in related code + +### Code Style + +- **Black** formatting (enforced in CI) +- Run `black .` before committing +- Pre-commit hooks auto-format + +### Adding Dependencies + +```bash +# Runtime dependency +poetry add package-name + +# Dev dependency +poetry add --group dev package-name + +# Test dependency +poetry add --group test package-name +``` + +## Integration Points + +### ftrack Server API +- REST API for entity operations +- WebSocket for event streaming +- Schema endpoint for entity type definitions +- File upload/download endpoints + +### Storage Systems +- Local disk via `ftrack_api.accessor.disk` +- ftrack server storage via `ftrack_api.accessor.server` +- Custom accessors can be implemented + +### Event System +- Subscribe to server events +- Publish custom events +- Action handlers for UI extensions + +## Troubleshooting + +### Common Issues + +1. **Authentication failures** + - Check `FTRACK_SERVER`, `FTRACK_API_KEY`, `FTRACK_API_USER` + - Verify API key is active and has permissions + +2. **Connection timeouts** + - Adjust `timeout` parameter in Session + - Check network connectivity + - Recent fix in commit 60d77d0 for server accessor timeout + +3. **Event hub not connecting** + - Ensure `auto_connect_event_hub=True` + - Check WebSocket ports (typically 443/80) + - Verify firewall rules + +4. **Thread safety issues** + - Don't share sessions across threads + - Use separate session per thread + - Recent fix in commit 95ac2ae for thread-safe session sharing + +5. **Cache inconsistencies** + - Clear cache: `session.reset()` + - Disable cache: `session = Session(cache=None)` + - Use custom cache with invalidation logic + +### Debugging + +```python +# Enable debug logging +import logging +logging.basicConfig(level=logging.DEBUG) + +# Session with strict API (raises on deprecations) +session = Session(strict_api=True) + +# Inspect operations before commit +print(session.recorded_operations) +``` + +## Recent Changes + +Based on recent commits: +- **60d77d0**: Fixed server accessor timeout issue +- **47730e4**: Fixed UnboundLocalError in python-api (#59) +- **4f26f7f**: Added support for date type (#57) +- **89dc2c6**: Fixed publish jobs picking up correct tag (#56) +- **95ac2ae**: Fixed thread-safe session sharing across threads (#55) + +## Resources + +- **GitHub Issues**: Report bugs and request features +- **Developer Docs**: https://developer.ftrack.com/api-clients/python/ +- **API Reference**: https://ftrack-python-api.readthedocs.io/ +- **ftrack Community**: Support forum and discussion + +## Notes for AI Agents + +1. **Session is central**: Almost all operations go through the Session object +2. **Schema-driven**: Entity types are dynamically constructed from server schema +3. **Lazy loading**: Entities populate attributes on access, not at creation +4. **Query language**: Custom DSL, not SQL - use session.query() examples +5. **Event-driven**: Many ftrack operations trigger events that can be subscribed to +6. **Location system**: File storage abstraction - understand accessor vs structure +7. **Thread model**: One session per thread, event hub runs in separate thread +8. **Cache implications**: Cached entities may be stale, use session.reset() or disable +9. **Commit required**: Changes are tracked but not saved until session.commit() +10. **Plugin system**: Extensible via plugins - check resource/plugin/ for examples \ No newline at end of file From 8372e2a13f56ded00b09326aa1e2a9d0100eea53 Mon Sep 17 00:00:00 2001 From: lorenzo angeli Date: Thu, 9 Apr 2026 16:08:50 +0200 Subject: [PATCH 2/5] add ftrack_api stubs --- stubs/ftrack_api/__init__.pyi | 5 + .../_centralized_storage_scenario.pyi | 25 ++++ stubs/ftrack_api/_python_ntpath.pyi | 46 ++++++ stubs/ftrack_api/_version.pyi | 1 + stubs/ftrack_api/accessor/__init__.pyi | 0 stubs/ftrack_api/accessor/base.pyi | 25 ++++ stubs/ftrack_api/accessor/disk.pyi | 20 +++ stubs/ftrack_api/accessor/server.pyi | 24 +++ stubs/ftrack_api/attribute.pyi | 65 +++++++++ stubs/ftrack_api/cache.pyi | 78 ++++++++++ stubs/ftrack_api/collection.pyi | 61 ++++++++ stubs/ftrack_api/data.pyi | 33 +++++ stubs/ftrack_api/entity/__init__.pyi | 0 stubs/ftrack_api/entity/asset_version.pyi | 6 + stubs/ftrack_api/entity/base.pyi | 26 ++++ stubs/ftrack_api/entity/component.pyi | 8 + stubs/ftrack_api/entity/factory.pyi | 20 +++ stubs/ftrack_api/entity/job.pyi | 5 + stubs/ftrack_api/entity/location.pyi | 29 ++++ stubs/ftrack_api/entity/note.pyi | 8 + stubs/ftrack_api/entity/project_schema.pyi | 6 + stubs/ftrack_api/entity/user.pyi | 8 + stubs/ftrack_api/event/__init__.pyi | 0 stubs/ftrack_api/event/base.pyi | 12 ++ stubs/ftrack_api/event/expression.pyi | 24 +++ stubs/ftrack_api/event/hub.pyi | 50 +++++++ stubs/ftrack_api/event/subscriber.pyi | 9 ++ stubs/ftrack_api/event/subscription.pyi | 6 + stubs/ftrack_api/exception.pyi | 138 ++++++++++++++++++ stubs/ftrack_api/formatter.pyi | 5 + stubs/ftrack_api/inspection.pyi | 4 + stubs/ftrack_api/logging.pyi | 9 ++ stubs/ftrack_api/operation.pyi | 30 ++++ stubs/ftrack_api/plugin.pyi | 4 + stubs/ftrack_api/query.pyi | 12 ++ .../__init__.pyi | 0 .../resource_identifier_transformer/base.pyi | 7 + stubs/ftrack_api/session.pyi | 97 ++++++++++++ stubs/ftrack_api/structure/__init__.pyi | 0 stubs/ftrack_api/structure/base.pyi | 9 ++ stubs/ftrack_api/structure/entity_id.pyi | 5 + stubs/ftrack_api/structure/id.pyi | 5 + stubs/ftrack_api/structure/origin.pyi | 5 + stubs/ftrack_api/structure/standard.pyi | 9 ++ stubs/ftrack_api/symbol.pyi | 22 +++ 45 files changed, 961 insertions(+) create mode 100644 stubs/ftrack_api/__init__.pyi create mode 100644 stubs/ftrack_api/_centralized_storage_scenario.pyi create mode 100644 stubs/ftrack_api/_python_ntpath.pyi create mode 100644 stubs/ftrack_api/_version.pyi create mode 100644 stubs/ftrack_api/accessor/__init__.pyi create mode 100644 stubs/ftrack_api/accessor/base.pyi create mode 100644 stubs/ftrack_api/accessor/disk.pyi create mode 100644 stubs/ftrack_api/accessor/server.pyi create mode 100644 stubs/ftrack_api/attribute.pyi create mode 100644 stubs/ftrack_api/cache.pyi create mode 100644 stubs/ftrack_api/collection.pyi create mode 100644 stubs/ftrack_api/data.pyi create mode 100644 stubs/ftrack_api/entity/__init__.pyi create mode 100644 stubs/ftrack_api/entity/asset_version.pyi create mode 100644 stubs/ftrack_api/entity/base.pyi create mode 100644 stubs/ftrack_api/entity/component.pyi create mode 100644 stubs/ftrack_api/entity/factory.pyi create mode 100644 stubs/ftrack_api/entity/job.pyi create mode 100644 stubs/ftrack_api/entity/location.pyi create mode 100644 stubs/ftrack_api/entity/note.pyi create mode 100644 stubs/ftrack_api/entity/project_schema.pyi create mode 100644 stubs/ftrack_api/entity/user.pyi create mode 100644 stubs/ftrack_api/event/__init__.pyi create mode 100644 stubs/ftrack_api/event/base.pyi create mode 100644 stubs/ftrack_api/event/expression.pyi create mode 100644 stubs/ftrack_api/event/hub.pyi create mode 100644 stubs/ftrack_api/event/subscriber.pyi create mode 100644 stubs/ftrack_api/event/subscription.pyi create mode 100644 stubs/ftrack_api/exception.pyi create mode 100644 stubs/ftrack_api/formatter.pyi create mode 100644 stubs/ftrack_api/inspection.pyi create mode 100644 stubs/ftrack_api/logging.pyi create mode 100644 stubs/ftrack_api/operation.pyi create mode 100644 stubs/ftrack_api/plugin.pyi create mode 100644 stubs/ftrack_api/query.pyi create mode 100644 stubs/ftrack_api/resource_identifier_transformer/__init__.pyi create mode 100644 stubs/ftrack_api/resource_identifier_transformer/base.pyi create mode 100644 stubs/ftrack_api/session.pyi create mode 100644 stubs/ftrack_api/structure/__init__.pyi create mode 100644 stubs/ftrack_api/structure/base.pyi create mode 100644 stubs/ftrack_api/structure/entity_id.pyi create mode 100644 stubs/ftrack_api/structure/id.pyi create mode 100644 stubs/ftrack_api/structure/origin.pyi create mode 100644 stubs/ftrack_api/structure/standard.pyi create mode 100644 stubs/ftrack_api/symbol.pyi diff --git a/stubs/ftrack_api/__init__.pyi b/stubs/ftrack_api/__init__.pyi new file mode 100644 index 00000000..ec7d10f4 --- /dev/null +++ b/stubs/ftrack_api/__init__.pyi @@ -0,0 +1,5 @@ +from ._version import __version__ as __version__ +from .session import Session as Session +from _typeshed import Incomplete + +def mixin(instance, mixin_class, name: Incomplete | None = None) -> None: ... diff --git a/stubs/ftrack_api/_centralized_storage_scenario.pyi b/stubs/ftrack_api/_centralized_storage_scenario.pyi new file mode 100644 index 00000000..2a54a9f9 --- /dev/null +++ b/stubs/ftrack_api/_centralized_storage_scenario.pyi @@ -0,0 +1,25 @@ +from _typeshed import Incomplete + +scenario_name: str + +class ConfigureCentralizedStorageScenario: + logger: Incomplete + def __init__(self) -> None: ... + @property + def storage_scenario(self): ... + @property + def existing_centralized_storage_configuration(self): ... + def configure_scenario(self, event): ... + def discover_centralized_scenario(self, event): ... + session: Incomplete + def register(self, session) -> None: ... + +class ActivateCentralizedStorageScenario: + logger: Incomplete + def __init__(self) -> None: ... + def activate(self, event) -> None: ... + session: Incomplete + def register(self, session) -> None: ... + +def register(session) -> None: ... +def register_configuration(session) -> None: ... diff --git a/stubs/ftrack_api/_python_ntpath.pyi b/stubs/ftrack_api/_python_ntpath.pyi new file mode 100644 index 00000000..f31a0007 --- /dev/null +++ b/stubs/ftrack_api/_python_ntpath.pyi @@ -0,0 +1,46 @@ +from genericpath import * +from _typeshed import Incomplete +from nt import _isdir as isdir + +__all__ = ['normcase', 'isabs', 'join', 'splitdrive', 'split', 'splitext', 'basename', 'dirname', 'commonprefix', 'getsize', 'getmtime', 'getatime', 'getctime', 'islink', 'exists', 'lexists', 'isdir', 'isfile', 'ismount', 'walk', 'expanduser', 'expandvars', 'normpath', 'abspath', 'splitunc', 'curdir', 'pardir', 'sep', 'pathsep', 'defpath', 'altsep', 'extsep', 'devnull', 'realpath', 'supports_unicode_filenames', 'relpath'] + +curdir: str +pardir: str +extsep: str +sep: str +pathsep: str +altsep: str +defpath: str +devnull: str + +def normcase(s): ... +def isabs(s): ... +def join(a, *p): ... +def splitdrive(p): ... +def splitunc(p): ... +def split(p): ... +def splitext(p): ... +def basename(p): ... +def dirname(p): ... +def islink(path): ... +lexists = exists + +def ismount(path): ... +def walk(top, func, arg) -> None: ... +def expanduser(path): ... +def expandvars(path): ... +def normpath(path): ... +def abspath(path): ... +realpath = abspath +supports_unicode_filenames: Incomplete + +def relpath(path, start=...): ... + +# Names in __all__ with no definition: +# commonprefix +# exists +# getatime +# getctime +# getmtime +# getsize +# isfile diff --git a/stubs/ftrack_api/_version.pyi b/stubs/ftrack_api/_version.pyi new file mode 100644 index 00000000..bda5b5a7 --- /dev/null +++ b/stubs/ftrack_api/_version.pyi @@ -0,0 +1 @@ +__version__: str diff --git a/stubs/ftrack_api/accessor/__init__.pyi b/stubs/ftrack_api/accessor/__init__.pyi new file mode 100644 index 00000000..e69de29b diff --git a/stubs/ftrack_api/accessor/base.pyi b/stubs/ftrack_api/accessor/base.pyi new file mode 100644 index 00000000..23e69490 --- /dev/null +++ b/stubs/ftrack_api/accessor/base.pyi @@ -0,0 +1,25 @@ +import abc + +class Accessor(metaclass=abc.ABCMeta): + def __init__(self) -> None: ... + @abc.abstractmethod + def list(self, resource_identifier): ... + @abc.abstractmethod + def exists(self, resource_identifier): ... + @abc.abstractmethod + def is_file(self, resource_identifier): ... + @abc.abstractmethod + def is_container(self, resource_identifier): ... + @abc.abstractmethod + def is_sequence(self, resource_identifier): ... + @abc.abstractmethod + def open(self, resource_identifier, mode: str = 'rb'): ... + @abc.abstractmethod + def remove(self, resource_identifier): ... + @abc.abstractmethod + def make_container(self, resource_identifier, recursive: bool = True): ... + @abc.abstractmethod + def get_container(self, resource_identifier): ... + def remove_container(self, resource_identifier): ... + def get_filesystem_path(self, resource_identifier) -> None: ... + def get_url(self, resource_identifier) -> None: ... diff --git a/stubs/ftrack_api/accessor/disk.pyi b/stubs/ftrack_api/accessor/disk.pyi new file mode 100644 index 00000000..db24136a --- /dev/null +++ b/stubs/ftrack_api/accessor/disk.pyi @@ -0,0 +1,20 @@ +import ftrack_api.accessor.base +from _typeshed import Incomplete +from collections.abc import Generator +from ftrack_api.exception import AccessorContainerNotEmptyError as AccessorContainerNotEmptyError, AccessorFilesystemPathError as AccessorFilesystemPathError, AccessorOperationFailedError as AccessorOperationFailedError, AccessorParentResourceNotFoundError as AccessorParentResourceNotFoundError, AccessorPermissionDeniedError as AccessorPermissionDeniedError, AccessorResourceInvalidError as AccessorResourceInvalidError, AccessorResourceNotFoundError as AccessorResourceNotFoundError, AccessorUnsupportedOperationError as AccessorUnsupportedOperationError + +class DiskAccessor(ftrack_api.accessor.base.Accessor): + prefix: Incomplete + def __init__(self, prefix, **kw) -> None: ... + def list(self, resource_identifier): ... + def exists(self, resource_identifier): ... + def is_file(self, resource_identifier): ... + def is_container(self, resource_identifier): ... + def is_sequence(self, resource_identifier) -> None: ... + def open(self, resource_identifier, mode: str = 'rb'): ... + def remove(self, resource_identifier) -> None: ... + def make_container(self, resource_identifier, recursive: bool = True) -> None: ... + def get_container(self, resource_identifier): ... + def get_filesystem_path(self, resource_identifier): ... + +def error_handler(**kw) -> Generator[None]: ... diff --git a/stubs/ftrack_api/accessor/server.pyi b/stubs/ftrack_api/accessor/server.pyi new file mode 100644 index 00000000..112c04a3 --- /dev/null +++ b/stubs/ftrack_api/accessor/server.pyi @@ -0,0 +1,24 @@ +from ..data import String as String +from .base import Accessor as Accessor +from _typeshed import Incomplete + +class ServerFile(String): + mode: Incomplete + resource_identifier: Incomplete + def __init__(self, resource_identifier, session, mode: str = 'rb') -> None: ... + def flush(self) -> None: ... + def read(self, limit: Incomplete | None = None): ... + +class _ServerAccessor(Accessor): + def __init__(self, session, **kw) -> None: ... + def open(self, resource_identifier, mode: str = 'rb'): ... + def remove(self, resourceIdentifier) -> None: ... + def get_container(self, resource_identifier) -> None: ... + def make_container(self, resource_identifier, recursive: bool = True) -> None: ... + def list(self, resource_identifier) -> None: ... + def exists(self, resource_identifier): ... + def is_file(self, resource_identifier) -> None: ... + def is_container(self, resource_identifier) -> None: ... + def is_sequence(self, resource_identifier) -> None: ... + def get_url(self, resource_identifier): ... + def get_thumbnail_url(self, resource_identifier, size: Incomplete | None = None): ... diff --git a/stubs/ftrack_api/attribute.pyi b/stubs/ftrack_api/attribute.pyi new file mode 100644 index 00000000..0c28c276 --- /dev/null +++ b/stubs/ftrack_api/attribute.pyi @@ -0,0 +1,65 @@ +import ftrack_api.collection +from _typeshed import Incomplete + +logger: Incomplete + +def merge_references(function): ... + +class Attributes: + def __init__(self, attributes: Incomplete | None = None) -> None: ... + def add(self, attribute) -> None: ... + def remove(self, attribute) -> None: ... + def get(self, name): ... + def keys(self): ... + def __contains__(self, item) -> bool: ... + def __iter__(self): ... + def __len__(self) -> int: ... + +class Attribute: + default_value: Incomplete + def __init__(self, name, default_value=..., mutable: bool = True, computed: bool = False) -> None: ... + def get_entity_storage(self, entity): ... + @property + def name(self): ... + @property + def mutable(self): ... + @property + def computed(self): ... + def get_value(self, entity): ... + def get_local_value(self, entity): ... + def get_remote_value(self, entity): ... + def set_local_value(self, entity, value) -> None: ... + def set_remote_value(self, entity, value) -> None: ... + def populate_remote_value(self, entity) -> None: ... + def is_modified(self, entity): ... + def is_set(self, entity): ... + +class ScalarAttribute(Attribute): + data_type: Incomplete + def __init__(self, name, data_type, **kw) -> None: ... + +class ReferenceAttribute(Attribute): + entity_type: Incomplete + def __init__(self, name, entity_type, **kw) -> None: ... + def populate_remote_value(self, entity) -> None: ... + def is_modified(self, entity): ... + def get_value(self, entity): ... + +class AbstractCollectionAttribute(Attribute): + collection_class: Incomplete + def get_value(self, entity): ... + def set_local_value(self, entity, value) -> None: ... + def set_remote_value(self, entity, value) -> None: ... + +class CollectionAttribute(AbstractCollectionAttribute): + collection_class = ftrack_api.collection.Collection + +class KeyValueMappedCollectionAttribute(AbstractCollectionAttribute): + collection_class = ftrack_api.collection.KeyValueMappedCollectionProxy + creator: Incomplete + key_attribute: Incomplete + value_attribute: Incomplete + def __init__(self, name, creator, key_attribute, value_attribute, **kw) -> None: ... + +class CustomAttributeCollectionAttribute(AbstractCollectionAttribute): + collection_class = ftrack_api.collection.CustomAttributeCollectionProxy diff --git a/stubs/ftrack_api/cache.pyi b/stubs/ftrack_api/cache.pyi new file mode 100644 index 00000000..9c3984a3 --- /dev/null +++ b/stubs/ftrack_api/cache.pyi @@ -0,0 +1,78 @@ +import abc +from _typeshed import Incomplete + +class Cache(metaclass=abc.ABCMeta): + @abc.abstractmethod + def get(self, key): ... + @abc.abstractmethod + def set(self, key, value): ... + @abc.abstractmethod + def remove(self, key): ... + def keys(self) -> None: ... + def values(self): ... + def clear(self, pattern: Incomplete | None = None) -> None: ... + +class ProxyCache(Cache): + proxied: Incomplete + def __init__(self, proxied) -> None: ... + def get(self, key): ... + def set(self, key, value): ... + def remove(self, key): ... + def keys(self): ... + +class LayeredCache(Cache): + caches: Incomplete + def __init__(self, caches) -> None: ... + def get(self, key): ... + def set(self, key, value) -> None: ... + def remove(self, key) -> None: ... + def keys(self): ... + +class MemoryCache(Cache): + def __init__(self) -> None: ... + def get(self, key): ... + def set(self, key, value) -> None: ... + def remove(self, key) -> None: ... + def keys(self): ... + +class FileCache(Cache): + path: Incomplete + def __init__(self, path) -> None: ... + def get(self, key): ... + def set(self, key, value) -> None: ... + def remove(self, key) -> None: ... + def keys(self): ... + +class SerialisedCache(ProxyCache): + encode: Incomplete + decode: Incomplete + def __init__(self, proxied, encode: Incomplete | None = None, decode: Incomplete | None = None) -> None: ... + def get(self, key): ... + def set(self, key, value) -> None: ... + +class KeyMaker(metaclass=abc.ABCMeta): + item_separator: str + def __init__(self) -> None: ... + def key(self, *items): ... + +class StringKeyMaker(KeyMaker): ... + +class ObjectKeyMaker(KeyMaker): + item_separator: bytes + mapping_identifier: bytes + mapping_pair_separator: bytes + iterable_identifier: bytes + name_identifier: bytes + def __init__(self) -> None: ... + +class Memoiser: + cache: Incomplete + key_maker: Incomplete + return_copies: Incomplete + def __init__(self, cache: Incomplete | None = None, key_maker: Incomplete | None = None, return_copies: bool = True) -> None: ... + def call(self, function, args: Incomplete | None = None, kw: Incomplete | None = None): ... + +def memoise_decorator(memoiser): ... + +memoiser: Incomplete +memoise: Incomplete diff --git a/stubs/ftrack_api/collection.pyi b/stubs/ftrack_api/collection.pyi new file mode 100644 index 00000000..b7694d8b --- /dev/null +++ b/stubs/ftrack_api/collection.pyi @@ -0,0 +1,61 @@ +import abc +import collections.abc +import ftrack_api.cache +from _typeshed import Incomplete + +class Collection(collections.abc.MutableSequence): + entity: Incomplete + attribute: Incomplete + mutable: bool + def __init__(self, entity, attribute, mutable: bool = True, data: Incomplete | None = None) -> None: ... + def __copy__(self): ... + def insert(self, index, item) -> None: ... + def __contains__(self, value) -> bool: ... + def __getitem__(self, index): ... + def __setitem__(self, index, item) -> None: ... + def __delitem__(self, index) -> None: ... + def __len__(self) -> int: ... + def __eq__(self, other): ... + def __ne__(self, other): ... + +class MappedCollectionProxy(collections.abc.MutableMapping, metaclass=abc.ABCMeta): + logger: Incomplete + collection: Incomplete + def __init__(self, collection) -> None: ... + def __copy__(self): ... + @property + def mutable(self): ... + @mutable.setter + def mutable(self, value) -> None: ... + @property + def attribute(self): ... + @attribute.setter + def attribute(self, value) -> None: ... + +class KeyValueMappedCollectionProxy(MappedCollectionProxy): + creator: Incomplete + key_attribute: Incomplete + value_attribute: Incomplete + def __init__(self, collection, creator, key_attribute, value_attribute) -> None: ... + def __getitem__(self, key): ... + def __setitem__(self, key, value) -> None: ... + def __delitem__(self, key) -> None: ... + def __iter__(self): ... + def __len__(self) -> int: ... + def keys(self): ... + +class PerSessionDefaultKeyMaker(ftrack_api.cache.KeyMaker): ... + +memoise_session: Incomplete + +class CustomAttributeCollectionProxy(MappedCollectionProxy): + key_attribute: str + value_attribute: str + def __init__(self, collection) -> None: ... + def get_configuration_id_from_key(self, key): ... + def __getitem__(self, key): ... + def __setitem__(self, key, value) -> None: ... + def __delitem__(self, key) -> None: ... + def __eq__(self, collection): ... + def __iter__(self): ... + def __len__(self) -> int: ... diff --git a/stubs/ftrack_api/data.pyi b/stubs/ftrack_api/data.pyi new file mode 100644 index 00000000..6f24e847 --- /dev/null +++ b/stubs/ftrack_api/data.pyi @@ -0,0 +1,33 @@ +from _typeshed import Incomplete +from abc import ABCMeta, abstractmethod + +class Data(metaclass=ABCMeta): + closed: bool + def __init__(self) -> None: ... + @abstractmethod + def read(self, limit: Incomplete | None = None): ... + @abstractmethod + def write(self, content): ... + def flush(self) -> None: ... + def seek(self, offset, whence=...) -> None: ... + def tell(self) -> None: ... + def close(self) -> None: ... + +class FileWrapper(Data): + wrapped_file: Incomplete + def __init__(self, wrapped_file) -> None: ... + def read(self, limit: Incomplete | None = None): ... + def write(self, content) -> None: ... + def flush(self) -> None: ... + def seek(self, offset, whence=...) -> None: ... + def tell(self): ... + def close(self) -> None: ... + +class File(FileWrapper): + def __init__(self, path, mode: str = 'rb') -> None: ... + +class String(FileWrapper): + is_binary: bool + def __init__(self, content: Incomplete | None = None) -> None: ... + def write(self, content) -> None: ... + def read(self, limit: Incomplete | None = None): ... diff --git a/stubs/ftrack_api/entity/__init__.pyi b/stubs/ftrack_api/entity/__init__.pyi new file mode 100644 index 00000000..e69de29b diff --git a/stubs/ftrack_api/entity/asset_version.pyi b/stubs/ftrack_api/entity/asset_version.pyi new file mode 100644 index 00000000..d1d79a91 --- /dev/null +++ b/stubs/ftrack_api/entity/asset_version.pyi @@ -0,0 +1,6 @@ +import ftrack_api.entity.base +from _typeshed import Incomplete + +class AssetVersion(ftrack_api.entity.base.Entity): + def create_component(self, path, data: Incomplete | None = None, location: Incomplete | None = None): ... + def encode_media(self, media, keep_original: str = 'auto'): ... diff --git a/stubs/ftrack_api/entity/base.pyi b/stubs/ftrack_api/entity/base.pyi new file mode 100644 index 00000000..19fc5866 --- /dev/null +++ b/stubs/ftrack_api/entity/base.pyi @@ -0,0 +1,26 @@ +import abc +import collections.abc +from _typeshed import Incomplete + +class _EntityBase: ... +class DynamicEntityTypeMetaclass(abc.ABCMeta): ... + +class Entity(_EntityBase, collections.abc.MutableMapping, metaclass=DynamicEntityTypeMetaclass): + entity_type: str + attributes: Incomplete + primary_key_attributes: Incomplete + default_projections: Incomplete + logger: Incomplete + session: Incomplete + def __init__(self, session, data: Incomplete | None = None, reconstructing: bool = False) -> None: ... + def __hash__(self): ... + def __eq__(self, other): ... + def __getitem__(self, key): ... + def __setitem__(self, key, value) -> None: ... + def __delitem__(self, key) -> None: ... + def __iter__(self): ... + def __len__(self) -> int: ... + def values(self): ... + def items(self): ... + def clear(self) -> None: ... + def merge(self, entity, merged: Incomplete | None = None): ... diff --git a/stubs/ftrack_api/entity/component.pyi b/stubs/ftrack_api/entity/component.pyi new file mode 100644 index 00000000..428d6fe8 --- /dev/null +++ b/stubs/ftrack_api/entity/component.pyi @@ -0,0 +1,8 @@ +import ftrack_api.entity.base +from _typeshed import Incomplete + +class Component(ftrack_api.entity.base.Entity): + def get_availability(self, locations: Incomplete | None = None): ... + +class CreateThumbnailMixin: + def create_thumbnail(self, path, data: Incomplete | None = None): ... diff --git a/stubs/ftrack_api/entity/factory.pyi b/stubs/ftrack_api/entity/factory.pyi new file mode 100644 index 00000000..9cee4609 --- /dev/null +++ b/stubs/ftrack_api/entity/factory.pyi @@ -0,0 +1,20 @@ +import ftrack_api.cache +from _typeshed import Incomplete + +class Factory: + logger: Incomplete + def __init__(self) -> None: ... + def create(self, schema, bases: Incomplete | None = None): ... + def create_scalar_attribute(self, class_name, name, mutable, computed, default, data_type): ... + def create_reference_attribute(self, class_name, name, mutable, reference): ... + def create_collection_attribute(self, class_name, name, mutable): ... + def create_mapped_collection_attribute(self, class_name, name, mutable, reference) -> None: ... + +class PerSessionDefaultKeyMaker(ftrack_api.cache.KeyMaker): ... + +memoise_defaults: Incomplete +memoise_session: Incomplete + +class StandardFactory(Factory): + def create(self, schema, bases: Incomplete | None = None): ... + def create_mapped_collection_attribute(self, class_name, name, mutable, reference): ... diff --git a/stubs/ftrack_api/entity/job.pyi b/stubs/ftrack_api/entity/job.pyi new file mode 100644 index 00000000..75e813eb --- /dev/null +++ b/stubs/ftrack_api/entity/job.pyi @@ -0,0 +1,5 @@ +import ftrack_api.entity.base +from _typeshed import Incomplete + +class Job(ftrack_api.entity.base.Entity): + def __init__(self, session, data: Incomplete | None = None, reconstructing: bool = False) -> None: ... diff --git a/stubs/ftrack_api/entity/location.pyi b/stubs/ftrack_api/entity/location.pyi new file mode 100644 index 00000000..769b4172 --- /dev/null +++ b/stubs/ftrack_api/entity/location.pyi @@ -0,0 +1,29 @@ +import abc +import collections.abc +import ftrack_api.entity.base +from _typeshed import Incomplete + +class Location(ftrack_api.entity.base.Entity): + accessor: Incomplete + structure: Incomplete + resource_identifier_transformer: Incomplete + priority: int + def __init__(self, session, data: Incomplete | None = None, reconstructing: bool = False) -> None: ... + def add_component(self, component, source, recursive: bool = True): ... + def add_components(self, components, sources, recursive: bool = True, _depth: int = 0) -> None: ... + def remove_component(self, component, recursive: bool = True): ... + def remove_components(self, components, recursive: bool = True) -> None: ... + def get_component_availability(self, component): ... + def get_component_availabilities(self, components): ... + def get_resource_identifier(self, component): ... + def get_resource_identifiers(self, components): ... + def get_filesystem_path(self, component): ... + def get_filesystem_paths(self, components): ... + def get_url(self, component): ... + +class MemoryLocationMixin(ftrack_api.entity.base._EntityBase, collections.abc.MutableMapping, metaclass=ftrack_api.entity.base.DynamicEntityTypeMetaclass): ... +class UnmanagedLocationMixin(ftrack_api.entity.base._EntityBase, collections.abc.MutableMapping, metaclass=ftrack_api.entity.base.DynamicEntityTypeMetaclass): ... +class OriginLocationMixin(MemoryLocationMixin, UnmanagedLocationMixin, metaclass=abc.ABCMeta): ... + +class ServerLocationMixin(ftrack_api.entity.base._EntityBase, collections.abc.MutableMapping, metaclass=ftrack_api.entity.base.DynamicEntityTypeMetaclass): + def get_thumbnail_url(self, component, size: Incomplete | None = None): ... diff --git a/stubs/ftrack_api/entity/note.pyi b/stubs/ftrack_api/entity/note.pyi new file mode 100644 index 00000000..91e27b34 --- /dev/null +++ b/stubs/ftrack_api/entity/note.pyi @@ -0,0 +1,8 @@ +import ftrack_api.entity.base +from _typeshed import Incomplete + +class Note(ftrack_api.entity.base.Entity): + def create_reply(self, content, author): ... + +class CreateNoteMixin: + def create_note(self, content, author, recipients: Incomplete | None = None, category: Incomplete | None = None, labels: Incomplete | None = None): ... diff --git a/stubs/ftrack_api/entity/project_schema.pyi b/stubs/ftrack_api/entity/project_schema.pyi new file mode 100644 index 00000000..3b6f0aac --- /dev/null +++ b/stubs/ftrack_api/entity/project_schema.pyi @@ -0,0 +1,6 @@ +import ftrack_api.entity.base +from _typeshed import Incomplete + +class ProjectSchema(ftrack_api.entity.base.Entity): + def get_statuses(self, schema, type_id: Incomplete | None = None): ... + def get_types(self, schema): ... diff --git a/stubs/ftrack_api/entity/user.pyi b/stubs/ftrack_api/entity/user.pyi new file mode 100644 index 00000000..982563a2 --- /dev/null +++ b/stubs/ftrack_api/entity/user.pyi @@ -0,0 +1,8 @@ +import ftrack_api.entity.base +from _typeshed import Incomplete + +class User(ftrack_api.entity.base.Entity): + def start_timer(self, context: Incomplete | None = None, comment: str = '', name: Incomplete | None = None, force: bool = False): ... + def stop_timer(self): ... + def send_invite(self) -> None: ... + def reset_api_key(self): ... diff --git a/stubs/ftrack_api/event/__init__.pyi b/stubs/ftrack_api/event/__init__.pyi new file mode 100644 index 00000000..e69de29b diff --git a/stubs/ftrack_api/event/base.pyi b/stubs/ftrack_api/event/base.pyi new file mode 100644 index 00000000..5379bc0f --- /dev/null +++ b/stubs/ftrack_api/event/base.pyi @@ -0,0 +1,12 @@ +import collections.abc +from _typeshed import Incomplete + +class Event(collections.abc.MutableMapping): + def __init__(self, topic, id: Incomplete | None = None, data: Incomplete | None = None, sent: Incomplete | None = None, source: Incomplete | None = None, target: str = '', in_reply_to_event: Incomplete | None = None) -> None: ... + def stop(self) -> None: ... + def is_stopped(self): ... + def __getitem__(self, key): ... + def __setitem__(self, key, value) -> None: ... + def __delitem__(self, key) -> None: ... + def __iter__(self): ... + def __len__(self) -> int: ... diff --git a/stubs/ftrack_api/event/expression.pyi b/stubs/ftrack_api/event/expression.pyi new file mode 100644 index 00000000..05420647 --- /dev/null +++ b/stubs/ftrack_api/event/expression.pyi @@ -0,0 +1,24 @@ +from _typeshed import Incomplete + +class Parser: + def __init__(self) -> None: ... + def parse(self, expression): ... + +class Expression: + def match(self, candidate): ... + +class All(Expression): + def __init__(self, expressions: Incomplete | None = None) -> None: ... + def match(self, candidate): ... + +class Any(Expression): + def __init__(self, expressions: Incomplete | None = None) -> None: ... + def match(self, candidate): ... + +class Not(Expression): + def __init__(self, expression) -> None: ... + def match(self, candidate): ... + +class Condition(Expression): + def __init__(self, key, operator, value) -> None: ... + def match(self, candidate): ... diff --git a/stubs/ftrack_api/event/hub.pyi b/stubs/ftrack_api/event/hub.pyi new file mode 100644 index 00000000..a3ffa901 --- /dev/null +++ b/stubs/ftrack_api/event/hub.pyi @@ -0,0 +1,50 @@ +import threading +from _typeshed import Incomplete +from typing import NamedTuple + +class SocketIoSession(NamedTuple): + id: Incomplete + heartbeatTimeout: Incomplete + supportedTransports: Incomplete + +class ServerDetails(NamedTuple): + scheme: Incomplete + hostname: Incomplete + port: Incomplete + +class EventHub: + logger: Incomplete + id: Incomplete + server: Incomplete + def __init__(self, server_url, api_user, api_key, headers: Incomplete | None = None, cookies: Incomplete | None = None) -> None: ... + def get_server_url(self): ... + def get_network_location(self): ... + @property + def secure(self): ... + def init_connection(self) -> None: ... + def connect(self) -> None: ... + @property + def connected(self): ... + def disconnect(self, unsubscribe: bool = True, reconnect: bool = False) -> None: ... + def reconnect(self, attempts: int = 10, delay: int = 5) -> None: ... + def wait(self, duration: Incomplete | None = None) -> None: ... + def get_subscriber_by_identifier(self, identifier): ... + def subscribe(self, subscription, callback, subscriber: Incomplete | None = None, priority: int = 100): ... + def unsubscribe(self, subscriber_identifier) -> None: ... + def publish(self, event, synchronous: bool = False, on_reply: Incomplete | None = None, on_error: str = 'raise'): ... + def publish_reply(self, source_event, data, source: Incomplete | None = None) -> None: ... + def subscription(self, subscription, callback, subscriber: Incomplete | None = None, priority: int = 100): ... + +class _SubscriptionContext: + def __init__(self, hub, subscription, callback, subscriber, priority) -> None: ... + def __enter__(self) -> None: ... + def __exit__(self, exception_type: type[BaseException] | None, exception_value: BaseException | None, traceback: types.TracebackType | None) -> None: ... + +class _ProcessorThread(threading.Thread): + daemon: bool + logger: Incomplete + client: Incomplete + done: Incomplete + def __init__(self, client) -> None: ... + def run(self) -> None: ... + def cancel(self) -> None: ... diff --git a/stubs/ftrack_api/event/subscriber.pyi b/stubs/ftrack_api/event/subscriber.pyi new file mode 100644 index 00000000..2b3fcd2a --- /dev/null +++ b/stubs/ftrack_api/event/subscriber.pyi @@ -0,0 +1,9 @@ +from _typeshed import Incomplete + +class Subscriber: + subscription: Incomplete + callback: Incomplete + metadata: Incomplete + priority: Incomplete + def __init__(self, subscription, callback, metadata, priority) -> None: ... + def interested_in(self, event): ... diff --git a/stubs/ftrack_api/event/subscription.pyi b/stubs/ftrack_api/event/subscription.pyi new file mode 100644 index 00000000..4524fb40 --- /dev/null +++ b/stubs/ftrack_api/event/subscription.pyi @@ -0,0 +1,6 @@ +from _typeshed import Incomplete + +class Subscription: + parser: Incomplete + def __init__(self, subscription) -> None: ... + def includes(self, event): ... diff --git a/stubs/ftrack_api/exception.pyi b/stubs/ftrack_api/exception.pyi new file mode 100644 index 00000000..e49b665d --- /dev/null +++ b/stubs/ftrack_api/exception.pyi @@ -0,0 +1,138 @@ +from _typeshed import Incomplete + +class Error(Exception): + default_message: str + message: Incomplete + details: Incomplete + traceback: Incomplete + def __init__(self, message: Incomplete | None = None, details: Incomplete | None = None) -> None: ... + +class AuthenticationError(Error): + default_message: str + +class ServerError(Error): + default_message: str + +class ServerCompatibilityError(ServerError): + default_message: str + +class NotFoundError(Error): + default_message: str + +class NotUniqueError(Error): + default_message: str + +class IncorrectResultError(Error): + default_message: str + +class NoResultFoundError(IncorrectResultError): + default_message: str + +class MultipleResultsFoundError(IncorrectResultError): + default_message: str + +class EntityTypeError(Error): + default_message: str + +class UnrecognisedEntityTypeError(EntityTypeError): + default_message: str + def __init__(self, entity_type, **kw) -> None: ... + +class OperationError(Error): + default_message: str + +class InvalidStateError(Error): + default_message: str + +class InvalidStateTransitionError(InvalidStateError): + default_message: str + def __init__(self, current_state, target_state, entity, **kw) -> None: ... + +class AttributeError(Error): + default_message: str + +class ImmutableAttributeError(AttributeError): + default_message: str + def __init__(self, attribute, **kw) -> None: ... + +class CollectionError(Error): + default_message: str + def __init__(self, collection, **kw) -> None: ... + +class ImmutableCollectionError(CollectionError): + default_message: str + +class DuplicateItemInCollectionError(CollectionError): + default_message: str + def __init__(self, item, collection, **kw) -> None: ... + +class ParseError(Error): + default_message: str + +class EventHubError(Error): + default_message: str + +class EventHubConnectionError(EventHubError): + default_message: str + +class EventHubPacketError(EventHubError): + default_message: str + +class PermissionDeniedError(Error): + default_message: str + +class LocationError(Error): + default_message: str + +class ComponentNotInAnyLocationError(LocationError): + default_message: str + +class ComponentNotInLocationError(LocationError): + default_message: str + def __init__(self, components, location, **kw) -> None: ... + +class ComponentInLocationError(LocationError): + default_message: str + def __init__(self, components, location, **kw) -> None: ... + +class AccessorError(Error): + default_message: str + +class AccessorOperationFailedError(AccessorError): + default_message: str + def __init__(self, operation: str = '', resource_identifier: Incomplete | None = None, error: Incomplete | None = None, **kw) -> None: ... + +class AccessorUnsupportedOperationError(AccessorOperationFailedError): + default_message: str + +class AccessorPermissionDeniedError(AccessorOperationFailedError): + default_message: str + +class AccessorResourceIdentifierError(AccessorError): + default_message: str + def __init__(self, resource_identifier, **kw) -> None: ... + +class AccessorFilesystemPathError(AccessorResourceIdentifierError): + default_message: str + +class AccessorResourceError(AccessorError): + default_message: str + def __init__(self, operation: str = '', resource_identifier: Incomplete | None = None, error: Incomplete | None = None, **kw) -> None: ... + +class AccessorResourceNotFoundError(AccessorResourceError): + default_message: str + +class AccessorParentResourceNotFoundError(AccessorResourceError): + default_message: str + +class AccessorResourceInvalidError(AccessorResourceError): + default_message: str + +class AccessorContainerNotEmptyError(AccessorResourceError): + default_message: str + +class StructureError(Error): + default_message: str + +class ConnectionClosedError(Error): + default_message: str diff --git a/stubs/ftrack_api/formatter.pyi b/stubs/ftrack_api/formatter.pyi new file mode 100644 index 00000000..c3b120be --- /dev/null +++ b/stubs/ftrack_api/formatter.pyi @@ -0,0 +1,5 @@ +from _typeshed import Incomplete + +FILTER: Incomplete + +def format(entity, formatters: Incomplete | None = None, attribute_filter: Incomplete | None = None, recursive: bool = False, indent: int = 0, indent_first_line: bool = True, _seen: Incomplete | None = None): ... diff --git a/stubs/ftrack_api/inspection.pyi b/stubs/ftrack_api/inspection.pyi new file mode 100644 index 00000000..49bfed1b --- /dev/null +++ b/stubs/ftrack_api/inspection.pyi @@ -0,0 +1,4 @@ +def identity(entity): ... +def primary_key(entity): ... +def state(entity): ... +def states(entities): ... diff --git a/stubs/ftrack_api/logging.pyi b/stubs/ftrack_api/logging.pyi new file mode 100644 index 00000000..66174dbb --- /dev/null +++ b/stubs/ftrack_api/logging.pyi @@ -0,0 +1,9 @@ +from _typeshed import Incomplete + +def deprecation_warning(message): ... + +class LazyLogMessage: + message: Incomplete + args: Incomplete + kwargs: Incomplete + def __init__(self, message, *args, **kwargs) -> None: ... diff --git a/stubs/ftrack_api/operation.pyi b/stubs/ftrack_api/operation.pyi new file mode 100644 index 00000000..0bcde1cd --- /dev/null +++ b/stubs/ftrack_api/operation.pyi @@ -0,0 +1,30 @@ +from _typeshed import Incomplete + +class Operations: + def __init__(self) -> None: ... + def clear(self) -> None: ... + def push(self, operation) -> None: ... + def pop(self): ... + def __len__(self) -> int: ... + def __iter__(self): ... + +class Operation: ... + +class CreateEntityOperation(Operation): + entity_type: Incomplete + entity_key: Incomplete + entity_data: Incomplete + def __init__(self, entity_type, entity_key, entity_data) -> None: ... + +class UpdateEntityOperation(Operation): + entity_type: Incomplete + entity_key: Incomplete + attribute_name: Incomplete + old_value: Incomplete + new_value: Incomplete + def __init__(self, entity_type, entity_key, attribute_name, old_value, new_value) -> None: ... + +class DeleteEntityOperation(Operation): + entity_type: Incomplete + entity_key: Incomplete + def __init__(self, entity_type, entity_key) -> None: ... diff --git a/stubs/ftrack_api/plugin.pyi b/stubs/ftrack_api/plugin.pyi new file mode 100644 index 00000000..eb23a7c9 --- /dev/null +++ b/stubs/ftrack_api/plugin.pyi @@ -0,0 +1,4 @@ +from _typeshed import Incomplete + +def load_source(modname, filename): ... +def discover(paths, positional_arguments: Incomplete | None = None, keyword_arguments: Incomplete | None = None) -> None: ... diff --git a/stubs/ftrack_api/query.pyi b/stubs/ftrack_api/query.pyi new file mode 100644 index 00000000..95f7d0cb --- /dev/null +++ b/stubs/ftrack_api/query.pyi @@ -0,0 +1,12 @@ +import collections.abc +from _typeshed import Incomplete + +class QueryResult(collections.abc.Sequence): + OFFSET_EXPRESSION: Incomplete + LIMIT_EXPRESSION: Incomplete + def __init__(self, session, expression, page_size: int = 500) -> None: ... + def __getitem__(self, index): ... + def __len__(self) -> int: ... + def all(self): ... + def one(self): ... + def first(self): ... diff --git a/stubs/ftrack_api/resource_identifier_transformer/__init__.pyi b/stubs/ftrack_api/resource_identifier_transformer/__init__.pyi new file mode 100644 index 00000000..e69de29b diff --git a/stubs/ftrack_api/resource_identifier_transformer/base.pyi b/stubs/ftrack_api/resource_identifier_transformer/base.pyi new file mode 100644 index 00000000..754e9cc9 --- /dev/null +++ b/stubs/ftrack_api/resource_identifier_transformer/base.pyi @@ -0,0 +1,7 @@ +from _typeshed import Incomplete + +class ResourceIdentifierTransformer: + session: Incomplete + def __init__(self, session) -> None: ... + def encode(self, resource_identifier, context: Incomplete | None = None): ... + def decode(self, resource_identifier, context: Incomplete | None = None): ... diff --git a/stubs/ftrack_api/session.pyi b/stubs/ftrack_api/session.pyi new file mode 100644 index 00000000..28429352 --- /dev/null +++ b/stubs/ftrack_api/session.pyi @@ -0,0 +1,97 @@ +import collections.abc +import requests.auth +from _typeshed import Incomplete + +class SessionAuthentication(requests.auth.AuthBase): + api_key: Incomplete + api_user: Incomplete + def __init__(self, api_key, api_user) -> None: ... + def __call__(self, request): ... + +class Session: + logger: Incomplete + recorded_operations: Incomplete + cache_key_maker: Incomplete + cache: Incomplete + merge_lock: Incomplete + request_timeout: Incomplete + schemas: Incomplete + types: Incomplete + def __init__(self, server_url: Incomplete | None = None, api_key: Incomplete | None = None, api_user: Incomplete | None = None, auto_populate: bool = True, plugin_paths: Incomplete | None = None, cache: Incomplete | None = None, cache_key_maker: Incomplete | None = None, auto_connect_event_hub: bool = False, schema_cache_path: Incomplete | None = None, plugin_arguments: Incomplete | None = None, timeout: int = 60, cookies: Incomplete | None = None, headers: Incomplete | None = None, strict_api: bool = False) -> None: ... + def __enter__(self): ... + def __exit__(self, exception_type: type[BaseException] | None, exception_value: BaseException | None, traceback: types.TracebackType | None) -> None: ... + @property + def auto_populate(self): ... + @auto_populate.setter + def auto_populate(self, value) -> None: ... + @property + def record_operations(self): ... + @record_operations.setter + def record_operations(self, value) -> None: ... + @property + def closed(self): ... + @property + def server_information(self): ... + @property + def server_url(self): ... + @property + def api_user(self): ... + @property + def api_key(self): ... + @property + def event_hub(self): ... + def check_server_compatibility(self) -> None: ... + def close(self) -> None: ... + def reset(self) -> None: ... + def auto_populating(self, auto_populate): ... + def operation_recording(self, record_operations): ... + @property + def created(self): ... + @property + def modified(self): ... + @property + def deleted(self): ... + def reset_remote(self, reset_type, entity: Incomplete | None = None): ... + def create(self, entity_type, data: Incomplete | None = None, reconstructing: bool = False): ... + def ensure(self, entity_type, data, identifying_keys: Incomplete | None = None): ... + def delete(self, entity) -> None: ... + def get(self, entity_type, entity_key): ... + def query(self, expression, page_size: int = 500): ... + def merge(self, value, merged: Incomplete | None = None): ... + def populate(self, entities, projections) -> None: ... + def commit(self) -> None: ... + def rollback(self) -> None: ... + def call(self, data): ... + def encode(self, data, entity_attribute_strategy: str = 'set_only'): ... + def entity_reference(self, entity): ... + def decode(self, string): ... + def pick_location(self, component: Incomplete | None = None): ... + def pick_locations(self, components): ... + def create_component(self, path, data: Incomplete | None = None, location: str = 'auto'): ... + def get_component_availability(self, component, locations: Incomplete | None = None): ... + def get_component_availabilities(self, components, locations: Incomplete | None = None): ... + def get_widget_url(self, name, entity: Incomplete | None = None, theme: Incomplete | None = None): ... + def encode_media(self, media, version_id: Incomplete | None = None, keep_original: str = 'auto'): ... + def get_upload_metadata(self, component_id, file_name, file_size, checksum: Incomplete | None = None): ... + def send_user_invite(self, user) -> None: ... + def send_user_invites(self, users) -> None: ... + def send_review_session_invite(self, invitee) -> None: ... + def send_review_session_invites(self, invitees) -> None: ... + +class AutoPopulatingContext: + def __init__(self, session, auto_populate) -> None: ... + def __enter__(self) -> None: ... + def __exit__(self, exception_type: type[BaseException] | None, exception_value: BaseException | None, traceback: types.TracebackType | None) -> None: ... + +class OperationRecordingContext: + def __init__(self, session, record_operations) -> None: ... + def __enter__(self) -> None: ... + def __exit__(self, exception_type: type[BaseException] | None, exception_value: BaseException | None, traceback: types.TracebackType | None) -> None: ... + +class OperationPayload(collections.abc.MutableMapping): + def __init__(self, *args, **kwargs) -> None: ... + def __getitem__(self, key): ... + def __setitem__(self, key, value) -> None: ... + def __delitem__(self, key) -> None: ... + def __iter__(self): ... + def __len__(self) -> int: ... diff --git a/stubs/ftrack_api/structure/__init__.pyi b/stubs/ftrack_api/structure/__init__.pyi new file mode 100644 index 00000000..e69de29b diff --git a/stubs/ftrack_api/structure/base.pyi b/stubs/ftrack_api/structure/base.pyi new file mode 100644 index 00000000..1dbf212e --- /dev/null +++ b/stubs/ftrack_api/structure/base.pyi @@ -0,0 +1,9 @@ +from _typeshed import Incomplete +from abc import ABCMeta, abstractmethod + +class Structure(metaclass=ABCMeta): + prefix: Incomplete + path_separator: str + def __init__(self, prefix: str = '') -> None: ... + @abstractmethod + def get_resource_identifier(self, entity, context: Incomplete | None = None): ... diff --git a/stubs/ftrack_api/structure/entity_id.pyi b/stubs/ftrack_api/structure/entity_id.pyi new file mode 100644 index 00000000..65b522b9 --- /dev/null +++ b/stubs/ftrack_api/structure/entity_id.pyi @@ -0,0 +1,5 @@ +import ftrack_api.structure.base +from _typeshed import Incomplete + +class EntityIdStructure(ftrack_api.structure.base.Structure): + def get_resource_identifier(self, entity, context: Incomplete | None = None): ... diff --git a/stubs/ftrack_api/structure/id.pyi b/stubs/ftrack_api/structure/id.pyi new file mode 100644 index 00000000..4a34e68d --- /dev/null +++ b/stubs/ftrack_api/structure/id.pyi @@ -0,0 +1,5 @@ +import ftrack_api.structure.base +from _typeshed import Incomplete + +class IdStructure(ftrack_api.structure.base.Structure): + def get_resource_identifier(self, entity, context: Incomplete | None = None): ... diff --git a/stubs/ftrack_api/structure/origin.pyi b/stubs/ftrack_api/structure/origin.pyi new file mode 100644 index 00000000..382625d7 --- /dev/null +++ b/stubs/ftrack_api/structure/origin.pyi @@ -0,0 +1,5 @@ +from .base import Structure as Structure +from _typeshed import Incomplete + +class OriginStructure(Structure): + def get_resource_identifier(self, entity, context: Incomplete | None = None): ... diff --git a/stubs/ftrack_api/structure/standard.pyi b/stubs/ftrack_api/structure/standard.pyi new file mode 100644 index 00000000..8eeb60cb --- /dev/null +++ b/stubs/ftrack_api/structure/standard.pyi @@ -0,0 +1,9 @@ +import ftrack_api.structure.base +from _typeshed import Incomplete + +class StandardStructure(ftrack_api.structure.base.Structure): + project_versions_prefix: Incomplete + illegal_character_substitute: Incomplete + def __init__(self, project_versions_prefix: Incomplete | None = None, illegal_character_substitute: str = '_') -> None: ... + def sanitise_for_filesystem(self, value): ... + def get_resource_identifier(self, entity, context: Incomplete | None = None): ... diff --git a/stubs/ftrack_api/symbol.pyi b/stubs/ftrack_api/symbol.pyi new file mode 100644 index 00000000..3ecdc7b8 --- /dev/null +++ b/stubs/ftrack_api/symbol.pyi @@ -0,0 +1,22 @@ +from _typeshed import Incomplete + +class Symbol: + name: Incomplete + value: Incomplete + def __init__(self, name, value: bool = True) -> None: ... + def __bool__(self) -> bool: ... + def __copy__(self): ... + +NOT_SET: Incomplete +CREATED: Incomplete +MODIFIED: Incomplete +DELETED: Incomplete +COMPONENT_ADDED_TO_LOCATION_TOPIC: str +COMPONENT_REMOVED_FROM_LOCATION_TOPIC: str +ORIGIN_LOCATION_ID: str +UNMANAGED_LOCATION_ID: str +REVIEW_LOCATION_ID: str +CONNECT_LOCATION_ID: str +SERVER_LOCATION_ID: str +CHUNK_SIZE: Incomplete +JOB_SYNC_USERS_LDAP: Incomplete From 6edd53798867733dc90d513f39fe56444f7ed689 Mon Sep 17 00:00:00 2001 From: Octavian Ionescu Date: Thu, 9 Apr 2026 17:11:41 +0300 Subject: [PATCH 3/5] added CLAUDE.md --- CLAUDE.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..43c994c2 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md From a3b0b265d690c7ec14e1fcfc5bf0d32fe21a64db Mon Sep 17 00:00:00 2001 From: lorenzo angeli Date: Tue, 14 Apr 2026 09:42:53 +0200 Subject: [PATCH 4/5] remove python stubs from this PR --- stubs/ftrack_api/__init__.pyi | 5 - .../_centralized_storage_scenario.pyi | 25 ---- stubs/ftrack_api/_python_ntpath.pyi | 46 ------ stubs/ftrack_api/_version.pyi | 1 - stubs/ftrack_api/accessor/__init__.pyi | 0 stubs/ftrack_api/accessor/base.pyi | 25 ---- stubs/ftrack_api/accessor/disk.pyi | 20 --- stubs/ftrack_api/accessor/server.pyi | 24 --- stubs/ftrack_api/attribute.pyi | 65 --------- stubs/ftrack_api/cache.pyi | 78 ---------- stubs/ftrack_api/collection.pyi | 61 -------- stubs/ftrack_api/data.pyi | 33 ----- stubs/ftrack_api/entity/__init__.pyi | 0 stubs/ftrack_api/entity/asset_version.pyi | 6 - stubs/ftrack_api/entity/base.pyi | 26 ---- stubs/ftrack_api/entity/component.pyi | 8 - stubs/ftrack_api/entity/factory.pyi | 20 --- stubs/ftrack_api/entity/job.pyi | 5 - stubs/ftrack_api/entity/location.pyi | 29 ---- stubs/ftrack_api/entity/note.pyi | 8 - stubs/ftrack_api/entity/project_schema.pyi | 6 - stubs/ftrack_api/entity/user.pyi | 8 - stubs/ftrack_api/event/__init__.pyi | 0 stubs/ftrack_api/event/base.pyi | 12 -- stubs/ftrack_api/event/expression.pyi | 24 --- stubs/ftrack_api/event/hub.pyi | 50 ------- stubs/ftrack_api/event/subscriber.pyi | 9 -- stubs/ftrack_api/event/subscription.pyi | 6 - stubs/ftrack_api/exception.pyi | 138 ------------------ stubs/ftrack_api/formatter.pyi | 5 - stubs/ftrack_api/inspection.pyi | 4 - stubs/ftrack_api/logging.pyi | 9 -- stubs/ftrack_api/operation.pyi | 30 ---- stubs/ftrack_api/plugin.pyi | 4 - stubs/ftrack_api/query.pyi | 12 -- .../__init__.pyi | 0 .../resource_identifier_transformer/base.pyi | 7 - stubs/ftrack_api/session.pyi | 97 ------------ stubs/ftrack_api/structure/__init__.pyi | 0 stubs/ftrack_api/structure/base.pyi | 9 -- stubs/ftrack_api/structure/entity_id.pyi | 5 - stubs/ftrack_api/structure/id.pyi | 5 - stubs/ftrack_api/structure/origin.pyi | 5 - stubs/ftrack_api/structure/standard.pyi | 9 -- stubs/ftrack_api/symbol.pyi | 22 --- 45 files changed, 961 deletions(-) delete mode 100644 stubs/ftrack_api/__init__.pyi delete mode 100644 stubs/ftrack_api/_centralized_storage_scenario.pyi delete mode 100644 stubs/ftrack_api/_python_ntpath.pyi delete mode 100644 stubs/ftrack_api/_version.pyi delete mode 100644 stubs/ftrack_api/accessor/__init__.pyi delete mode 100644 stubs/ftrack_api/accessor/base.pyi delete mode 100644 stubs/ftrack_api/accessor/disk.pyi delete mode 100644 stubs/ftrack_api/accessor/server.pyi delete mode 100644 stubs/ftrack_api/attribute.pyi delete mode 100644 stubs/ftrack_api/cache.pyi delete mode 100644 stubs/ftrack_api/collection.pyi delete mode 100644 stubs/ftrack_api/data.pyi delete mode 100644 stubs/ftrack_api/entity/__init__.pyi delete mode 100644 stubs/ftrack_api/entity/asset_version.pyi delete mode 100644 stubs/ftrack_api/entity/base.pyi delete mode 100644 stubs/ftrack_api/entity/component.pyi delete mode 100644 stubs/ftrack_api/entity/factory.pyi delete mode 100644 stubs/ftrack_api/entity/job.pyi delete mode 100644 stubs/ftrack_api/entity/location.pyi delete mode 100644 stubs/ftrack_api/entity/note.pyi delete mode 100644 stubs/ftrack_api/entity/project_schema.pyi delete mode 100644 stubs/ftrack_api/entity/user.pyi delete mode 100644 stubs/ftrack_api/event/__init__.pyi delete mode 100644 stubs/ftrack_api/event/base.pyi delete mode 100644 stubs/ftrack_api/event/expression.pyi delete mode 100644 stubs/ftrack_api/event/hub.pyi delete mode 100644 stubs/ftrack_api/event/subscriber.pyi delete mode 100644 stubs/ftrack_api/event/subscription.pyi delete mode 100644 stubs/ftrack_api/exception.pyi delete mode 100644 stubs/ftrack_api/formatter.pyi delete mode 100644 stubs/ftrack_api/inspection.pyi delete mode 100644 stubs/ftrack_api/logging.pyi delete mode 100644 stubs/ftrack_api/operation.pyi delete mode 100644 stubs/ftrack_api/plugin.pyi delete mode 100644 stubs/ftrack_api/query.pyi delete mode 100644 stubs/ftrack_api/resource_identifier_transformer/__init__.pyi delete mode 100644 stubs/ftrack_api/resource_identifier_transformer/base.pyi delete mode 100644 stubs/ftrack_api/session.pyi delete mode 100644 stubs/ftrack_api/structure/__init__.pyi delete mode 100644 stubs/ftrack_api/structure/base.pyi delete mode 100644 stubs/ftrack_api/structure/entity_id.pyi delete mode 100644 stubs/ftrack_api/structure/id.pyi delete mode 100644 stubs/ftrack_api/structure/origin.pyi delete mode 100644 stubs/ftrack_api/structure/standard.pyi delete mode 100644 stubs/ftrack_api/symbol.pyi diff --git a/stubs/ftrack_api/__init__.pyi b/stubs/ftrack_api/__init__.pyi deleted file mode 100644 index ec7d10f4..00000000 --- a/stubs/ftrack_api/__init__.pyi +++ /dev/null @@ -1,5 +0,0 @@ -from ._version import __version__ as __version__ -from .session import Session as Session -from _typeshed import Incomplete - -def mixin(instance, mixin_class, name: Incomplete | None = None) -> None: ... diff --git a/stubs/ftrack_api/_centralized_storage_scenario.pyi b/stubs/ftrack_api/_centralized_storage_scenario.pyi deleted file mode 100644 index 2a54a9f9..00000000 --- a/stubs/ftrack_api/_centralized_storage_scenario.pyi +++ /dev/null @@ -1,25 +0,0 @@ -from _typeshed import Incomplete - -scenario_name: str - -class ConfigureCentralizedStorageScenario: - logger: Incomplete - def __init__(self) -> None: ... - @property - def storage_scenario(self): ... - @property - def existing_centralized_storage_configuration(self): ... - def configure_scenario(self, event): ... - def discover_centralized_scenario(self, event): ... - session: Incomplete - def register(self, session) -> None: ... - -class ActivateCentralizedStorageScenario: - logger: Incomplete - def __init__(self) -> None: ... - def activate(self, event) -> None: ... - session: Incomplete - def register(self, session) -> None: ... - -def register(session) -> None: ... -def register_configuration(session) -> None: ... diff --git a/stubs/ftrack_api/_python_ntpath.pyi b/stubs/ftrack_api/_python_ntpath.pyi deleted file mode 100644 index f31a0007..00000000 --- a/stubs/ftrack_api/_python_ntpath.pyi +++ /dev/null @@ -1,46 +0,0 @@ -from genericpath import * -from _typeshed import Incomplete -from nt import _isdir as isdir - -__all__ = ['normcase', 'isabs', 'join', 'splitdrive', 'split', 'splitext', 'basename', 'dirname', 'commonprefix', 'getsize', 'getmtime', 'getatime', 'getctime', 'islink', 'exists', 'lexists', 'isdir', 'isfile', 'ismount', 'walk', 'expanduser', 'expandvars', 'normpath', 'abspath', 'splitunc', 'curdir', 'pardir', 'sep', 'pathsep', 'defpath', 'altsep', 'extsep', 'devnull', 'realpath', 'supports_unicode_filenames', 'relpath'] - -curdir: str -pardir: str -extsep: str -sep: str -pathsep: str -altsep: str -defpath: str -devnull: str - -def normcase(s): ... -def isabs(s): ... -def join(a, *p): ... -def splitdrive(p): ... -def splitunc(p): ... -def split(p): ... -def splitext(p): ... -def basename(p): ... -def dirname(p): ... -def islink(path): ... -lexists = exists - -def ismount(path): ... -def walk(top, func, arg) -> None: ... -def expanduser(path): ... -def expandvars(path): ... -def normpath(path): ... -def abspath(path): ... -realpath = abspath -supports_unicode_filenames: Incomplete - -def relpath(path, start=...): ... - -# Names in __all__ with no definition: -# commonprefix -# exists -# getatime -# getctime -# getmtime -# getsize -# isfile diff --git a/stubs/ftrack_api/_version.pyi b/stubs/ftrack_api/_version.pyi deleted file mode 100644 index bda5b5a7..00000000 --- a/stubs/ftrack_api/_version.pyi +++ /dev/null @@ -1 +0,0 @@ -__version__: str diff --git a/stubs/ftrack_api/accessor/__init__.pyi b/stubs/ftrack_api/accessor/__init__.pyi deleted file mode 100644 index e69de29b..00000000 diff --git a/stubs/ftrack_api/accessor/base.pyi b/stubs/ftrack_api/accessor/base.pyi deleted file mode 100644 index 23e69490..00000000 --- a/stubs/ftrack_api/accessor/base.pyi +++ /dev/null @@ -1,25 +0,0 @@ -import abc - -class Accessor(metaclass=abc.ABCMeta): - def __init__(self) -> None: ... - @abc.abstractmethod - def list(self, resource_identifier): ... - @abc.abstractmethod - def exists(self, resource_identifier): ... - @abc.abstractmethod - def is_file(self, resource_identifier): ... - @abc.abstractmethod - def is_container(self, resource_identifier): ... - @abc.abstractmethod - def is_sequence(self, resource_identifier): ... - @abc.abstractmethod - def open(self, resource_identifier, mode: str = 'rb'): ... - @abc.abstractmethod - def remove(self, resource_identifier): ... - @abc.abstractmethod - def make_container(self, resource_identifier, recursive: bool = True): ... - @abc.abstractmethod - def get_container(self, resource_identifier): ... - def remove_container(self, resource_identifier): ... - def get_filesystem_path(self, resource_identifier) -> None: ... - def get_url(self, resource_identifier) -> None: ... diff --git a/stubs/ftrack_api/accessor/disk.pyi b/stubs/ftrack_api/accessor/disk.pyi deleted file mode 100644 index db24136a..00000000 --- a/stubs/ftrack_api/accessor/disk.pyi +++ /dev/null @@ -1,20 +0,0 @@ -import ftrack_api.accessor.base -from _typeshed import Incomplete -from collections.abc import Generator -from ftrack_api.exception import AccessorContainerNotEmptyError as AccessorContainerNotEmptyError, AccessorFilesystemPathError as AccessorFilesystemPathError, AccessorOperationFailedError as AccessorOperationFailedError, AccessorParentResourceNotFoundError as AccessorParentResourceNotFoundError, AccessorPermissionDeniedError as AccessorPermissionDeniedError, AccessorResourceInvalidError as AccessorResourceInvalidError, AccessorResourceNotFoundError as AccessorResourceNotFoundError, AccessorUnsupportedOperationError as AccessorUnsupportedOperationError - -class DiskAccessor(ftrack_api.accessor.base.Accessor): - prefix: Incomplete - def __init__(self, prefix, **kw) -> None: ... - def list(self, resource_identifier): ... - def exists(self, resource_identifier): ... - def is_file(self, resource_identifier): ... - def is_container(self, resource_identifier): ... - def is_sequence(self, resource_identifier) -> None: ... - def open(self, resource_identifier, mode: str = 'rb'): ... - def remove(self, resource_identifier) -> None: ... - def make_container(self, resource_identifier, recursive: bool = True) -> None: ... - def get_container(self, resource_identifier): ... - def get_filesystem_path(self, resource_identifier): ... - -def error_handler(**kw) -> Generator[None]: ... diff --git a/stubs/ftrack_api/accessor/server.pyi b/stubs/ftrack_api/accessor/server.pyi deleted file mode 100644 index 112c04a3..00000000 --- a/stubs/ftrack_api/accessor/server.pyi +++ /dev/null @@ -1,24 +0,0 @@ -from ..data import String as String -from .base import Accessor as Accessor -from _typeshed import Incomplete - -class ServerFile(String): - mode: Incomplete - resource_identifier: Incomplete - def __init__(self, resource_identifier, session, mode: str = 'rb') -> None: ... - def flush(self) -> None: ... - def read(self, limit: Incomplete | None = None): ... - -class _ServerAccessor(Accessor): - def __init__(self, session, **kw) -> None: ... - def open(self, resource_identifier, mode: str = 'rb'): ... - def remove(self, resourceIdentifier) -> None: ... - def get_container(self, resource_identifier) -> None: ... - def make_container(self, resource_identifier, recursive: bool = True) -> None: ... - def list(self, resource_identifier) -> None: ... - def exists(self, resource_identifier): ... - def is_file(self, resource_identifier) -> None: ... - def is_container(self, resource_identifier) -> None: ... - def is_sequence(self, resource_identifier) -> None: ... - def get_url(self, resource_identifier): ... - def get_thumbnail_url(self, resource_identifier, size: Incomplete | None = None): ... diff --git a/stubs/ftrack_api/attribute.pyi b/stubs/ftrack_api/attribute.pyi deleted file mode 100644 index 0c28c276..00000000 --- a/stubs/ftrack_api/attribute.pyi +++ /dev/null @@ -1,65 +0,0 @@ -import ftrack_api.collection -from _typeshed import Incomplete - -logger: Incomplete - -def merge_references(function): ... - -class Attributes: - def __init__(self, attributes: Incomplete | None = None) -> None: ... - def add(self, attribute) -> None: ... - def remove(self, attribute) -> None: ... - def get(self, name): ... - def keys(self): ... - def __contains__(self, item) -> bool: ... - def __iter__(self): ... - def __len__(self) -> int: ... - -class Attribute: - default_value: Incomplete - def __init__(self, name, default_value=..., mutable: bool = True, computed: bool = False) -> None: ... - def get_entity_storage(self, entity): ... - @property - def name(self): ... - @property - def mutable(self): ... - @property - def computed(self): ... - def get_value(self, entity): ... - def get_local_value(self, entity): ... - def get_remote_value(self, entity): ... - def set_local_value(self, entity, value) -> None: ... - def set_remote_value(self, entity, value) -> None: ... - def populate_remote_value(self, entity) -> None: ... - def is_modified(self, entity): ... - def is_set(self, entity): ... - -class ScalarAttribute(Attribute): - data_type: Incomplete - def __init__(self, name, data_type, **kw) -> None: ... - -class ReferenceAttribute(Attribute): - entity_type: Incomplete - def __init__(self, name, entity_type, **kw) -> None: ... - def populate_remote_value(self, entity) -> None: ... - def is_modified(self, entity): ... - def get_value(self, entity): ... - -class AbstractCollectionAttribute(Attribute): - collection_class: Incomplete - def get_value(self, entity): ... - def set_local_value(self, entity, value) -> None: ... - def set_remote_value(self, entity, value) -> None: ... - -class CollectionAttribute(AbstractCollectionAttribute): - collection_class = ftrack_api.collection.Collection - -class KeyValueMappedCollectionAttribute(AbstractCollectionAttribute): - collection_class = ftrack_api.collection.KeyValueMappedCollectionProxy - creator: Incomplete - key_attribute: Incomplete - value_attribute: Incomplete - def __init__(self, name, creator, key_attribute, value_attribute, **kw) -> None: ... - -class CustomAttributeCollectionAttribute(AbstractCollectionAttribute): - collection_class = ftrack_api.collection.CustomAttributeCollectionProxy diff --git a/stubs/ftrack_api/cache.pyi b/stubs/ftrack_api/cache.pyi deleted file mode 100644 index 9c3984a3..00000000 --- a/stubs/ftrack_api/cache.pyi +++ /dev/null @@ -1,78 +0,0 @@ -import abc -from _typeshed import Incomplete - -class Cache(metaclass=abc.ABCMeta): - @abc.abstractmethod - def get(self, key): ... - @abc.abstractmethod - def set(self, key, value): ... - @abc.abstractmethod - def remove(self, key): ... - def keys(self) -> None: ... - def values(self): ... - def clear(self, pattern: Incomplete | None = None) -> None: ... - -class ProxyCache(Cache): - proxied: Incomplete - def __init__(self, proxied) -> None: ... - def get(self, key): ... - def set(self, key, value): ... - def remove(self, key): ... - def keys(self): ... - -class LayeredCache(Cache): - caches: Incomplete - def __init__(self, caches) -> None: ... - def get(self, key): ... - def set(self, key, value) -> None: ... - def remove(self, key) -> None: ... - def keys(self): ... - -class MemoryCache(Cache): - def __init__(self) -> None: ... - def get(self, key): ... - def set(self, key, value) -> None: ... - def remove(self, key) -> None: ... - def keys(self): ... - -class FileCache(Cache): - path: Incomplete - def __init__(self, path) -> None: ... - def get(self, key): ... - def set(self, key, value) -> None: ... - def remove(self, key) -> None: ... - def keys(self): ... - -class SerialisedCache(ProxyCache): - encode: Incomplete - decode: Incomplete - def __init__(self, proxied, encode: Incomplete | None = None, decode: Incomplete | None = None) -> None: ... - def get(self, key): ... - def set(self, key, value) -> None: ... - -class KeyMaker(metaclass=abc.ABCMeta): - item_separator: str - def __init__(self) -> None: ... - def key(self, *items): ... - -class StringKeyMaker(KeyMaker): ... - -class ObjectKeyMaker(KeyMaker): - item_separator: bytes - mapping_identifier: bytes - mapping_pair_separator: bytes - iterable_identifier: bytes - name_identifier: bytes - def __init__(self) -> None: ... - -class Memoiser: - cache: Incomplete - key_maker: Incomplete - return_copies: Incomplete - def __init__(self, cache: Incomplete | None = None, key_maker: Incomplete | None = None, return_copies: bool = True) -> None: ... - def call(self, function, args: Incomplete | None = None, kw: Incomplete | None = None): ... - -def memoise_decorator(memoiser): ... - -memoiser: Incomplete -memoise: Incomplete diff --git a/stubs/ftrack_api/collection.pyi b/stubs/ftrack_api/collection.pyi deleted file mode 100644 index b7694d8b..00000000 --- a/stubs/ftrack_api/collection.pyi +++ /dev/null @@ -1,61 +0,0 @@ -import abc -import collections.abc -import ftrack_api.cache -from _typeshed import Incomplete - -class Collection(collections.abc.MutableSequence): - entity: Incomplete - attribute: Incomplete - mutable: bool - def __init__(self, entity, attribute, mutable: bool = True, data: Incomplete | None = None) -> None: ... - def __copy__(self): ... - def insert(self, index, item) -> None: ... - def __contains__(self, value) -> bool: ... - def __getitem__(self, index): ... - def __setitem__(self, index, item) -> None: ... - def __delitem__(self, index) -> None: ... - def __len__(self) -> int: ... - def __eq__(self, other): ... - def __ne__(self, other): ... - -class MappedCollectionProxy(collections.abc.MutableMapping, metaclass=abc.ABCMeta): - logger: Incomplete - collection: Incomplete - def __init__(self, collection) -> None: ... - def __copy__(self): ... - @property - def mutable(self): ... - @mutable.setter - def mutable(self, value) -> None: ... - @property - def attribute(self): ... - @attribute.setter - def attribute(self, value) -> None: ... - -class KeyValueMappedCollectionProxy(MappedCollectionProxy): - creator: Incomplete - key_attribute: Incomplete - value_attribute: Incomplete - def __init__(self, collection, creator, key_attribute, value_attribute) -> None: ... - def __getitem__(self, key): ... - def __setitem__(self, key, value) -> None: ... - def __delitem__(self, key) -> None: ... - def __iter__(self): ... - def __len__(self) -> int: ... - def keys(self): ... - -class PerSessionDefaultKeyMaker(ftrack_api.cache.KeyMaker): ... - -memoise_session: Incomplete - -class CustomAttributeCollectionProxy(MappedCollectionProxy): - key_attribute: str - value_attribute: str - def __init__(self, collection) -> None: ... - def get_configuration_id_from_key(self, key): ... - def __getitem__(self, key): ... - def __setitem__(self, key, value) -> None: ... - def __delitem__(self, key) -> None: ... - def __eq__(self, collection): ... - def __iter__(self): ... - def __len__(self) -> int: ... diff --git a/stubs/ftrack_api/data.pyi b/stubs/ftrack_api/data.pyi deleted file mode 100644 index 6f24e847..00000000 --- a/stubs/ftrack_api/data.pyi +++ /dev/null @@ -1,33 +0,0 @@ -from _typeshed import Incomplete -from abc import ABCMeta, abstractmethod - -class Data(metaclass=ABCMeta): - closed: bool - def __init__(self) -> None: ... - @abstractmethod - def read(self, limit: Incomplete | None = None): ... - @abstractmethod - def write(self, content): ... - def flush(self) -> None: ... - def seek(self, offset, whence=...) -> None: ... - def tell(self) -> None: ... - def close(self) -> None: ... - -class FileWrapper(Data): - wrapped_file: Incomplete - def __init__(self, wrapped_file) -> None: ... - def read(self, limit: Incomplete | None = None): ... - def write(self, content) -> None: ... - def flush(self) -> None: ... - def seek(self, offset, whence=...) -> None: ... - def tell(self): ... - def close(self) -> None: ... - -class File(FileWrapper): - def __init__(self, path, mode: str = 'rb') -> None: ... - -class String(FileWrapper): - is_binary: bool - def __init__(self, content: Incomplete | None = None) -> None: ... - def write(self, content) -> None: ... - def read(self, limit: Incomplete | None = None): ... diff --git a/stubs/ftrack_api/entity/__init__.pyi b/stubs/ftrack_api/entity/__init__.pyi deleted file mode 100644 index e69de29b..00000000 diff --git a/stubs/ftrack_api/entity/asset_version.pyi b/stubs/ftrack_api/entity/asset_version.pyi deleted file mode 100644 index d1d79a91..00000000 --- a/stubs/ftrack_api/entity/asset_version.pyi +++ /dev/null @@ -1,6 +0,0 @@ -import ftrack_api.entity.base -from _typeshed import Incomplete - -class AssetVersion(ftrack_api.entity.base.Entity): - def create_component(self, path, data: Incomplete | None = None, location: Incomplete | None = None): ... - def encode_media(self, media, keep_original: str = 'auto'): ... diff --git a/stubs/ftrack_api/entity/base.pyi b/stubs/ftrack_api/entity/base.pyi deleted file mode 100644 index 19fc5866..00000000 --- a/stubs/ftrack_api/entity/base.pyi +++ /dev/null @@ -1,26 +0,0 @@ -import abc -import collections.abc -from _typeshed import Incomplete - -class _EntityBase: ... -class DynamicEntityTypeMetaclass(abc.ABCMeta): ... - -class Entity(_EntityBase, collections.abc.MutableMapping, metaclass=DynamicEntityTypeMetaclass): - entity_type: str - attributes: Incomplete - primary_key_attributes: Incomplete - default_projections: Incomplete - logger: Incomplete - session: Incomplete - def __init__(self, session, data: Incomplete | None = None, reconstructing: bool = False) -> None: ... - def __hash__(self): ... - def __eq__(self, other): ... - def __getitem__(self, key): ... - def __setitem__(self, key, value) -> None: ... - def __delitem__(self, key) -> None: ... - def __iter__(self): ... - def __len__(self) -> int: ... - def values(self): ... - def items(self): ... - def clear(self) -> None: ... - def merge(self, entity, merged: Incomplete | None = None): ... diff --git a/stubs/ftrack_api/entity/component.pyi b/stubs/ftrack_api/entity/component.pyi deleted file mode 100644 index 428d6fe8..00000000 --- a/stubs/ftrack_api/entity/component.pyi +++ /dev/null @@ -1,8 +0,0 @@ -import ftrack_api.entity.base -from _typeshed import Incomplete - -class Component(ftrack_api.entity.base.Entity): - def get_availability(self, locations: Incomplete | None = None): ... - -class CreateThumbnailMixin: - def create_thumbnail(self, path, data: Incomplete | None = None): ... diff --git a/stubs/ftrack_api/entity/factory.pyi b/stubs/ftrack_api/entity/factory.pyi deleted file mode 100644 index 9cee4609..00000000 --- a/stubs/ftrack_api/entity/factory.pyi +++ /dev/null @@ -1,20 +0,0 @@ -import ftrack_api.cache -from _typeshed import Incomplete - -class Factory: - logger: Incomplete - def __init__(self) -> None: ... - def create(self, schema, bases: Incomplete | None = None): ... - def create_scalar_attribute(self, class_name, name, mutable, computed, default, data_type): ... - def create_reference_attribute(self, class_name, name, mutable, reference): ... - def create_collection_attribute(self, class_name, name, mutable): ... - def create_mapped_collection_attribute(self, class_name, name, mutable, reference) -> None: ... - -class PerSessionDefaultKeyMaker(ftrack_api.cache.KeyMaker): ... - -memoise_defaults: Incomplete -memoise_session: Incomplete - -class StandardFactory(Factory): - def create(self, schema, bases: Incomplete | None = None): ... - def create_mapped_collection_attribute(self, class_name, name, mutable, reference): ... diff --git a/stubs/ftrack_api/entity/job.pyi b/stubs/ftrack_api/entity/job.pyi deleted file mode 100644 index 75e813eb..00000000 --- a/stubs/ftrack_api/entity/job.pyi +++ /dev/null @@ -1,5 +0,0 @@ -import ftrack_api.entity.base -from _typeshed import Incomplete - -class Job(ftrack_api.entity.base.Entity): - def __init__(self, session, data: Incomplete | None = None, reconstructing: bool = False) -> None: ... diff --git a/stubs/ftrack_api/entity/location.pyi b/stubs/ftrack_api/entity/location.pyi deleted file mode 100644 index 769b4172..00000000 --- a/stubs/ftrack_api/entity/location.pyi +++ /dev/null @@ -1,29 +0,0 @@ -import abc -import collections.abc -import ftrack_api.entity.base -from _typeshed import Incomplete - -class Location(ftrack_api.entity.base.Entity): - accessor: Incomplete - structure: Incomplete - resource_identifier_transformer: Incomplete - priority: int - def __init__(self, session, data: Incomplete | None = None, reconstructing: bool = False) -> None: ... - def add_component(self, component, source, recursive: bool = True): ... - def add_components(self, components, sources, recursive: bool = True, _depth: int = 0) -> None: ... - def remove_component(self, component, recursive: bool = True): ... - def remove_components(self, components, recursive: bool = True) -> None: ... - def get_component_availability(self, component): ... - def get_component_availabilities(self, components): ... - def get_resource_identifier(self, component): ... - def get_resource_identifiers(self, components): ... - def get_filesystem_path(self, component): ... - def get_filesystem_paths(self, components): ... - def get_url(self, component): ... - -class MemoryLocationMixin(ftrack_api.entity.base._EntityBase, collections.abc.MutableMapping, metaclass=ftrack_api.entity.base.DynamicEntityTypeMetaclass): ... -class UnmanagedLocationMixin(ftrack_api.entity.base._EntityBase, collections.abc.MutableMapping, metaclass=ftrack_api.entity.base.DynamicEntityTypeMetaclass): ... -class OriginLocationMixin(MemoryLocationMixin, UnmanagedLocationMixin, metaclass=abc.ABCMeta): ... - -class ServerLocationMixin(ftrack_api.entity.base._EntityBase, collections.abc.MutableMapping, metaclass=ftrack_api.entity.base.DynamicEntityTypeMetaclass): - def get_thumbnail_url(self, component, size: Incomplete | None = None): ... diff --git a/stubs/ftrack_api/entity/note.pyi b/stubs/ftrack_api/entity/note.pyi deleted file mode 100644 index 91e27b34..00000000 --- a/stubs/ftrack_api/entity/note.pyi +++ /dev/null @@ -1,8 +0,0 @@ -import ftrack_api.entity.base -from _typeshed import Incomplete - -class Note(ftrack_api.entity.base.Entity): - def create_reply(self, content, author): ... - -class CreateNoteMixin: - def create_note(self, content, author, recipients: Incomplete | None = None, category: Incomplete | None = None, labels: Incomplete | None = None): ... diff --git a/stubs/ftrack_api/entity/project_schema.pyi b/stubs/ftrack_api/entity/project_schema.pyi deleted file mode 100644 index 3b6f0aac..00000000 --- a/stubs/ftrack_api/entity/project_schema.pyi +++ /dev/null @@ -1,6 +0,0 @@ -import ftrack_api.entity.base -from _typeshed import Incomplete - -class ProjectSchema(ftrack_api.entity.base.Entity): - def get_statuses(self, schema, type_id: Incomplete | None = None): ... - def get_types(self, schema): ... diff --git a/stubs/ftrack_api/entity/user.pyi b/stubs/ftrack_api/entity/user.pyi deleted file mode 100644 index 982563a2..00000000 --- a/stubs/ftrack_api/entity/user.pyi +++ /dev/null @@ -1,8 +0,0 @@ -import ftrack_api.entity.base -from _typeshed import Incomplete - -class User(ftrack_api.entity.base.Entity): - def start_timer(self, context: Incomplete | None = None, comment: str = '', name: Incomplete | None = None, force: bool = False): ... - def stop_timer(self): ... - def send_invite(self) -> None: ... - def reset_api_key(self): ... diff --git a/stubs/ftrack_api/event/__init__.pyi b/stubs/ftrack_api/event/__init__.pyi deleted file mode 100644 index e69de29b..00000000 diff --git a/stubs/ftrack_api/event/base.pyi b/stubs/ftrack_api/event/base.pyi deleted file mode 100644 index 5379bc0f..00000000 --- a/stubs/ftrack_api/event/base.pyi +++ /dev/null @@ -1,12 +0,0 @@ -import collections.abc -from _typeshed import Incomplete - -class Event(collections.abc.MutableMapping): - def __init__(self, topic, id: Incomplete | None = None, data: Incomplete | None = None, sent: Incomplete | None = None, source: Incomplete | None = None, target: str = '', in_reply_to_event: Incomplete | None = None) -> None: ... - def stop(self) -> None: ... - def is_stopped(self): ... - def __getitem__(self, key): ... - def __setitem__(self, key, value) -> None: ... - def __delitem__(self, key) -> None: ... - def __iter__(self): ... - def __len__(self) -> int: ... diff --git a/stubs/ftrack_api/event/expression.pyi b/stubs/ftrack_api/event/expression.pyi deleted file mode 100644 index 05420647..00000000 --- a/stubs/ftrack_api/event/expression.pyi +++ /dev/null @@ -1,24 +0,0 @@ -from _typeshed import Incomplete - -class Parser: - def __init__(self) -> None: ... - def parse(self, expression): ... - -class Expression: - def match(self, candidate): ... - -class All(Expression): - def __init__(self, expressions: Incomplete | None = None) -> None: ... - def match(self, candidate): ... - -class Any(Expression): - def __init__(self, expressions: Incomplete | None = None) -> None: ... - def match(self, candidate): ... - -class Not(Expression): - def __init__(self, expression) -> None: ... - def match(self, candidate): ... - -class Condition(Expression): - def __init__(self, key, operator, value) -> None: ... - def match(self, candidate): ... diff --git a/stubs/ftrack_api/event/hub.pyi b/stubs/ftrack_api/event/hub.pyi deleted file mode 100644 index a3ffa901..00000000 --- a/stubs/ftrack_api/event/hub.pyi +++ /dev/null @@ -1,50 +0,0 @@ -import threading -from _typeshed import Incomplete -from typing import NamedTuple - -class SocketIoSession(NamedTuple): - id: Incomplete - heartbeatTimeout: Incomplete - supportedTransports: Incomplete - -class ServerDetails(NamedTuple): - scheme: Incomplete - hostname: Incomplete - port: Incomplete - -class EventHub: - logger: Incomplete - id: Incomplete - server: Incomplete - def __init__(self, server_url, api_user, api_key, headers: Incomplete | None = None, cookies: Incomplete | None = None) -> None: ... - def get_server_url(self): ... - def get_network_location(self): ... - @property - def secure(self): ... - def init_connection(self) -> None: ... - def connect(self) -> None: ... - @property - def connected(self): ... - def disconnect(self, unsubscribe: bool = True, reconnect: bool = False) -> None: ... - def reconnect(self, attempts: int = 10, delay: int = 5) -> None: ... - def wait(self, duration: Incomplete | None = None) -> None: ... - def get_subscriber_by_identifier(self, identifier): ... - def subscribe(self, subscription, callback, subscriber: Incomplete | None = None, priority: int = 100): ... - def unsubscribe(self, subscriber_identifier) -> None: ... - def publish(self, event, synchronous: bool = False, on_reply: Incomplete | None = None, on_error: str = 'raise'): ... - def publish_reply(self, source_event, data, source: Incomplete | None = None) -> None: ... - def subscription(self, subscription, callback, subscriber: Incomplete | None = None, priority: int = 100): ... - -class _SubscriptionContext: - def __init__(self, hub, subscription, callback, subscriber, priority) -> None: ... - def __enter__(self) -> None: ... - def __exit__(self, exception_type: type[BaseException] | None, exception_value: BaseException | None, traceback: types.TracebackType | None) -> None: ... - -class _ProcessorThread(threading.Thread): - daemon: bool - logger: Incomplete - client: Incomplete - done: Incomplete - def __init__(self, client) -> None: ... - def run(self) -> None: ... - def cancel(self) -> None: ... diff --git a/stubs/ftrack_api/event/subscriber.pyi b/stubs/ftrack_api/event/subscriber.pyi deleted file mode 100644 index 2b3fcd2a..00000000 --- a/stubs/ftrack_api/event/subscriber.pyi +++ /dev/null @@ -1,9 +0,0 @@ -from _typeshed import Incomplete - -class Subscriber: - subscription: Incomplete - callback: Incomplete - metadata: Incomplete - priority: Incomplete - def __init__(self, subscription, callback, metadata, priority) -> None: ... - def interested_in(self, event): ... diff --git a/stubs/ftrack_api/event/subscription.pyi b/stubs/ftrack_api/event/subscription.pyi deleted file mode 100644 index 4524fb40..00000000 --- a/stubs/ftrack_api/event/subscription.pyi +++ /dev/null @@ -1,6 +0,0 @@ -from _typeshed import Incomplete - -class Subscription: - parser: Incomplete - def __init__(self, subscription) -> None: ... - def includes(self, event): ... diff --git a/stubs/ftrack_api/exception.pyi b/stubs/ftrack_api/exception.pyi deleted file mode 100644 index e49b665d..00000000 --- a/stubs/ftrack_api/exception.pyi +++ /dev/null @@ -1,138 +0,0 @@ -from _typeshed import Incomplete - -class Error(Exception): - default_message: str - message: Incomplete - details: Incomplete - traceback: Incomplete - def __init__(self, message: Incomplete | None = None, details: Incomplete | None = None) -> None: ... - -class AuthenticationError(Error): - default_message: str - -class ServerError(Error): - default_message: str - -class ServerCompatibilityError(ServerError): - default_message: str - -class NotFoundError(Error): - default_message: str - -class NotUniqueError(Error): - default_message: str - -class IncorrectResultError(Error): - default_message: str - -class NoResultFoundError(IncorrectResultError): - default_message: str - -class MultipleResultsFoundError(IncorrectResultError): - default_message: str - -class EntityTypeError(Error): - default_message: str - -class UnrecognisedEntityTypeError(EntityTypeError): - default_message: str - def __init__(self, entity_type, **kw) -> None: ... - -class OperationError(Error): - default_message: str - -class InvalidStateError(Error): - default_message: str - -class InvalidStateTransitionError(InvalidStateError): - default_message: str - def __init__(self, current_state, target_state, entity, **kw) -> None: ... - -class AttributeError(Error): - default_message: str - -class ImmutableAttributeError(AttributeError): - default_message: str - def __init__(self, attribute, **kw) -> None: ... - -class CollectionError(Error): - default_message: str - def __init__(self, collection, **kw) -> None: ... - -class ImmutableCollectionError(CollectionError): - default_message: str - -class DuplicateItemInCollectionError(CollectionError): - default_message: str - def __init__(self, item, collection, **kw) -> None: ... - -class ParseError(Error): - default_message: str - -class EventHubError(Error): - default_message: str - -class EventHubConnectionError(EventHubError): - default_message: str - -class EventHubPacketError(EventHubError): - default_message: str - -class PermissionDeniedError(Error): - default_message: str - -class LocationError(Error): - default_message: str - -class ComponentNotInAnyLocationError(LocationError): - default_message: str - -class ComponentNotInLocationError(LocationError): - default_message: str - def __init__(self, components, location, **kw) -> None: ... - -class ComponentInLocationError(LocationError): - default_message: str - def __init__(self, components, location, **kw) -> None: ... - -class AccessorError(Error): - default_message: str - -class AccessorOperationFailedError(AccessorError): - default_message: str - def __init__(self, operation: str = '', resource_identifier: Incomplete | None = None, error: Incomplete | None = None, **kw) -> None: ... - -class AccessorUnsupportedOperationError(AccessorOperationFailedError): - default_message: str - -class AccessorPermissionDeniedError(AccessorOperationFailedError): - default_message: str - -class AccessorResourceIdentifierError(AccessorError): - default_message: str - def __init__(self, resource_identifier, **kw) -> None: ... - -class AccessorFilesystemPathError(AccessorResourceIdentifierError): - default_message: str - -class AccessorResourceError(AccessorError): - default_message: str - def __init__(self, operation: str = '', resource_identifier: Incomplete | None = None, error: Incomplete | None = None, **kw) -> None: ... - -class AccessorResourceNotFoundError(AccessorResourceError): - default_message: str - -class AccessorParentResourceNotFoundError(AccessorResourceError): - default_message: str - -class AccessorResourceInvalidError(AccessorResourceError): - default_message: str - -class AccessorContainerNotEmptyError(AccessorResourceError): - default_message: str - -class StructureError(Error): - default_message: str - -class ConnectionClosedError(Error): - default_message: str diff --git a/stubs/ftrack_api/formatter.pyi b/stubs/ftrack_api/formatter.pyi deleted file mode 100644 index c3b120be..00000000 --- a/stubs/ftrack_api/formatter.pyi +++ /dev/null @@ -1,5 +0,0 @@ -from _typeshed import Incomplete - -FILTER: Incomplete - -def format(entity, formatters: Incomplete | None = None, attribute_filter: Incomplete | None = None, recursive: bool = False, indent: int = 0, indent_first_line: bool = True, _seen: Incomplete | None = None): ... diff --git a/stubs/ftrack_api/inspection.pyi b/stubs/ftrack_api/inspection.pyi deleted file mode 100644 index 49bfed1b..00000000 --- a/stubs/ftrack_api/inspection.pyi +++ /dev/null @@ -1,4 +0,0 @@ -def identity(entity): ... -def primary_key(entity): ... -def state(entity): ... -def states(entities): ... diff --git a/stubs/ftrack_api/logging.pyi b/stubs/ftrack_api/logging.pyi deleted file mode 100644 index 66174dbb..00000000 --- a/stubs/ftrack_api/logging.pyi +++ /dev/null @@ -1,9 +0,0 @@ -from _typeshed import Incomplete - -def deprecation_warning(message): ... - -class LazyLogMessage: - message: Incomplete - args: Incomplete - kwargs: Incomplete - def __init__(self, message, *args, **kwargs) -> None: ... diff --git a/stubs/ftrack_api/operation.pyi b/stubs/ftrack_api/operation.pyi deleted file mode 100644 index 0bcde1cd..00000000 --- a/stubs/ftrack_api/operation.pyi +++ /dev/null @@ -1,30 +0,0 @@ -from _typeshed import Incomplete - -class Operations: - def __init__(self) -> None: ... - def clear(self) -> None: ... - def push(self, operation) -> None: ... - def pop(self): ... - def __len__(self) -> int: ... - def __iter__(self): ... - -class Operation: ... - -class CreateEntityOperation(Operation): - entity_type: Incomplete - entity_key: Incomplete - entity_data: Incomplete - def __init__(self, entity_type, entity_key, entity_data) -> None: ... - -class UpdateEntityOperation(Operation): - entity_type: Incomplete - entity_key: Incomplete - attribute_name: Incomplete - old_value: Incomplete - new_value: Incomplete - def __init__(self, entity_type, entity_key, attribute_name, old_value, new_value) -> None: ... - -class DeleteEntityOperation(Operation): - entity_type: Incomplete - entity_key: Incomplete - def __init__(self, entity_type, entity_key) -> None: ... diff --git a/stubs/ftrack_api/plugin.pyi b/stubs/ftrack_api/plugin.pyi deleted file mode 100644 index eb23a7c9..00000000 --- a/stubs/ftrack_api/plugin.pyi +++ /dev/null @@ -1,4 +0,0 @@ -from _typeshed import Incomplete - -def load_source(modname, filename): ... -def discover(paths, positional_arguments: Incomplete | None = None, keyword_arguments: Incomplete | None = None) -> None: ... diff --git a/stubs/ftrack_api/query.pyi b/stubs/ftrack_api/query.pyi deleted file mode 100644 index 95f7d0cb..00000000 --- a/stubs/ftrack_api/query.pyi +++ /dev/null @@ -1,12 +0,0 @@ -import collections.abc -from _typeshed import Incomplete - -class QueryResult(collections.abc.Sequence): - OFFSET_EXPRESSION: Incomplete - LIMIT_EXPRESSION: Incomplete - def __init__(self, session, expression, page_size: int = 500) -> None: ... - def __getitem__(self, index): ... - def __len__(self) -> int: ... - def all(self): ... - def one(self): ... - def first(self): ... diff --git a/stubs/ftrack_api/resource_identifier_transformer/__init__.pyi b/stubs/ftrack_api/resource_identifier_transformer/__init__.pyi deleted file mode 100644 index e69de29b..00000000 diff --git a/stubs/ftrack_api/resource_identifier_transformer/base.pyi b/stubs/ftrack_api/resource_identifier_transformer/base.pyi deleted file mode 100644 index 754e9cc9..00000000 --- a/stubs/ftrack_api/resource_identifier_transformer/base.pyi +++ /dev/null @@ -1,7 +0,0 @@ -from _typeshed import Incomplete - -class ResourceIdentifierTransformer: - session: Incomplete - def __init__(self, session) -> None: ... - def encode(self, resource_identifier, context: Incomplete | None = None): ... - def decode(self, resource_identifier, context: Incomplete | None = None): ... diff --git a/stubs/ftrack_api/session.pyi b/stubs/ftrack_api/session.pyi deleted file mode 100644 index 28429352..00000000 --- a/stubs/ftrack_api/session.pyi +++ /dev/null @@ -1,97 +0,0 @@ -import collections.abc -import requests.auth -from _typeshed import Incomplete - -class SessionAuthentication(requests.auth.AuthBase): - api_key: Incomplete - api_user: Incomplete - def __init__(self, api_key, api_user) -> None: ... - def __call__(self, request): ... - -class Session: - logger: Incomplete - recorded_operations: Incomplete - cache_key_maker: Incomplete - cache: Incomplete - merge_lock: Incomplete - request_timeout: Incomplete - schemas: Incomplete - types: Incomplete - def __init__(self, server_url: Incomplete | None = None, api_key: Incomplete | None = None, api_user: Incomplete | None = None, auto_populate: bool = True, plugin_paths: Incomplete | None = None, cache: Incomplete | None = None, cache_key_maker: Incomplete | None = None, auto_connect_event_hub: bool = False, schema_cache_path: Incomplete | None = None, plugin_arguments: Incomplete | None = None, timeout: int = 60, cookies: Incomplete | None = None, headers: Incomplete | None = None, strict_api: bool = False) -> None: ... - def __enter__(self): ... - def __exit__(self, exception_type: type[BaseException] | None, exception_value: BaseException | None, traceback: types.TracebackType | None) -> None: ... - @property - def auto_populate(self): ... - @auto_populate.setter - def auto_populate(self, value) -> None: ... - @property - def record_operations(self): ... - @record_operations.setter - def record_operations(self, value) -> None: ... - @property - def closed(self): ... - @property - def server_information(self): ... - @property - def server_url(self): ... - @property - def api_user(self): ... - @property - def api_key(self): ... - @property - def event_hub(self): ... - def check_server_compatibility(self) -> None: ... - def close(self) -> None: ... - def reset(self) -> None: ... - def auto_populating(self, auto_populate): ... - def operation_recording(self, record_operations): ... - @property - def created(self): ... - @property - def modified(self): ... - @property - def deleted(self): ... - def reset_remote(self, reset_type, entity: Incomplete | None = None): ... - def create(self, entity_type, data: Incomplete | None = None, reconstructing: bool = False): ... - def ensure(self, entity_type, data, identifying_keys: Incomplete | None = None): ... - def delete(self, entity) -> None: ... - def get(self, entity_type, entity_key): ... - def query(self, expression, page_size: int = 500): ... - def merge(self, value, merged: Incomplete | None = None): ... - def populate(self, entities, projections) -> None: ... - def commit(self) -> None: ... - def rollback(self) -> None: ... - def call(self, data): ... - def encode(self, data, entity_attribute_strategy: str = 'set_only'): ... - def entity_reference(self, entity): ... - def decode(self, string): ... - def pick_location(self, component: Incomplete | None = None): ... - def pick_locations(self, components): ... - def create_component(self, path, data: Incomplete | None = None, location: str = 'auto'): ... - def get_component_availability(self, component, locations: Incomplete | None = None): ... - def get_component_availabilities(self, components, locations: Incomplete | None = None): ... - def get_widget_url(self, name, entity: Incomplete | None = None, theme: Incomplete | None = None): ... - def encode_media(self, media, version_id: Incomplete | None = None, keep_original: str = 'auto'): ... - def get_upload_metadata(self, component_id, file_name, file_size, checksum: Incomplete | None = None): ... - def send_user_invite(self, user) -> None: ... - def send_user_invites(self, users) -> None: ... - def send_review_session_invite(self, invitee) -> None: ... - def send_review_session_invites(self, invitees) -> None: ... - -class AutoPopulatingContext: - def __init__(self, session, auto_populate) -> None: ... - def __enter__(self) -> None: ... - def __exit__(self, exception_type: type[BaseException] | None, exception_value: BaseException | None, traceback: types.TracebackType | None) -> None: ... - -class OperationRecordingContext: - def __init__(self, session, record_operations) -> None: ... - def __enter__(self) -> None: ... - def __exit__(self, exception_type: type[BaseException] | None, exception_value: BaseException | None, traceback: types.TracebackType | None) -> None: ... - -class OperationPayload(collections.abc.MutableMapping): - def __init__(self, *args, **kwargs) -> None: ... - def __getitem__(self, key): ... - def __setitem__(self, key, value) -> None: ... - def __delitem__(self, key) -> None: ... - def __iter__(self): ... - def __len__(self) -> int: ... diff --git a/stubs/ftrack_api/structure/__init__.pyi b/stubs/ftrack_api/structure/__init__.pyi deleted file mode 100644 index e69de29b..00000000 diff --git a/stubs/ftrack_api/structure/base.pyi b/stubs/ftrack_api/structure/base.pyi deleted file mode 100644 index 1dbf212e..00000000 --- a/stubs/ftrack_api/structure/base.pyi +++ /dev/null @@ -1,9 +0,0 @@ -from _typeshed import Incomplete -from abc import ABCMeta, abstractmethod - -class Structure(metaclass=ABCMeta): - prefix: Incomplete - path_separator: str - def __init__(self, prefix: str = '') -> None: ... - @abstractmethod - def get_resource_identifier(self, entity, context: Incomplete | None = None): ... diff --git a/stubs/ftrack_api/structure/entity_id.pyi b/stubs/ftrack_api/structure/entity_id.pyi deleted file mode 100644 index 65b522b9..00000000 --- a/stubs/ftrack_api/structure/entity_id.pyi +++ /dev/null @@ -1,5 +0,0 @@ -import ftrack_api.structure.base -from _typeshed import Incomplete - -class EntityIdStructure(ftrack_api.structure.base.Structure): - def get_resource_identifier(self, entity, context: Incomplete | None = None): ... diff --git a/stubs/ftrack_api/structure/id.pyi b/stubs/ftrack_api/structure/id.pyi deleted file mode 100644 index 4a34e68d..00000000 --- a/stubs/ftrack_api/structure/id.pyi +++ /dev/null @@ -1,5 +0,0 @@ -import ftrack_api.structure.base -from _typeshed import Incomplete - -class IdStructure(ftrack_api.structure.base.Structure): - def get_resource_identifier(self, entity, context: Incomplete | None = None): ... diff --git a/stubs/ftrack_api/structure/origin.pyi b/stubs/ftrack_api/structure/origin.pyi deleted file mode 100644 index 382625d7..00000000 --- a/stubs/ftrack_api/structure/origin.pyi +++ /dev/null @@ -1,5 +0,0 @@ -from .base import Structure as Structure -from _typeshed import Incomplete - -class OriginStructure(Structure): - def get_resource_identifier(self, entity, context: Incomplete | None = None): ... diff --git a/stubs/ftrack_api/structure/standard.pyi b/stubs/ftrack_api/structure/standard.pyi deleted file mode 100644 index 8eeb60cb..00000000 --- a/stubs/ftrack_api/structure/standard.pyi +++ /dev/null @@ -1,9 +0,0 @@ -import ftrack_api.structure.base -from _typeshed import Incomplete - -class StandardStructure(ftrack_api.structure.base.Structure): - project_versions_prefix: Incomplete - illegal_character_substitute: Incomplete - def __init__(self, project_versions_prefix: Incomplete | None = None, illegal_character_substitute: str = '_') -> None: ... - def sanitise_for_filesystem(self, value): ... - def get_resource_identifier(self, entity, context: Incomplete | None = None): ... diff --git a/stubs/ftrack_api/symbol.pyi b/stubs/ftrack_api/symbol.pyi deleted file mode 100644 index 3ecdc7b8..00000000 --- a/stubs/ftrack_api/symbol.pyi +++ /dev/null @@ -1,22 +0,0 @@ -from _typeshed import Incomplete - -class Symbol: - name: Incomplete - value: Incomplete - def __init__(self, name, value: bool = True) -> None: ... - def __bool__(self) -> bool: ... - def __copy__(self): ... - -NOT_SET: Incomplete -CREATED: Incomplete -MODIFIED: Incomplete -DELETED: Incomplete -COMPONENT_ADDED_TO_LOCATION_TOPIC: str -COMPONENT_REMOVED_FROM_LOCATION_TOPIC: str -ORIGIN_LOCATION_ID: str -UNMANAGED_LOCATION_ID: str -REVIEW_LOCATION_ID: str -CONNECT_LOCATION_ID: str -SERVER_LOCATION_ID: str -CHUNK_SIZE: Incomplete -JOB_SYNC_USERS_LDAP: Incomplete From 614d7018c1431b32758f16831f9ee730ff41af74 Mon Sep 17 00:00:00 2001 From: loren Date: Tue, 21 Apr 2026 17:07:20 +0200 Subject: [PATCH 5/5] Update Agents.md with latest stubs changes --- AGENTS.md | 55 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 41 insertions(+), 14 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 3bb1ab5b..2df4b3df 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -54,20 +54,27 @@ ``` source/ftrack_api/ ├── __init__.py # Main package exports (Session, mixin) +├── __init__.pyi # Type stubs for main exports +├── py.typed # PEP 561 marker for typed package ├── session.py # Core session implementation (2,700+ lines) +├── session.pyi # Type stubs for Session ├── entity/ # Entity type system │ ├── factory.py # Entity creation │ ├── base.py # Base entity class -│ └── location.py # Location management +│ ├── location.py # Location management +│ └── *.pyi # Type stubs for entities ├── event/ # Event system │ ├── hub.py # Event hub -│ └── base.py # Event classes +│ ├── base.py # Event classes +│ └── *.pyi # Type stubs for events ├── accessor/ # Storage accessors │ ├── disk.py # Local disk I/O -│ └── server.py # Server-based storage +│ ├── server.py # Server-based storage +│ └── *.pyi # Type stubs for accessors ├── structure/ # File structure patterns │ ├── origin.py -│ └── entity_id.py +│ ├── entity_id.py +│ └── *.pyi # Type stubs for structures ├── resource_identifier_transformer/ ├── attribute.py # Entity attributes ├── cache.py # Caching layer @@ -117,9 +124,10 @@ Required for API access: - `platformdirs>=4.0.0,<5` - Platform-specific directories **Development:** -- `black` - Code formatting +- `black==24.0` - Code formatting (updated from legacy versions) - `pre-commit` - Git hooks - `sphinx` + `sphinx_rtd_theme` - Documentation +- `twine` - Package validation and upload **Testing:** - `pytest` - Test framework @@ -275,6 +283,11 @@ ftrack_api.mixin(entity, CustomMixin, name='CustomEntity') - `doc/api_reference/` - API reference docs - `README.rst` - Package overview +### Type Safety +- `source/ftrack_api/**/*.pyi` - Type stub files (PEP 561) +- `source/ftrack_api/py.typed` - Marker file indicating typed package +- `test/unit/test_stubs.py` - Type stub validation tests + ### Code Quality - `.git-blame-ignore-revs` - Git blame configuration - `CODEOWNERS` - GitHub code ownership @@ -291,7 +304,7 @@ ftrack_api.mixin(entity, CustomMixin, name='CustomEntity') 1. Understand the entity schema from ftrack server 2. Implement in appropriate module (`entity/`, `accessor/`, etc.) 3. Add unit tests in `test/unit/` -4. Update type stubs in `stubs/` if applicable +4. Update type stubs (`.pyi` files) alongside implementation for type safety 5. Document in `doc/` ### Fixing Bugs @@ -303,9 +316,10 @@ ftrack_api.mixin(entity, CustomMixin, name='CustomEntity') ### Code Style -- **Black** formatting (enforced in CI) +- **Black 24.0** formatting (enforced in CI) - Run `black .` before committing - Pre-commit hooks auto-format +- Type hints: Use `.pyi` stub files for type annotations (PEP 561 compliant) ### Adding Dependencies @@ -382,12 +396,21 @@ print(session.recorded_operations) ## Recent Changes -Based on recent commits: -- **60d77d0**: Fixed server accessor timeout issue -- **47730e4**: Fixed UnboundLocalError in python-api (#59) -- **4f26f7f**: Added support for date type (#57) -- **89dc2c6**: Fixed publish jobs picking up correct tag (#56) -- **95ac2ae**: Fixed thread-safe session sharing across threads (#55) +Based on recent commits (2025-2026): +- **51e8c27** (Apr 2026): Added comprehensive Python type stubs (.pyi files) for full type safety (#64) + - All modules now have corresponding `.pyi` stub files + - Package marked as typed with `py.typed` marker (PEP 561) + - Includes stubs for Session, entities, events, accessors, structures, and more + - Enables better IDE autocompletion and static type checking +- **fa82e38** (Apr 2026): Updated Black formatter to version 24.0 (#65) +- **79a5596** (2025): Enabled Python 3.13 in CI testing (#53) +- **b2c1c36** (2025): Fixed restricted projections not being properly hidden (#49) +- **576d2db** (2025): Augmented source event with additional data (#40) +- **60d77d0** (2024): Fixed server accessor timeout issue +- **47730e4** (2024): Fixed UnboundLocalError in python-api (#59) +- **4f26f7f** (2024): Added support for date type (#57) +- **89dc2c6** (2024): Fixed publish jobs picking up correct tag (#56) +- **95ac2ae** (2024): Fixed thread-safe session sharing across threads (#55) ## Resources @@ -407,4 +430,8 @@ Based on recent commits: 7. **Thread model**: One session per thread, event hub runs in separate thread 8. **Cache implications**: Cached entities may be stale, use session.reset() or disable 9. **Commit required**: Changes are tracked but not saved until session.commit() -10. **Plugin system**: Extensible via plugins - check resource/plugin/ for examples \ No newline at end of file +10. **Plugin system**: Extensible via plugins - check resource/plugin/ for examples +11. **Type safety**: Package is fully typed with `.pyi` stub files (PEP 561 compliant) + - Use type stubs for better IDE support and static analysis + - When adding new code, create or update corresponding `.pyi` files + - Type stubs are distributed with the package in wheels and sdist \ No newline at end of file