How to extend arrow? (and similar classes in modules) - python

I am trying to extend arrow and fail to understand how I can replicate the functionality of the base classes. This is probably due to a lack of clear understanding on how to extend classes in modules (emphasized by my arrow case - this is to say that the question is probably more general than limited to arrow only).
arrow basic usage:
>>> import arrow
>>> arrow.now()
<Arrow [2016-11-19T15:13:23.897484+01:00]>
>>> arrow.get("2016-11-20")
<Arrow [2016-11-20T00:00:00+00:00]>
I would like to add a when method which will return 'today', 'tomorrow' or 'later'. I first tried this:
import arrow
class MyArrow(arrow.Arrow):
def __init__(self, *args):
arrow.Arrow.__init__(self, *args)
def when(self):
now = arrow.now()
end_today = now.ceil('day')
end_tomorrow = now.replace(days=+1).ceil('day')
start_tomorrow = now.replace(days=+1).floor('day')
if self < end_today:
return 'today'
elif self < end_tomorrow:
return 'tomorrow'
else:
return 'later'
if __name__ == "__main__":
tom = MyArrow.now().replace(days=+1)
print(tom.when())
someday = MyArrow.get("2016-11-19")
The result is
tomorrow
Traceback (most recent call last):
File "D:/Dropbox/dev/domotique/testing/myarrow.py", line 23, in <module>
someday = MyArrow.get("2016-11-19")
AttributeError: type object 'MyArrow' has no attribute 'get'
So the first part worked, but get() failed. I had a look at the sources and get is in ArrowFactory. If I extend ArrowFactory instead of Arrow I will be able to use get but not now() anymore.
This is the point I am at loss: the "basic usage" above shows that I can call arrow.whatever_is_available no matter if it is defined in the class Arrow or ArrowFactory.
How does this work?
How can I add my when method to keep the rest of arrow as it is (and all its methods)?

Extensible for your own Arrow-derived types
is one of the highlighted features in Arrow's documentation, which actually demonstrates exactly how to create and use a custom Arrow subclass:
Factories
Use factories to harness Arrow’s module API for a custom Arrow-derived
type. First, derive your type:
>>> class CustomArrow(arrow.Arrow):
...
... def days_till_xmas(self):
...
... xmas = arrow.Arrow(self.year, 12, 25)
...
... if self > xmas:
... xmas = xmas.replace(years=1)
...
... return (xmas - self).days
Then get and use a factory for it:
>>> factory = arrow.Factory(CustomArrow)
>>> custom = factory.utcnow()
>>> custom
>>> <CustomArrow [2013-05-27T23:35:35.533160+00:00]>
>>> custom.days_till_xmas()
>>> 211
You can then call the .get, .now and .utcnow methods on the factory and get your custom subclass, with its .when method.
This is specific to dealing with Arrow and its module-level API; with simpler modules, you could just subclass their classes directly.

Related

Python3 script using SQLAlchemy returns object address vice string [duplicate]

I have a function below which I want to output lines of values relating to 'O', instead it prints the location of these values, how do I amend this? allReactions is an empty array initially. I've tried a number of ways to get around this but keep getting errors. Also I think my methods are less efficient than can be.
allReactions = []
reactionFile = "/Databases/reactionsDatabase.txt"
with open(reactionFile) as sourceFile:
for line in sourceFile:
if line[0] == "!" or len(line.strip()) == 0: continue
allReactions.append(Reaction(line, sourceType="Unified Data"))
def find_allReactions(allReactions, reactant_set):
reactant_set = set(reactant_set)
relevant_reactions = []
previous_reactant_count = None
while len(reactant_set) != previous_reactant_count:
previous_reactant_count = len(reactant_set)
for reaction in allReactions:
if set(reaction.reactants).issubset(reactant_set):
relevant_reactions.append(reaction)
reactant_set = reactant_set.union(set(reaction.products))
return relevant_reactions
print find_allReactions(allReactions, ["O"])
You are trying to print a list of Reaction objects. By default, python prints a class object's ID because it really doesn't have much to say about it. If you have control over the class definition, you can change that by adding __str__ and __repr__ method to the class.
>>> class C(object):
... pass
...
>>> print C()
<__main__.C object at 0x7fbe3af3f9d0>
>>> class C(object):
... def __str__(self):
... return "A C Object"
...
>>> print C()
A C Object
>>>
If you don't have control of the class... well, the author didn't implement a pretty view of the class. You could create subclasses with the methods or write a function to pull out the stuff you want.

Issues with 'self' argument and python requests module

Having an issue calling function dynamic_exit from class dynamic, called from an imported python file within the project file. Only including enough code to depict an efficient example of my issue.
Call example below:
from lib.core import dynamic
import ...
if requests.get(url).status_code != 200:
clear()
print(" xxxxx \n\n\n")
print("[ !! | Invalid URL ] Status code: {0}".format(
str(requests.get(url).status_code)))
time.sleep(1)
print("\n\n Please enter a valid URL.\nExiting...")
dynamic.dynamic_exit(self=dynamic())
time.sleep(3)
exit()
Lib.core contains:
class dynamic:
def __init__(self):
self.loadSwitch = False
self.analyzeSwitch = False
self.exitSwitch = False
def dynamic_load(self, loadSwitch=True):
self.loadSwitch = loadSwitch
done = False
for c in itertools.cycle(['[ | ]', '[ / ]', '[ - ]', '[ \\ ]']):
if done:
break
sys.stdout.write('\rLoading ' + c)
sys.stdout.flush()
time.sleep(0.1)
# Further along...
if dynamic.dynamic_analyze(): # Separate function -- Irrelevant
t = threading.Thread(target=dynamic_analyze())
t.start()
elif dynamic_exit(): # Separate function -- Irrelevant
t2 = threading.Thread(target=dynamic_exit())
t2.start()
else: # dynamic_load -- Example function
t3 = threading.Thread(target=dynamic_load())
t3.start()
sys.stdout.write('\r[ ✓ ] Process Complete ')
time.sleep(4.5)
done = True
loadSwitch = False
exitSwitch = False
analyzeSwitch = False
Lord, I know it's a mess. First time actually working with classes like this.
Error is as follows:
File "~/test-delete.py", line 11, in <module>
from lib.core import dynamic
File "~/lib/core.py", line 55, in <module>
if dynamic.dynamic_analyze():
TypeError: dynamic_analyze() missing 1 required positional argument: 'self'
The IDE is wanting more than a simple self parameter, it is recommending self=. So unsure of how to handle this.
Basically, need help under the context of the __init__ function and using the self parameter. Trying to call the function setting either exitSwitch, analyzeSwitch, or loadSwitch = True, ifswitch == True, perform either function dynamic_load, dynamic_exit, or dynamic_analyze. Post-completion, set all switches back to False.
The problem is that you are calling instance methods as if they are static methods. In other words, you call the methods as dynamic.dynamic_analyse() where dynamic is a reference to the class, not to an instance of that class.
So proceed as follows:
Name your class with PascalCase -- a common practice to distinguish classes from other things. So yours should be named Dynamic.
Create an instance and assign it to a variable. This one could actually get the name dynamic with lower case initial letter.
Don't pass an instance as argument when calling methods on the instance. Because in the notation a.b(), b will be called with the value for self set to a.
So define the class as:
class Dynamic:
def __init__(self):
self.loadSwitch = False
self.analyzeSwitch = False
self.exitSwitch = False
# ...etc.
Import the class and create an instance like this:
from lib.core import Dynamic
# ...
dynamic = Dynamic() # Create instance
# ...
if dynamic.dynamic_analyze(): # Call method on the instance
# ..etc
Your exit code should have:
dynamic.dynamic_exit() # No argument.
I cannot comment on the rest of your code, as it is hard to tell what it is doing. For instance, I do wonder why you call dynamic_analyse() twice... but this at least will solve the problem with the error you got.

How to make nested enum also have value

Consider the following code example:
from enum import Enum
class Location(Enum):
Outside = 'outside'
Inside = 'inside'
class Inside(Enum): # TypeError for conflicting names
Downstairs = 'downstairs'
Upstairs = 'upstairs'
How do I make Inside have the value 'inside' whilst also being a nested enum for accessing Downstairs and Upstairs?
Desired input:
print(Location.Inside)
print(Location.Inside.value)
print(Location.Inside.Downstairs)
print(Location.Inside.Downstairs.value)
Desired output:
Location.Inside
inside
Location.Inside.Downstairs
downstairs
UPDATE 1:
Some more context to my specific problem:
class Location(Enum):
Outside = 'outside'
Inside = 'inside'
class Inside(Enum): # TypeError for conflicting names
Downstairs = 'downstairs'
Upstairs = 'upstairs'
class Human:
def __init__(self, location):
self.location = location
def getLocationFromAPI():
# this function returns either 'inside' or 'outside'
# make calls to external API
return location # return location from api in str
def whereInside(human):
if human.location != Location.Inside:
return None
# here goes logic that determines if human is downstairs or upstairs
return locationInside # return either Location.Downstairs or Location.Upstairs
location_str = getLocationFromAPI() # will return 'inside' or 'outside'
location = Location(location_str) # make Enum
human = Human(location) # create human with basic location
if human.location == Location.Inside:
where_inside = whereInside(human)
human.location = where_inside # update location to be more precise
The problem is when I create the Human object I only know of a basic location, as in 'inside' or 'outside'. Only after that can I update the location to be more precise.
You can accomplish this by embedding an enum.Enum inside another like so: (just watch out for names conflicting)
from enum import Enum
class _Inside(Enum):
Downstairs = 'downstairs'
Upstairs = 'upstairs'
class Location(Enum):
Outside = 'outside'
Inside = _Inside
print(Location.Inside.value.Downstairs.value)
downstairs
it may be a bit late and the one who asked the question is no longer necessary, but I leave it here in case someone wants to take a look at it, and even if it has already been validated as one, although the same comment that it is not completely complete .
But I have been thinking about it and in the end I have solved it by looking at the same documentation XD.
You cannot extend classes of Enums, but you can extend methods, I have followed this way and the only thing I have done has been to override the new and init methods, the use case can be modified, this is only to nest enumerators.
from enum import Enum
class SuperNestedEnum(Enum):
def __new__(cls, *args):
obj = object.__new__(cls)
value = None
# Normal Enumerator definition
if len(args) == 1:
value = args[0]
# Have a tuple of values, first de value and next the nested enum (I will set in __init__ method)
if len(args) == 2:
value = args[0]
if value:
obj._value_ = value
return obj
def __init__(self, name, nested=None):
# At this point you can set any attribute what you want
if nested:
# Check if is an Enumerator you can comment this if. if you want another object
if isinstance(nested, EnumMeta):
for enm in nested:
self.__setattr__(enm.name, enm)
class Homework(Enum):
Task = "5"
class Subjects(SuperNestedEnum):
Maths = "maths"
English = "english"
Physics = "nested", Homework
class School(SuperNestedEnum):
Name = "2"
Subjects = "subjects", Subjects
Ignore the use case because it doesn't make sense, it's just an example
>>> School.Name
<School.Name: '2'>
>>> School.Subjects
<School.Subjects: 'subjects'>
>>> School.Subjects.value
'subjects'
>>> School.Subjects.Maths
<Subjects.Maths: 'maths'>
>>> School.Subjects.Physics.value
'nested'
>>> School.Subjects.Physics.Task
<Homework.Task: '5'>
>>> School.Subjects.Physics.Task.value
'5'
If anyone has similar issues and just wants a simple solution for the topic without patching any functions or additional imports for enums containing strings, follow these steps:
Create the value enums, in your lower hierarchy, like:
class __private_enum1__(str, enum.Enum):
VAL11 = "abc"
VAL12 = "def"
class enum2(str, enum.Enum):
VAL21 = "123"
VAL22 = "456"
Create a base class (a container) for these enums. Where you can either import the enums classes or simply directly acccess the enums.
class myValues:
VAL11 = __private_enum1__.VAL11
VAL12 = __private_enum1__.VAL12
VALS2X = enum2
Then you can access your values by:
print(myValues.VAL11.value)
print(myValues.VAL2X.VAL21.value)
.value is not necessary here but it shows that you both access the string inside the enum for passing it to other functions but also the enum itself, which is pretty neat. So basically, first create the values, then the structure. That way you have a class but it provides you the basic functionality of enums and you can nest them as deep as you want to without further imports.

How to create dynamic methods with python?

For my project I need to dynamically create custom (Class) methods.
I found out it is not so easy in Python:
class UserFilter(django_filters.FilterSet):
'''
This filter is used in the API
'''
# legacy below, this has to be added dynamically
#is_field_type1 = MethodFilter(action='filter_field_type1')
#def filter_field_type1(self, queryset, value):
# return queryset.filter(related_field__field_type1=value)
class Meta:
model = get_user_model()
fields = []
But it is giving me errors (and headaches...). Is this even possible?
I try to make the code between #legacy dynamic
One option to do this I found was to create the class dynamically
def create_filter_dict():
new_dict = {}
for field in list_of_fields:
def func(queryset, value):
_filter = {'stableuser__'+field:value}
return queryset.filter(**_filter)
new_dict.update({'filter_'+field: func})
new_dict.update({'is_'+field: MethodFilter(action='filter_'+field)})
return new_dict
meta_model_dict = {'model': get_user_model(), 'fields':[]}
meta_type = type('Meta',(), meta_model_dict)
filter_dict = create_filter_dict()
filter_dict['Meta'] = meta_type
UserFilter = type('UserFilter', (django_filters.FilterSet,), filter_dict)
However, this is giving me
TypeError at /api/v2/users/
func() takes 2 positional arguments but 3 were given
Does anyone know how to solve this dilemma?
Exception Value: 'UserFilter' object has no attribute 'is_bound'
You are getting this error because the class methods you are generating, are not bound to any class. To bound them to the class, you need to use setattr()
Try this on a console:
class MyClass(object):
pass
#classmethod
def unbound(cls):
print "Now I'm bound to ", cls
print unbound
setattr(MyClass, "bound", unbound)
print MyClass.bound
print MyClass.bound()
Traceback:
UserFilter = type('Foo', (django_filters.FilterSet, ), create_filter_dict().update({'Meta':type('Meta',(), {'model':
get_user_model(), 'fields':[]} )})) TypeError: type() argument 3 must
be dict, not None
Now, this is failing because dict.update() doesn't return the same instance, returns None. That can be fixed easily
class_dict = create_filter_dict()
class_dict.update({'Meta':type('Meta',(), {'model': get_user_model(), 'fields':[]})}
UserFilter = type('Foo', (django_filters.FilterSet, ), class_dict))
However, just look how messy that code looks. I recommend to you to try to be
clearer with the code you write even if it requires to write a few extra lines. In the long run, the code will be easier to maintain for you and your team.
meta_model_dict = {'model': get_user_model(), 'fields':[]}
meta_type = type('Meta',(), meta_model_dict)
filter_dict = create_filter_dict()
filter_dict['Meta'] = meta_type
UserFilter = type('Foo', (django_filters.FilterSet,), filter_dict)
This code might not be perfect but it is more readable than the original line of code you posted:
UserFilter = type('Foo', (django_filters.FilterSet, ), create_filter_dict().update({'Meta':type('Meta',(), {'model': get_user_model(), 'fields':[]})}))
And removes a complication on an already kinda difficult concept to grasp.
You might want to learn about metaclasses. Maybe you can overwrite the new method of a class. I can recommend you 1 or 2 posts about that.
Another option is that maybe you are not adding the filters correctly or in a way django doesn't expect? That would explain why you get no errors but none of your functions gets called.
You can use classmethod. Here is example how you can use it:
class UserFilter:
#classmethod
def filter_field(cls, queryset, value, field = None):
# do somthing
return "{0} ==> {1} {2}".format(field, queryset, value)
#classmethod
def init(cls,list_of_fields ):
for field in list_of_fields:
ff = lambda cls, queryset, value, field=field: cls.filter_field(queryset, value, field )
setattr(cls, 'filter_'+field, classmethod( ff ))
UserFilter.init( ['a','b'] )
print(UserFilter.filter_a(1,2)) # a ==> 1 2
print(UserFilter.filter_b(3,4)) # b ==> 3 4
You are asking for:
custom (Class) methods.
So we take an existing class and derive a subclass where you can add new methods or overwrite the methods of the original existing class (look into the code of the original class for the methods you need) like this:
from universe import World
class NewEarth(World.Earth):
def newDirectionUpsideDown(self,direction):
self.rotationDirection = direction
All the other Methods and features of World.Earth apply to NewEarth only you can now change the direction to make the world turn your new way.
To overwrite an existing method of a class is as as easy as this.
class NewEarth(World.Earth):
def leIitRain(self,amount): # let's assume leIitRain() is a standard-function of our world
return self.asteroidStorm(amount) #let's assume this is possible Method of World.Earth
So if someone likes a cool shower on earth he/she/it or whatever makes room for new development on the toy marble the burning way.
So have fun in your way learning python - and don't start with complicated things.
If I got you completely wrong - you might explain your problem in more detail - so more wise people than me can share their wisdom.

python, dynamically implement a class onthefly

this is related to python, dynamically implement a class onthefly.
when i restarted my pc, couldnt get back to add comments to the post - below is an example to explain what meant by save the class_with_the_methods_used
class bank(object):
def __init__(self, bal=0):
self.bal = bal
def deposit(self, amount):
self.bal+=amount
print self.bal
def debit(self, amt):
self.bal-=amt
print self.bal
bank.debit = debit
myacct = bank()
myacct.deposit(1000) # prints 1000
myacct.debit(99) # print 901
dir(myacct) # print [ ....'bal', 'debit', 'deposit']
then i used pickle and saved the object myacct
after saving, restarted my python and tried the commands below
>>> import pickle
>>> obj = pickle.load(open('bank.pkl'))
>>> dir(obj) # prints [....'bal', 'deposit']
note that 'debit' is not among the attributes . So my problem is how to make methods like 'debit' persistent?
Check out the new module (http://docs.python.org/library/new.html)
It has a lot of tools for doing things dynamically. The problem you are having is debit is not a instance method, it is just a normal function. Methods defined in classes are different than functions defined outside.
This is due to the way pickle dumps custom classes.
>>> class Bank(object):
... pass
...
>>> def debit(self, amt):
... print amt
...
>>> Bank.debit = debit
>>>
>>> acct = Bank()
>>> acct.debit
<bound method Bank.debit of <__main__.Bank object at 0x023B57D0>>
>>> import pickle
Look at the following:
>>> print pickle.dumps(acct)
ccopy_reg
_reconstructor
p0
(c__main__
Bank
p1
c__builtin__
object
p2
Ntp3
Rp4
.
You'll see that in fact the entire instance isn't pickled; instead, pickle simply records that it is an instance of Bank and recreates it by re-instantiating Bank. You will have to define a custom pickle protocol if you want to do this properly, which is complicated.

Categories

Resources