This repository has been archived by the owner on Jan 18, 2024. It is now read-only.
generated from ethho/poetry-demo
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4 from ethho/dev-v0.1.0
PLAT-180: Release v0.1.0
- Loading branch information
Showing
79 changed files
with
5,144 additions
and
448 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
name: Build GitHub Pages Documentation | ||
|
||
on: | ||
push: | ||
branches: | ||
- main | ||
paths: | ||
- "docs/**.md" | ||
- "mkdocs.yml" | ||
workflow_dispatch: | ||
|
||
jobs: | ||
docs: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v2 | ||
with: | ||
fetch-depth: 0 | ||
- uses: actions/setup-python@v2 | ||
with: | ||
python-version: 3.11 | ||
- name: Install Python dependencies | ||
run: | | ||
pipx install poetry | ||
poetry config virtualenvs.create false | ||
poetry install --with docs --sync | ||
- name: Setup git | ||
run: | | ||
git config --global user.name 'github-actions[bot]' | ||
git config --global user.email 'github-actions[bot]@users.noreply.github.com' | ||
- name: Publish docs | ||
run: poetry run mkdocs gh-deploy |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
name: Test | ||
|
||
on: | ||
push: | ||
branches: | ||
- main | ||
paths-ignore: | ||
- '**.md' | ||
- 'docs/**' | ||
- 'docsrc/**' | ||
|
||
pull_request: | ||
branches: | ||
- main | ||
paths-ignore: | ||
- '**.md' | ||
- 'docs/**' | ||
- 'docsrc/**' | ||
|
||
jobs: | ||
test: | ||
name: Run unit tests | ||
runs-on: ubuntu-latest | ||
strategy: | ||
matrix: | ||
python-version: | ||
- "3.7" | ||
- "3.8" | ||
- "3.9" | ||
- "3.10" | ||
- "3.11" | ||
steps: | ||
- uses: actions/checkout@v2 | ||
- name: Set up Python ${{ matrix.python-version }} | ||
uses: actions/setup-python@v2 | ||
with: | ||
python-version: ${{ matrix.python-version }} | ||
- name: Install Python dependencies | ||
run: | | ||
pipx install poetry | ||
poetry install --with 'dev,docs' --sync | ||
- name: Run all pytests | ||
run: poetry run pytest --cov-report term-missing --cov=datajoint_file_validator tests | ||
- name: Check formatting with black | ||
run: | | ||
poetry run black --check datajoint_file_validator tests |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
## Release Notes | ||
|
||
<!-- ### Upcoming --> | ||
|
||
### 0.1.1 -- March 1, 2024 | ||
<!-- - d --> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
import os | ||
from typing import Optional, Dict, Any, Union, get_type_hints, get_args, get_origin | ||
from dotenv import dotenv_values | ||
|
||
|
||
class BaseSettings: | ||
"""Settings class for an application. Mimics Pydantic's BaseSettings.""" | ||
|
||
ENV_PATH = ".env" | ||
|
||
# Define settings attributes here | ||
# my_config_val: str = "default value" | ||
# my_optional_attr: Optional[str] = None | ||
|
||
# Setting MY_FLAG=1 in .env will set this to True | ||
# my_flag: bool = False | ||
|
||
# Setting env var MY_CASTED_ATTR='4' will try to cast this as int first, then str | ||
# my_casted_attr: Union[int, str] = 2 | ||
|
||
@staticmethod | ||
def _cast_val(val: str, type_annot: Optional[Any]) -> Any: | ||
""" | ||
Cast a string `val` to the type of `type_annot`. | ||
""" | ||
if val is None: | ||
return None | ||
if type_annot is None: | ||
return val | ||
if type_annot is bool: | ||
if str(val).lower() in ["true", "1"]: | ||
return True | ||
elif str(val).lower() in ["false", "0"]: | ||
return False | ||
else: | ||
raise ValueError(f"Failed to parse '{val}' as bool.") | ||
|
||
# Handle generic types | ||
if get_origin(type_annot) is Union: # includes Optional | ||
for constr in get_args(type_annot): | ||
try: | ||
return constr(val) | ||
except (TypeError, ValueError): | ||
continue | ||
elif get_origin(type_annot) is not None: | ||
raise TypeError( | ||
f"Cannot parse '{val}' as instance of '{type_annot.__name__}'." | ||
) | ||
else: | ||
constr = type_annot | ||
|
||
# Cast to type | ||
try: | ||
return constr(val) | ||
except (TypeError, ValueError) as e: | ||
raise TypeError( | ||
f"Failed to parse '{val}' as instance of '{type_annot.__name__}'." | ||
) from e | ||
|
||
def _populate_from_dot_env(self, env_path: str): | ||
""" | ||
Set attributes from a .env file at `env_path`. | ||
""" | ||
d = dotenv_values(env_path) | ||
self._populate_from_dict(d, match_upper=True) | ||
|
||
def _populate_from_env_vars(self): | ||
""" | ||
Set attributes from environment variables. | ||
""" | ||
d = os.environ | ||
self._populate_from_dict(d, match_upper=True) | ||
|
||
def _populate_from_dict(self, d: Dict[str, Any], match_upper: bool = False): | ||
""" | ||
Set attributes from a dictionary `d`. | ||
Skips setting attributes that are upper-cased, start with an underscore, | ||
are callable, have no type annotation, or are not class attributes. | ||
""" | ||
attrs = { | ||
**get_type_hints(self), | ||
# Include attribute names that have no type annotation but a default value | ||
**self.__class__.__dict__, | ||
} | ||
for k in attrs: | ||
key_in_d = k.upper() if match_upper else k | ||
if ( | ||
k.upper() == k | ||
or k.startswith("_") | ||
or callable(getattr(self, k, None)) | ||
or key_in_d not in d | ||
): | ||
continue | ||
val = d[key_in_d] | ||
|
||
type_annot = get_type_hints(self).get(k) | ||
try: | ||
setattr(self, k, self._cast_val(val, type_annot)) | ||
except (TypeError, ValueError) as e: | ||
raise ValueError( | ||
f"Error parsing {key_in_d}={val} as {type_annot}: {e}" | ||
) from e | ||
|
||
def __init__(self, env_path: Optional[str] = None, **values): | ||
""" | ||
Create a new settings object, which allows settings to imported from | ||
environment variables, .env files, and keyword arguments, and accessed | ||
as attributes. Attributes will be set in the following order: | ||
1. From default values set in the class definition. | ||
2. From a .env file at `env_path` (default: `.env`) | ||
3. From environment variables. Environment variables are matched to | ||
attributes by upper-casing the attribute name. e.g. to set the | ||
attribute `my_attr`, set the environment variable `MY_ATTR`. | ||
4. From keyword arguments passed as `**values` to this constructor. | ||
The successive step will overwrite any previously set attributes. | ||
Attribute names that are upper-cased in the class definition, start | ||
with an underscore, are callable, have no type annotation, or are not | ||
class attributes will be ignored. | ||
Parameters | ||
---------- | ||
env_path : str | ||
Path to a .env file. Will be set to `.env` by default. | ||
**values : Any | ||
Keyword arguments to set as attributes. | ||
""" | ||
if not hasattr(self, "__annotations__"): | ||
self.__annotations__ = {} | ||
|
||
self._populate_from_dict(self.__class__.__dict__) # From default values | ||
env_path = env_path or self.ENV_PATH | ||
if os.path.isfile(env_path): | ||
self._populate_from_dot_env(env_path) | ||
self._populate_from_env_vars() | ||
if values: | ||
self._populate_from_dict(values) | ||
|
||
# Check that all attributes have been set | ||
unset_attrs = [] | ||
for k in get_type_hints(self): | ||
if k.upper() == k or k.startswith("_"): | ||
continue | ||
if not hasattr(self, k): | ||
unset_attrs.append(k) | ||
if unset_attrs: | ||
raise ValueError(f"Missing values for attributes: {unset_attrs}") |
Oops, something went wrong.