def create( self, name: str = "Anonymous Python Stream", description: str = "No description provided", is_public: bool = True, ) -> str: """Create a new stream Arguments: name {str} -- the name of the string description {str} -- a short description of the stream is_public {bool} -- whether or not the stream can be viewed by anyone with the id Returns: id {str} -- the id of the newly created stream """ metrics.track(metrics.STREAM_CREATE) query = gql(""" mutation StreamCreate($stream: StreamCreateInput!) { streamCreate(stream: $stream) } """) params = { "stream": { "name": name, "description": description, "isPublic": is_public } } return self.make_request(query=query, params=params, return_type="streamCreate", parse_response=False)
def send( base: Base, transports: List[AbstractTransport] = [], use_default_cache: bool = True, ): """Sends an object via the provided transports. Defaults to the local cache. Arguments: obj {Base} -- the object you want to send transports {list} -- where you want to send them use_default_cache {bool} -- toggle for the default cache. If set to false, it will only send to the provided transports Returns: str -- the object id of the sent object """ metrics.track(metrics.SEND) if not transports and not use_default_cache: raise SpeckleException( message="You need to provide at least one transport: cannot send with an empty transport list and no default cache" ) if use_default_cache: transports.insert(0, SQLiteTransport()) serializer = BaseObjectSerializer(write_transports=transports) for t in transports: t.begin_write() hash, _ = serializer.write_json(base=base) for t in transports: t.end_write() return hash
def get_local_accounts(base_path: str = None) -> List[Account]: """Gets all the accounts present in this environment Arguments: base_path {str} -- custom base path if you are not using the system default Returns: List[Account] -- list of all local accounts or an empty list if no accounts were found """ metrics.track(metrics.ACCOUNT_LIST) account_storage = SQLiteTransport(scope="Accounts", base_path=base_path) json_path = os.path.join(account_storage._base_path, "Accounts") os.makedirs(json_path, exist_ok=True) json_acct_files = [ file for file in os.listdir(json_path) if file.endswith(".json") ] accounts = [] res = account_storage.get_all_objects() if res: accounts.extend(Account.parse_raw(r[1]) for r in res) if json_acct_files: try: accounts.extend( Account.parse_file(os.path.join(json_path, json_file)) for json_file in json_acct_files) except Exception as ex: raise SpeckleException( "Invalid json accounts could not be read. Please fix or remove them.", ex, ) return accounts
def create(self, stream_id: str, name: str, description: str = "No description provided") -> str: """Create a new branch on this stream Arguments: name {str} -- the name of the new branch description {str} -- a short description of the branch Returns: id {str} -- the newly created branch's id """ metrics.track(metrics.BRANCH, self.account, {"name": "create"}) query = gql(""" mutation BranchCreate($branch: BranchCreateInput!) { branchCreate(branch: $branch) } """) params = { "branch": { "streamId": stream_id, "name": name, "description": description, } } return self.make_request(query=query, params=params, return_type="branchCreate", parse_response=False)
def revoke_permission(self, stream_id: str, user_id: str): """Revoke permissions from a user on a given stream Arguments: stream_id {str} -- the id of the stream to revoke permissions from user_id {str} -- the id of the user to revoke permissions from Returns: bool -- True if the operation was successful """ metrics.track(metrics.PERMISSION, self.account, {"name": "revoke"}) query = gql(""" mutation StreamRevokePermission($permission_params: StreamRevokePermissionInput !) { streamRevokePermission(permissionParams: $permission_params) } """) params = { "permission_params": { "streamId": stream_id, "userId": user_id } } return self.make_request( query=query, params=params, return_type="streamRevokePermission", parse_response=False, )
def get(self, id: str = None) -> User: """Gets the profile of a user. If no id argument is provided, will return the current authenticated user's profile (as extracted from the authorization header). Arguments: id {str} -- the user id Returns: User -- the retrieved user """ metrics.track(metrics.USER, self.account, {"name": "get"}) query = gql(""" query User($id: String) { user(id: $id) { id email name bio company avatar verified profiles role } } """) params = {"id": id} return self.make_request(query=query, params=params, return_type="user")
def grant_permission(self, stream_id: str, user_id: str, role: str): """Grant permissions to a user on a given stream Arguments: stream_id {str} -- the id of the stream to grant permissions to user_id {str} -- the id of the user to grant permissions for role {str} -- the role to grant the user Returns: bool -- True if the operation was successful """ metrics.track(metrics.PERMISSION, self.account, { "name": "add", "role": role }) query = gql(""" mutation StreamGrantPermission($permission_params: StreamGrantPermissionInput !) { streamGrantPermission(permissionParams: $permission_params) } """) params = { "permission_params": { "streamId": stream_id, "userId": user_id, "role": role, } } return self.make_request( query=query, params=params, return_type="streamGrantPermission", parse_response=False, )
def search(self, search_query: str, limit: int = 25) -> List[User]: """Searches for user by name or email. The search query must be at least 3 characters long Arguments: search_query {str} -- a string to search for limit {int} -- the maximum number of results to return Returns: List[User] -- a list of User objects that match the search query """ if len(search_query) < 3: return SpeckleException( message="User search query must be at least 3 characters") metrics.track(metrics.USER, self.account, {"name": "search"}) query = gql(""" query UserSearch($search_query: String!, $limit: Int!) { userSearch(query: $search_query, limit: $limit) { items { id name bio company avatar verified } } } """) params = {"search_query": search_query, "limit": limit} return self.make_request(query=query, params=params, return_type=["userSearch", "items"])
def received( self, stream_id: str, commit_id: str, source_application: str = "python", message: Optional[str] = None, ) -> bool: """ Mark a commit object a received by the source application. """ metrics.track(metrics.COMMIT, self.account, {"name": "received"}) query = gql(""" mutation CommitReceive($receivedInput:CommitReceivedInput!){ commitReceive(input:$receivedInput) } """) params = { "receivedInput": { "sourceApplication": source_application, "streamId": stream_id, "commitId": commit_id, "message": "message", } } try: return self.make_request( query=query, params=params, return_type="commitReceive", parse_response=False, ) except Exception as ex: print(ex.with_traceback) return False
def update(self, stream_id: str, commit_id: str, message: str) -> bool: """ Update a commit Arguments: stream_id {str} -- the id of the stream that contains the commit you'd like to update commit_id {str} -- the id of the commit you'd like to update message {str} -- the updated commit message Returns: bool -- True if the operation succeeded """ metrics.track(metrics.COMMIT, self.account, {"name": "update"}) query = gql(""" mutation CommitUpdate($commit: CommitUpdateInput!){ commitUpdate(commit: $commit)} """) params = { "commit": { "streamId": stream_id, "id": commit_id, "message": message } } return self.make_request(query=query, params=params, return_type="commitUpdate", parse_response=False)
def list(self, stream_id: str, branches_limit: int = 10, commits_limit: int = 10): """Get a list of branches from a given stream Arguments: stream_id {str} -- the id of the stream to get the branches from branches_limit {int} -- maximum number of branches to get commits_limit {int} -- maximum number of commits to get Returns: List[Branch] -- the branches on the stream """ metrics.track(metrics.BRANCH, self.account, {"name": "get"}) query = gql(""" query BranchesGet($stream_id: String!, $branches_limit: Int!, $commits_limit: Int!) { stream(id: $stream_id) { branches(limit: $branches_limit) { items { id name description commits(limit: $commits_limit) { totalCount items{ id message referencedObject sourceApplication parents authorId authorName branchName createdAt } } } } } } """) params = { "stream_id": stream_id, "branches_limit": branches_limit, "commits_limit": commits_limit, } return self.make_request(query=query, params=params, return_type=["stream", "branches", "items"])
def get(self, stream_id: str, name: str, commits_limit: int = 10): """Get a branch by name from a stream Arguments: stream_id {str} -- the id of the stream to get the branch from name {str} -- the name of the branch to get commits_limit {int} -- maximum number of commits to get Returns: Branch -- the fetched branch with its latest commits """ metrics.track(metrics.BRANCH, self.account, {"name": "get"}) query = gql(""" query BranchGet($stream_id: String!, $name: String!, $commits_limit: Int!) { stream(id: $stream_id) { branch(name: $name) { id, name, description, commits (limit: $commits_limit) { totalCount, cursor, items { id, referencedObject, sourceApplication, totalChildrenCount, message, authorName, authorId, branchName, parents, createdAt } } } } } """) params = { "stream_id": stream_id, "name": name, "commits_limit": commits_limit } return self.make_request(query=query, params=params, return_type=["stream", "branch"])
def list(self, stream_limit: int = 10) -> List[Stream]: """Get a list of the user's streams Arguments: stream_limit {int} -- The maximum number of streams to return Returns: List[Stream] -- A list of Stream objects """ metrics.track(metrics.STREAM_LIST) query = gql(""" query User($stream_limit: Int!) { user { id email name bio company avatar verified profiles role streams(limit: $stream_limit) { totalCount cursor items { id name description isPublic createdAt updatedAt collaborators { id name role } } } } } """) params = {"stream_limit": stream_limit} return self.make_request(query=query, params=params, return_type=["user", "streams", "items"])
def serialize(base: Base, write_transports: List[AbstractTransport] = []) -> str: """ Serialize a base object. If no write transports are provided, the object will be serialized without detaching or chunking any of the attributes. Arguments: base {Base} -- the object to serialize write_transports {List[AbstractTransport]} -- optional: the transports to write to Returns: str -- the serialized object """ metrics.track(metrics.SERIALIZE) serializer = BaseObjectSerializer(write_transports=write_transports) return serializer.write_json(base)[1]
def get_default_account(base_path: str = None) -> Account: """Gets this environment's default account if any. If there is no default, the first found will be returned and set as default. Arguments: base_path {str} -- custom base path if you are not using the system default Returns: Account -- the default account or None if no local accounts were found """ metrics.track(metrics.ACCOUNT_DEFAULT) accounts = get_local_accounts(base_path=base_path) if not accounts: return None default = next((acc for acc in accounts if acc.isDefault), None) if not default: default = accounts[0] default.isDefault = True return default
def create( self, stream_id: str, object_id: str, branch_name: str = "main", message: str = "", source_application: str = "python", parents: List[str] = None, ) -> str: """ Creates a commit on a branch Arguments: stream_id {str} -- the stream you want to commit to object_id {str} -- the hash of your commit object branch_name {str} -- the name of the branch to commit to (defaults to "main") message {str} -- optional: a message to give more information about the commit source_application{str} -- optional: the application from which the commit was created (defaults to "python") parents {List[str]} -- optional: the id of the parent commits Returns: str -- the id of the created commit """ metrics.track(metrics.COMMIT, self.account, {"name": "create"}) query = gql(""" mutation CommitCreate ($commit: CommitCreateInput!){ commitCreate(commit: $commit)} """) params = { "commit": { "streamId": stream_id, "branchName": branch_name, "objectId": object_id, "message": message, "sourceApplication": source_application, } } if parents: params["commit"]["parents"] = parents return self.make_request(query=query, params=params, return_type="commitCreate", parse_response=False)
def deserialize(obj_string: str, read_transport: AbstractTransport = None) -> Base: """ Deserialize a string object into a Base object. If the object contains referenced child objects that are not stored in the local db, a read transport needs to be provided in order to recompose the base with the children objects. Arguments: obj_string {str} -- the string object to deserialize read_transport {AbstractTransport} -- the transport to fetch children objects from (defaults to SQLiteTransport) Returns: Base -- the deserialized object """ metrics.track(metrics.DESERIALIZE) if not read_transport: read_transport = SQLiteTransport() serializer = BaseObjectSerializer(read_transport=read_transport) return serializer.read_json(obj_string=obj_string)
def update(self, name: str = None, company: str = None, bio: str = None, avatar: str = None): """Updates your user profile. All arguments are optional. Arguments: name {str} -- your name company {str} -- the company you may or may not work for bio {str} -- tell us about yourself avatar {str} -- a nice photo of yourself Returns: bool -- True if your profile was updated successfully """ metrics.track(metrics.USER, self.account, {"name": "update"}) query = gql(""" mutation UserUpdate($user: UserUpdateInput!) { userUpdate(user: $user) } """) params = { "name": name, "company": company, "bio": bio, "avatar": avatar } params = {"user": {k: v for k, v in params.items() if v is not None}} if not params["user"]: return SpeckleException( message= "You must provide at least one field to update your user profile" ) return self.make_request(query=query, params=params, return_type="userUpdate", parse_response=False)
def list(self, stream_id: str, limit: int = 10) -> List[Commit]: """ Get a list of commits on a given stream Arguments: stream_id {str} -- the stream where the commits are limit {int} -- the maximum number of commits to fetch (default = 10) Returns: List[Commit] -- a list of the most recent commit objects """ metrics.track(metrics.COMMIT, self.account, {"name": "get"}) query = gql(""" query Commits($stream_id: String!, $limit: Int!) { stream(id: $stream_id) { commits(limit: $limit) { items { id message referencedObject authorName authorId authorName authorAvatar branchName createdAt sourceApplication totalChildrenCount parents } } } } """) params = {"stream_id": stream_id, "limit": limit} return self.make_request(query=query, params=params, return_type=["stream", "commits", "items"])
def delete(self, id: str) -> bool: """Delete a stream given its id Arguments: id {str} -- the id of the stream to delete Returns: bool -- whether the deletion was successful """ metrics.track(metrics.STREAM_DELETE) query = gql(""" mutation StreamDelete($id: String!) { streamDelete(id: $id) } """) params = {"id": id} return self.make_request(query=query, params=params, return_type="streamDelete", parse_response=False)
def update(self, stream_id: str, branch_id: str, name: str = None, description: str = None): """Update a branch Arguments: stream_id {str} -- the id of the stream containing the branch to update branch_id {str} -- the id of the branch to update name {str} -- optional: the updated branch name description {str} -- optional: the updated branch description Returns: bool -- True if update is successfull """ metrics.track(metrics.BRANCH, self.account, {"name": "update"}) query = gql(""" mutation BranchUpdate($branch: BranchUpdateInput!) { branchUpdate(branch: $branch) } """) params = { "branch": { "streamId": stream_id, "id": branch_id, } } if name: params["branch"]["name"] = name if description: params["branch"]["description"] = description return self.make_request(query=query, params=params, return_type="branchUpdate", parse_response=False)
def delete(self, stream_id: str, branch_id: str): """Delete a branch Arguments: stream_id {str} -- the id of the stream containing the branch to delete branch_id {str} -- the branch to delete Returns: bool -- True if deletion is successful """ metrics.track(metrics.BRANCH, self.account, {"name": "delete"}) query = gql(""" mutation BranchDelete($branch: BranchDeleteInput!) { branchDelete(branch: $branch) } """) params = {"branch": {"streamId": stream_id, "id": branch_id}} return self.make_request(query=query, params=params, return_type="branchDelete", parse_response=False)
def receive( obj_id: str, remote_transport: AbstractTransport = None, local_transport: AbstractTransport = None, ) -> Base: """Receives an object from a transport. Arguments: obj_id {str} -- the id of the object to receive remote_transport {Transport} -- the transport to receive from local_transport {Transport} -- the local cache to check for existing objects (defaults to `SQLiteTransport`) Returns: Base -- the base object """ metrics.track(metrics.RECEIVE) if not local_transport: local_transport = SQLiteTransport() serializer = BaseObjectSerializer(read_transport=local_transport) # try local transport first. if the parent is there, we assume all the children are there and continue wth deserialisation using the local transport obj_string = local_transport.get_object(obj_id) if obj_string: return serializer.read_json(obj_string=obj_string) if not remote_transport: raise SpeckleException( message="Could not find the specified object using the local transport, and you didn't provide a fallback remote from which to pull it." ) obj_string = remote_transport.copy_object_and_children( id=obj_id, target_transport=local_transport ) return serializer.read_json(obj_string=obj_string)
def __init__(self, url: str) -> None: metrics.track("streamwrapper") self.stream_url = url parsed = urlparse(url) self.host = parsed.netloc self.use_ssl = parsed.scheme == "https" segments = parsed.path.strip("/").split("/") if not segments or len(segments) > 4 or len(segments) < 2: raise SpeckleException( f"Cannot parse {url} into a stream wrapper class - invalid URL provided." ) while segments: segment = segments.pop(0) if segments and segment.lower() == "streams": self.stream_id = segments.pop(0) elif segments and segment.lower() == "commits": self.commit_id = segments.pop(0) elif segments and segment.lower() == "branches": self.branch_name = unquote(segments.pop(0)) elif segments and segment.lower() == "objects": self.object_id = segments.pop(0) elif segment.lower() == "globals": self.branch_name = "globals" if segments: self.commit_id = segments.pop(0) else: raise SpeckleException( f"Cannot parse {url} into a stream wrapper class - invalid URL provided." ) if not self.stream_id: raise SpeckleException( f"Cannot parse {url} into a stream wrapper class - no stream id found." )
def update(self, id: str, name: str = None, description: str = None, is_public: bool = None) -> bool: """Update an existing stream Arguments: id {str} -- the id of the stream to be updated name {str} -- the name of the string description {str} -- a short description of the stream is_public {bool} -- whether or not the stream can be viewed by anyone with the id Returns: bool -- whether the stream update was successful """ metrics.track(metrics.STREAM_UPDATE) query = gql(""" mutation StreamUpdate($stream: StreamUpdateInput!) { streamUpdate(stream: $stream) } """) params = { "id": id, "name": name, "description": description, "isPublic": is_public, } # remove None values so graphql doesn't cry params = {"stream": {k: v for k, v in params.items() if v is not None}} return self.make_request(query=query, params=params, return_type="streamUpdate", parse_response=False)
def get(self, id: str, branch_limit: int = 10, commit_limit: int = 10) -> Stream: """Get the specified stream from the server Arguments: id {str} -- the stream id branch_limit {int} -- the maximum number of branches to return commit_limit {int} -- the maximum number of commits to return Returns: Stream -- the retrieved stream """ metrics.track(metrics.STREAM_GET) query = gql(""" query Stream($id: String!, $branch_limit: Int!, $commit_limit: Int!) { stream(id: $id) { id name description isPublic createdAt updatedAt collaborators { id name role avatar } branches(limit: $branch_limit) { totalCount cursor items { id name description commits(limit: $commit_limit) { totalCount cursor items { id referencedObject message authorName authorId createdAt } } } } } } """) params = { "id": id, "branch_limit": branch_limit, "commit_limit": commit_limit } return self.make_request(query=query, params=params, return_type="stream")
def search( self, search_query: str, limit: int = 25, branch_limit: int = 10, commit_limit: int = 10, ): """Search for streams by name, description, or id Arguments: search_query {str} -- a string to search for limit {int} -- the maximum number of results to return branch_limit {int} -- the maximum number of branches to return commit_limit {int} -- the maximum number of commits to return Returns: List[Stream] -- a list of Streams that match the search query """ metrics.track(metrics.STREAM_SEARCH) query = gql(""" query StreamSearch($search_query: String!,$limit: Int!, $branch_limit:Int!, $commit_limit:Int!) { streams(query: $search_query, limit: $limit) { items { id name description isPublic createdAt updatedAt collaborators { id name role avatar } branches(limit: $branch_limit) { totalCount cursor items { id name description commits(limit: $commit_limit) { totalCount cursor items { id referencedObject message authorName authorId createdAt } } } } } } } """) params = { "search_query": search_query, "limit": limit, "branch_limit": branch_limit, "commit_limit": commit_limit, } return self.make_request(query=query, params=params, return_type=["streams", "items"])