Why cannot I not create an object like this in Python? - python

Question about objects in python. I have created the following object....
class http(object):
def __init__(self):
self._resource = None
self._response = None
#property
def resource(self):
return self._resource
#resource.setter
def resource(self, value):
self._resource = "http://127.0.0.1:8000/%s" % value
def get(self, resource=None):
self.resource = resource
self._response = requests.get(self.resource)
return self._response
Init does not need anything at this stage so I was hoping I could create the object like this....
content = http.get("users/")
but it won't let me do this, instead I have to pass use the syntax http() but pass nothing...
content = http().get("users/")
which seems silly if I don't pass anything to __init__. I'm wondering how the a Python package like requests achieves the following syntax....
requests.get('https://api.github.com/user')
without doing this...
requests().get('https://api.github.com/user')
why, what does requests package do different?

Requests defines some extra methods that create an instance of Requests.request behind the scenes. You can do the same thing for your http class.
class http(object):
def get(self, resource=None):
self.resource = resource
self._response = requests.get(self.resource)
return self._response
def get(resource=None):
temp_instance = http()
return temp_instance.get(resource)

Related

Create mock object with a member function that returns a class attribute

I want to patch requests.get to make my tests independent from network connections. The mocking method should return a Response object with valid json and status code. I created the mocking function which defines a new MockResponse class with everything I need. This solution works as intended. It is the commented out section.
However, pylint warned that the class only has one public function and I've been trying to remove that warning by creating a Mock Object with mock.Mock, however I can't seem to make it work. Is it possible to do this mocking without creating a "small" class?
EDIT: Waket Zheng improved my WebTools code with an edit, and used a property method ok - which I also have to mock and now I've got 2 class methods so the pylint warning does not show anymore.
EDIT TLDR: An edit to the question provided an alternative solution, however not the solution to my question.
Test:
class TestWebtools(TestCase):
VALID_TEST_CASES = [
('https://testurl.com/simple.json', {"value": "someValue"}, "someValue"),
('https://testurl.com/valueDoesNotExist.json', {}, ""),
('https://testurl.com/error1', None, ""),
]
def _mocked_requests_get(*args, **_):
# class MockResponse:
# def __init__(self, json_data, status_code):
# self.json_data = json_data
# self.status_code = status_code
#
# def json(self):
# return self.json_data
#
# #property
# def ok(self):
# return self.status_code == 200
MockResponse = mock.Mock()
MockResponse.json.return_value = MockResponse.json_data
for url, value, _ in TestWebtools.VALID_TEST_CASES:
if args[0] == url:
return MockResponse(json_data=value, status_code=200)
return MockResponse(json_data=None, status_code=404)
#mock.patch('requests.get', _mocked_requests_get)
def test_download_json(self):
for url, expected, _ in self.VALID_TEST_CASES:
self.assertEqual(expected, download_json(url))
WebTools:
def download_json(fromUrl: str) -> Optional[dict]:
response = requests.get(fromUrl, timeout=5)
if response.ok:
return response.json()
return None

Instantiate superclass before calling factory method

I'm trying to initialize a superclass before calling the subclass. Here is an example of what I'm trying to do:
class AbstractSourceParser(object):
def __init__(self, filepath):
self.source_type = get_type_from_filepath(filepath)
#staticmethod
def factory(source_type):
source_type = source_type.upper() if source_type else None
if source_type == SourceType.CSV.upper():
return CSVSourceParser()
class CSVSourceParser(AbstractSourceParser):
...
And then I want to be able to call it like this:
parser = AbstractSourceParser("/tmp/file.csv").factory(self.type)
I think what I'm writing above doesn't make sense in code, but basically I want to retrieve the factory method 'after' passing in some data to the super class. How would this be done?
Currently, what I'm doing is the following, which I think is quite ugly (if not possibly incorrect) --
>>> _parser = AbstractSourceParser("/tmp/file.csv")
>>> parser = _parser.factory(_parser.source_type)
You could make factory() a regular instance method, and let it do the work:
class AbstractSourceParser(object):
def __init__(self, filepath):
self.source_type = get_type_from_filepath(filepath)
def factory(self, source_type=None):
if source_type is None:
source_type = self.source_type
source_type = source_type.upper() if source_type else None
if source_type == SourceType.CSV.upper():
return CSVSourceParser()
So that if you want the source type defined in the parent constructor, you can call factory() with no arguments. But you can still provide a different source_type if you want.
Does that get at what you're asking?

How to dynamically add a reify property to a Python3 object

I'm trying to do some advanced wizardry and I don't completely understand the problem which is no doubt why I'm having trouble solving it.
If I do something super hacky and let the child (DailyPic) know about it's parent (Site) then I can make everything work, but I can't figure out how to dynamically do this just from Site.
I'm trying to dynamically add the fantastic reify (slightly modified) to DailyPic but have the DailyPic instance call a method on an instance of Site.
hacky but it works
class reify():
def __init__(self, wrapped, name=None):
self.wrapped = wrapped
if name is None:
from functools import update_wrapper
update_wrapper(self, wrapped)
else:
self.wrapped.__name__ = name
def __get__(self, inst, objtype=None):
if inst is None:
return self
val = self.wrapped(inst)
setattr(inst, self.wrapped.__name__, val)
return val
class Site:
def __init__(self):
self.counter = 0
def mk_filename(self, pic):
self.counter += 1
return f"{self.__class__.__name__}-{self.counter}.{pic.ext()}"
def save(self):
pic = DailyPic()
from functools import partial
pic._mk_filename = partial(self.mk_filename, pic)
return pic
class DailyPic:
def ext(self):
return 'gif' # simplified for example
#reify
def filename(self):
return self._mk_filename() # YUCK!!!
# works but ugly...
class Site1(Site): pass
class Site2(Site): pass
pic1 = Site1().save()
pic2 = Site2().save()
print(pic1.filename) # Site1-1
print(pic2.filename) # Site2-1
I'm trying to get to something like this:
class Site:
def save(self):
pic = DailyPic()
DailyPic.filename = reify(
functools.partial(lambda pic: self.mk_filename(pic)),
'filename'
)
return pic
# sorta works...
print(pic1.filename) # Site2-1 , should be Site1-1
print(pic2.filename) # Site2-2 , should be Site2-1
If an advanced wizard could chime in that would be fantastic!
unless you really, really, need it to be a property, just ignore reify and properties and set a function on each instance that overwrites itself when run once.
class Site:
def save(self):
pic = DailyPic()
def filename(pic_self):
val = self.mk_filename(pic_self)
pic_self.filename = lambda _: val
return val
pic.filename = filename
return pic
then it's just:
print(pic1.filename())
if you really want it to be a property you could always set pic._filename = filename and have a property on DailyPic that returns self._filename(). which is basically what you were doing to begin with.

Python decorator to limit a method to a particular class?

I've got a large library of Django apps that are shared by a handful of Django projects/sites. Within each project/site there is an option to define a 'Mix In' class that will be mixed in to one of the in-library base classes (which many models sub-class from).
For this example let's say the in-library base class is PermalinkBase and the mix-in class is ProjectPermalinkBaseMixIn.
Because so many models subclass from PermalinkBase, not all the methods/properities defined in ProjectPermalinkBaseMixIn will be utilitized by all of PermalinkBase's subclasses.
I'd like to write a decorator that can be applied to methods/properties within ProjectPermalinkBaseMixIn in order to limit them from running (or at least returning None) if they are accessed from a non-approved class.
Here's how I'm doing it now:
class ProjectPermalinkBaseMixIn(object):
"""
Project-specific Mix-In Class to `apps.base.models.PermalinkBase`
"""
def is_video_in_season(self, season):
# Ensure this only runs if it is being called from the video model
if self.__class__.__name__ != 'Video':
to_return = None
else:
videos_in_season = season.videos_in_this_season.all()
if self in list(videos_in_season):
to_return = True
else:
to_return False
return to_return
Here's how I'd like to do it:
class ProjectPermalinkBaseMixIn(object):
"""
Project-specific Mix-In Class to `apps.base.models.PermalinkBase`
"""
#limit_to_model('Video')
def is_video_in_season(self, season):
videos_in_season = season.videos_in_this_season.all()
if self in list(videos_in_season):
to_return = True
else:
to_return = False
return to_return
Is this possible with decorators? This answer helped me to better understand decorators but I couldn't figure out how to modify it to solve the problem I listed above.
Are decorators the right tool for this job? If so, how would I write the limit_to_model decorator function? If not, what would be the best way to approach this problem?
was looking at your problem and I think this might be an overcomplicated way to achieve what you are trying to do. However I wrote this bit of code:
def disallow_class(*klass_names):
def function_handler(fn):
def decorated(self, *args, **kwargs):
if self.__class__.__name__ in klass_names:
print "access denied to class: %s" % self.__class__.__name__
return None
return fn(self, *args, **kwargs)
return decorated
return function_handler
class MainClass(object):
#disallow_class('DisallowedClass', 'AnotherDisallowedClass')
def my_method(self, *args, **kwargs):
print "my_method running!! %s" % self
class DisallowedClass(MainClass): pass
class AnotherDisallowedClass(MainClass): pass
class AllowedClass(MainClass): pass
if __name__ == "__main__":
x = DisallowedClass()
y = AnotherDisallowedClass()
z = AllowedClass()
x.my_method()
y.my_method()
z.my_method()
If you run this bit of code on your command line the output will be something like:
access denied to class: DisallowedClass
access denied to class: AnotherDisallowedClass
my_method running!! <__main__.AllowedClass object at 0x7f2b7105ad50>
Regards

How to use the pyramid_traversalwrapper?

I'm new to pyramid as well as the traversal concept. I have a basic object model working with traversal however the objects are location un-aware, so reading up on pyramid documentation found on this page http://docs.pylonsproject.org/projects/pyramid/en/1.0-branch/narr/resources.html#location-aware it talks about using the pyramid_traversalwrapper.
Following the instruction I added the following lines to my main:
config = Configurator(root_factory=Root)
config.registry.registerAdapter(ModelGraphTraverser, (Interface,),
ITraverser)
The rest of my traversal tree objects look like this:
class Root(object):
def __init__(self, request):
pass
def __getitem__(self, key):
if key == 'users':
return UserList()
raise KeyError
class UserList():
def __getitem__(self, key):
users = {'a':None,'b':None, 'c':None}
if key in users:
return User()
raise KeyError
class User(object):
def __init__(self):
pass
def __getitem__(self, key):
if (key == 'channels'):
return Channels()
def GET(self):
return Response("got user")
When I ran the code it does seem to use the ModelGraphTraverser when resolving urls, however what do I have to do to make my model location-aware, as in knowing the __parent__ and __name__ and such? Do I have to add wrapper classes? If so how do I go about doing it? pyramid_traversalwrapper is supposed to make managing __parent__ and __name__ effortless, but I have no idea how to take advantage of it.
pyramid_traversalwrapper automatically sets the __name__ and __parent__ attributes of the objects while traversing (you would have to do this by hand otherwise).
This means that you can use these attributes of the objects in your views. Taking your example :
#view_config(context='Channels')
def some_view(context, request):
user = context.__parent__
userlist = user.__parent__
print user.__name__ # Prints a, b or c
print userlist.__name__ # Prints 'users'

Categories