ProjectApi

class ProjectApi[source]

Bases: supervisely.api.module_api.CloneableModuleApi, supervisely.api.module_api.UpdateableModule, supervisely.api.module_api.RemoveableModuleApi

API for working with Project. ProjectApi object is immutable.

Parameters
api : Api

API connection to the server

Usage example
import os
from dotenv import load_dotenv

import supervisely as sly

# Load secrets and create API object from .env file (recommended)
# Learn more here: https://developer.supervisely.com/getting-started/basics-of-authentication
if sly.is_development():
    load_dotenv(os.path.expanduser("~/supervisely.env"))
api = sly.Api.from_env()

# Pass values into the API constructor (optional, not recommended)
# api = sly.Api(server_address="https://app.supervise.ly", token="4r47N...xaTatb")

project_id = 1951
project_info = api.project.get_info_by_id(project_id)

Methods

archive

Archive Project by ID and save backup URLs in Project info.

archive_batch

Archive Projects by ID and save backup URLs in Project info for every Project.

check_imageset_backup

Check if a backup of the project image set exists.

clone

clone_advanced

clone_by_shared_link

clone_from_explore

create

Create Project with given name in the given Workspace ID.

download_images_tags

Get matching tag names to ImageInfos.

edit_info

exists

Checks if an entity with the given parent_id and name exists

get_activity

Get Project activity by ID.

get_archivation_list

List of all projects in all available workspaces that can be archived.

get_datasets_count

Number of Datasets in the given Project by ID.

get_free_name

Generates a free name for an entity with the given parent_id and name.

get_images_count

Number of images in the given Project by ID.

get_info_by_id

Get Project information by ID.

get_info_by_name

Get Project information by name.

get_list

List of Projects in the given Workspace.

get_list_all_pages

Get list of all or limited quantity entities from the Supervisely server.

get_list_all_pages_generator

This generator function retrieves a list of all or a limited quantity of entities from the Supervisely server, yielding batches of entities as they are retrieved

get_meta

Get ProjectMeta by Project ID.

get_or_clone_from_explore

get_or_create

get_stats

Get Project stats by ID.

images_grouping

Enables images grouping in project.

info_sequence

NamedTuple ProjectInfo with API Fields containing information about Project.

info_tuple_name

NamedTuple name - ProjectInfo.

merge_metas

Merges ProjectMeta from given Project to given destination Project.

move

Move project between workspaces within current team.

pull_meta_ids

remove

Remove an entity with the specified ID from the Supervisely server.

remove_batch

Remove entities with given IDs from the Supervisely server.

update

update_custom_data

Updates custom data of the Project by ID

update_meta

Updates given Project with given ProjectMeta.

update_settings

Updates project wuth given project settings by id.

url

Get Project URL by ID.

Attributes

MAX_WAIT_ATTEMPTS

Maximum number of attempts that will be made to wait for a certain condition to be met.

WAIT_ATTEMPT_TIMEOUT_SEC

Number of seconds for intervals between attempts.

InfoType

alias of supervisely.api.module_api.ProjectInfo

archive(id, archive_url, ann_archive_url=None)[source]

Archive Project by ID and save backup URLs in Project info.

Parameters
id : int

Project ID in Supervisely.

archive_url : str

Shared URL of files backup on Dropbox.

ann_archive_url : str, optional

Shared URL of annotations backup on Dropbox.

Returns

None

Return type

NoneType

Usage example

import supervisely as sly

id = 18464
archive_url = 'https://www.dropbox.com/...'

os.environ['SERVER_ADDRESS'] = 'https://app.supervise.ly'
os.environ['API_TOKEN'] = 'Your Supervisely API Token'
api = sly.Api.from_env()

api.project.archive(id, archive_url, ann_archive_url)
archive_batch(ids, archive_urls, ann_archive_urls=None)[source]

Archive Projects by ID and save backup URLs in Project info for every Project.

Parameters
ids : List[int]

Project IDs in Supervisely.

archive_urls : List[str]

Shared URLs of files backup on Dropbox.

ann_archive_urls : List[str], optional

Shared URLs of annotations backup on Dropbox.

Returns

None

Return type

NoneType

Usage example

import supervisely as sly

ids = [18464, 18461]
archive_urls = ['https://www.dropbox.com/...', 'https://www.dropbox.com/...']

os.environ['SERVER_ADDRESS'] = 'https://app.supervise.ly'
os.environ['API_TOKEN'] = 'Your Supervisely API Token'
api = sly.Api.from_env()

api.project.archive_batch(ids, archive_urls, ann_archive_urls)
check_imageset_backup(id)[source]

Check if a backup of the project image set exists. If yes, it returns a link to the archive.

Parameters
id : int

Project ID

Returns

dict with shared URL of files backup or None

Return type

Dict, optional

Usage example
import os
from dotenv import load_dotenv

import supervisely as sly

# Load secrets and create API object from .env file (recommended)
# Learn more here: https://developer.supervisely.com/getting-started/basics-of-authentication
if sly.is_development():
   load_dotenv(os.path.expanduser("~/supervisely.env"))
api = sly.Api.from_env()

# Pass values into the API constructor (optional, not recommended)
# api = sly.Api(server_address="https://app.supervise.ly", token="4r47N...xaTatb")

response = check_imageset_backup(project_id)
archive_url = response['imagesArchiveUrl']
clone(id, dst_workspace_id, dst_name)
clone_from_explore(explore_path, dst_workspace_id, dst_name)
create(workspace_id, name, type=ProjectType.IMAGES, description='', change_name_if_conflict=False)[source]

Create Project with given name in the given Workspace ID.

Parameters
workspace_id : int

Workspace ID in Supervisely where Project will be created.

name : str

Project Name.

type : ProjectType

Type of created Project.

description : str

Project description.

change_name_if_conflict : bool, optional

Checks if given name already exists and adds suffix to the end of the name.

Returns

Information about Project. See info_sequence

Return type

ProjectInfo

Usage example
import supervisely as sly

workspace_id = 8

os.environ['SERVER_ADDRESS'] = 'https://app.supervise.ly'
os.environ['API_TOKEN'] = 'Your Supervisely API Token'
api = sly.Api.from_env()

new_proj = api.project.create(workspace_id, "fruits_test", sly.ProjectType.IMAGES)
print(new_proj)
# Output: ProjectInfo(id=1993,
#                     name='fruits_test',
#                     description='',
#                     size='0',
#                     readme='',
#                     workspace_id=58,
#                     images_count=None,
#                     items_count=None,
#                     datasets_count=None,
#                     created_at='2021-03-11T09:28:42.585Z',
#                     updated_at='2021-03-11T09:28:42.585Z',
#                     type='images',
#                     reference_image_url=None),
#                     custom_data={},
#                     backup_archive={})
download_images_tags(id, progress_cb=None)[source]

Get matching tag names to ImageInfos.

Parameters
id : int

Project ID in Supervisely.

progress_cb : tqdm or callable, optional

Function for tracking download progress.

Returns

Defaultdict matching tag names to ImageInfos

Return type

defaultdict

Usage example
import supervisely as sly

os.environ['SERVER_ADDRESS'] = 'https://app.supervise.ly'
os.environ['API_TOKEN'] = 'Your Supervisely API Token'
api = sly.Api.from_env()

project_id = 8200
tags_to_infos = api.project.download_images_tags(project_id)
for tag_name in tags_to_infos:
    print(tag_name, tags_to_infos[tag_name])
# Output:
# train [ImageInfo(id=2389064, name='IMG_4451_JjH4WPkHlk.jpeg', link=None, hash='6EpjCL+lBdMBYo...
# val [ImageInfo(id=2389066, name='IMG_1836.jpeg', link=None, hash='Si0WvJreU6pmrx1EDa1itkqqSkQkZFzNJSu...
exists(parent_id, name)

Checks if an entity with the given parent_id and name exists

Parameters
parent_id : int

ID of the parent entity.

name : str

Name of the entity.

Returns

Returns True if entity exists, and False if not

Return type

bool

Usage example
import supervisely as sly

# You can connect to API directly
address = 'https://app.supervise.ly/'
token = 'Your Supervisely API Token'
api = sly.Api(address, token)

# Or you can use API from environment
os.environ['SERVER_ADDRESS'] = 'https://app.supervise.ly'
os.environ['API_TOKEN'] = 'Your Supervisely API Token'
api = sly.Api.from_env()


name = "IMG_0315.jpeg"
dataset_id = 55832
exists = api.image.exists(dataset_id, name)
print(exists) # True
get_activity(id, progress_cb=None)[source]

Get Project activity by ID.

Parameters
id : int

Project ID in Supervisely.

Returns

Pandas DataFrame

Return type

DataFrame

Usage example
import supervisely as sly

project_id = 1951

os.environ['SERVER_ADDRESS'] = 'https://app.supervise.ly'
os.environ['API_TOKEN'] = 'Your Supervisely API Token'
api = sly.Api.from_env()

project_activity = api.project.get_activity(project_id)
print(project_activity)
# Output:    userId               action  ... tagId             meta
#         0       7  annotation_duration  ...  None  {'duration': 1}
#         1       7  annotation_duration  ...  None  {'duration': 2}
#         2       7        create_figure  ...  None               {}
#
#         [3 rows x 18 columns]
get_archivation_list(to_day=None, from_day=None, skip_exported=None, sort=None, sort_order=None)[source]

List of all projects in all available workspaces that can be archived.

Parameters
to_day : int, optional

Sets the number of days from today. If the project has not been updated during this period, it will be added to the list.

from_day : int, optional

Sets the number of days from today. If the project has not been updated before this period, it will be added to the list.

skip_exported : bool, optional.

Determines whether to skip already archived projects.

sort : str, optional.

Specifies by which parameter to sort the project list.

sort_order : str, optional.

Determines which value to list from.

Returns

List of all projects with information. See info_sequence

Return type

List[ProjectInfo]

Usage example

import supervisely as sly

os.environ['SERVER_ADDRESS'] = 'https://app.supervisely.com'
os.environ['API_TOKEN'] = 'Your Supervisely API Token'
api = sly.Api.from_env()

project_list = api.project.get_archivation_list()
print(project_list)
# Output: [
# ProjectInfo(id=861,
#             name='Project_COCO'
#             size='22172241',
#             workspace_id=58,
#             created_at='2020-11-09T18:21:32.356Z',
#             updated_at='2020-11-09T18:21:32.356Z',
#             type='images',),
# ProjectInfo(id=777,
#             name='Trucks',
#             size='76154769',
#             workspace_id=58,
#             created_at='2021-07-077T17:44:28.158Z',
#             updated_at='2023-07-15T12:33:45.747Z',
#             type='images',)
# ]

# Project list for desired date range
project_list = api.project.get_archivation_list(to_day=2)
print(project_list)
# Output: ProjectInfo(id=777,
#                     name='Trucks',
#                     size='76154769',
#                     workspace_id=58,
#                     created_at='2021-07-077T17:44:28.158Z',
#                     updated_at='2023-07-15T12:33:45.747Z',
#                     type='images',)
# ]
get_datasets_count(id)[source]

Number of Datasets in the given Project by ID.

Parameters
id : int

Project ID in Supervisely.

Returns

Number of Datasets in the given Project

Return type

int

Usage example
import supervisely as sly

project_id = 454

os.environ['SERVER_ADDRESS'] = 'https://app.supervise.ly'
os.environ['API_TOKEN'] = 'Your Supervisely API Token'
api = sly.Api.from_env()

project_ds_count = api.project.get_datasets_count(project_id)
print(project_ds_count)
# Output: 4
get_free_name(parent_id, name)

Generates a free name for an entity with the given parent_id and name. Adds an increasing suffix to original name until a unique name is found.

Parameters
parent_id : int

ID of the parent entity.

name : str

Name of the entity.

Returns

Returns free name.

Return type

str

Usage example
import supervisely as sly

# You can connect to API directly
address = 'https://app.supervise.ly/'
token = 'Your Supervisely API Token'
api = sly.Api(address, token)

# Or you can use API from environment
os.environ['SERVER_ADDRESS'] = 'https://app.supervise.ly'
os.environ['API_TOKEN'] = 'Your Supervisely API Token'
api = sly.Api.from_env()


name = "IMG_0315.jpeg"
dataset_id = 55832
free_name = api.image.get_free_name(dataset_id, name)
print(free_name) # IMG_0315_001.jpeg
get_images_count(id)[source]

Number of images in the given Project by ID.

Parameters
id : int

Project ID in Supervisely.

Returns

Number of images in the given Project

Return type

int

Usage example
import supervisely as sly

project_id = 454

os.environ['SERVER_ADDRESS'] = 'https://app.supervise.ly'
os.environ['API_TOKEN'] = 'Your Supervisely API Token'
api = sly.Api.from_env()

project_imgs_count = api.project.get_images_count(project_id)
print(project_imgs_count)
# Output: 24
get_info_by_id(id, expected_type=None, raise_error=False)[source]

Get Project information by ID.

Parameters
id : int

Project ID in Supervisely.

expected_type : ProjectType, optional

Expected ProjectType.

raise_error : bool, optional

If True raise error if given name is missing in the Project, otherwise skips missing names.

Raises

Error if type of project is not None and != expected type

Returns

Information about Project. See info_sequence

Return type

ProjectInfo

Usage example
import supervisely as sly

project_id = 1951

os.environ['SERVER_ADDRESS'] = 'https://app.supervise.ly'
os.environ['API_TOKEN'] = 'Your Supervisely API Token'
api = sly.Api.from_env()

project_info = api.project.get_info_by_id(project_id)
print(project_info)
# Output: ProjectInfo(id=861,
#                     name='fruits_annotated',
#                     description='',
#                     size='22172241',
#                     readme='',
#                     workspace_id=58,
#                     images_count=6,
#                     items_count=6,
#                     datasets_count=1,
#                     created_at='2020-11-09T18:21:32.356Z',
#                     updated_at='2020-11-09T18:21:32.356Z',
#                     type='images',
#                     reference_image_url='http://78.46.75.100:38585/h5un6l2bnaz1vj8a9qgms4-public/images/original/...jpg'),
#                     custom_data={},
#                     backup_archive={})
get_info_by_name(parent_id, name, expected_type=None, raise_error=False)[source]

Get Project information by name.

Parameters
parent_id : int

Workspace ID.

name : str

Project name.

expected_type : ProjectType, optional

Expected ProjectType.

raise_error : bool, optional

If True raise error if given name is missing in the Project, otherwise skips missing names.

Returns

Information about Project. See info_sequence

Return type

ProjectInfo

Usage example
import supervisely as sly

os.environ['SERVER_ADDRESS'] = 'https://app.supervise.ly'
os.environ['API_TOKEN'] = 'Your Supervisely API Token'
api = sly.Api.from_env()

project_info = api.project.get_info_by_name(58, "fruits_annotated")
print(project_info)
# Output: ProjectInfo(id=861,
#                     name='fruits_annotated',
#                     description='',
#                     size='22172241',
#                     readme='',
#                     workspace_id=58,
#                     images_count=6,
#                     items_count=6,
#                     datasets_count=1,
#                     created_at='2020-11-09T18:21:32.356Z',
#                     updated_at='2020-11-09T18:21:32.356Z',
#                     type='images',
#                     reference_image_url='http://78.46.75.100:38585/h5un6l2bnaz1vj8a9qgms4-public/images/original/...jpg'),
#                     custom_data={},
#                     backup_archive={})
get_list(workspace_id, filters=None)[source]

List of Projects in the given Workspace.

Parameters
workspace_id : int

Workspace ID in which the Projects are located.

filters : List[dict], optional

List of params to sort output Projects.

Returns

List of all projects with information for the given Workspace. See info_sequence

Return type

List[ProjectInfo]

Usage example
import supervisely as sly

workspace_id = 58

os.environ['SERVER_ADDRESS'] = 'https://app.supervise.ly'
os.environ['API_TOKEN'] = 'Your Supervisely API Token'
api = sly.Api.from_env()

project_list = api.project.get_list(workspace_id)
print(project_list)
# Output: [
# ProjectInfo(id=861,
#             name='Project_COCO',
#             description='',
#             size='22172241',
#             readme='',
#             workspace_id=58,
#             images_count=6,
#             items_count=6,
#             datasets_count=1,
#             created_at='2020-11-09T18:21:32.356Z',
#             updated_at='2020-11-09T18:21:32.356Z',
#             type='images',
#             reference_image_url='http://78.46.75.100:38585/h5un6l2bnaz1vj8a9qgms4-public/images/original/...jpg',
#             custom_data={},
#             backup_archive={}),
# ProjectInfo(id=999,
#             name='Cat_breeds',
#             description='',
#             size='861069',
#             readme='',
#             workspace_id=58,
#             images_count=10,
#             items_count=10,
#             datasets_count=2,
#             created_at='2020-11-17T17:44:28.158Z',
#             updated_at='2021-03-01T10:51:57.545Z',
#             type='images',
#             reference_image_url='http://78.46.75.100:38585/h5un6l2bnaz1vj8a9qgms4-public/images/original/...jpg'),
#             custom_data={},
#             backup_archive={})
# ]

# Filtered Project list
project_list = api.project.get_list(workspace_id, filters=[{ 'field': 'name', 'operator': '=', 'value': 'Cat_breeds'}])
print(project_list)
# Output: ProjectInfo(id=999,
#                     name='Cat_breeds',
#                     description='',
#                     size='861069',
#                     readme='',
#                     workspace_id=58,
#                     images_count=10,
#                     items_count=10,
#                     datasets_count=2,
#                     created_at='2020-11-17T17:44:28.158Z',
#                     updated_at='2021-03-01T10:51:57.545Z',
#                     type='images',
#                     reference_image_url='http://78.46.75.100:38585/h5un6l2bnaz1vj8a9qgms4-public/images/original/...jpg'),
#                     custom_data={},
#                     backup_archive={})
# ]
get_list_all_pages(method, data, progress_cb=None, convert_json_info_cb=None, limit=None, return_first_response=False)

Get list of all or limited quantity entities from the Supervisely server.

Parameters
method : str

Request method name

data : dict

Dictionary with request body info

progress_cb : Progress, optional

Function for tracking download progress.

convert_json_info_cb : Callable, optional

Function for convert json info

limit : int, optional

Number of entity to retrieve

return_first_response : bool, optional

Specify if return first response

get_list_all_pages_generator(method, data, progress_cb=None, convert_json_info_cb=None, limit=None, return_first_response=False)

This generator function retrieves a list of all or a limited quantity of entities from the Supervisely server, yielding batches of entities as they are retrieved

Parameters
method : str

Request method name

data : dict

Dictionary with request body info

progress_cb : Progress, optional

Function for tracking download progress.

convert_json_info_cb : Callable, optional

Function for convert json info

limit : int, optional

Number of entity to retrieve

return_first_response : bool, optional

Specify if return first response

get_meta(id)[source]

Get ProjectMeta by Project ID.

Parameters
id : int

Project ID in Supervisely.

Returns

ProjectMeta dict

Return type

dict

Usage example
import supervisely as sly

os.environ['SERVER_ADDRESS'] = 'https://app.supervise.ly'
os.environ['API_TOKEN'] = 'Your Supervisely API Token'
api = sly.Api.from_env()

project_meta = api.project.get_meta(project_id)
print(project_meta)
# Output: {
#     "classes":[
#         {
#             "id":22310,
#             "title":"kiwi",
#             "shape":"bitmap",
#             "hotkey":"",
#             "color":"#FF0000"
#         },
#         {
#             "id":22309,
#             "title":"lemon",
#             "shape":"bitmap",
#             "hotkey":"",
#             "color":"#51C6AA"
#         }
#     ],
#     "tags":[],
#     "projectType":"images"
# }
get_or_clone_from_explore(explore_path, dst_workspace_id, dst_name)
get_stats(id)[source]

Get Project stats by ID.

Parameters
id : int

Project ID in Supervisely.

Returns

Project statistics

Return type

dict

Usage example
import supervisely as sly

project_id = 1951

os.environ['SERVER_ADDRESS'] = 'https://app.supervise.ly'
os.environ['API_TOKEN'] = 'Your Supervisely API Token'
api = sly.Api.from_env()

project_stats = api.project.get_stats(project_id)
images_grouping(id, enable, tag_name, sync=False)[source]

Enables images grouping in project.

Parameters
id : int

Project ID

enable : Dict[str, str]

if True groups images by given tag name

tag_name : str

Name of the tag. Images will be grouped by this tag

Return type

None

static info_sequence()[source]

NamedTuple ProjectInfo with API Fields containing information about Project.

Example
ProjectInfo(id=999,
            name='Cat_breeds',
            description='',
            size='861069',
            readme='',
            workspace_id=58,
            images_count=10,
            items_count=10,
            datasets_count=2,
            created_at='2020-11-17T17:44:28.158Z',
            updated_at='2021-03-01T10:51:57.545Z',
            type='images',
            reference_image_url='http://app.supervise.ly/h5un6l2bnaz1vj8a9qgms4-public/images/original/...jpg'),
            custom_data={}
            backup_archive={}
static info_tuple_name()[source]

NamedTuple name - ProjectInfo.

merge_metas(src_project_id, dst_project_id)[source]

Merges ProjectMeta from given Project to given destination Project.

Parameters
src_project_id : int

Source Project ID.

dst_project_id : int

Destination Project ID.

Returns

ProjectMeta dict

Return type

dict

Usage example
import supervisely as sly

os.environ['SERVER_ADDRESS'] = 'https://app.supervise.ly'
os.environ['API_TOKEN'] = 'Your Supervisely API Token'
api = sly.Api.from_env()

lemons_proj_id = 1951
kiwis_proj_id = 1980

merged_projects = api.project.merge_metas(lemons_proj_id, kiwis_proj_id)
move(id, workspace_id)[source]

Move project between workspaces within current team.

Parameters
id : int

Project ID

workspace_id : int

Workspace ID the project will move in

Returns

None

Return type

NoneType

Usage example
import supervisely as sly

os.environ['SERVER_ADDRESS'] = 'https://app.supervise.ly'
os.environ['API_TOKEN'] = 'Your Supervisely API Token'
api = sly.Api.from_env()

workspace_id = 688
project_id = 17173

api.project.move(id=project_id, workspace_id=workspace_id)
remove(id)

Remove an entity with the specified ID from the Supervisely server.

Parameters
id : int

Entity ID in Supervisely

remove_batch(ids, progress_cb=None)

Remove entities with given IDs from the Supervisely server.

Parameters
ids : List[int]

IDs of entities in Supervisely.

progress_cb : Callable

Function for control remove progress.

update(id, name=None, description=None)
update_custom_data(id, data)[source]

Updates custom data of the Project by ID

Parameters
id : int

Project ID in Supervisely.

data : dict

Custom data

Returns

Project information in dict format

Return type

dict

Usage example
import supervisely as sly

project_id = 1951
custom_data = {1:2}

os.environ['SERVER_ADDRESS'] = 'https://app.supervise.ly'
os.environ['API_TOKEN'] = 'Your Supervisely API Token'
api = sly.Api.from_env()

new_info = api.project.update_custom_data(project_id, custom_data)
update_meta(id, meta)[source]

Updates given Project with given ProjectMeta.

Parameters
id : int

Project ID in Supervisely.

meta : ProjectMeta or dict

ProjectMeta object or ProjectMeta in JSON format.

Returns

None

Return type

NoneType

Usage example
import supervisely as sly

lemons_proj_id = 1951
kiwis_proj_id = 1952

os.environ['SERVER_ADDRESS'] = 'https://app.supervise.ly'
os.environ['API_TOKEN'] = 'Your Supervisely API Token'
api = sly.Api.from_env()

# Using ProjectMeta in JSON format

project_meta_json = api.project.get_meta(lemons_proj_id)
api.project.update_meta(kiwis_proj_id, project_meta_json)

# Using ProjectMeta object

project_meta_json = api.project.get_meta(lemons_proj_id)
project_meta = sly.ProjectMeta.from_json(path_to_meta)
api.project.update_meta(kiwis_proj_id, project_meta)

# Using programmatically created ProjectMeta

cat_class = sly.ObjClass("cat", sly.Rectangle, color=[0, 255, 0])
scene_tag = sly.TagMeta("scene", sly.TagValueType.ANY_STRING)
project_meta = sly.ProjectMeta(obj_classes=[cat_class], tag_metas=[scene_tag])
api.project.update_meta(kiwis_proj_id, project_meta)

# Update ProjectMeta from local `meta.json`
from supervisely.io.json import load_json_file

path_to_meta = "/path/project/meta.json"
project_meta_json = load_json_file(path_to_meta)
api.project.update_meta(kiwis_proj_id, project_meta)
update_settings(id, settings)[source]

Updates project wuth given project settings by id.

Parameters
id : int

Project ID

settings : Dict[str, str]

Project settings

Return type

None

url(id)[source]

Get Project URL by ID.

Parameters
id : int

Project ID in Supervisely.

Returns

Project URL

Return type

str

Usage example
import supervisely as sly

project_id = 1951

os.environ['SERVER_ADDRESS'] = 'https://app.supervise.ly'
os.environ['API_TOKEN'] = 'Your Supervisely API Token'
api = sly.Api.from_env()

project_url = api.project.url(project_id)
print(project_url)
# Output: http://supervise.ly/projects/1951/datasets