Skip to content

Commit 82776fb

Browse files
committed
Merge master commits into refactorPZMM
2 parents f5789b7 + ed93fae commit 82776fb

File tree

13 files changed

+561
-89
lines changed

13 files changed

+561
-89
lines changed

.conda/meta.yaml

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
{% set data = load_setup_py_data(setup_file='../setup.py', from_recipe_dir=True) %}
2+
{% set name = "sasctl" %}
3+
{% set version = data.get('version') %}
4+
5+
package:
6+
name: {{ name|lower }}
7+
version: {{ data.version }}
8+
9+
source:
10+
path: ..
11+
12+
build:
13+
entry_points:
14+
- sasctl = sasctl.utils.cli:main
15+
noarch: python
16+
script: {{ PYTHON }} -m pip install . -vv
17+
number: 0
18+
19+
requirements:
20+
host:
21+
- python >=3.6
22+
- pip
23+
run:
24+
- python >=3.6
25+
- pandas
26+
- requests
27+
- pyyaml
28+
- packaging
29+
30+
test:
31+
imports:
32+
- sasctl
33+
commands:
34+
- pip check
35+
- sasctl --help
36+
requires:
37+
- pip
38+
39+
about:
40+
home: https://github.com/sassoftware/python-sasctl/
41+
summary: "Python package and CLI for user-friendly integration with SAS Viya"
42+
license: Apache-2.0
43+
license_file: LICENSE
44+
doc_url: https://sassoftware.github.io/python-sasctl/
45+
dev_url: https://github.com/sassoftware/python-sasctl/

.github/workflows/build-test-deploy.yml

Lines changed: 84 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,12 @@ jobs:
118118
name: html-docs
119119
path: ./docs/_build/html
120120

121-
build:
122-
name: "Build Package"
121+
# Build a package for distribution through PyPI.org (pip install sasctl)
122+
build_pypi:
123+
name: "Build PyPI Package"
123124
runs-on: ubuntu-latest
124125
needs: test
125-
if: startsWith(github.ref, 'refs/tags/') # run only on tagged commits
126+
if: startsWith(github.ref, 'refs/tags/') # run only on tagged commits
126127

127128
steps:
128129
- name: Checkout repository
@@ -158,38 +159,74 @@ jobs:
158159
159160
- name: Archive distribution artifacts
160161
# Archive distribution files for use by auto (or manual) PyPI upload
161-
uses: actions/upload-artifact@v2
162+
uses: actions/upload-artifact@v3
162163
with:
163164
name: pypi-dist
164165
path: ./dist
165166

166167
- name: Archive changelog artifacts
167-
uses: actions/upload-artifact@v2
168+
uses: actions/upload-artifact@v3
168169
with:
169170
name: release_notes
170171
path: release_notes.md
171172

173+
# Build a package for distribution through Anaconda.org (conda install sasctl)
174+
build_conda:
175+
name: "Build Conda Package"
176+
runs-on: ubuntu-latest
177+
needs: test
178+
if: startsWith(github.ref, 'refs/tags/') # run only on tagged commits
179+
180+
steps:
181+
# Setup Miniconda
182+
- uses: conda-incubator/setup-miniconda@v2
183+
with:
184+
auto-update-conda: true
185+
186+
- name: Install conda-build
187+
shell: bash -l {0}
188+
run: |
189+
conda install conda-build
190+
191+
- name: Checkout repository
192+
uses: actions/checkout@v3
172193

194+
# Build package and store results in .build folder
195+
- name: Build package
196+
shell: bash -l {0}
197+
run: |
198+
conda build --output-folder .build .conda
199+
200+
# Archive distribution files. Will upload in a downstream job.
201+
- name: Archive distribution artifacts
202+
uses: actions/upload-artifact@v3
203+
with:
204+
name: conda-dist
205+
path: .build
206+
207+
208+
# Publishes the new package to PyPI, uploads the latest documentation to GitHub Pages
209+
# and creates a new release with change notes on GitHub.
173210
publish:
174211
name: "Publish"
175212
runs-on: ubuntu-latest
176-
needs: [gh-pages, build]
177-
steps:
213+
needs: [gh-pages, build_pypi, build_conda]
178214

215+
steps:
179216
- name: Download documentation
180-
uses: actions/download-artifact@v2
217+
uses: actions/download-artifact@v3
181218
with:
182219
name: html-docs
183220
path: ./html-docs
184221

185222
- name: Download release
186-
uses: actions/download-artifact@v2
223+
uses: actions/download-artifact@v3
187224
with:
188225
name: pypi-dist
189226
path: ./dist
190227

191228
- name: Download release notes
192-
uses: actions/download-artifact@v2
229+
uses: actions/download-artifact@v3
193230
with:
194231
name: release_notes
195232

@@ -199,6 +236,7 @@ jobs:
199236
- name: Display structure of downloaded files
200237
run: ls -R
201238

239+
# Create a draft release on GitHub
202240
- name: Create Release
203241
id: create_release
204242
uses: softprops/action-gh-release@v1
@@ -208,6 +246,7 @@ jobs:
208246
body: ""
209247
files: documentation.zip
210248

249+
# Publish the documentation to GitHub Pages
211250
- name: Deploy documentation
212251
uses: peaceiris/actions-gh-pages@v3
213252
with:
@@ -221,10 +260,45 @@ jobs:
221260
password: ${{ secrets.PYPI_API_TOKEN }}
222261
verbose: true
223262

263+
# Publish the release on GitHub (remove draft status)
224264
- name: Publish release
225265
uses: StuYarrow/publish-release@v1
226266
env:
227267
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
228268
with:
229269
id: ${{ steps.create_release.outputs.id }}
230270

271+
272+
# Uploads the package to Anaconda.
273+
# NOTE: could be merged with `publish` job above. Left as a separate, final job since it
274+
# involves multiple steps to setup the environment and if this job fails, the package
275+
# has already been made available through pip, and the release info published.
276+
upload_conda:
277+
name: "Upload Conda Package"
278+
runs-on: ubuntu-latest
279+
needs: [publish]
280+
281+
steps:
282+
# Setup Miniconda
283+
- uses: conda-incubator/setup-miniconda@v2
284+
with:
285+
auto-update-conda: true
286+
287+
# Setup Anaconda client (required for upload)
288+
- name: Install anaconda client
289+
shell: bash -l {0}
290+
run: |
291+
conda install anaconda-client
292+
293+
# Download release files
294+
- name: Download release
295+
uses: actions/download-artifact@v3
296+
with:
297+
name: conda-dist
298+
path: ./dist
299+
300+
# Upload release to Anaconda.org
301+
- name: Upload release
302+
shell: bash -l {0}
303+
run: |
304+
anaconda -t ${{ secrets.ANACONDA_TOKEN }} upload -u sas-institute ./dist/noarch/sasctl-*.tar.bz2

CHANGELOG.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,20 @@
11
Unreleased
22
----------
3-
-
3+
**Bugfixes**
4+
- Fixed an issue where invalid HTTP responses could cause an error when using `Session.version_info()`.
5+
6+
v1.8.2 (2023-01-30)
7+
-------------------
8+
**Improvements**
9+
- `folders.get_folder()` can now handle folder paths and delegates (e.g. @public).
10+
11+
**Bugfixes**
12+
- Fixed an issue with `model_management.execute_model_workflow_definition()` where input values for
13+
workflow prompts were not correctly submitted. Note that the `input=` parameter was renamed to
14+
`prompts=` to avoid conflicting with the built-in `input()`.
15+
- Fixed an issue with `pzmm.importModel.model_exists()` where project versions were incorrectly
16+
compared, resulting in improper behavior when the project version already existed.
17+
- Better handling for invalid project versions included.
418

519
v1.8.1 (2023-01-19)
620
----------

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
The sasctl package enables easy communication between the SAS Viya
4848
platform and a Python runtime. It can be used as a module or as a command line interface.
4949
```
50-
sasctl.folders.list_folders()
50+
sasctl.services.folders.list_folders()
5151
```
5252

5353
```
@@ -89,6 +89,10 @@ install the latest source code:
8989

9090
```pip install git+https://github.com/sassoftware/python-sasctl```
9191

92+
Alternatively, if you're using Anaconda you can install with:
93+
```
94+
conda install -c sas-institute sasctl
95+
```
9296

9397
## Getting Started
9498

src/sasctl/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# Copyright © 2019, SAS Institute Inc., Cary, NC, USA. All Rights Reserved.
55
# SPDX-License-Identifier: Apache-2.0
66

7-
__version__ = "1.8.1"
7+
__version__ = "1.8.2"
88
__author__ = "SAS"
99
__credits__ = [
1010
"Yi Jian Ching",

src/sasctl/_services/folders.py

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class Folders(Service):
1919

2020
_SERVICE_ROOT = "/folders"
2121

22-
list_folders, get_folder, update_folder, delete_folder = Service._crud_funcs(
22+
list_folders, _get_folder, update_folder, delete_folder = Service._crud_funcs(
2323
"/folders", "folder"
2424
)
2525

@@ -62,3 +62,76 @@ def create_folder(cls, name, parent=None, description=None):
6262
params={"parentFolderUri": parent_uri},
6363
headers={"Content-Type": "application/vnd.sas.content.folder+json"},
6464
)
65+
66+
@classmethod
67+
def get_folder(cls, folder, refresh=False):
68+
"""Return a folder instance.
69+
70+
Parameters
71+
----------
72+
folder : str or dict
73+
May be one of:
74+
- folder name
75+
- folder ID
76+
- folder path
77+
- folder delegate string
78+
- dictionary representation of the folder
79+
refresh : bool, optional
80+
Obtain an updated copy of the folder.
81+
82+
Returns
83+
-------
84+
RestObj or None
85+
A dictionary containing the folder attributes or None.
86+
87+
Notes
88+
-------
89+
If `folder` is a complete representation of the folder it will be
90+
returned unless `refresh` is set. This prevents unnecessary REST
91+
calls when data is already available on the client.
92+
93+
Examples
94+
--------
95+
The following four examples are all functionally equivalent.
96+
97+
>>> get_folder("Public")
98+
{"name": "Public", "id": "4a737209-5662"}
99+
100+
>>> get_folder("/Public")
101+
{"name": "Public", "id": "4a737209-5662"}
102+
103+
>>> get_folder("@public")
104+
{"name": "Public", "id": "4a737209-5662"}
105+
106+
>>> get_folder("@public")
107+
{"name": "Public", "id": "4a737209-5662"}
108+
109+
>>> get_folder("4a737209-5662")
110+
{"name": "Public", "id": "4a737209-5662"}
111+
112+
The full folder path can also be specified.
113+
114+
>>> get_folder("/Public/Demo")
115+
{"name": "Demo", "id": "148081bf-1c86"}
116+
117+
Special folders can be identified using a delegate string. Currently supported
118+
are: @myFolder, @appDataFolder, @myHistory, @myFavorites, and @public.
119+
120+
>>> get_folder("@myFolder")
121+
{"name": "My Folder", "id": "71687cd2-db4b"}
122+
123+
"""
124+
# If a folder path is specified, lookup folder using the full path instead of the name.
125+
if isinstance(folder, str) and "/" in folder:
126+
# Path must include a leading "/"
127+
if not folder.startswith("/"):
128+
folder = f"/{folder}"
129+
130+
return cls.get("/folders/@item", params={"path": folder})
131+
132+
# Its possible to lookup special folders by using a handle (called a delegate string in docs)
133+
# Current values (2022.09) are @myFolder, @appDataFolder, @myHistory, @myFavorites, @public.
134+
if isinstance(folder, str) and folder.startswith("@"):
135+
return cls.get(f"/folders/{folder}")
136+
137+
return cls._get_folder(folder, refresh=refresh)

0 commit comments

Comments
 (0)