コード例 #1
0
    def on_connectBtn_clicked(self):
        tator_api=tator.get_api(self.url)
        credentials={'username': self.ui.username_field.text(),
                     'password': self.ui.password_field.text()}
        try:
            token=tator_api.create_obtain_auth_token(credentials=credentials)
            self.ui.login_widget.setVisible(False)

            tator_api=tator.get_api(self.url,
                                    token.token)
            projects=tator_api.get_project_list()
            projects=[x.to_dict() for x in projects]
            # TODO landing page
            self.ui.tabWidget.addTab(QtWidgets.QWidget(self), "Welcome")
            for project in projects:
                self.ui.tabWidget.addTab(
                    ProjectDetail(self,
                                  self.background_thread,
                                  self.url,
                                  token.token,
                                  project['id']),
                    project['name'])
            self.ui.tabWidget.setVisible(True)
            self.adjustSize()
            screenGeometry = QtWidgets.QApplication.desktop().screenGeometry()
            marginLeft = (screenGeometry.width() - self.width()) / 2
            marginRight = (screenGeometry.height() - self.height()) / 2
            self.move(marginLeft, marginRight)
        except Exception as e:
            traceback.print_exc()
            logging.warning("Access Denied")
            QtWidgets.QMessageBox.critical(self,"Access Denied","Please check your username and password.")
コード例 #2
0
def get_tator_api(strategy):
    if os.getenv('TATOR_API_SERVICE'):
        host = os.getenv("TATOR_API_SERVICE").replace('/rest', '')
        token = os.getenv('TATOR_AUTH_TOKEN')
        return tator.get_api(host, token)
    else:
        try:
            host = strategy['tator']['host']
            token = strategy['tator']['token']
            return tator.get_api(host, token)
        except:
            print("ERROR: No tator credentials provided.")
            return None
コード例 #3
0
ファイル: migrate.py プロジェクト: cvisionai/tator-py
def setup_apis(args):
    """ Sets up API objects.
    """
    # Set up API objects.
    src_api = tator.get_api(host=args.host, token=args.token)
    if (args.dest_host is not None) and (args.dest_token is not None):
        dest_api = tator.get_api(host=args.dest_host, token=args.dest_token)
        logger.info(
            f"Migrating to different host (to {args.dest_host} from {args.host})."
        )
    else:
        dest_api = src_api
        logger.info(f"Migrating to same host ({args.host}).")
    return src_api, dest_api
コード例 #4
0
def test_clone_images_util_different_host(host, token, project, image_type,
                                          image):
    tator_api = tator.get_api(host, token)
    dest_api = tator.get_api(host, token)
    assert tator_api is not dest_api
    query_params = {'project': project, 'media_id': [image]}
    section = 'Cloned media util different host'
    created_ids = []
    generator = tator.util.clone_media_list(tator_api, query_params, project,
                                            {}, image_type, section, dest_api)
    for num_created, num_total, response, id_map in generator:
        print(f"Created {num_created} of {num_total} files...")
        created_ids.append(response.id)
    print(f"Finished creating {num_created} files!")
    assert len(created_ids) == 1
コード例 #5
0
ファイル: test_extract.py プロジェクト: cvisionai/tator-py
def test_extract(host, token, project, video_temp, box_type, image_type,
                 state_type):
    video = video_temp
    tator_api = tator.get_api(host, token)
    video_obj = tator_api.get_media(video)
    localization = {
        'x': 0.50,
        'y': 0.50,
        'width': 0.25,
        'height': 0.25,
        'type': box_type,
        'media_id': video,
        'frame': 0
    }
    state = {'frame': 1, 'media_ids': [video], 'type': state_type}
    api = tator.get_api(host, token)
    response = api.create_localization_list(project, [localization])
    localization_id = response.id[0]
    response = api.create_state_list(project, [state])
    state_id = response.id[0]

    with tempfile.TemporaryDirectory() as td:
        out = os.path.join(td, "temp.mp4")
        for _ in tator.download_media(api, api.get_media(video), out):
            pass

        process_file(api, project, out, api.get_media(video),
                     'localization_thumbnail',
                     api.get_localization_list(project, media_id=[video]), td)

        process_file(api, project, out, api.get_media(video),
                     'localization_keyframe',
                     api.get_localization_list(project, media_id=[video]), td)

        process_file(api, project, out, api.get_media(video), 'state',
                     api.get_state_list(project, media_id=[video]), td)

        image_cnt = 0
        for _, __, files in os.walk(td):
            for fp in files:
                if os.path.splitext(fp)[1] == '.png':
                    image_cnt += 1

        assert image_cnt == 3

    # Clean up.
    api.delete_localization(localization_id)
    api.delete_state(state_id)
コード例 #6
0
def attribute_video(request, project, attribute_video_type, attribute_video_file):
    import tator

    host = request.config.option.host
    token = request.config.option.token
    tator_api = tator.get_api(host, token)
    for progress, response in tator.util.upload_media(tator_api, attribute_video_type, attribute_video_file):
        print(f"Upload video progress: {progress}%")
    print(response.message)
    while True:
        response = tator_api.get_media_list(
            project, name="AudioVideoSyncTest_BallastMedia_attribute.mp4"
        )
        print("Waiting for transcode...")
        time.sleep(2.5)
        if len(response) == 0:
            continue
        if response[0].media_files is None:
            continue
        have_streaming = response[0].media_files.streaming is not None
        have_archival = response[0].media_files.archival is not None
        if have_streaming and have_archival:
            video_id = response[0].id
            break
    yield video_id
コード例 #7
0
def video(request, project, video_type, video_file):
    import tator
    host = request.config.option.host
    token = request.config.option.token
    tator_api = tator.get_api(host, token)
    attributes = {"test_string": str(uuid1())}
    for progress, response in tator.util.upload_media(tator_api, video_type, video_file, attributes=attributes):
        print(f"Upload video progress: {progress}%")
    print(response.message)
    while True:
        response = tator_api.get_media_list(project, name='AudioVideoSyncTest_BallastMedia.mp4')
        print("Waiting for transcode...")
        time.sleep(2.5)
        if len(response) == 0:
            continue
        if response[0].media_files is None:
            continue
        streaming = response[0].media_files.streaming
        have_archival = response[0].media_files.archival is not None
        if streaming and have_archival and len(streaming) == 4:
            video_id = response[0].id
            break
    # Check for proper attribute setting via upload_file
    assert response[0].attributes.get("test_string") == attributes.get("test_string")

    # If all is kosher return the video_id
    yield video_id
コード例 #8
0
def _create_workflow_manifest(
        host: str,
        token: str,
        project: int) -> str:
    """ Creates the argo workflow manifest file used by the tests in this module

    Args:
        host: Project URL
        token: User token used for connecting to the host
        project: Unique identifier of test project

    Returns:
        URL to uploaded and saved algorithm manifest file
    """
    tator_api = tator.get_api(host=host, token=token)

    fd, local_yaml_file = tempfile.mkstemp()
    try:
        with os.fdopen(fd, 'w') as file_handle:
            file_handle.write(_create_yaml_file_str())

        for progress, upload_info in _upload_file(tator_api, project, local_yaml_file):
            pass
        url = tator_api.get_download_info(project, {'keys': [upload_info.key]})[0].url

        # Save the uploaded file using the save algorithm manifest endpoint
        spec = tator.models.AlgorithmManifestSpec(name='workflow.yaml', upload_url=url)
        response = tator_api.save_algorithm_manifest(project=project, algorithm_manifest_spec=spec)

    finally:
        os.remove(local_yaml_file)

    return response.url
コード例 #9
0
def test_get_by_id(host, token, project, video):
    tator_api = tator.get_api(host, token)
    video_obj = tator_api.get_media(video)
    other_obj = tator_api.get_media_list_by_id(project, {'ids': [video]})[0]
    assert video_obj.id == other_obj.id
    other_obj = tator_api.get_media_list_by_id(project, {'ids': [video]}, force_es=1)[0]
    assert video_obj.id == other_obj.id
コード例 #10
0
def test_temporary_file(host, token, project):
    tator_api = tator.get_api(host, token)

    all_temps = tator_api.get_temporary_file_list(project)
    assert all_temps is not None
    assert len(all_temps) == 0

    with tempfile.NamedTemporaryFile(mode='w', suffix=".txt") as temp:
        temp.write("foo")
        temp.flush()
        for progress, response in tator.util.upload_temporary_file(
                tator_api, project, temp.name):
            print(f"Temporary file upload progress: {progress}%")
        assert isinstance(response, tator.models.CreateResponse)
        print(response.message)
        all_temps = tator_api.get_temporary_file_list(project)
        assert len(all_temps) == 1

    with tempfile.TemporaryDirectory() as temp_dir:
        temp_fp = os.path.join(temp_dir, "foo.txt")
        temp_element = tator_api.get_temporary_file_list(project)[0]
        for progress in tator.util.download_temporary_file(
                tator_api, temp_element, temp_fp):
            print(f"Temporary file download progress: {progress}%")
        with open(temp_fp, 'r') as temp_file:
            contents = temp_file.read()
            assert contents == "foo"
コード例 #11
0
def main(
    host: str, token: str, project: int, localization_type_id: int, new_attribute: dict
) -> None:
    """Main routine of this script"""

    # Get the interface to Tator
    tator_api = tator.get_api(host=host, token=token)

    # Get attribute type list before addition
    localization_type = tator_api.get_localization_type(localization_type_id)
    logger.info(f"Existing list of attributes:\n{pformat(localization_type.attribute_types)}")

    # Create the attribute addition message
    addition = {"entity_type": "LocalizationType", "addition": new_attribute}
    logger.info(f"Calling add_attribute with id '{localization_type_id}' and "
                f"attribute_type_spec\n{pformat(addition)}")

    # Add the attribute to the given localization type
    response = tator_api.add_attribute(id=localization_type_id, attribute_type_spec=addition)

    # Get attribute type list after addition
    localization_type = tator_api.get_localization_type(localization_type_id)
    logger.info(f"New list of attributes:\n{pformat(localization_type.attribute_types)}")

    logger.info("[FINISHED] localization_attribute_addition.py")
コード例 #12
0
def test_add_same_attribute_twice(host, token, project, line_type):
    tator_api = tator.get_api(host, token)
    new_attr_name = f"New attribute {uuid4()}"

    # Make sure the new attribute does not exist already
    entity_type = tator_api.get_localization_type(line_type)
    assert all(attr.name != new_attr_name
               for attr in entity_type.attribute_types)
    addition = {
        "entity_type": "LocalizationType",
        "addition": {
            "name": new_attr_name,
            "dtype": "int"
        },
    }
    tator_api.add_attribute(id=line_type, attribute_type_spec=addition)
    entity_type = tator_api.get_localization_type(line_type)

    # Check for added attribute
    assert any(attr.name == new_attr_name
               for attr in entity_type.attribute_types)

    # Adding the same attribute a second time should raise an exception
    with pytest.raises(
            tator.openapi.tator_openapi.exceptions.ApiException) as excinfo:
        tator_api.add_attribute(id=line_type, attribute_type_spec=addition)

    # Check the exeption message for expected content
    assert "but one with that name already exists" in str(excinfo.value)
コード例 #13
0
def test_add_enum_without_choices(host, token, project, attribute_video_type):
    dtype = "enum"
    tator_api = tator.get_api(host, token)
    new_attr_name = f"New {dtype} {uuid4()}"
    entity_type = tator_api.get_media_type(attribute_video_type)

    # Make sure the new attribute does not exist already
    assert all(attr.name != new_attr_name
               for attr in entity_type.attribute_types)
    addition = {
        "entity_type": "MediaType",
        "addition": {
            "name": new_attr_name,
            "dtype": dtype
        },
    }

    # Adding an enum attribute without a `choices` field should raise an exception
    with pytest.raises(
            tator.openapi.tator_openapi.exceptions.ApiException) as excinfo:
        tator_api.add_attribute(id=attribute_video_type,
                                attribute_type_spec=addition)

    # Check the exeption message for expected content
    assert "ValueError: enum attribute type definition missing 'choices' field" in str(
        excinfo.value)
コード例 #14
0
def test_temporary_file(host, token, project):
    tator_api = tator.get_api(host, token)

    all_temps = tator_api.get_temporary_file_list(project)
    assert all_temps is not None
    n_temps = len(all_temps)

    with tempfile.NamedTemporaryFile(mode='w', suffix=".txt") as temp:
        temp.write("foo")
        temp.flush()
        for progress, response in tator.util.upload_temporary_file(
                tator_api, project, temp.name):
            print(f"Temporary file upload progress: {progress}%")
        assert isinstance(response, tator.models.CreateResponse)
        print(f"ID: {response.id}; Message: {response.message}")
        temp_id = response.id
        all_temps = tator_api.get_temporary_file_list(project)
        assert len(all_temps) == 1 + n_temps

    with tempfile.TemporaryDirectory() as temp_dir:
        temp_fp = os.path.join(temp_dir, "foo.txt")
        temp_elements = tator_api.get_temporary_file_list(project)
        for temp_element in temp_elements:
            if temp_element.id == temp_id:
                break
        else:
            assert False, f"Temp file {temp_id} not found in list:\n{temp_elements}"
        for progress in tator.util.download_temporary_file(
                tator_api, temp_element, temp_fp):
            print(f"Temporary file download progress: {progress}%")
        with open(temp_fp, 'r') as temp_file:
            contents = temp_file.read()
            assert contents == "foo"
コード例 #15
0
def test_clone_version_same_host(host, token, project, clone_project):
    tator_api = tator.get_api(host, token)
    response = tator_api.create_version(project=project,
                                        version_spec={'name': str(uuid1())})
    version = response.id
    response = tator.util.clone_version(tator_api, version, clone_project)
    assert (isinstance(response, tator.models.CreateResponse))
コード例 #16
0
def test_download_temporary_file(host, token, project):
    tator_api = tator.get_api(host, token)

    with tempfile.NamedTemporaryFile(mode='w', suffix=".txt") as temp:
        temp.write("foo")
        temp.flush()
        for progress, response in tator.util.upload_temporary_file(
                tator_api, project, temp.name):
            print(f"Temporary file upload progress: {progress}%")
        print(response.message)
        temporary_file_id = response.id

    # Run the example.
    cmd = [
        'python3',
        'examples/download_temporary_file.py',
        '--host',
        host,
        '--token',
        token,
        '--temporary_file_id',
        str(temporary_file_id),
        '--file_path',
        '/tmp/asdf',
    ]
    subprocess.run(cmd, check=True)
コード例 #17
0
def test_get_audio(host, token, project, video):
    tator_api = tator.get_api(host, token)
    video_obj = tator_api.get_media(video)

    audio = video_obj.media_files.audio
    assert len(audio) > 0
    assert audio[0].codec == 'aac'
コード例 #18
0
def project(request, organization):
    """ Project ID for a created project. """
    import tator
    host = request.config.option.host
    token = request.config.option.token
    bucket = request.config.option.bucket
    keep = request.config.option.keep
    tator_api = tator.get_api(host, token)
    current_dt = datetime.datetime.now()
    dt_str = current_dt.strftime('%Y_%m_%d__%H_%M_%S')
    project_spec = {
        'name': f'test_project_{dt_str}',
        'summary': f'Test project created by tator-py unit tests on {current_dt}',
        'organization': organization,
    }

    # Create bucket object if bucket spec is given.
    if bucket is not None:
        with open(bucket, 'r') as f:
            bucket_spec = yaml.safe_load(f)
        response = tator_api.create_bucket(organization, bucket_spec=bucket_spec)
        project_spec['bucket'] = response.id

    response = tator_api.create_project(project_spec=project_spec)
    project_id = response.id
    yield project_id
    if not keep:
        status = tator_api.delete_project(project_id)
コード例 #19
0
def main():
    """ Main function of script
    """

    args = parse_args()

    tator_api = tator.get_api(host=args.host, token=args.token)

    media_types = tator_api.get_media_type_list(project=args.project)
    multi_type_id = None
    for media_type in media_types:
        if media_type.dtype == "multi":
            multi_type_id = media_type.id
            break

    if multi_type_id is None:
        raise ValueError("ERROR: Could not find a registered media type of dtype=multi")

    layout = [args.layout_rows, args.layout_cols]

    response = tator.util.make_multi_stream(
        api=tator_api,
        type_id=multi_type_id,
        media_ids=args.media,
        layout=layout,
        name=args.multi_media_name,
        section=args.section_name,
        quality=args.quality)

    logger.info(response)
コード例 #20
0
def test_version_crud(host, token, project):
    tator_api = tator.get_api(host, token)

    # Test single create.
    response = tator_api.create_version(project, version_spec={
        'name': 'Test Version',
        'description': 'A version for testing',
    })
    assert isinstance(response, tator.models.CreateResponse)
    print(response.message)
    pk = response.id

    # Test patch.
    response = tator_api.update_version(pk, version_update={'name': 'Updated Version'})
    assert isinstance(response, tator.models.MessageResponse)
    print(response.message)

    # Compare with get results.
    updated = tator_api.get_version(pk)
    assert isinstance(updated, tator.models.Version)
    assert updated.name == 'Updated Version'

    # Test delete.
    response = tator_api.delete_version(pk)
    assert isinstance(response, tator.models.MessageResponse)
    print(response.message)
コード例 #21
0
def test_bad_file(host, token, project, video_type, image_file):
    failed = False
    try:
        cmd = [
            'python3',
            '-m',
            'tator.transcode',
            image_file,
            '--host',
            host,
            '--token',
            token,
            '--project',
            str(project),
            '--type',
            str(video_type),
            '--section',
            'Bad transcodes',
        ]
        subprocess.run(cmd, check=True)
    except subprocess.CalledProcessError as cpe:
        failed = True
    assert (failed)
    time.sleep(2)
    # Make sure media file is gone.
    api = tator.get_api(host, token)
    medias = api.get_media_list(
        project, attribute=['tator_user_sections::Bad transcodes'])
    assert (len(medias) == 0)
コード例 #22
0
def test_stategraphic(host, token, project, video, box_type, track_type):
    tator_api = tator.get_api(host, token)
    video_obj = tator_api.get_media(video)

    # Make boxes for track.
    boxes = [_make_box(project, box_type, video, frame) for frame in range(10)]
    response = tator_api.create_localization_list(project, localization_spec=boxes)
    assert isinstance(response, tator.models.CreateListResponse)
    print(response.message)
    box_ids = response.id

    # Make track.
    response = tator_api.create_state_list(project, state_spec=[{
        'project': project,
        'type': track_type,
        'media_ids': [video],
        'localization_ids': box_ids,
    }])
    print(response.message)
    assert isinstance(response, tator.models.CreateListResponse)
    track_id = response.id[0]

    # Get state graphic.
    file_path = tator_api.get_state_graphic(track_id, mode='tile')
    state = tator_api.get_state(track_id)
    stategraphic = tator.util.get_images(file_path, state)
    assert(len(stategraphic) == 10)
    for frame_data in stategraphic:
        size = (frame_data.height, frame_data.width, len(frame_data.mode))
        assert_vector_equal(size, (720,1280,3))
コード例 #23
0
ファイル: location_query.py プロジェクト: cvisionai/tator-py
def main() -> None:
    """ Main routine of this script
    """

    args = parse_args()

    # Get the interface to Tator
    tator_api = tator.get_api(host=args.host, token=args.token)

    # Create the filter that will get all the media in the provided section
    attribute_contains_filter = [f'tator_user_sections::{args.section}']

    # Create the distance filter
    attribute_distance_filter = \
        [f'{args.location_field}::{args.radius}::{args.longitude}::{args.latitude}']

    # Get the media using the section and distance filter
    medias = tator_api.get_media_list(
        project=args.project,
        type=args.media_type_id,
        attribute_contains=attribute_contains_filter,
        attribute_distance=attribute_distance_filter)

    # Now, grab the localizations associated with these media and save it
    # to this script's log file
    media_id_list = []
    for media in medias:
        media_id_list.append(media.id)

    localizations = tator_api.get_localization_list(project=args.project,
                                                    media_id=media_id_list)
    logger.info(localizations)

    print(f"{len(localizations)} localizations logged in: {log_filename}")
    print(f"[FINISHED] location_query.py ")
コード例 #24
0
def main() -> None:
    """ Main function of this script
    """

    # Process the arguments
    args = parse_args()

    # Setup the interface to the tator server
    url = urllib.parse.urlparse(args.url)
    host = f"{url.scheme}://{url.netloc}"
    tator_api = tator.get_api(host=host, token=args.token)

    # Launch the algorithm depending on the provided arguments
    if args.algo == 'fillgaps':
        fill_sparse_track(tator_api=tator_api,
                          media_id=args.media,
                          state_id=args.track,
                          work_folder=args.work_folder)

    elif args.algo == 'extend':
        extend_track(tator_api=tator_api,
                     media_id=args.media,
                     state_id=args.track,
                     start_localization_id=args.extend_detection_id,
                     direction=args.extend_direction,
                     work_folder=args.work_folder,
                     max_coast_frames=args.extend_max_coast,
                     max_extend_frames=args.extend_max_frames)

    else:
        raise ValueError(f"Invalid algorithm provided: {args.algo}")
コード例 #25
0
def test_attribute_box_type_change_log(host, token, project, attribute_video,
                                       attribute_box_type):
    tator_api = tator.get_api(host, token)
    video_obj = tator_api.get_media(attribute_video)
    random_entity = partial(random_localization, project, attribute_box_type,
                            video_obj)
    create_list = tator_api.create_localization_list
    update_one = tator_api.update_localization
    update_list = partial(tator_api.update_localization_list,
                          project,
                          media_id=[attribute_video])
    params = {"media_id": [attribute_video], "type": attribute_box_type}
    delete_one = tator_api.delete_localization
    delete_list = partial(tator_api.delete_localization_list, project,
                          **params)
    change_log_helper(
        tator_api,
        random_entity,
        project,
        create_list,
        update_one,
        update_list,
        delete_one,
        delete_list,
    )
コード例 #26
0
def test_register_algorithm(host: str, token: str, project: int):

    ALGORITHM_NAME = str(uuid.uuid1())

    # Create a temporary file
    fd, local_yaml_file = tempfile.mkstemp()
    try:
        with os.fdopen(fd, 'w') as file_handle:
            file_handle.write(_create_yaml_file_str())

        # Run the example.
        cmd = [
            'python3', 'examples/register_algorithm.py', '--host', host,
            '--token', token, '--project',
            str(project), '--manifest', local_yaml_file, '--algorithm_name',
            ALGORITHM_NAME, '--files_per_job', '100'
        ]

        subprocess.run(cmd, check=True)

    finally:
        os.remove(local_yaml_file)

        tator_api = tator.get_api(host=host, token=token)
        algorithms = tator_api.get_algorithm_list(project=project)
        for alg in algorithms:
            if alg.name == ALGORITHM_NAME:
                tator_api.delete_algorithm(id=alg.id)
                print(f'Deleting algorithm: {alg.name}')
                break
コード例 #27
0
def test_download_media(host, token, project, video):

    # Get project and video.
    tator_api = tator.get_api(host, token)
    video_obj = tator_api.get_media(video)
    project_obj = tator_api.get_project(project)

    # Clear the media on disk if it exists.
    expected_path = os.path.join('/tmp', video_obj.name)
    if os.path.exists(expected_path):
        os.remove(expected_path)

    # Run the example.
    cmd = [
        'python3',
        'examples/download_media.py',
        '--host',
        host,
        '--token',
        token,
        '--media_name',
        video_obj.name,
        '--project_name',
        project_obj.name,
        '--save_path',
        '/tmp',
    ]
    subprocess.run(cmd, check=True)

    # Assert the download exists.
    assert os.path.exists(expected_path)
コード例 #28
0
ファイル: conftest.py プロジェクト: cvisionai/tator
def multi_rgb(request, base_url, token, project, rgb_test, rgb_test_2):
    api = tator.get_api(host=base_url, token=token)
    media_types = api.get_media_type_list(project)
    multi_types = [m for m in media_types if m.dtype == "multi"]
    multi_type_id = multi_types[0]
    response = tator.util.make_multi_stream(api, multi_type_id.id, [1, 2],
                                            "test.multi",
                                            [rgb_test, rgb_test_2], "Multis")
    yield response.id
コード例 #29
0
def multi(request, project, multi_type, video):
    import tator
    host = request.config.option.host
    token = request.config.option.token
    tator_api = tator.get_api(host, token)
    response = tator.util.make_multi_stream(tator_api, multi_type, [1, 1], 
                                            'Test multi', [video], 'Multi Videos')
    multi_id = response.id
    yield multi_id
コード例 #30
0
def test_get_file(host, token, project, video):
    tator_api = tator.get_api(host, token)
    video_obj = tator_api.get_media(video)

    with tempfile.TemporaryDirectory() as temp_dir:
        outpath = os.path.join(temp_dir, "video.mp4")
        for progress in tator.download_media(tator_api, video_obj, outpath):
            print(f"Video download progress: {progress}%")
        assert(os.path.exists(outpath))