Skip to content

Commit 01df8f3

Browse files
authored
Merge pull request #159 from synccomputingcode/shughes/python38-less-restrictive-deps
2 parents 39a9f73 + d7878cc commit 01df8f3

File tree

7 files changed

+95
-59
lines changed

7 files changed

+95
-59
lines changed

.github/workflows/pull-request.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ jobs:
1313
with:
1414
fetch-depth: 0
1515

16-
- name: Set up Python 3.7.x
16+
- name: Set up Python 3.8.x
1717
uses: actions/setup-python@v4
1818
with:
19-
python-version: "3.7.16"
19+
python-version: "3.8.18"
2020

2121
- name: Install dependencies
2222
run: pip install .[dev]

.github/workflows/release.yml

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,10 @@ on:
77

88
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
99
jobs:
10-
1110
release-latest:
12-
1311
permissions:
14-
id-token: write # to verify the deployment originates from an appropriate source
15-
contents: write # To allow pushing tags/etc.
12+
id-token: write # to verify the deployment originates from an appropriate source
13+
contents: write # To allow pushing tags/etc.
1614

1715
# Specify runner + deployment step
1816
runs-on: ubuntu-22.04
@@ -22,7 +20,7 @@ jobs:
2220
fetch-depth: 0
2321
- uses: actions/setup-python@v4
2422
with:
25-
python-version: "3.7.16"
23+
python-version: "3.8.18"
2624
- name: Install dependencies
2725
run: pip install .
2826
- name: version-tag
@@ -59,7 +57,7 @@ jobs:
5957
- uses: actions/checkout@v3
6058
- uses: actions/setup-python@v4
6159
with:
62-
python-version: "3.7.16"
60+
python-version: "3.8.18"
6361
- name: Install dependencies
6462
run: pip install .[dev]
6563
- name: Build docs
@@ -70,14 +68,13 @@ jobs:
7068
path: docs/_build/html
7169

7270
release-docs:
73-
7471
# Add a dependency to the build job
7572
needs: build-docs
7673

7774
# Grant GITHUB_TOKEN the permissions required to make a Pages deployment
7875
permissions:
79-
pages: write # to deploy to Pages
80-
id-token: write # to verify the deployment originates from an appropriate source
76+
pages: write # to deploy to Pages
77+
id-token: write # to verify the deployment originates from an appropriate source
8178

8279
# Deploy to the github-pages environment
8380
environment:

pyproject.toml

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -30,25 +30,26 @@ dependencies = [
3030
"boto3>=1.26.0,<2.0.0",
3131
"click~=8.1.0",
3232
"httpx~=0.23",
33-
"platformdirs",
34-
"pydantic~=1.10.0",
33+
"platformdirs~=4.0",
34+
"pydantic-settings~=2.0",
35+
"pydantic~=2.0",
3536
"python-dateutil>=2.7,<3",
36-
"tenacity~=8.2",
37+
"tenacity~=9.0",
3738
]
3839
dynamic = ["description", "version"]
3940
name = "syncsparkpy"
4041
readme = "README.md"
41-
requires-python = ">=3.7"
42+
requires-python = ">=3.8,<3.13"
4243

4344
[project.optional-dependencies]
4445
dev = [
45-
"Sphinx==4.3.0",
46-
"deepdiff==6.3.0",
47-
"pytest-asyncio==0.21.0",
48-
"pytest-env==0.8.1",
49-
"pytest==7.2.0",
50-
"respx==0.20.1",
51-
"ruff==0.7.2",
46+
"deepdiff~=6.3",
47+
"pytest-asyncio~=0.21",
48+
"pytest-env~=0.8",
49+
"pytest~=7.2",
50+
"respx~=0.20",
51+
"ruff<=1",
52+
"sphinx~=5.3",
5253
]
5354

5455
[tool.hatch.version]
@@ -73,9 +74,9 @@ pythonpath = ["."]
7374
[tool.ruff]
7475
exclude = ["artifacts/*"]
7576
line-length = 100
76-
target-version = "py37"
77+
target-version = "py38"
7778
[tool.ruff.lint]
78-
ignore = ["E501"]
79+
ignore = ["B903", "E501"]
7980
preview = true
8081
select = ["ASYNC", "B", "C9", "E", "F", "I", "PLE", "RUF", "TID", "UP", "W"]
8182

@@ -96,7 +97,7 @@ max-complexity = 10
9697

9798
[tool.pyright]
9899
pythonPlatform = "All"
99-
pythonVersion = "3.7"
100+
pythonVersion = "3.8"
100101
reportUnnecessaryTypeIgnoreComment = "error"
101102
typeCheckingMode = "standard"
102103
useLibraryCodeForTypes = false

sync/_databricks.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -684,11 +684,9 @@ def get_recommendation_cluster(
684684
# Recommendations to set these appropriately. Since we may recommend a Static cluster (i.e. a cluster
685685
# with `num_workers`) for a cluster that was originally autoscaled, we want to make sure to remove this
686686
# prior configuration
687-
if "num_workers" in cluster:
688-
del cluster["num_workers"]
687+
cluster.pop("num_workers", None)
689688

690-
if "autoscale" in cluster:
691-
del cluster["autoscale"]
689+
cluster.pop("autoscale", None)
692690

693691
recommendation_cluster = deep_update(cluster, recommendation["configuration"])
694692

sync/clients/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ def __init__(self, client: Union[httpx.Client, httpx.AsyncClient]):
4747
self._client: Union[httpx.Client, httpx.AsyncClient] = client
4848

4949
def _send_request(self, request: httpx.Request) -> httpx.Response:
50+
response = None
5051
try:
5152
for attempt in Retrying(
5253
stop=stop_after_attempt(20),

sync/config.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
from urllib.parse import urlparse
99

1010
import boto3 as boto
11-
from pydantic import BaseSettings, Extra, Field, validator
11+
from pydantic import Extra, Field, validator
12+
from pydantic_settings import BaseSettings
1213

1314
CREDENTIALS_FILE = "credentials"
1415
CONFIG_FILE = "config"
@@ -33,7 +34,11 @@ class APIKey(BaseSettings):
3334
class Config:
3435
@classmethod
3536
def customise_sources(cls, init_settings, env_settings, file_secret_settings):
36-
return (init_settings, env_settings, json_config_settings_source(CREDENTIALS_FILE))
37+
return (
38+
init_settings,
39+
env_settings,
40+
json_config_settings_source(CREDENTIALS_FILE),
41+
)
3742

3843

3944
class Configuration(BaseSettings):
@@ -44,13 +49,19 @@ class Config:
4449

4550
@classmethod
4651
def customise_sources(cls, init_settings, env_settings, file_secret_settings):
47-
return (init_settings, env_settings, json_config_settings_source(CONFIG_FILE))
52+
return (
53+
init_settings,
54+
env_settings,
55+
json_config_settings_source(CONFIG_FILE),
56+
)
4857

4958

5059
class DatabricksConf(BaseSettings):
5160
host: str = Field(..., env="DATABRICKS_HOST")
5261
token: str = Field(..., env="DATABRICKS_TOKEN")
53-
aws_region_name: str = Field(boto.client("s3").meta.region_name, env="DATABRICKS_AWS_REGION")
62+
aws_region_name: str = Field(
63+
boto.client("s3").meta.region_name, env="DATABRICKS_AWS_REGION"
64+
)
5465

5566
@validator("host")
5667
def validate_host(cls, host):

sync/models.py

Lines changed: 54 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,9 @@ class AccessReportLine:
5757

5858
class AccessReport(List[AccessReportLine]):
5959
def __str__(self):
60-
return "\n".join(f"{line.name}\n {line.status}: {line.message}" for line in self)
60+
return "\n".join(
61+
f"{line.name}\n {line.status}: {line.message}" for line in self
62+
)
6163

6264
def add_boto_method_call(
6365
self,
@@ -95,15 +97,15 @@ def __str__(self):
9597

9698

9799
class ProjectError(Error):
98-
code: str = Field("Project Error", const=True)
100+
code: str = "Project Error"
99101

100102

101103
class RecommendationError(Error):
102-
code: str = Field("Recommendation Error", const=True)
104+
code: str = "Recommendation Error"
103105

104106

105107
class SubmissionError(Error):
106-
code: str = Field("Submission Error", const=True)
108+
code: str = "Submission Error"
107109

108110

109111
@unique
@@ -139,13 +141,13 @@ class AzureDatabricksClusterReport(DatabricksClusterReport):
139141

140142

141143
class DatabricksError(Error):
142-
code: str = Field("Databricks Error", const=True)
144+
code: str = "Databricks Error"
143145

144146

145147
class MissingOrIncompleteEventlogError(Error):
146148
dbfs_eventlog_file_size: Union[int, None] = None
147-
code: str = Field("Retryable Databricks Error", const=True)
148-
message: str = Field("Event log was missing or incomplete. Please retry.", const=True)
149+
code: str = "Retryable Databricks Error"
150+
message: str = "Event log was missing or incomplete. Please retry."
149151

150152

151153
class DatabricksAPIError(Error):
@@ -162,8 +164,8 @@ def validate_error(cls, values):
162164

163165

164166
class Response(GenericModel, Generic[DataType]):
165-
result: Union[DataType, None]
166-
error: Union[Error, None]
167+
result: Union[DataType, None] = None
168+
error: Union[Error, None] = None
167169

168170
@validator("error", always=True)
169171
def check_consistency(cls, err, values):
@@ -265,9 +267,13 @@ class AwsRegionEnum(str, Enum):
265267
"Statement": [
266268
{
267269
"Effect": "Allow",
268-
"Principal": {"AWS": "arn:aws:iam::533267411813:role/sync-computing-collector"},
270+
"Principal": {
271+
"AWS": "arn:aws:iam::533267411813:role/sync-computing-collector"
272+
},
269273
"Action": "sts:AssumeRole",
270-
"Condition": {"StringEquals": {"sts:ExternalId": "PLACEHOLDER_EXTERNAL_ID"}},
274+
"Condition": {
275+
"StringEquals": {"sts:ExternalId": "PLACEHOLDER_EXTERNAL_ID"}
276+
},
271277
}
272278
],
273279
}
@@ -276,15 +282,15 @@ class AwsRegionEnum(str, Enum):
276282
class AwsHostedIAMInstructions(BaseModel):
277283
step_1_prompt: str = "Step 1: Copy the JSON and paste in AWS IAM Permissions page:"
278284
step_1_value: str = json.dumps(IAMRoleRequiredPermissions)
279-
step_2_prompt: str = (
280-
"Step 2: Copy the JSON and paste in AWS IAM Trust relationships page with External ID:"
281-
)
285+
step_2_prompt: str = "Step 2: Copy the JSON and paste in AWS IAM Trust relationships page with External ID:"
282286
external_id: str
283287

284288
@property
285289
def step_2_value(self) -> str:
286290
policy = copy.deepcopy(IAMRoleTrustPolicy)
287-
policy["Statement"][0]["Condition"]["StringEquals"]["sts:ExternalId"] = self.external_id
291+
policy["Statement"][0]["Condition"]["StringEquals"]["sts:ExternalId"] = (
292+
self.external_id
293+
)
288294
return json.dumps(policy)
289295

290296

@@ -299,16 +305,26 @@ class ComputeProviderHostedValues(BaseModel):
299305
class CreateWorkspaceConfig(BaseModel):
300306
workspace_id: str = Field(..., description="Unique identifier for the workspace")
301307
databricks_host: str = Field(..., description="Databricks service host URL")
302-
databricks_token: str = Field(..., description="Authentication token for Databricks service")
303-
sync_api_key_id: str = Field(..., description="API Key ID for synchronization service")
304-
sync_api_key_secret: str = Field(..., description="API Key secret for synchronization service")
305-
instance_profile_arn: Optional[str] = Field(None, description="AWS instance profile ARN")
308+
databricks_token: str = Field(
309+
..., description="Authentication token for Databricks service"
310+
)
311+
sync_api_key_id: str = Field(
312+
..., description="API Key ID for synchronization service"
313+
)
314+
sync_api_key_secret: str = Field(
315+
..., description="API Key secret for synchronization service"
316+
)
317+
instance_profile_arn: Optional[str] = Field(
318+
None, description="AWS instance profile ARN"
319+
)
306320
webhook_id: Optional[str] = Field(None, description="Webhook ID for notifications")
307321
databricks_plan_type: DatabricksPlanType = Field(
308322
DatabricksPlanType.STANDARD, description="Plan type for Databricks deployment"
309323
)
310324
aws_region: Optional[str] = Field(None, description="AWS region if applicable")
311-
cluster_policy_id: Optional[str] = Field(None, description="Cluster policy ID for Databricks")
325+
cluster_policy_id: Optional[str] = Field(
326+
None, description="Cluster policy ID for Databricks"
327+
)
312328
collection_type: WorkspaceCollectionTypeEnum = Field(
313329
..., description="Type of hosting for the workspace"
314330
)
@@ -318,10 +334,18 @@ class CreateWorkspaceConfig(BaseModel):
318334
compute_provider: ComputeProvider = Field(
319335
..., description="Cloud provider for compute resources"
320336
)
321-
external_id: Optional[str] = Field(None, description="External ID for AWS configurations")
322-
aws_iam_role_arn: Optional[str] = Field(None, description="AWS IAM role ARN if needed")
323-
azure_tenant_id: Optional[str] = Field(None, description="Azure tenant ID if using Azure")
324-
azure_client_id: Optional[str] = Field(None, description="Azure client ID if using Azure")
337+
external_id: Optional[str] = Field(
338+
None, description="External ID for AWS configurations"
339+
)
340+
aws_iam_role_arn: Optional[str] = Field(
341+
None, description="AWS IAM role ARN if needed"
342+
)
343+
azure_tenant_id: Optional[str] = Field(
344+
None, description="Azure tenant ID if using Azure"
345+
)
346+
azure_client_id: Optional[str] = Field(
347+
None, description="Azure client ID if using Azure"
348+
)
325349
azure_client_secret: Optional[str] = Field(
326350
None, description="Azure client secret if using Azure"
327351
)
@@ -352,7 +376,9 @@ def check_aws_iam_role_arn(cls, aws_iam_role_arn, values):
352376
compute_provider = values.get("compute_provider")
353377
if values.get("collection_type") == WorkspaceCollectionTypeEnum.HOSTED:
354378
if compute_provider == ComputeProvider.AWS and not aws_iam_role_arn:
355-
raise ValueError("AWS IAM Role ARN is required for AWS compute provider")
379+
raise ValueError(
380+
"AWS IAM Role ARN is required for AWS compute provider"
381+
)
356382
return aws_iam_role_arn
357383

358384
@validator("compute_provider", pre=False)
@@ -367,7 +393,9 @@ def check_azure_hosted_fields(cls, compute_provider, values):
367393
"azure_client_secret",
368394
"azure_subscription_id",
369395
]
370-
missing_fields = [field for field in required_fields if not values.get(field)]
396+
missing_fields = [
397+
field for field in required_fields if not values.get(field)
398+
]
371399
if missing_fields:
372400
raise ValueError(
373401
f"Missing required fields for Azure compute provider: "

0 commit comments

Comments
 (0)