Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1. added possibility to download file with context manager #240

Closed
wants to merge 1 commit into from
Closed

1. added possibility to download file with context manager #240

wants to merge 1 commit into from

Conversation

beliaev-maksim
Copy link
Contributor

Not sure if this function is not implemented in different way.

If already there please let me know and I will recreate example for such scenario

@vgrem
Copy link
Owner

vgrem commented Jul 31, 2020

Greetings!

Thanks for the proposal!

Although your scenario is supported and with current implementation file could be downloaded like this (from abs url)

abs_file_url = "{site_url}sites/team/Shared Documents/sample.docx".format(site_url=settings.get('url'))
user_credentials = UserCredential(username, password)


file_name = os.path.basename(abs_file_url)
with tempfile.TemporaryDirectory() as local_path:
    with open(os.path.join(local_path, file_name), 'wb') as local_file:
        file = File.from_url(abs_file_url).with_credentials(user_credentials).download(local_file).execute_query()
    print("'{0}' file has been downloaded into {1}".format(file.serverRelativeUrl, local_file.name)) 

In a similar manner file could be downloaded by server relative url, refer download_file.py example for a details.

Introducing with_context looks like syntactic sugar for me does not seem to bring any value , any entity at the moment exposes context property (read-only)

@vgrem vgrem closed this Jul 31, 2020
@beliaev-maksim
Copy link
Contributor Author

@vgrem

yes, that makes sense. Actually first example does not support Context with App auth. Or is there a method in File class?

while second example works fine for this type but uses directly context manager, which is fine

@beliaev-maksim
Copy link
Contributor Author

@vgrem
actually I made a mistake when said that second method works

I do not see a method to download file from abs_url and using App Auth
that is why I created this modification, see example download_file_from_url_app_auth.py

or do I overlook something?

@vgrem
Copy link
Owner

vgrem commented Jul 31, 2020

@beliaev-maksim, probably you've installed the package via pip, right?

If so, unfortunately it does not correspond to the latest version, please refer this thread for the details.

Meanwhile, would recommend to download the latest version via GitHub

pip install git+https://github.com/vgrem/Office365-REST-Python-Client.git

or alternative index: https://pypi.org/project/office365-rest-client/

In the latest version file could be downloaded like this:

client_credentials = ClientCredential(client_id, client_secret)

file_name = os.path.basename(abs_file_url)
with tempfile.TemporaryDirectory() as local_path:
    with open(os.path.join(local_path, file_name), 'wb') as local_file:
        file = File.from_url(abs_file_url).with_credentials(client_credentials).download(local_file).execute_query()
    print("'{0}' file has been downloaded into {1}".format(file.serverRelativeUrl, local_file.name))

@beliaev-maksim
Copy link
Contributor Author

@vgrem

I will not exclude possibility that I am completely stupid :)

However, how does this work for App Auth?

in which place does ACSTokenProvider is executed?
In last code example it looks like just username and password
while I am referring to:

context_auth = AuthenticationContext(url=site_url)
context_auth.acquire_token_for_app(client_id=app_principal['client_id'], client_secret=app_principal['client_secret'])

@beliaev-maksim
Copy link
Contributor Author

@vgrem
Hello,
were you able to check authorisation with App Auth and download with full url in current implementation?

If you do not mind I would be glad to have a short audio call where can explain my idea

@vgrem
Copy link
Owner

vgrem commented Aug 3, 2020

Hi @beliaev-maksim,

here is a complete example which demonstrates how to:

  • authenticate via client credentials (this flow is explained here App-Only policy)

  • and finally download a file from an absolute url

root_site_url = settings.get('url')
client_credentials = ClientCredential(settings.get('client_credentials').get('client_id'),
                                      settings.get('client_credentials').get('client_secret'))

abs_file_url = "{site_url}sites/team/Shared Documents/big_buck_bunny.mp4".format(site_url=root_site_url)
with tempfile.TemporaryDirectory() as local_path:
    file_name = os.path.basename(abs_file_url)
    with open(os.path.join(local_path, file_name), 'wb') as local_file:
        file = File.from_url(abs_file_url).with_credentials(client_credentials).download(local_file).execute_query()
    print("'{0}' file has been downloaded into {1}".format(file.serverRelativeUrl, local_file.name))

We could arrange a call (if needed), but not sure when i have any spare time this week yet.

@beliaev-maksim
Copy link
Contributor Author

@vgrem

I tried this method, this does not work for me

if you go deep level by level of this solution there is no place where you call:
acquire_token() from class AuthenticationContext

so basically this method works only for standard auth with username and password

when I use method I propose I get:
'/sites/EMEA-FES-E812/Software/test.pptx' file has been downloaded into C:\Users\mbeliaev\AppData\Local\Temp\tmpy91o81_7\test.pptx

if I use example you provided:
office365.runtime.client_request_exception.ClientRequestException: ('-2147024891, System.UnauthorizedAccessException', 'Access denied. You do not have permission to perform this action or access this resource.', '403 Client Error: Forbidden for url: https://***.sharepoint.com/_api/SP.Web.GetWebUrlFromPageUrl')

@vgrem
Copy link
Owner

vgrem commented Aug 3, 2020

@beliaev-maksim , you know what, it appears you are right and spotted the bug, it appears context is getting lost is this case, will double check and get back to you.

@vgrem
Copy link
Owner

vgrem commented Aug 4, 2020

Hey,

the latest version available from GitHub contains a fix to prevent File.from_url method from losing context.

Could you give it another shot?

@beliaev-maksim
Copy link
Contributor Author

@vgrem
Hi,
I do not think this fixes the issue

I use following code with the latest pull from upstream
(I took part from updated example)

import os
import tempfile

from settings import settings
from office365.runtime.auth.client_credential import ClientCredential
from office365.sharepoint.files.file import File

root_site_url = settings.get('url')
client_credentials = ClientCredential(os.environ.get('sp_client_id'),
                                      os.environ.get('sp_client_secret'))

abs_file_url = "https://****.sharepoint.com/sites/EMEA-FES-E812/Software/****/****.pptx"
with tempfile.TemporaryDirectory() as local_path:
    file_name = os.path.basename(abs_file_url)
    with open(os.path.join(local_path, file_name), 'wb') as local_file:
        file = File.from_url(abs_file_url).with_credentials(client_credentials).download(local_file).execute_query()
    print("'{0}' file has been downloaded into {1}".format(file.serverRelativeUrl, local_file.name))

error is the same and I think this is again because we do not acquire token in this method

In this case I would say with_context method simplifies how library should behave. Basically if methods changed/added the method will still work. I see the concern about protecting context property. So may be we can fix a bug in different way

we can reset the call today

@kkarthik21
Copy link

Even i had similar use case and i tried in latest v2.1.10.1, it shows ValueError: Unknown credential type. please clarify.

@rorokaloom
Copy link

I also tried the above code and get the following error using client id/secret:
('-2147024891, System.UnauthorizedAccessException', 'Access denied. You do not have permission to perform this action or access this resource.', "403 Client Error: Forbidden for url:
Downloaded via:
pip install git+https://github.com/vgrem/Office365-REST-Python-Client.gi

Can someone perhaps provide a solution if there is one without using username/password?

@beliaev-maksim
Copy link
Contributor Author

@kkarthik21 @Bobroro

you can use solution from my fork:
https://github.com/beliaev-maksim/Office365-REST-Python-Client/tree/context_download

branch with fix is called: context_download

@rorokaloom
Copy link

@beliaev-maksim Can I also upload with your fork via the context? Not sure if upload was ever a problem with this but it was something I was going to try after getting a download to work.

@beliaev-maksim
Copy link
Contributor Author

@Bobroro

should work. see example in download_file_from_url_app_auth.py

there you get a context.
then by combining with upload_file.py it should work

smth like following:

import os
from office365.sharepoint.client_context import ClientContext
from office365.runtime.auth.authentication_context import AuthenticationContext

site_url = "https://company.sharepoint.com/sites/my-team/"
app_principal = {
    'client_id': 'client ID',
    'client_secret': 'client Secret',
}

context_auth = AuthenticationContext(url=site_url)
context_auth.acquire_token_for_app(client_id=app_principal['client_id'], client_secret=app_principal['client_secret'])

ctx = ClientContext(site_url, context_auth)

path = "../../../tests/data/SharePoint User Guide.docx"
with open(path, 'rb') as content_file:
    file_content = content_file.read()

list_title = "Documents"
target_folder = ctx.web.lists.get_by_title(list_title).rootFolder
name = os.path.basename(path)
target_file = target_folder.upload_file(name, file_content)
ctx.execute_query()
print("File url: {0}".format(target_file.serverRelativeUrl))


@rorokaloom
Copy link

rorokaloom commented Aug 19, 2020

@beliaev-maksim how do you install your fork and branch with pip?
Ok never mind, this did it:
pip install git+https://github.com/beliaev-maksim/Office365-REST-Python-Client@context_download

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants