Skip to content
This repository was archived by the owner on Oct 30, 2026. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 12 additions & 36 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
vws-python
==========

Python library for the Vuforia Web Services (VWS) API and the Vuforia Web Query API.
Python clients for the Vuforia Model Target Web API and VuMark generation.

Installation
------------
Expand All @@ -20,47 +20,23 @@ Getting Started

.. code-block:: python

"""Add a target to VWS and then query it."""
"""Generate a VuMark instance."""

import os
import pathlib
import uuid

from vws import VWS, CloudRecoService
from vws import VuMarkService
from vws.vumark_accept import VuMarkAccept

server_access_key = os.environ["VWS_SERVER_ACCESS_KEY"]
server_secret_key = os.environ["VWS_SERVER_SECRET_KEY"]
client_access_key = os.environ["VWS_CLIENT_ACCESS_KEY"]
client_secret_key = os.environ["VWS_CLIENT_SECRET_KEY"]

vws_client = VWS(
server_access_key=server_access_key,
server_secret_key=server_secret_key,
client = VuMarkService(
server_access_key=os.environ["VWS_SERVER_ACCESS_KEY"],
server_secret_key=os.environ["VWS_SERVER_SECRET_KEY"],
)

cloud_reco_client = CloudRecoService(
client_access_key=client_access_key,
client_secret_key=client_secret_key,
image = client.generate_vumark_instance(
target_id=os.environ["VUMARK_TARGET_ID"],
instance_id="123",
accept=VuMarkAccept.PNG,
)

name = "my_image_name_" + uuid.uuid4().hex

image = pathlib.Path("high_quality_image.jpg")
with image.open(mode="rb") as my_image_file:
target_id = vws_client.add_target(
name=name,
width=1,
image=my_image_file,
active_flag=True,
application_metadata=None,
)

vws_client.wait_for_target_processed(target_id=target_id)

with image.open(mode="rb") as my_image_file:
matching_targets = cloud_reco_client.query(image=my_image_file)

assert matching_targets[0].target_id == target_id
assert image.startswith(b"\x89PNG")

Full Documentation
------------------
Expand Down
39 changes: 8 additions & 31 deletions conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@

from __future__ import annotations

import io
import uuid
from collections.abc import Generator
from doctest import ELLIPSIS
from pathlib import Path

import pytest
from mock_vws import MockVWS
from mock_vws.database import CloudDatabase
from mock_vws.database import VuMarkDatabase
from mock_vws.target import VuMarkTarget
from sybil import Sybil
from sybil.parsers.rest import (
ClearNamespaceParser,
Expand All @@ -19,22 +18,6 @@
)


@pytest.fixture(name="make_image_file")
def fixture_make_image_file(
*,
high_quality_image: io.BytesIO,
) -> Generator[None]:
"""Make an image file available in the test directory.

The path of this file matches the path in the documentation.
"""
new_image = Path("high_quality_image.jpg")
buffer = high_quality_image.getvalue()
_ = new_image.write_bytes(data=buffer)
yield
new_image.unlink()


@pytest.fixture(name="mock_vws")
def fixture_mock_vws(
*,
Expand All @@ -46,23 +29,17 @@ def fixture_mock_vws(
"""
server_access_key = uuid.uuid4().hex
server_secret_key = uuid.uuid4().hex
client_access_key = uuid.uuid4().hex
client_secret_key = uuid.uuid4().hex
database_id = uuid.uuid4().hex
target = VuMarkTarget(name="example-template")

database = CloudDatabase(
database = VuMarkDatabase(
server_access_key=server_access_key,
server_secret_key=server_secret_key,
client_access_key=client_access_key,
client_secret_key=client_secret_key,
database_id=database_id,
vumark_targets={target},
)

monkeypatch.setenv(name="VWS_SERVER_ACCESS_KEY", value=server_access_key)
monkeypatch.setenv(name="VWS_SERVER_SECRET_KEY", value=server_secret_key)
monkeypatch.setenv(name="VWS_CLIENT_ACCESS_KEY", value=client_access_key)
monkeypatch.setenv(name="VWS_CLIENT_SECRET_KEY", value=client_secret_key)
monkeypatch.setenv(name="VWS_DATABASE_ID", value=database_id)
monkeypatch.setenv(name="VUMARK_TARGET_ID", value=target.target_id)
# The mock accepts one hard-coded pair of Model Target Web API OAuth2
# credentials, which it does not expose.
monkeypatch.setenv(
Expand All @@ -75,7 +52,7 @@ def fixture_mock_vws(
)
# We use a low processing time so that tests run quickly.
with MockVWS(processing_time_seconds=0.2) as mock:
mock.add_cloud_database(cloud_database=database)
mock.add_vumark_database(vumark_database=database)
yield


Expand All @@ -86,5 +63,5 @@ def fixture_mock_vws(
PythonCodeBlockParser(),
],
patterns=["*.rst", "*.py"],
fixtures=["make_image_file", "mock_vws"],
fixtures=["mock_vws"],
).pytest()
12 changes: 0 additions & 12 deletions docs/source/api-reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,6 @@ API Reference
:undoc-members:
:members:

.. automodule:: vws.async_vws
:undoc-members:
:members:

.. automodule:: vws.async_query
:undoc-members:
:members:

.. automodule:: vws.async_vumark_service
:undoc-members:
:members:
Expand All @@ -37,10 +29,6 @@ API Reference
:undoc-members:
:members:

.. automodule:: vws.include_target_data
:undoc-members:
:members:

.. automodule:: vws.vumark_accept
:undoc-members:
:members:
Expand Down
9 changes: 0 additions & 9 deletions docs/source/exceptions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,6 @@ VWS exceptions
:inherited-members: Exception
:exclude-members: errno, filename, filename2, strerror

CloudRecoService exceptions
---------------------------

.. automodule:: vws.exceptions.cloud_reco_exceptions
:members:
:show-inheritance:
:inherited-members: Exception
:exclude-members: errno, filename, filename2, strerror

ModelTargetService exceptions
-----------------------------

Expand Down
168 changes: 12 additions & 156 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,97 +18,23 @@ See the :doc:`api-reference` for full usage details.

.. code-block:: python

"""Add a target to VWS and then query it."""
"""Generate a VuMark instance."""

import os
import pathlib
import uuid

from vws import VWS, CloudRecoService
from vws import VuMarkService
from vws.vumark_accept import VuMarkAccept

server_access_key = os.environ["VWS_SERVER_ACCESS_KEY"]
server_secret_key = os.environ["VWS_SERVER_SECRET_KEY"]
client_access_key = os.environ["VWS_CLIENT_ACCESS_KEY"]
client_secret_key = os.environ["VWS_CLIENT_SECRET_KEY"]

vws_client = VWS(
server_access_key=server_access_key,
server_secret_key=server_secret_key,
)

cloud_reco_client = CloudRecoService(
client_access_key=client_access_key,
client_secret_key=client_secret_key,
)

name = "my_image_name_" + uuid.uuid4().hex

image = pathlib.Path("high_quality_image.jpg")
with image.open(mode="rb") as my_image_file:
target_id = vws_client.add_target(
name=name,
width=1,
image=my_image_file,
active_flag=True,
application_metadata=None,
)

vws_client.wait_for_target_processed(target_id=target_id)

with image.open(mode="rb") as my_image_file:
matching_targets = cloud_reco_client.query(image=my_image_file)

assert matching_targets[0].target_id == target_id

Recognition counts
------------------

Vuforia can generate a report of the number of recognitions of each target in a database in a month.
Only the current month and the previous month can be requested.

This needs the ID of the database, which is shown in the Vuforia target manager.

The report is generated in the background, and the URL it is served from expires just under seven days after it is requested.

.. clear-namespace

.. code-block:: python

"""Get the number of recognitions of each target this month."""

import calendar
import datetime as dt
import os

from vws import VWS

server_access_key = os.environ["VWS_SERVER_ACCESS_KEY"]
server_secret_key = os.environ["VWS_SERVER_SECRET_KEY"]
database_id = os.environ["VWS_DATABASE_ID"]

vws_client = VWS(
server_access_key=server_access_key,
server_secret_key=server_secret_key,
database_id=database_id,
client = VuMarkService(
server_access_key=os.environ["VWS_SERVER_ACCESS_KEY"],
server_secret_key=os.environ["VWS_SERVER_SECRET_KEY"],
)

now = dt.datetime.now(tz=dt.UTC)

report_request = vws_client.request_database_reco_counts_report(
year=now.year,
month=calendar.Month(value=now.month),
image = client.generate_vumark_instance(
target_id=os.environ["VUMARK_TARGET_ID"],
instance_id="123",
accept=VuMarkAccept.PNG,
)

report = vws_client.wait_for_reco_counts_report(
presigned_url=report_request.presigned_url,
)

reco_counts_by_target_id = {
item.target_id: item.reco_count for item in report.reco_counts
}

# This database has no targets, so nothing has been recognized.
assert reco_counts_by_target_id == {}
assert image.startswith(b"\x89PNG")

Model Targets
-------------
Expand Down Expand Up @@ -199,84 +125,14 @@ Transports are available for `requests`_, `httpx`_ and `HTTPX2`_.

.. clear-namespace

.. code-block:: python

"""List targets using HTTPX2."""

import os

from vws import VWS
from vws.transports import HTTPX2Transport

server_access_key = os.environ["VWS_SERVER_ACCESS_KEY"]
server_secret_key = os.environ["VWS_SERVER_SECRET_KEY"]

vws_client = VWS(
server_access_key=server_access_key,
server_secret_key=server_secret_key,
transport=HTTPX2Transport(),
)

# This database has no targets.
assert len(vws_client.list_targets()) == 0

.. _requests: https://pypi.org/project/requests/
.. _httpx: https://pypi.org/project/httpx/
.. _HTTPX2: https://httpx2.pydantic.dev/

Testing
-------

To write unit tests for code which uses this library, without using your Vuforia quota, you can use the `VWS Python Mock`_ tool:

.. code-block:: console

$ pip install vws-python-mock

.. clear-namespace

.. code-block:: python

"""Add a target to VWS and then query it."""

import pathlib

from mock_vws import MockVWS
from mock_vws.database import CloudDatabase

from vws import VWS, CloudRecoService

with MockVWS() as mock:
database = CloudDatabase()
mock.add_cloud_database(cloud_database=database)
vws_client = VWS(
server_access_key=database.server_access_key,
server_secret_key=database.server_secret_key,
)
cloud_reco_client = CloudRecoService(
client_access_key=database.client_access_key,
client_secret_key=database.client_secret_key,
)

image = pathlib.Path("high_quality_image.jpg")
with image.open(mode="rb") as my_image_file:
target_id = vws_client.add_target(
name="example_image_name",
width=1,
image=my_image_file,
application_metadata=None,
active_flag=True,
)

vws_client.wait_for_target_processed(target_id=target_id)
matching_targets = cloud_reco_client.query(image=my_image_file)

assert matching_targets[0].target_id == target_id

There are some differences between the mock and the real Vuforia.
See https://vws-python.github.io/vws-python-mock/differences-to-vws for details.

.. _VWS Python Mock: https://github.com/VWS-Python/vws-python-mock
Use `VWS Python Mock <https://github.com/VWS-Python/vws-python-mock>`_ to test Model Target and VuMark clients without calling Vuforia.

Reference
---------
Expand Down
3 changes: 3 additions & 0 deletions newsfragments/3328.change.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Remove Cloud Image Recognition, cloud image target management, recognition reports, and their synchronous/asynchronous public clients.
`ModelTargetService`, `AsyncModelTargetService`, `VuMarkService`, `AsyncVuMarkService`, and their transports remain supported.
This breaks imports of `VWS`, `AsyncVWS`, `CloudRecoService`, `AsyncCloudRecoService`, and cloud-only models and exceptions.
Loading
Loading