Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
groups:
actions-deps:
patterns:
- "*"

# - package-ecosystem: "uv"
# directory: "/"
# schedule:
# interval: "daily"
# groups:
# dev-deps:
# dependency-type: "development"
46 changes: 29 additions & 17 deletions .github/workflows/python-app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ on:

env:
DEFAULT_PYTHON: "3.10"
RUFF_VERSION: 0.14.10
UV_VERSION: 0.9.22

permissions:
contents: read
Expand All @@ -16,13 +18,21 @@ jobs:
ruff:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v6
- uses: chartboost/ruff-action@v1
with:
args: "check --fix"
version: ${{ env.RUFF_VERSION }}
# A proposal to replace black & pylint
# - uses: chartboost/ruff-action@v1
# with:
# args: "format --check"
# version: ${{ env.RUFF_VERSION }}

black:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v6
- uses: actions/setup-python@v3
with:
python-version: ${{ env.DEFAULT_PYTHON }}
Expand All @@ -31,18 +41,19 @@ jobs:
pylint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v6
- uses: actions/setup-python@v4
with:
python-version: ${{ env.DEFAULT_PYTHON }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -r requirements-dev.txt
- name: Install uv
uses: astral-sh/setup-uv@v7
with:
version: ${{ env.UV_VERSION }}
- name: Install Requirements
run: uv sync --frozen --all-extras
- name: Run Pylint
run: |
pylint --disable=too-many-positional-arguments office365
uv run pylint office365

pytest:
runs-on: ubuntu-latest
Expand All @@ -51,16 +62,17 @@ jobs:
- black
- pylint
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v6
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v3
uses: actions/setup-python@v6
with:
python-version: ${{ env.DEFAULT_PYTHON }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -r requirements-dev.txt
- name: Install uv
uses: astral-sh/setup-uv@v7
with:
version: ${{ env.UV_VERSION }}
- name: Install Requirements
run: uv sync --frozen --all-extras
- name: Test with pytest (skip entirely if secrets missing)
env:
office365_python_sdk_securevars: ${{ secrets.OFFICE365_PYTHON_SDK_SECUREVARS }}
Expand All @@ -69,5 +81,5 @@ jobs:
echo "No secrets available; skipping pytest"; \
exit 0; \
else \
pytest; \
uv run pytest; \
fi
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ venv.bak/
# C extensions
*.so

# Caches
.mypy_cache
.ruff_cache

# Distribution / packaging
.Python
build/
Expand Down
47 changes: 38 additions & 9 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,12 +1,41 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.0.292
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
- repo: https://github.com/psf/black
rev: 23.9.1

- repo: local
hooks:
- id: pyproject-fmt
name: pyproject-fmt
entry: uv run pyproject-fmt pyproject.toml
language: system
pass_filenames: false

- id: uv-lock
name: uv lock
entry: uv lock
language: system
pass_filenames: false

- id: ruff-check
name: ruff-check
entry: uv run ruff check --fix --exit-non-zero-on-fix
language: system
pass_filenames: false

# A proposal to replace black & pylint
# - id: ruff-format
# name: ruff-format
# entry: uv run ruff format --exit-non-zero-on-fix
# language: system
# pass_filenames: false

- id: black
args:
- --quiet
name: black
entry: uv run black .
language: system
pass_filenames: false

- id: pylint
name: pylint
entry: uv run pylint office365
language: system
pass_filenames: false

43 changes: 15 additions & 28 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
## Welcome Contributors! 🎉
# Welcome Contributors! 🎉

Thank you for your interest in contributing to the Office365-REST-Python-Client library. This project provides a comprehensive Python client for Microsoft 365 and Microsoft Graph APIs.

Expand Down Expand Up @@ -34,26 +34,17 @@ cd Office365-REST-Python-Client

## Development Environment Setup

### Virtual Environment
Activate the Virtual Environment and install dependencies:

```bash
python3 -m venv venv
. venv/bin/activate # On Windows: venv\Scripts\activate
```

### Install Dependencies

```bash
pip install -r requirements.txt
pip install -r requirements-dev.txt
uv sync --all-extras
```

### Pre-commit hooks (recommended)

```bash
pip install pre-commit
pre-commit install
pre-commit run -a
uv tool install prek
prek run --all-files
```

## Code Style and Quality Standards
Expand All @@ -69,9 +60,7 @@ Line length: 121 characters (configured in `pyproject.toml`).
Run locally before pushing:

```bash
black .
ruff check .
pylint office365
prek
```

## Testing Guidelines
Expand All @@ -82,15 +71,15 @@ Most tests are end-to-end and require actual Microsoft 365 credentials.

1. Create a `.env` file in the project root:

```bash
export office365_python_sdk_securevars='{username};{password};{client_id};{client_secret}'
```
```bash
export office365_python_sdk_securevars='{username};{password};{client_id};{client_secret}'
```

2. Source the environment file:

```bash
. .env
```
```bash
. .env
```

Note: The order of values is significant because tests parse by index.

Expand Down Expand Up @@ -128,9 +117,9 @@ CI note: Full E2E tests in CI rely on repository secrets and may not run on fork

1. Create a feature branch from `master`:

```bash
git checkout -b feature/your-feature-name
```
```bash
git checkout -b feature/your-feature-name
```

2. Make your changes with clear, focused commits
3. Ensure all tests pass and quality checks are satisfied
Expand Down Expand Up @@ -180,5 +169,3 @@ This project is maintained by the community. Be respectful and constructive in a
### License

MIT License. By contributing, you agree that your contributions are licensed under these terms.


20 changes: 8 additions & 12 deletions README-dev.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,27 @@
# Installing to virtualenv
In the pipenv/poetry era one would already forget these commands...

```bash
$ python3 -m venv venv
$ . venv/bin/activate
$ pip install -r requirements.txt
$ pip install -r requirements-dev.txt
uv sync
```

# Running tests
## Running tests

Most of the tests are end-to-end - operations are invoked against actual tenant (not mocked).
So one has to configure his/her office/sharepoint credentials.
Most of the tests are end-to-end - operations are invoked against actual tenant (not mocked).
So one has to configure his/her office/sharepoint credentials.
To do so, create a file ```.env``` like this (replace the bracketed values by your values):

```
```bash
export office365_python_sdk_securevars='{username};{password};{client_id};{client_secret}'
```

This file is in .gitignore, so it will never be committed.

```bash
$ . .env # source it to export the variable
$ pytest ... # run the test(s) you need...
. .env # source it to export the variable
pytest ... # run the test(s) you need...
```

#### Configure Tenant
## Configure Tenant

Roles:

Expand Down
1 change: 0 additions & 1 deletion examples/sharepoint/files/download_from_lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
download_root_path = Path(tempfile.mkdtemp())

for item in items:

download_path = download_root_path / item.properties.get("FileDirRef").lstrip("/")
download_path.mkdir(parents=True, exist_ok=True)

Expand Down
1 change: 0 additions & 1 deletion generator/generate_model.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

from generator import load_settings
from generator.builders.type_builder import TypeBuilder
from office365.runtime.odata.v3.metadata_reader import ODataV3Reader
Expand Down
1 change: 0 additions & 1 deletion office365/azure_env.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
class AzureEnvironment(object):

Global = "Global"
"""Referred to as Azure or Azure Global."""

Expand Down
1 change: 0 additions & 1 deletion office365/directory/serviceprincipals/service_principal.py
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,6 @@ def _get_application_permissions(app_id):
return_type.value.add(app_role)

def _resolve_app():

def _after(service_principal):
_get_application_permissions(service_principal.id)

Expand Down
3 changes: 1 addition & 2 deletions office365/entity_collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from typing_extensions import Self

from office365.entity import Entity
from office365.runtime.client_object import T
from office365.runtime.client_object_collection import ClientObjectCollection
from office365.runtime.compat import is_string_type
from office365.runtime.paths.resource_path import ResourcePath
Expand All @@ -12,8 +13,6 @@
if TYPE_CHECKING:
from office365.graph_client import GraphClient

from office365.runtime.client_object import T


class EntityCollection(ClientObjectCollection[T]):
"""A collection container which represents a named collections of entities"""
Expand Down
2 changes: 1 addition & 1 deletion office365/intune/devices/detail.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def __init__(
is_compliant=None,
is_managed=None,
operating_system=None,
trust_type=None
trust_type=None,
):
"""
:param str browser: Indicates the browser information of the used for signing in.
Expand Down
2 changes: 1 addition & 1 deletion office365/intune/devices/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def approximate_last_signin_datetime(self):

@property
def compliance_expiration_datetime(self):
""" The timestamp when the device is no longer deemed compliant. The timestamp type represents date and
"""The timestamp when the device is no longer deemed compliant. The timestamp type represents date and
time information using ISO 8601 format and is always in UTC time.
For example, midnight UTC on Jan 1, 2014 is 2014-01-01T00:00:00Z. Read-only."""
return self.properties.get("complianceExpirationDateTime", datetime.min)
Expand Down
1 change: 0 additions & 1 deletion office365/migration/assessment/scanners/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ def wrapper(self):


class BaseScanner(ABC, Generic[T]):

def __init__(self, source):
# type: (T) -> None
self.source = source
Expand Down
1 change: 0 additions & 1 deletion office365/migration/assessment/scanners/list.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@


class ListScanner(BaseScanner[List]):

@property
def files_count(self):
return self._properties.get("FilesCount", None)
Expand Down
Empty file added office365/py.typed
Empty file.
Loading