@@ -599,3 +599,224 @@ def update(self, obj, **kwargs):
599599r = self ._raw_put (url ,data = data ,content_type = 'application/json' )
600600raise_error_from_response (r ,GitlabUpdateError )
601601return r .json ()
602+
603+ def _build_url (self ,path ):
604+ """Returns the full url from path.
605+
606+ If path is already a url, return it unchanged. If it's a path, append
607+ it to the stored url.
608+
609+ This is a low-level method, different from _construct_url _build_url
610+ have no knowledge of GitlabObject's.
611+
612+ Returns:
613+ str: The full URL
614+ """
615+ if path .startswith ('http://' )or path .startswith ('https://' ):
616+ return path
617+ else :
618+ return '%s%s' % (self ._url ,path )
619+
620+ def http_request (self ,verb ,path ,query_data = {},post_data = {},
621+ streamed = False ,** kwargs ):
622+ """Make an HTTP request to the Gitlab server.
623+
624+ Args:
625+ verb (str): The HTTP method to call ('get', 'post', 'put',
626+ 'delete')
627+ path (str): Path or full URL to query ('/projects' or
628+ 'http://whatever/v4/api/projecs')
629+ query_data (dict): Data to send as query parameters
630+ post_data (dict): Data to send in the body (will be converted to
631+ json)
632+ streamed (bool): Whether the data should be streamed
633+ **kwargs: Extra data to make the query (e.g. sudo, per_page, page)
634+
635+ Returns:
636+ A requests result object.
637+
638+ Raises:
639+ GitlabHttpError: When the return code is not 2xx
640+ """
641+ url = self ._build_url (path )
642+ params = query_data .copy ()
643+ params .update (kwargs )
644+ opts = self ._get_session_opts (content_type = 'application/json' )
645+ result = self .session .request (verb ,url ,json = post_data ,
646+ params = params ,stream = streamed ,** opts )
647+ if not (200 <= result .status_code < 300 ):
648+ raise GitlabHttpError (response_code = result .status_code )
649+ return result
650+
651+ def http_get (self ,path ,query_data = {},streamed = False ,** kwargs ):
652+ """Make a GET request to the Gitlab server.
653+
654+ Args:
655+ path (str): Path or full URL to query ('/projects' or
656+ 'http://whatever/v4/api/projecs')
657+ query_data (dict): Data to send as query parameters
658+ streamed (bool): Whether the data should be streamed
659+ **kwargs: Extra data to make the query (e.g. sudo, per_page, page)
660+
661+ Returns:
662+ A requests result object is streamed is True or the content type is
663+ not json.
664+ The parsed json data otherwise.
665+
666+ Raises:
667+ GitlabHttpError: When the return code is not 2xx
668+ GitlabParsingError: IF the json data could not be parsed
669+ """
670+ result = self .http_request ('get' ,path ,query_data = query_data ,
671+ streamed = streamed ,** kwargs )
672+ if (result .headers ['Content-Type' ]== 'application/json' and
673+ not streamed ):
674+ try :
675+ return result .json ()
676+ except Exception as e :
677+ raise GitlaParsingError (
678+ message = "Failed to parse the server message" )
679+ else :
680+ return r
681+
682+ def http_list (self ,path ,query_data = {},** kwargs ):
683+ """Make a GET request to the Gitlab server for list-oriented queries.
684+
685+ Args:
686+ path (str): Path or full URL to query ('/projects' or
687+ 'http://whatever/v4/api/projecs')
688+ query_data (dict): Data to send as query parameters
689+ **kwargs: Extra data to make the query (e.g. sudo, per_page, page,
690+ all)
691+
692+ Returns:
693+ GitlabList: A generator giving access to the objects. If an ``all``
694+ kwarg is defined and True, returns a list of all the objects (will
695+ possibly make numerous calls to the Gtilab server and eat a lot of
696+ memory)
697+
698+ Raises:
699+ GitlabHttpError: When the return code is not 2xx
700+ GitlabParsingError: IF the json data could not be parsed
701+ """
702+ url = self ._build_url (path )
703+ get_all = kwargs .pop ('all' ,False )
704+ obj_gen = GitlabList (self ,url ,query_data ,** kwargs )
705+ return list (obj_gen )if get_all else obj_gen
706+
707+ def http_post (self ,path ,query_data = {},post_data = {},** kwargs ):
708+ """Make a POST request to the Gitlab server.
709+
710+ Args:
711+ path (str): Path or full URL to query ('/projects' or
712+ 'http://whatever/v4/api/projecs')
713+ query_data (dict): Data to send as query parameters
714+ post_data (dict): Data to send in the body (will be converted to
715+ json)
716+ **kwargs: Extra data to make the query (e.g. sudo, per_page, page)
717+
718+ Returns:
719+ The parsed json returned by the server.
720+
721+ Raises:
722+ GitlabHttpError: When the return code is not 2xx
723+ GitlabParsingError: IF the json data could not be parsed
724+ """
725+ result = self .http_request ('post' ,path ,query_data = query_data ,
726+ post_data = post_data ,** kwargs )
727+ try :
728+ return result .json ()
729+ except Exception as e :
730+ raise GitlabParsingError (message = "Failed to parse the server message" )
731+
732+ def http_put (self ,path ,query_data = {},post_data = {},** kwargs ):
733+ """Make a PUT request to the Gitlab server.
734+
735+ Args:
736+ path (str): Path or full URL to query ('/projects' or
737+ 'http://whatever/v4/api/projecs')
738+ query_data (dict): Data to send as query parameters
739+ post_data (dict): Data to send in the body (will be converted to
740+ json)
741+ **kwargs: Extra data to make the query (e.g. sudo, per_page, page)
742+
743+ Returns:
744+ The parsed json returned by the server.
745+
746+ Raises:
747+ GitlabHttpError: When the return code is not 2xx
748+ GitlabParsingError: IF the json data could not be parsed
749+ """
750+ result = self .hhtp_request ('put' ,path ,query_data = query_data ,
751+ post_data = post_data ,** kwargs )
752+ try :
753+ return result .json ()
754+ except Exception as e :
755+ raise GitlabParsingError (message = "Failed to parse the server message" )
756+
757+ def http_delete (self ,path ,** kwargs ):
758+ """Make a PUT request to the Gitlab server.
759+
760+ Args:
761+ path (str): Path or full URL to query ('/projects' or
762+ 'http://whatever/v4/api/projecs')
763+ **kwargs: Extra data to make the query (e.g. sudo, per_page, page)
764+
765+ Returns:
766+ True.
767+
768+ Raises:
769+ GitlabHttpError: When the return code is not 2xx
770+ """
771+ result = self .http_request ('delete' ,path ,** kwargs )
772+ return True
773+
774+
775+ class GitlabList (object ):
776+ """Generator representing a list of remote objects.
777+
778+ The object handles the links returned by a query to the API, and will call
779+ the API again when needed.
780+ """
781+
782+ def __init__ (self ,gl ,url ,query_data ,** kwargs ):
783+ self ._gl = gl
784+ self ._query (url ,query_data ,** kwargs )
785+
786+ def _query (self ,url ,query_data = {},** kwargs ):
787+ result = self ._gl .http_request ('get' ,url ,query_data = query_data ,
788+ ** kwargs )
789+ try :
790+ self ._next_url = result .links ['next' ]['url' ]
791+ except KeyError :
792+ self ._next_url = None
793+ self ._current_page = result .headers .get ('X-Page' )
794+ self ._next_page = result .headers .get ('X-Next-Page' )
795+ self ._per_page = result .headers .get ('X-Per-Page' )
796+ self ._total_pages = result .headers .get ('X-Total-Pages' )
797+ self ._total = result .headers .get ('X-Total' )
798+
799+ try :
800+ self ._data = result .json ()
801+ except Exception as e :
802+ raise GitlabParsingError (message = "Failed to parse the server message" )
803+
804+ self ._current = 0
805+
806+ def __iter__ (self ):
807+ return self
808+
809+ def __next__ (self ):
810+ return self .next ()
811+
812+ def next (self ):
813+ try :
814+ item = self ._data [self ._current ]
815+ self ._current += 1
816+ return item
817+ except IndexError :
818+ if self ._next_url :
819+ self ._query (self ._next_url )
820+ return self ._data [self ._current ]
821+
822+ raise StopIteration