I am doing map processing. I solved the maze and got the address of the turnings. Below is my result.
(28,136)
(122,136)
(344,391)
(548,493)
(548,191)
(344,191)
(122,391)
But the addresses are not in correct order. My expected output is:
28 136
122 136
122 391
344 391
344 191
548 191
549 493
MY program is below. I programmed to get direction also
for(i=1:tblob)
if (shape(i).order==1)
map(i).cen=shape(i).cen;
end
end
White=[255 255 255];
i=1;
order=1;
left=0;
right=0;
up=0;
down=0;
left(1)=0;
right(1)=0;
up(1)=0;
down(1)=0;
left(2)=0;
right(2)=0;
up(2)=0;
down(2)=0;
left(3)=0;
right(3)=0;
up(3)=0;
down(3)=0;
left(4)=0;
right(4)=0;
up(4)=0;
down(4)=0;
left(5)=0;
right(5)=0;
up(5)=0;
down(5)=0;
left(6)=0;
right(6)=0;
up(6)=0;
down(6)=0;
left(7)=0;
right(7)=0;
up(7)=0;
down(7)=0;
left(8)=0;
right(8)=0;
up(8)=0;
down(8)=0;
x=map(i).cen(1,:);
y=map(i).cen(2,:);
for(z=1:100)
xi=x+1;
xj=x-1;
yi=y+1;
yj=y-1;
colorvalxi=color(y,xi,RGB);
colorvalxi
colorvalxj=color(y,xj,RGB);
colorvalxj
colorvalyi=color(yi,x,RGB);
colorvalyi
colorvalyj=color(yj,x,RGB);
colorvalyj
if(i>1)
s=i-1;
else
s=1;
end
if (left(s)==0)
if(colorvalxi==White)
n=1;
end
else
if (right(s)==0)
if(colorvalxj==White)
n=2;
end
else
if(up(s)==0)
if (colorvalyi==White)
n=3;
end
else
if(down(s)==0)
if(colorvalyj==White)
n=4;
end
else
break;
end
end
end
end
switch(n)
case 1 %RIGHT
for(ks=1:1000)
color_val=color(y,x,RGB);
if(color_val==White)
x=x+1;
else
right(i)=1;
instruction(i)=1;
i=i+1;
x=x-1;
map(i).cen(1,1)=x;
map(i).cen(2,1)=y;
break;
end
end
case 2 %LEFT
for(ks=1:1000)
color_val==color(y,x,RGB)
if(color_val==White)
x=x-1;
else
left(i)=1;
instruction(i)=2;
i=i+1;
x=x+1;
map(i).cen(1,1)=x;
map(i).cen(2,1)=y;
break;
end
end
case 3 %DOWN
for(ks=1:1000)
color_val=color(y,x,RGB);
if(color_val==White)
y=y+1;
else
down(i)=1;
instruction(i)=3;
i=i+1;
y=y-1;
map(i).cen(1,1)=x;
map(i).cen(2,1)=y;
break;
end
end
case 4 %UPWARD
for(ks=1:1000)
color_val=color(y,x,RGB);
if(color_val==White)
y=y-1;
else
up(i)=1;
instruction(i)=4;
i=i+1;
y=y-1;
map(i).cen(1,1)=x;
map(i).cen(2,1)=y;
break;
end
end
end
end
Related
I try to transfer learn a LightningModule. The relevant part of the code is this:
class DeepFilteringTransferLearning(pl.LightningModule):
def __init__(self, chk_path = None):
super().__init__()
#init class members
self.prediction = []
self.label = []
self.loss = MSELoss()
#init pretrained model
self.chk_path = chk_path
model = DeepFiltering.load_from_checkpoint(chk_path)
backbone = model.sequential
layers = list(backbone.children())[:-1]
self.groundModel = Sequential(*layers)
#use the pretrained modell the same way to regress Lshall and neq
self.regressor = nn.Linear(64,2)
def forward(self, x):
self.groundModel.eval()
with torch.no_grad():
groundOut = self.groundModel(x)
yPred = self.regressor(groundOut)
return yPred
I save my model in a different, main file which relevant part is:
#callbacks
callbacks = [
ModelCheckpoint(
dirpath = "checkpoints/maxPooling16StandardizedL2RegularizedReproduceableSeeded42Ampl1ConvTransferLearned",
save_top_k=5,
monitor="val_loss",
),
]
#trainer
trainer = pl.Trainer(gpus=[1,2],strategy="dp",max_epochs=150,logger=wandb_logger,callbacks=callbacks,precision=32,deterministic=True)
trainer.fit(model,train_dataloaders=trainDl,val_dataloaders=valDl)
After try to load the modell from checkpoint like this:
chk_patH = "path/to/transfer_learned/model"
standardizedL2RegularizedL1 = DeepFilteringTransferLearning("path/to/model/trying/to/use/for/transfer_learning").load_from_checkpoint(chk_patH)
I got the following error:
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
~/anaconda3/envs/skimageTrial/lib/python3.6/site-packages/torch/serialization.py in _check_seekable(f)
307 try:
--> 308 f.seek(f.tell())
309 return True
AttributeError: 'NoneType' object has no attribute 'seek'
During handling of the above exception, another exception occurred:
AttributeError Traceback (most recent call last)
<ipython-input-6-13f5fd0c7b85> in <module>
1 chk_patH = "checkpoints/maxPooling16StandardizedL2RegularizedReproduceableSeeded42Ampl1/epoch=4-step=349.ckpt"
----> 2 standardizedL2RegularizedL1 = DeepFilteringTransferLearning("checkpoints/maxPooling16StandardizedL2RegularizedReproduceableSeeded42Ampl2/epoch=145-step=10219.ckpt").load_from_checkpoint(chk_patH)
~/anaconda3/envs/skimageTrial/lib/python3.6/site-packages/pytorch_lightning/core/saving.py in load_from_checkpoint(cls, checkpoint_path, map_location, hparams_file, strict, **kwargs)
154 checkpoint[cls.CHECKPOINT_HYPER_PARAMS_KEY].update(kwargs)
155
--> 156 model = cls._load_model_state(checkpoint, strict=strict, **kwargs)
157 return model
158
~/anaconda3/envs/skimageTrial/lib/python3.6/site-packages/pytorch_lightning/core/saving.py in _load_model_state(cls, checkpoint, strict, **cls_kwargs_new)
196 _cls_kwargs = {k: v for k, v in _cls_kwargs.items() if k in cls_init_args_name}
197
--> 198 model = cls(**_cls_kwargs)
199
200 # give model a chance to load something
~/whistlerProject/gitHub/whistler/mathe/gwInspired/deepFilteringTransferLearning.py in __init__(self, chk_path)
34 #init pretrained model
35 self.chk_path = chk_path
---> 36 model = DeepFiltering.load_from_checkpoint(chk_path)
37 backbone = model.sequential
38 layers = list(backbone.children())[:-1]
~/anaconda3/envs/skimageTrial/lib/python3.6/site-packages/pytorch_lightning/core/saving.py in load_from_checkpoint(cls, checkpoint_path, map_location, hparams_file, strict, **kwargs)
132 checkpoint = pl_load(checkpoint_path, map_location=map_location)
133 else:
--> 134 checkpoint = pl_load(checkpoint_path, map_location=lambda storage, loc: storage)
135
136 if hparams_file is not None:
~/anaconda3/envs/skimageTrial/lib/python3.6/site-packages/pytorch_lightning/utilities/cloud_io.py in load(path_or_url, map_location)
31 if not isinstance(path_or_url, (str, Path)):
32 # any sort of BytesIO or similiar
---> 33 return torch.load(path_or_url, map_location=map_location)
34 if str(path_or_url).startswith("http"):
35 return torch.hub.load_state_dict_from_url(str(path_or_url), map_location=map_location)
~/anaconda3/envs/skimageTrial/lib/python3.6/site-packages/torch/serialization.py in load(f, map_location, pickle_module, **pickle_load_args)
579 pickle_load_args['encoding'] = 'utf-8'
580
--> 581 with _open_file_like(f, 'rb') as opened_file:
582 if _is_zipfile(opened_file):
583 # The zipfile reader is going to advance the current file position.
~/anaconda3/envs/skimageTrial/lib/python3.6/site-packages/torch/serialization.py in _open_file_like(name_or_buffer, mode)
233 return _open_buffer_writer(name_or_buffer)
234 elif 'r' in mode:
--> 235 return _open_buffer_reader(name_or_buffer)
236 else:
237 raise RuntimeError(f"Expected 'r' or 'w' in mode but got {mode}")
~/anaconda3/envs/skimageTrial/lib/python3.6/site-packages/torch/serialization.py in __init__(self, buffer)
218 def __init__(self, buffer):
219 super(_open_buffer_reader, self).__init__(buffer)
--> 220 _check_seekable(buffer)
221
222
~/anaconda3/envs/skimageTrial/lib/python3.6/site-packages/torch/serialization.py in _check_seekable(f)
309 return True
310 except (io.UnsupportedOperation, AttributeError) as e:
--> 311 raise_err_msg(["seek", "tell"], e)
312 return False
313
~/anaconda3/envs/skimageTrial/lib/python3.6/site-packages/torch/serialization.py in raise_err_msg(patterns, e)
302 + " Please pre-load the data into a buffer like io.BytesIO and"
303 + " try to load from it instead.")
--> 304 raise type(e)(msg)
305 raise e
306
AttributeError: 'NoneType' object has no attribute 'seek'. You can only torch.load from a file that is seekable. Please pre-load the data into a buffer like io.BytesIO and try to load from it instead.
which I can't resolve.
I try to this according to the available tutorials on the official page of pytorch lightning here. I can't figure it out what I miss.
Could somebody point me in the right direction?
I have a method that returns image size based upon the users selection and now I want to add another condition to my case statement. It is not setting the correct image size when I call the method again after my system call doing pdfinfo if the user chose STANDARD it should be 1250x1075 but it does not even do my case statement, it directly goes to else and sets 1728x1075
This is what I've tried
205 def FaxCall.set_image_size(resolution, pdf_size=nil)
206 case resolution
207 when STANDARD && (pdf_size != LEGAL_PDF_SIZE)]
208 image="1728x1075"
209 when FINE && pdf_size != LEGAL_PDF_SIZE
210 image="1728x2150"
211 when SUPERFINE && pdf_size != LEGAL_PDF_SIZE
212 image="1728x4300"
213 when [STANDARD, (pdf_size === LEGAL_PDF_SIZE)]
214 image="1250x1720"
215 when FINE && pdf_size == LEGAL_PDF_SIZE
216 image="1700x2800"
217 when SUPERFINE && pdf_size == LEGAL_PDF_SIZE
218 image="3400x5572"
219 else
220 image="1728x1075"
221 end
222 return image
223 end
This is where I call my method
135 def FaxCall.prepare_doc(in_file,out_file,res=STANDARD)
139 image = FaxCall.set_image_size(res)
140 res = STANDARD unless RESOLUTION_OPTIONS.values.include?(res)
145 if ext.eql?("pdf")
146 pdf_size = `pdfinfo "#{in_file}" | grep 'Page size:'`.gsub(/Page size:\s*\b/, '').chomp
147 if pdf_size == LEGAL_PDF_SIZE
148 image = FaxCall.set_image_size(res,pdf_size)
STANDARD && (pdf_size != LEGAL_PDF_SIZE), FINE && pdf_size != LEGAL_PDF_SIZE, SUPERFINE && pdf_size != LEGAL_PDF_SIZE, FINE && pdf_size == LEGAL_PDF_SIZE, and SUPERFINE && pdf_size == LEGAL_PDF_SIZE are all booleans, but resolution is a String, so they will never match.
[STANDARD, (pdf_size === LEGAL_PDF_SIZE)] is an Array. An Array will never match a String.
So, therefore, none of your cases will ever match, and you will always fall into the else case.
I'd create an array of hashes...
RES_MAP = [{res: STANDARD, legal: false, image: "1728x1075"},
{res: FINE, legal: false , image: "1728x2150"},
{res: SUPERFINE, legal: false , image: "1728x4300"},
{res: STANDARD, legal: true, image: "1250x1720"},
{res: FINE, legal: true , image: "1700x2800"},
{res: SUPERFINE, legal: true , image: "3400x5572"}]
and then change FaxCall.set_image_size(resolution, pdf_size=nil) to look up the matching hash and grab the image size.
def FaxCall.set_image_size(resolution, pdf_size)
is_legal = (pdf_size == LEGAL_PDF_SIZE)
match_res = RES_MAP.select{ |r| r[:res] == resolution && r[:legal] == is_legal}.first
return match_res.present? : match_res[:image] ? "1728x1075"
end
Easier to read and to add both more map values and extra criteria.
That's because STANDARD and ELSE have the same image size.
207 when STANDARD && (pdf_size != LEGAL_PDF_SIZE)]
208 image="1728x1075"
219 else
220 image="1728x1075"
See what I mean ?
#Jörg has explained the problem with your code. You might consider writing your method as follows.
DEFAULT_IMAGE_SIZE = "1728x1075"
def FaxCall.set_image_size(resolution, pdf_size=nil)
case pdf_size
when LEGAL_PDF_SIZE
case resolution
when STANDARD then "1250x1720"
when FINE then "1700x2800"
when SUPERFINE then "3400x5572"
else DEFAULT_IMAGE_SIZE
end
else
case resolution
when STANDARD then "1728x1075"
when FINE then "1728x2150"
when SUPERFINE then "1728x4300"
else DEFAULT_IMAGE_SIZE
end
end
end
I can get AOB from 4 bytes value (DWORD) using this function on Cheat Engine Lua:
local bt = dwordToByteTable(1075734118)
for i, v in ipairs(bt) do
print(i, string.format('%02x', v))
end
result = [[
1 66
2 66
3 1e
4 40
]]
but I want the result as '66 66 1e 40'.
How set the regex for this?.
If I have a table like this:
cd = {
1075734118,
1075734118,
1075996262,
1076953088,
1076651622,
1076953088,
1076835123
}
How I get AOB for each item on the table with output as no.1?
Found solution:
cd = { 1075734118, 1075734118, 1075996262, 1076953088, 1076651622, 1076953088, 1076835123 }
function byte2aob(b) return type(b)=='number' and b<256 and b>=0 and string.format('%02X',b) or '??' end
function aob2byte(a) a = tonumber(a,16) return type(a)=='number' and a <256 and a>=0 and a or -1 end
function imap(t,f) local s={} for i=1,#t do s[i]=f(t[i]) end return s end
function n2bt(n,t) t=type(t)=='string' and t or 'dword' return rawget(_G,t..'ToByteTable')(n) end
function t2aob(t,sep) return table.concat(imap(t,byte2aob),type(sep)=='string' and sep or ' ') end
function n2aob(n,t) return t2aob(n2bt(n,t)) end
for i = 1, #cd do
print(n2aob(cd[i],'dword'))
end
result = [[
66 66 1E 40
66 66 1E 40
66 66 22 40
00 00 31 40
66 66 2C 40
00 00 31 40
33 33 2F 40
]]
Try this code:
print((string.format("%08x",1075734118):reverse():gsub("(.)(.)","%2%1 ")))
I have rspec tests defined in my app but they are taking ages!
In my whole app, I have 438 tests running in 37 minutes. That's only 10 tests per minute.
I use Guard for rspec, Spork so I think it should be much faster. there must be something wrong going on.
For example, the rspec test on the model 'Prize' is taking 13 minutes for 134 tests. It is terribly slow! Here is my spec for Prize:
require 'spec_helper'
describe Prize do
let(:admin_user) { FactoryGirl.create(:admin_user) }
before(:each) do
#attr = {
prize_name: "lorem ipsum",
prize_short_description_for_modals: "yokoko gygy gygy",
prize_long_description_for_rules_and_user_account: "longer better longer better longer better",
prize_detailed_webpage_url: "http://www.example.com",
prize_image_url: "http://www.example2.com",
prize_image_alt:"French",
prize_type: "Jackpot prize",
prize_initial_stock_quantity: 100,
prize_remaining_stock_quantity: 5,
prize_unit_certified_market_value: 450,
prize_date_for_certified_market_value: 2.days.from_now,
prize_displayed_value_on_website: 456,
prize_require_additional_user_info: true,
prize_max_nb_days_for_claiming: 24,
prize_expiry_date: 75.days.from_now,
prize_category: "computer",
prize_sourcer_company_name: "Nefertiti",
prize_sourcer_contact_point_name: "Gentle Man",
prize_sourcer_contact_point_direct_phone: "01 45 67 68 77",
prize_sourcer_contact_point_email: "gentle.man#example.com",
prize_sourcer_how_to_contact_details: "From 9 TO 5pm, Mon. to Fri.",
prize_sourcer_crm_profile_url: "http://www.example3com",
prize_fully_stocked_validated: true,
# admin_user_id: 1,
# as: :admin_user
}
end
it { should respond_to(:prize_name) }
it { should respond_to(:prize_short_description_for_modals) }
it { should respond_to(:prize_long_description_for_rules_and_user_account) }
it { should respond_to(:prize_detailed_webpage_url) }
it { should respond_to(:prize_image_url) }
it { should respond_to(:prize_image_alt) }
it { should respond_to(:prize_type) }
it { should respond_to(:prize_initial_stock_quantity) }
it { should respond_to(:prize_remaining_stock_quantity) }
it { should respond_to(:prize_unit_certified_market_value) }
it { should respond_to(:prize_date_for_certified_market_value) }
it { should respond_to(:prize_displayed_value_on_website) }
it { should respond_to(:prize_require_additional_user_info) }
it { should respond_to(:prize_max_nb_days_for_claiming) }
it { should respond_to(:prize_expiry_date) }
it { should respond_to(:prize_category) }
it { should respond_to(:prize_sourcer_company_name) }
it { should respond_to(:prize_sourcer_contact_point_name) }
it { should respond_to(:prize_sourcer_contact_point_direct_phone) }
it { should respond_to(:prize_sourcer_contact_point_email) }
it { should respond_to(:prize_sourcer_how_to_contact_details) }
it { should respond_to(:prize_sourcer_crm_profile_url) }
it { should respond_to(:prize_fully_stocked_validated) }
it { should respond_to(:admin_user_id) }
it { should respond_to(:deal_id) }
# its(:admin_user) { should == admin_user }
# it { should be_valid }
# it "should create a new instance given a valid attribute" do
# prize.create!(#attr)
# end
# -- Active Records Tests --------------------------------------------------------
describe "tests on prize's active record" do
it { should belong_to(:admin_user).with_foreign_key('admin_user_id') }
it { should belong_to(:deal) }
end
# Tests on Mass-Assginement
describe "tests on prize's attributes mass assignement" do
it { should allow_mass_assignment_of(:prize_name) }
it { should allow_mass_assignment_of(:prize_short_description_for_modals) }
it { should allow_mass_assignment_of(:prize_long_description_for_rules_and_user_account) }
it { should allow_mass_assignment_of(:prize_detailed_webpage_url) }
it { should allow_mass_assignment_of(:prize_image_url) }
it { should allow_mass_assignment_of(:prize_image_alt) }
it { should allow_mass_assignment_of(:prize_type) }
it { should allow_mass_assignment_of(:prize_initial_stock_quantity) }
it { should allow_mass_assignment_of(:prize_remaining_stock_quantity) }
it { should allow_mass_assignment_of(:prize_unit_certified_market_value) }
it { should allow_mass_assignment_of(:prize_date_for_certified_market_value) }
it { should allow_mass_assignment_of(:prize_displayed_value_on_website) }
it { should allow_mass_assignment_of(:prize_require_additional_user_info) }
it { should allow_mass_assignment_of(:prize_max_nb_days_for_claiming) }
it { should allow_mass_assignment_of(:prize_expiry_date) }
it { should allow_mass_assignment_of(:prize_category) }
it { should allow_mass_assignment_of(:prize_sourcer_company_name) }
it { should allow_mass_assignment_of(:prize_sourcer_contact_point_name) }
it { should allow_mass_assignment_of(:prize_sourcer_contact_point_email) }
it { should allow_mass_assignment_of(:prize_sourcer_contact_point_direct_phone) }
it { should allow_mass_assignment_of(:prize_sourcer_how_to_contact_details) }
it { should allow_mass_assignment_of(:prize_sourcer_crm_profile_url) }
it { should allow_mass_assignment_of(:prize_fully_stocked_validated) }
it { should_not allow_mass_assignment_of(:admin_user_id) }
it { should_not allow_mass_assignment_of(:deal_id) }
it { should allow_mass_assignment_of(:admin_user_id).as(:admin_user) }
it { should allow_mass_assignment_of(:deal_id).as(:admin_user) }
end
# -- Controller Tests --------------------------------------------------------
describe "tests on prize's controllers" do
end
# -- Models Tests --------------------------------------------------------
describe "tests on prize's models validations for prize_name" do
it { should validate_presence_of(:prize_name) }
it { should_not allow_value(" ").for(:prize_name) }
it "should reject prize with names that are too long" do
long = "a" * 101
hash = #attr.merge(:prize_name => long)
Prize.new(hash).should have(1).error_on(:prize_name)
end
it "should reject prize with names that are too short" do
short = "a" * 4
hash = #attr.merge(:prize_name => short)
Prize.new(hash).should have(1).error_on(:prize_name)
end
end
describe "tests on prize's models validations for prize_short_description_for_modals" do
it { should validate_presence_of(:prize_short_description_for_modals) }
it { should_not allow_value(" ").for(:prize_short_description_for_modals) }
it "should reject attribute that are too long" do
long = "a" * 301
hash = #attr.merge(:prize_short_description_for_modals => long)
Prize.new(hash).should have(1).error_on(:prize_short_description_for_modals)
end
it "should reject attribute that are too short" do
short = "a" * 9
hash = #attr.merge(:prize_short_description_for_modals => short)
Prize.new(hash).should have(1).error_on(:prize_short_description_for_modals)
end
end
describe "tests on prize's models validations for prize_long_description_for_rules_and_user_account" do
it { should validate_presence_of(:prize_long_description_for_rules_and_user_account) }
it { should_not allow_value(" ").for(:prize_long_description_for_rules_and_user_account) }
it "should reject attribute that are too long" do
long = "a" * 10001
hash = #attr.merge(:prize_long_description_for_rules_and_user_account => long)
Prize.new(hash).should have(1).error_on(:prize_long_description_for_rules_and_user_account)
end
it "should reject attribute that are too short" do
short = "a" * 9
hash = #attr.merge(:prize_long_description_for_rules_and_user_account => short)
Prize.new(hash).should have(1).error_on(:prize_long_description_for_rules_and_user_account)
end
end
describe "tests on prize's models validations for prize_detailed_webpage_url" do
it { should validate_presence_of(:prize_detailed_webpage_url) }
it { should_not allow_value(" ").for(:prize_detailed_webpage_url) }
it { should_not allow_value("string but not url").for(:prize_detailed_webpage_url) }
end
describe "tests on prize's models validations for prize_image_url" do
it { should validate_presence_of(:prize_image_url) }
it { should validate_uniqueness_of(:prize_image_url).case_insensitive }
it { should_not allow_value(" ").for(:prize_image_url) }
it { should_not allow_value("stringbutnoturl").for(:prize_image_url) }
end
describe "tests on prize's models validations for prize_image_alt" do
it { should validate_presence_of(:prize_image_alt) }
it { should_not allow_value(" ").for(:prize_image_alt) }
it "should reject attribute that are too long" do
long = "a" * 31
hash = #attr.merge(:prize_image_alt => long)
Prize.new(hash).should have(1).error_on(:prize_image_alt)
end
end
describe "tests on prize's models validations for prize_type" do
it { should validate_presence_of(:prize_type) }
it { should_not allow_value(" ").for(:prize_type) }
it { should ensure_inclusion_of(:prize_type).in_array(PRIZE_TYPES) }
end
describe "tests on prize's models validations for prize_initial_stock_quantity" do
it { should validate_presence_of(:prize_initial_stock_quantity) }
it { should_not allow_value(" ").for(:prize_initial_stock_quantity) }
it { should validate_numericality_of(:prize_initial_stock_quantity).only_integer }
it { should validate_numericality_of(:prize_initial_stock_quantity).is_greater_than_or_equal_to(1) }
end
describe "tests on prize's models validations for prize_unit_certified_market_value" do
it { should validate_presence_of(:prize_unit_certified_market_value) }
it { should_not allow_value(" ").for(:prize_unit_certified_market_value) }
it { should validate_numericality_of(:prize_unit_certified_market_value).only_integer }
it { should validate_numericality_of(:prize_unit_certified_market_value).is_greater_than_or_equal_to(1) }
it { should validate_numericality_of(:prize_unit_certified_market_value).is_less_than_or_equal_to(1000000) }
end
describe "tests on prize's models validations for prize_date_for_certified_market_value" do
it { should validate_presence_of(:prize_date_for_certified_market_value) }
it { should_not allow_value(Time.zone.today - 1).for(:prize_date_for_certified_market_value).on(:create) } # has to be at least today
end
describe "tests on prize's models validations for prize_require_additional_user_info" do
it { should validate_presence_of(:prize_require_additional_user_info) }
it { should ensure_inclusion_of(:prize_require_additional_user_info).in_array(%w(true false)) }
end
describe "tests on prize's models validations for prize_max_nb_days_for_claiming" do
it { should validate_presence_of(:prize_max_nb_days_for_claiming) }
it { should_not allow_value(" ").for(:prize_max_nb_days_for_claiming) }
it { should validate_numericality_of(:prize_max_nb_days_for_claiming).only_integer }
it { should validate_numericality_of(:prize_max_nb_days_for_claiming).is_greater_than_or_equal_to(7) }
it { should validate_numericality_of(:prize_max_nb_days_for_claiming).is_less_than_or_equal_to(90) }
end
describe "tests on prize's models validations for prize_expiry_date" do
it { should_not allow_value(Time.zone.today - 1).for(:prize_expiry_date).on(:create) } # has to be at least today
end
describe "tests on prize's models validations for prize_category" do
it { should validate_presence_of(:prize_category) }
it { should_not allow_value(" ").for(:prize_category) }
it { should ensure_inclusion_of(:prize_category).in_array(PRIZE_CATEGORIES) }
end
describe "tests on prize's models validations for prize_sourcer_company_name" do
it "should reject attribute that are too long" do
long = "a" * 101
hash = #attr.merge(:prize_sourcer_company_name => long)
Prize.new(hash).should have(1).error_on(:prize_sourcer_company_name)
end
it "should reject attribute that are too short" do
short = "a" * 2
hash = #attr.merge(:prize_sourcer_company_name => short)
Prize.new(hash).should have(1).error_on(:prize_sourcer_company_name)
end
end
describe "tests on prize's models validations for prize_sourcer_contact_point_name" do
it { should validate_presence_of(:prize_sourcer_contact_point_name) }
it { should_not allow_value(" ").for(:prize_sourcer_contact_point_name)}
it "should reject attribute that are too long" do
long = "a" * 101
hash = #attr.merge(:prize_sourcer_contact_point_name => long)
Prize.new(hash).should have(1).error_on(:prize_sourcer_contact_point_name)
end
it "should reject attribute that are too short" do
short = "a" * 2
hash = #attr.merge(:prize_sourcer_contact_point_name => short)
Prize.new(hash).should have(1).error_on(:prize_sourcer_contact_point_name)
end
end
describe "tests on prize's models validations for prize_sourcer_contact_point_direct_phone" do
context "if prize_sourcer_contact_point_name present" do # test when sourcer is present
before { subject.stub(:prize_sourcer_company_name?) { true } }
it { should validate_presence_of(:prize_sourcer_contact_point_direct_phone) }
it { should_not allow_value(" ").for(:prize_sourcer_contact_point_direct_phone) }
end
context "if prize_sourcer_contact_point_name not present" do # test when sourcer is not present
before { subject.stub(:prize_sourcer_company_name?) { false } }
it { should_not validate_presence_of(:prize_sourcer_contact_point_direct_phone) }
end
it "should reject attribute that are too long" do
long = "a" * 21
hash = #attr.merge(:prize_sourcer_contact_point_direct_phone => long)
Prize.new(hash).should have(1).error_on(:prize_sourcer_contact_point_direct_phone)
end
it "should reject attribute that are too short" do
short = "a" * 3
hash = #attr.merge(:prize_sourcer_contact_point_direct_phone => short)
Prize.new(hash).should have(1).error_on(:prize_sourcer_contact_point_direct_phone)
end
end
describe "tests on prize's models validations for prize_sourcer_contact_point_email" do
context "if prize_sourcer_contact_point_name present" do # test when sourcer is present
before { subject.stub(:prize_sourcer_company_name?) { true } }
it { should validate_presence_of(:prize_sourcer_contact_point_email) }
it { should_not allow_value(" ").for(:prize_sourcer_contact_point_email) }
it { should_not allow_value("blah").for(:prize_sourcer_contact_point_email) } # need to include format with #
end
context "if prize_sourcer_contact_point_name not present" do # test when sourcer is not present
before { subject.stub(:prize_sourcer_company_name?) { false } }
it { should_not validate_presence_of(:prize_sourcer_contact_point_email) }
end
it "should reject attribute that are too long" do
long = "a#" * 51
hash = #attr.merge(:prize_sourcer_contact_point_email => long)
Prize.new(hash).should have(1).error_on(:prize_sourcer_contact_point_email)
end
end
describe "tests on prize's models validations for prize_sourcer_how_to_contact_details" do
context "if prize_sourcer_contact_point_name present" do # test when sourcer is present
before { subject.stub(:prize_sourcer_company_name?) { true } }
it { should validate_presence_of(:prize_sourcer_how_to_contact_details) }
it { should_not allow_value(" ").for(:prize_sourcer_how_to_contact_details) }
end
context "if prize_sourcer_contact_point_name not present" do # test when sourcer is not present
before { subject.stub(:prize_sourcer_company_name?) { false } }
it { should_not validate_presence_of(:prize_sourcer_how_to_contact_details) }
end
it "should reject attribute that are too long" do
long = "a" * 501
hash = #attr.merge(:prize_sourcer_how_to_contact_details => long)
Prize.new(hash).should have(1).error_on(:prize_sourcer_how_to_contact_details)
end
it "should reject attribute that are too short" do
short = "a" * 3
hash = #attr.merge(:prize_sourcer_how_to_contact_details => short)
Prize.new(hash).should have(1).error_on(:prize_sourcer_how_to_contact_details)
end
end
describe "tests on prize's models validations for prize_sourcer_crm_profile_url" do
context "if sourcer present" do # test when sourcer is present
before { subject.stub(:prize_sourcer_company_name?) { true } }
it { should validate_presence_of(:prize_sourcer_crm_profile_url) }
it { should_not allow_value(" ").for(:prize_sourcer_crm_profile_url) }
it { should_not allow_value("stringbuturl").for(:prize_sourcer_crm_profile_url) }
end
context "if sourcer not present" do # test when sourcer is not present
before { subject.stub(:prize_sourcer_company_name?) { false } }
it { should_not validate_presence_of(:prize_sourcer_crm_profile_url) }
end
end
describe "tests on prize's models validations for prize_fully_stocked_validated" do
# it { should validate_presence_of(:prize_fully_stocked_validated) }
# it { should ensure_inclusion_of(:prize_fully_stocked_validated).in_array(%w(true false)) }
end
describe "tests on prize's models validations for admin_user_id" do
it { should validate_presence_of(:admin_user_id) }
it { should_not allow_mass_assignment_of(:admin_user_id) }
it { should allow_mass_assignment_of(:admin_user_id).as(:admin_user) }
it { should validate_numericality_of(:admin_user_id) }
end
describe "tests on prize's models validations for deal_id" do
it { should validate_presence_of(:deal_id) }
it { should_not allow_mass_assignment_of(:deal_id) }
it { should allow_mass_assignment_of(:deal_id).as(:admin_user) }
it { should validate_numericality_of(:deal_id) }
end
end
I have adjusted Garbage collector(http://makandracards.com/makandra/950-speed-up-rspec-by-deferring-garbage-collection) but it almost had no effect.
class DeferredGarbageCollection
DEFERRED_GC_THRESHOLD = (ENV['DEFER_GC'] || 10.0).to_f
##last_gc_run = Time.now
def self.start
GC.disable if DEFERRED_GC_THRESHOLD > 0
end
def self.reconsider
if DEFERRED_GC_THRESHOLD > 0 && Time.now - ##last_gc_run >= DEFERRED_GC_THRESHOLD
GC.enable
GC.start
GC.disable
##last_gc_run = Time.now
end
end
end
I use https://github.com/tmm1/perftools.rb to assess the time spent and understand why it takes so long. Here is the analysis by perftools
Total: 533 samples
45 8.4% 8.4% 45 8.4% garbage_collector
38 7.1% 15.6% 40 7.5% String#gsub
35 6.6% 22.1% 35 6.6% String#=~
20 3.8% 25.9% 20 3.8% Hash#initialize_copy
15 2.8% 28.7% 29 5.4% Enumerable#inject
14 2.6% 31.3% 201 37.7% I18n::Backend::Base#translate
13 2.4% 33.8% 203 38.1% Kernel#catch
13 2.4% 36.2% 18 3.4% URI::Parser#make_regexp
12 2.3% 38.5% 12 2.3% PG::Connection#async_exec
10 1.9% 40.3% 483 90.6% Array#map
9 1.7% 42.0% 18 3.4% ActiveRecord::DynamicMatchers#respond_to?
9 1.7% 43.7% 9 1.7% Hash#has_key?
9 1.7% 45.4% 9 1.7% String#gsub!
7 1.3% 46.7% 7 1.3% Class#logger
7 1.3% 48.0% 7 1.3% Regexp#match
6 1.1% 49.2% 12 2.3% #<Module:0x00000002cbf5a0>#normalize_key
6 1.1% 50.3% 64 12.0% ActiveModel::Translation#human_attribute_name
6 1.1% 51.4% 6 1.1% Kernel#is_a?
6 1.1% 52.5% 7 1.3% Kernel.Float
6 1.1% 53.7% 6 1.1% Regexp#===
5 0.9% 54.6% 209 39.2% #<Module:0x00000002cbf5a0>#translate
5 0.9% 55.5% 282 52.9% ActiveModel::Errors#generate_message
5 0.9% 56.5% 5 0.9% Array#concat
5 0.9% 57.4% 47 8.8% Hash#each
5 0.9% 58.3% 5 0.9% I18n::Config#backend
5 0.9% 59.3% 18 3.4% Kernel#dup
5 0.9% 60.2% 10 1.9% MonitorMixin#mon_synchronize
4 0.8% 61.0% 6 1.1% #<Module:0x00000002cbf5a0>#config
4 0.8% 61.7% 24 4.5% #<Module:0x00000002cbf5a0>#normalize_keys
4 0.8% 62.5% 4 0.8% ActiveRecord::Translation#lookup_ancestors
4 0.8% 63.2% 4 0.8% Hash#delete
4 0.8% 64.0% 6 1.1% Hash#except!
4 0.8% 64.7% 4 0.8% Hash#values_at
4 0.8% 65.5% 51 9.6% I18n::Backend::Simple::Implementation#lookup
4 0.8% 66.2% 4 0.8% Kernel#require
4 0.8% 67.0% 4 0.8% Kernel#respond_to?
4 0.8% 67.7% 4 0.8% String#intern
3 0.6% 68.3% 3 0.6% #<Module:0x00000002cbf5a0>#normalized_key_cache
3 0.6% 68.9% 6 1.1% #<Module:0x007f8a0cd5fdc0>#__temp__
3 0.6% 69.4% 10 1.9% ActiveRecord::ConnectionAdapters::PostgreSQLAdapter#extract_pg_identifier_from_name
3 0.6% 70.0% 42 7.9% ActiveSupport::LogSubscriber#call
3 0.6% 70.5% 3 0.6% Array#-
3 0.6% 71.1% 9 1.7% Hash#merge
3 0.6% 71.7% 123 23.1% I18n::Backend::Base#default
3 0.6% 72.2% 8 1.5% I18n::MissingTranslation::Base#initialize
3 0.6% 72.8% 3 0.6% IO#write
3 0.6% 73.4% 3 0.6% Kernel#throw
3 0.6% 73.9% 480 90.1% RSpec::Core::Example#run
3 0.6% 74.5% 3 0.6% Regexp#initialize
3 0.6% 75.0% 3 0.6% String#%
3 0.6% 75.6% 7 1.3% Time#minus_with_coercion
2 0.4% 76.0% 22 4.1% ActiveModel::Validations::UrlValidator#validate_each
2 0.4% 76.4% 20 3.8% ActiveRecord::LogSubscriber#sql
2 0.4% 76.7% 3 0.6% ActiveSupport::LogSubscriber#color
2 0.4% 77.1% 2 0.4% ActiveSupport::Notifications::Fanout#listeners_for
2 0.4% 77.5% 4 0.8% Arel::Visitors::Visitor#visit
2 0.4% 77.9% 10 1.9% Array#collect
2 0.4% 78.2% 2 0.4% Array#flatten!
2 0.4% 78.6% 2 0.4% Array#hash
2 0.4% 79.0% 2 0.4% Class#configurations
2 0.4% 79.4% 7 1.3% Class#match
2 0.4% 79.7% 17 3.2% Hash#except
2 0.4% 80.1% 2 0.4% Logger::SimpleFormatter#call
2 0.4% 80.5% 2 0.4% Marshal.dump_without_mocks
2 0.4% 80.9% 63 11.8% Module#interpolate
2 0.4% 81.2% 361 67.7% Prize#_run__2501234485523728663__validate__1858047214644115366__callbacks
2 0.4% 81.6% 2 0.4% Symbol#to_s
2 0.4% 82.0% 2 0.4% Thread#[]
2 0.4% 82.4% 2 0.4% Time#initialize
1 0.2% 82.6% 2 0.4% #<Module:0x00000002cbf5a0>#handle_exception
1 0.2% 82.7% 1 0.2% ActiveModel::Errors#[]
1 0.2% 82.9% 280 52.5% ActiveModel::Errors#add
1 0.2% 83.1% 278 52.2% ActiveModel::Errors#normalize_message
1 0.2% 83.3% 67 12.6% ActiveModel::Name#human
1 0.2% 83.5% 364 68.3% ActiveModel::Validations::Callbacks#run_validations!
1 0.2% 83.7% 8 1.5% ActiveModel::Validations::NumericalityValidator#parse_raw_value_as_a_number
1 0.2% 83.9% 149 28.0% ActiveModel::Validations::PresenceValidator#validate
1 0.2% 84.1% 4 0.8% ActiveRecord::Associations::JoinDependency#initialize
1 0.2% 84.2% 5 0.9% ActiveRecord::AttributeMethods#respond_to?
1 0.2% 84.4% 1 0.2% ActiveRecord::AttributeMethods::BeforeTypeCast#read_attribute_before_type_cast
1 0.2% 84.6% 4 0.8% ActiveRecord::AttributeMethods::Dirty#write_attribute
1 0.2% 84.8% 1 0.2% ActiveRecord::AttributeMethods::Write#type_cast_attribute_for_write
1 0.2% 85.0% 62 11.6% ActiveRecord::ConnectionAdapters::AbstractAdapter#log
1 0.2% 85.2% 69 12.9% ActiveRecord::ConnectionAdapters::PostgreSQLAdapter#disable_referential_integrity
1 0.2% 85.4% 1 0.2% ActiveRecord::ConnectionAdapters::PostgreSQLAdapter#quote
1 0.2% 85.6% 1 0.2% ActiveRecord::ConnectionAdapters::PostgreSQLColumn#type_cast_with_extended_types
1 0.2% 85.7% 1 0.2% ActiveRecord::ExplainSubscriber#call
1 0.2% 85.9% 1 0.2% ActiveRecord::QueryMethods#where
1 0.2% 86.1% 1 0.2% ActiveRecord::Result#hash_rows
1 0.2% 86.3% 1 0.2% ActiveRecord::Scoping::ClassMethods#current_scope=
1 0.2% 86.5% 5 0.9% ActiveRecord::SpawnMethods#except
1 0.2% 86.7% 30 5.6%
The whole file is here if necessary: https://docs.google.com/document/d/16F38guxjBVFpu8Xp1rwK14TWREPcM3wtiLvfBGG7NB0/edit?usp=sharing
I read a few articles on how to improve time, but I would like first to understand why it is so slow (30 minutes!) and then I could pick the right test optimization techniques.
It seems like it's using most of the time generating the error messages for your validations. You could try to optimize that, but if what you're looking for is a simple speedup, you can just stub that whole part of the process. I would just stub ActiveModel::Errors#generate_message with "error message", which should save a lot of processing time.
ActiveModel::Errors.any_instance.stub(:generate_message).and_return('error message')
I'm currently using Declarative Authorization on my application, and trying to catch Exceptions from type Authorization::NotAuthorized.
I have an Entity that has a category. Depending on the role a user can create a new category when creating this entity. At my :before_validation callback I assign the category and want to be able to catch the authorization exception in case he doesn't have permission.
I could check it's role and make a conditional instruction, but then would have to write all the roles.
Exception is being thrown, but I'm not able to catch it, at the "new" instruction.
Code follows:
# Model
before_validation :set_category
def category_name
#category_name ||= category.name unless category.nil?
#category_name
end
def category_name=(name)
name.strip!
name.downcase!
#category_name = name
end
def set_category
if #category_name and not company.blank?
lookup_category = company.categories.not_deleted.find_by_name(#category_name)
begin
category = lookup_category.blank? ? company.categories.new(:name => #category_name) : lookup_category
rescue Authorization::NotAuthorized
errors.add(:category, I18n.t('activerecord.errors.messages.exclusion'))
end
end
end
# Controller
def create
#ticket = current_user.created_tickets.new(params[:ticket])
if #ticket.save # Line 88
...
Exception stack trace:
Authorization::NotAuthorized (No matching rules found for create for #<User id: 36,..."> (roles [:Requester], privileges [:create], context :categories).):
/Library/Ruby/Gems/1.8/gems/declarative_authorization-0.4.1/lib/declarative_authorization/authorization.rb:168:in `permit!'
/Library/Ruby/Gems/1.8/gems/declarative_authorization-0.4.1/lib/declarative_authorization/in_model.rb:131:in `using_access_control'
/Library/Ruby/Gems/1.8/gems/after_commit-1.0.7/lib/after_commit/connection_adapters.rb:12:in `transaction'
/Library/Ruby/Gems/1.8/gems/after_commit-1.0.7/lib/after_commit/connection_adapters.rb:12:in `transaction'
app/controllers/tickets_controller.rb:88:in `create'
Debugger goes inside the block:
# Debugger
lookup_category = company.categories.not_deleted.find_by_name(#category_name)
(rdb:3) list
[275, 284] in /Users/Pedro/projects/trunk/app/models/ticket.rb
275
276 def set_category
277 if #category_name and not self.company.blank?
278 begin
279 debugger
=> 280 lookup_category = company.categories.not_deleted.find_by_name(#category_name)
281 self.category = lookup_category.blank? ? company.categories.new(:name => #category_name) : lookup_category
282 rescue Authorization::NotAuthorized
283 self.errors.add(:category, I18n.t('activerecord.errors.messages.exclusion'))
284 end
(rdb:3) n
/Users/Pedro/projects/trunk/app/models/ticket.rb:281
self.category = lookup_category.blank? ? company.categories.new(:name => #category_name) : lookup_category
(rdb:3) list
[276, 285] in /Users/Pedro/projects/trunk/app/models/ticket.rb
276 def set_category
277 if #category_name and not self.company.blank?
278 begin
279 debugger
280 lookup_category = company.categories.not_deleted.find_by_name(#category_name)
=> 281 self.category = lookup_category.blank? ? company.categories.new(:name => #category_name) : lookup_category
282 rescue Authorization::NotAuthorized
283 self.errors.add(:category, I18n.t('activerecord.errors.messages.exclusion'))
284 end
285 end
(rdb:3) n
/Users/Pedro/.gem/ruby/1.8/gems/activesupport-2.3.8/lib/active_support/callbacks.rb:94
break result if terminator.call(result, object)
(rdb:3) list
[89, 98] in /Users/Pedro/.gem/ruby/1.8/gems/activesupport-2.3.8/lib/active_support/callbacks.rb
89 unless block_given?
90 send(enumerator) { |callback| callback.call(object) }
91 else
92 send(enumerator) do |callback|
93 result = callback.call(object)
=> 94 break result if terminator.call(result, object)
95 end
96 end
97 end
98
(rdb:3)
I'd say that it's breaking outside the begin ... rescue block and therefore not caught by the rescue. Try to do the same rescue on line 88 of your controller.
If you want to handle this in the validation process, maybe try to do a test on the roles or permissions of the user before creating your object instead of catching the exception that will only be thrown on creation.
It's not possible to catch the exception on a before callback. The best way I found to do this kind of validation is:
# Model code
begin
User.with_permissions_to :create, :categories # Raises exception if not permitted
... do whatever you want
rescue
... do whatever you want
end
Thanks for all the help