Last active
November 16, 2018 18:56
-
-
Save txomon/8b7b82b6e105d237a095ed27f2726465 to your computer and use it in GitHub Desktop.
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
# -*- coding: utf-8 -*- | |
from __future__ import absolute_import, division, print_function, unicode_literals | |
import string | |
from weakref import WeakKeyDictionary | |
class SafeDict(dict): | |
def __missing__(self, key): | |
return '{' + key + '}' | |
class GBQResource(str): | |
def __init__(self, value): | |
self.all_values = WeakKeyDictionary() | |
super(GBQResource, self).__init__(value) | |
self.default_value = value | |
self.project = self._dataset = self._table = None | |
values = value.split('.') | |
if len(values) not in (1, 2, 3): | |
raise ValueError('Resource needs to be {project}[.{dataset}[.{table}]]') | |
if len(values) == 1: | |
self.project, = values | |
elif len(values) == 2: | |
self.project, self._dataset = values | |
elif len(values) == 3: | |
self.project, self._dataset, self._table = values | |
def __get__(self, instance, owner): | |
if not self.all_values.get(instance): | |
obj = self.all_values[instance] = type(self)(self.default_value) | |
return obj | |
return self.all_values[instance] | |
def __set__(self, instance, value): | |
self.all_values[instance] = type(self)(value) | |
@property | |
def dataset(self): | |
if self._dataset: | |
return self._dataset | |
raise ValueError('Resource is only project, can not provide dataset') | |
@property | |
def table(self): | |
if self._table: | |
return self._table | |
raise ValueError('Resource is either project or dataset, can not provide table') | |
class CLASS(object): | |
def __new__(cls, *args, **kwargs): | |
fmt = string.Formatter() | |
obj = super(CLASS, cls).__new__(cls) | |
for key, value in kwargs.items(): | |
if hasattr(obj, key): | |
setattr(obj, key, value) | |
obj_attrs = {a: getattr(obj, a) for a in dir(obj) if a == a.upper()} | |
for i in range(5): # Four indirection levels | |
for attribute, value in obj_attrs.items(): | |
if not isinstance(value, (str, unicode)): | |
continue | |
obj_attrs[attribute] = fmt.vformat(value, (), SafeDict(obj_attrs)) | |
for attribute, value in obj_attrs.items(): | |
if not isinstance(value, (str, unicode)): | |
continue | |
assert '{' not in value, 'Attribute ' + attribute + ' failed with ' + value | |
assert '}' not in value, 'Attribute ' + attribute + ' failed with ' + value | |
setattr(obj, attribute, value) | |
return obj | |
FIELD = GBQResource('m.n.o') | |
a = CLASS(FIELD='z.x.y') | |
b = CLASS(FIELD='d.e.f') | |
c = CLASS() | |
print(a, a.FIELD, a.FIELD.table) | |
print(b, b.FIELD, b.FIELD.table) | |
print(c, c.FIELD, c.FIELD.table) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment