Skip to content

property

notion.property

RESEARCH_API_PATH module-attribute

RESEARCH_API_PATH = 'http://data.saige.in:8000/workspaces/notion/research_api_token.txt'

PROPERTIES module-attribute

PROPERTIES = {}

Filter

Filter(filter_: dict)

Filter class for handling Notion Filter object. Please see https://developers.notion.com/reference/post-database-query-filter for detail.

You can now query to notion DB with filtering as following:

import SaigeToolkit.SaigeToolkit.notion as notion
filter_1 = notion.property.Select.get_filter("select_col", "equals", "sel1")
filter_2 = notion.property.Number.get_filter("number_col", "does_not_equal", 10)
filter_3 = notion.property.Checkbox.get_filter("checkbox_col", "does_not_equal", True)
filter_4 = notion.filter.Filter.compound("and", [filter_1, filter_2, filter_3])
_, _, results = notion.database.query_database(
    db_id,
    RESEARCH_API_PATH,
    request_body=filter_4.to_dict()
)

See notion.so/8cd58f07a254405ebb1bc327d690c8aa for more examples.

Source code in ResearchToolkit/notion/filter.py
def __init__(self, filter_: dict):
    assert isinstance(filter_, dict)
    self.filter = filter_

filter instance-attribute

filter = filter_

to_dict

to_dict()
Source code in ResearchToolkit/notion/filter.py
def to_dict(self):
    keys = list(self.filter.keys())
    if "property" in keys:
        return {"filter": self.filter}
    assert len(keys) == 1 and keys[0] in ["or", "and"]
    return {
        "filter": {keys[0]: [filter_.to_dict().get("filter") for filter_ in self.filter[keys[0]]]}
    }

compound classmethod

compound(op: str, filters: List[object])
Source code in ResearchToolkit/notion/filter.py
@classmethod
def compound(cls, op: str, filters: List[object]):
    assert op in {"or", "and"}
    return cls({op: filters})

BasicProperty

BasicProperty(value, **kwargs)

Notion database basic properties are implemented. It converts values into property object structures specified by the notion api. Additionally, it can check whether given value is valid for the property. Note that status property is not implemented due to the limited notion api capabilites.

Source code in ResearchToolkit/notion/property.py
def __init__(self, value, **kwargs):
    self.value = value

value instance-attribute

value = value

__init_subclass__

__init_subclass__(**kwargs)
Source code in ResearchToolkit/notion/property.py
def __init_subclass__(cls, **kwargs):
    super().__init_subclass__(**kwargs)
    name = pascal_to_snake(cls.__name__)
    cls.name = (
        name.replace("text", "rich_text")
        .replace("person", "people")
        .replace("phone", "phone_number")
    )
    cls.filter_ops = get_avaliable_filter_ops(cls.name)
    register(cls, name)

__call__

__call__()
Source code in ResearchToolkit/notion/property.py
def __call__(self):
    return {self.name: self.value}

get_value classmethod

get_value(property_: dict)

extracts values from a property object structure specified by the notion api. (opposite operation of call method)

Parameters:

  • property_ (dict) –

    property dictionary output of notion api. must include "type" key.

Returns:

  • _type_

    value of given property. ex) 3.14 in above example.

Source code in ResearchToolkit/notion/property.py
@classmethod
def get_value(cls, property_: dict):
    """
    extracts values from a property object structure specified by the notion api.
    (opposite operation of __call__ method)


    Args:
        property_ (dict): property dictionary output of notion api. must include "type" key.
        ex)
        {
            "type": "number",
            "number": 3.14
        }

    Returns:
        _type_: value of given property. ex) 3.14 in above example.
    """
    return property_[property_["type"]]

get_filter classmethod

get_filter(property_name, filter_op, filter_val)
Source code in ResearchToolkit/notion/property.py
@classmethod
def get_filter(cls, property_name, filter_op, filter_val):
    assert filter_op in cls.filter_ops.keys()
    assert isinstance(filter_val, cls.filter_ops[filter_op])
    return Filter({"property": property_name, f"{cls.name}": {filter_op: filter_val}})

Text

Text(value, **kwargs)

Bases: BasicProperty

Source code in ResearchToolkit/notion/property.py
def __init__(self, value, **kwargs):
    self.value = value

__bool__

__bool__()
Source code in ResearchToolkit/notion/property.py
def __bool__(self):
    return isinstance(self.value, str)

__call__

__call__()
Source code in ResearchToolkit/notion/property.py
def __call__(self):
    return {self.name: [{"text": {"content": self.value}}]}

get_value classmethod

get_value(property_: dict)
Source code in ResearchToolkit/notion/property.py
@classmethod
def get_value(cls, property_: dict):
    return "".join([text[text["type"]]["content"] for text in property_[property_["type"]]])

Title

Title(value, **kwargs)

Bases: Text

Source code in ResearchToolkit/notion/property.py
def __init__(self, value, **kwargs):
    self.value = value

Number

Number(value, **kwargs)

Bases: BasicProperty

Source code in ResearchToolkit/notion/property.py
def __init__(self, value, **kwargs):
    self.value = value

__bool__

__bool__()
Source code in ResearchToolkit/notion/property.py
def __bool__(self):
    return isinstance(self.value, (float, int))

Select

Select(value, **kwargs)

Bases: BasicProperty

Source code in ResearchToolkit/notion/property.py
def __init__(self, value, **kwargs):
    self.value = value

__bool__

__bool__()
Source code in ResearchToolkit/notion/property.py
def __bool__(self):
    return isinstance(self.value, str)

__call__

__call__()
Source code in ResearchToolkit/notion/property.py
def __call__(self):
    return {self.name: {"name": self.value}}

get_value classmethod

get_value(property_: dict)
Source code in ResearchToolkit/notion/property.py
@classmethod
def get_value(cls, property_: dict):
    if property_["select"] is None:
        return None
    else:
        return property_["select"]["name"]

MultiSelect

MultiSelect(value, **kwargs)

Bases: BasicProperty

value should be a string or list of strings.

Source code in ResearchToolkit/notion/property.py
def __init__(self, value, **kwargs):
    self.value = value

__bool__

__bool__()
Source code in ResearchToolkit/notion/property.py
def __bool__(self):
    return isinstance(self.value, list) or isinstance(self.value, str)

__call__

__call__()
Source code in ResearchToolkit/notion/property.py
def __call__(self):
    if not isinstance(self.value, list):
        value = [self.value]
    else:
        value = self.value
    return {self.name: [{"name": v} for v in value]}

get_value classmethod

get_value(property_: dict)
Source code in ResearchToolkit/notion/property.py
@classmethod
def get_value(cls, property_: dict):
    return [p["name"] for p in property_["multi_select"]]

Date

Date(value, **kwargs)

Bases: BasicProperty

date should be in iso-format.

Source code in ResearchToolkit/notion/property.py
def __init__(self, value, **kwargs):
    self.value = value

__bool__

__bool__()
Source code in ResearchToolkit/notion/property.py
def __bool__(self):
    def check_isoformat(date):
        try:
            datetime.fromisoformat(date)
            return True
        except ValueError:
            print("date is not in iso-format")
            return False

    if isinstance(self.value, (tuple, list)):
        if len(self.value) > 2:
            return False
        else:
            return all(check_isoformat(date) for date in self.value)
    else:
        return check_isoformat(self.value)

__call__

__call__()
Source code in ResearchToolkit/notion/property.py
def __call__(self):
    if isinstance(self.value, (tuple, list)):
        if len(self.value) == 2:
            date = {"start": self.value[0], "end": self.value[1]}
        else:
            date = {"start": self.value[0]}
    else:
        date = {"start": self.value}
    return {self.name: date}

Person

Person(value, **kwargs)

Bases: BasicProperty

value should be either name or email used in Notion.

Source code in ResearchToolkit/notion/property.py
def __init__(self, value, **kwargs):
    self.value = value

users class-attribute instance-attribute

users = get_notion_users()

user_names class-attribute instance-attribute

user_names = {name: (info['id'])for (name, info) in (items())}

user_emails class-attribute instance-attribute

user_emails = {(info['email']): (info['id'])for info in (values())}

validate_member

validate_member(person)
Source code in ResearchToolkit/notion/property.py
def validate_member(self, person):
    if person in self.user_names or person in self.user_emails:
        return True
    else:
        return False

get_id

get_id(person)
Source code in ResearchToolkit/notion/property.py
def get_id(self, person):
    if "@" in person:
        id_ = self.user_emails[person]
    else:
        id_ = self.user_names[person]
    return id_

__bool__

__bool__()
Source code in ResearchToolkit/notion/property.py
def __bool__(self):
    if isinstance(self.value, list):
        return all(self.validate_member(v) for v in self.value)
    else:
        return self.validate_member(self.value)

__call__

__call__()
Source code in ResearchToolkit/notion/property.py
def __call__(self):
    if not isinstance(self.value, list):
        value = [self.value]
    else:
        value = self.value
    return {self.name: [{"id": self.get_id(v)} for v in value]}

get_person_with_user_info classmethod

get_person_with_user_info(user_name=None, user_email=None)
Source code in ResearchToolkit/notion/property.py
@classmethod
def get_person_with_user_info(cls, user_name=None, user_email=None):
    for user_info in [user_name, user_email]:
        person = cls(user_info)
        if person:
            return person

    raise Exception("user cannot be identifed")

get_value classmethod

get_value(property_: dict)
Source code in ResearchToolkit/notion/property.py
@classmethod
def get_value(cls, property_: dict):
    return [p["name"] for p in property_["people"]]

Files

Files(value, file_name='unknown')

Bases: BasicProperty

only files on remotes can be uploaded.

Source code in ResearchToolkit/notion/property.py
def __init__(self, value, file_name="unknown"):
    super(Files, self).__init__(value)
    self.file_name = file_name

file_name instance-attribute

file_name = file_name

__bool__

__bool__()
Source code in ResearchToolkit/notion/property.py
def __bool__(self):
    response = requests.get(self.value)
    return response.status_code == 200

__call__

__call__()
Source code in ResearchToolkit/notion/property.py
def __call__(self):
    return {self.name: [{"name": self.file_name, "file": {"url": self.value}}]}

get_value classmethod

get_value(property_: dict)
Source code in ResearchToolkit/notion/property.py
@classmethod
def get_value(cls, property_: dict):
    return [p["file"]["url"] for p in property_["files"]]

Checkbox

Checkbox(value, **kwargs)

Bases: BasicProperty

Source code in ResearchToolkit/notion/property.py
def __init__(self, value, **kwargs):
    self.value = value

__bool__

__bool__()
Source code in ResearchToolkit/notion/property.py
def __bool__(self):
    return isinstance(self.value, bool)

Url

Url(value, **kwargs)

Bases: BasicProperty

Source code in ResearchToolkit/notion/property.py
def __init__(self, value, **kwargs):
    self.value = value

__bool__

__bool__()
Source code in ResearchToolkit/notion/property.py
def __bool__(self):
    return isinstance(self.value, str)

Email

Email(value, **kwargs)

Bases: BasicProperty

Source code in ResearchToolkit/notion/property.py
def __init__(self, value, **kwargs):
    self.value = value

__bool__

__bool__()
Source code in ResearchToolkit/notion/property.py
def __bool__(self):
    return isinstance(self.value, str)

Phone

Phone(value, **kwargs)

Bases: BasicProperty

Source code in ResearchToolkit/notion/property.py
def __init__(self, value, **kwargs):
    self.value = value

__bool__

__bool__()
Source code in ResearchToolkit/notion/property.py
def __bool__(self):
    return isinstance(self.value, str)

Relation

Relation(value, **kwargs)

Bases: BasicProperty

value should be a notion page id

Source code in ResearchToolkit/notion/property.py
def __init__(self, value, **kwargs):
    self.value = value

__bool__

__bool__()
Source code in ResearchToolkit/notion/property.py
def __bool__(self):
    token = get_token(RESEARCH_API_PATH)

    headers = {
        "Authorization": f"Bearer {token}",
        "Notion-Version": "2022-06-28",
    }

    api_url = f"https://api.notion.com/v1/pages/{self.value}"

    response = requests.get(api_url, headers=headers)

    return response.status_code == 200

__call__

__call__()
Source code in ResearchToolkit/notion/property.py
def __call__(self):
    return {self.name: [{"id": self.value}]}

get_value classmethod

get_value(property_: dict)
Source code in ResearchToolkit/notion/property.py
@classmethod
def get_value(cls, property_: dict):
    return [p["id"] for p in property_["relation"]]

get_notion_users

get_notion_users()
Source code in ResearchToolkit/notion/user.py
def get_notion_users():
    token = get_token(RESEARCH_API_PATH)

    headers = {
        "Authorization": f"Bearer {token}",
        "Notion-Version": "2022-06-28",
    }

    api_url = "https://api.notion.com/v1/users"

    response = requests.get(api_url, headers=headers)
    result = response.json()["results"]

    users = {
        user["name"]: {"id": user["id"], "email": user["person"]["email"]}
        for user in result
        if "person" in user
    }

    return users

get_token

get_token(token_path: str = RESEARCH_API_PATH)
Source code in ResearchToolkit/notion/common.py
def get_token(token_path: str = RESEARCH_API_PATH):
    if "http" in token_path:
        token = urlopen(token_path).read().decode("utf-8")
    else:
        with open(token_path, "r") as file:
            token = file.read()

    return token

pascal_to_snake

pascal_to_snake(name)
Source code in ResearchToolkit/notion/common.py
def pascal_to_snake(name):
    return "_".join(re.sub(r"([A-Z])", r" \1", name).split()).lower()

get_avaliable_filter_ops

get_avaliable_filter_ops(property_name: str)
Source code in ResearchToolkit/notion/filter.py
def get_avaliable_filter_ops(property_name: str):

    none_type = type(None)

    text_filter_ops = {
        "equals": str,
        "does_not_equal": str,
        "contains": str,
        "does_not_contain": str,
        "starts_with": str,
        "ends_with": str,
        "is_empty": bool,
        "is_not_empty": bool,
    }

    number_filter_ops = {
        "equals": (int, float),
        "does_not_equal": (int, float),
        "greater_than": (int, float),
        "less_than": (int, float),
        "greater_than_or_equal_to": (int, float),
        "less_than_or_equal_to": (int, float),
        "is_empty": bool,
        "is_not_empty": bool,
    }

    checkbox_filter_ops = {"equals": bool, "does_not_equal": bool}

    select_filter_ops = {
        "equals": str,
        "does_not_equal": str,
        "is_empty": bool,
        "is_not_empty": bool,
    }

    multi_select_filter_ops = {
        "contains": str,
        "does_not_contain": str,
        "is_empty": bool,
        "is_not_empty": bool,
    }

    date_filter_ops = {
        "equals": str,
        "before": str,
        "after": str,
        "on_or_before": str,
        "is_empty": bool,
        "is_not_empty": bool,
        "on_or_after": str,
        "past_week": none_type,
        "past_month": none_type,
        "this_week": none_type,
        "next_week": none_type,
        "next_month": none_type,
        "next_year": none_type,
    }

    files_filter_ops = {
        "is_empty": bool,
        "is_not_empty": bool,
    }

    return {
        "title": text_filter_ops,
        "rich_text": text_filter_ops,
        "url": text_filter_ops,
        "email": text_filter_ops,
        "phone_number": text_filter_ops,
        "number": number_filter_ops,
        "checkbox": checkbox_filter_ops,
        "select": select_filter_ops,
        "multi_select": multi_select_filter_ops,
        "status": select_filter_ops,
        "date": date_filter_ops,
        "people": multi_select_filter_ops,
        "files": files_filter_ops,
        "relation": multi_select_filter_ops,
    }[property_name]

register

register(cls, name)
Source code in ResearchToolkit/notion/property.py
def register(cls, name):
    PROPERTIES[name] = cls
    return cls